I was advised yesterday that using normal vanilla JavaScript for a kata might be of a benefit.
You might have come across the FizzBuzz kata before. Well FooBarQix is the grown up brother of that, resulting in numbers that look like:
FooBarBar, Qix, 197, Foo, 199, Bar**, Foo*, 2*2, Qix*Foo, Foo*, Bar*Bar, 2*6, Foo*Qix, 2*8
The requirements are:
- If the number is divisible by 3, write “Foo” instead of the number
- If the number is divisible by 5, add “Bar”
- If the number is divisible by 7, add “Qix”
- For each digit 3, 5, 7, add “Foo”, “Bar”, “Qix” in the digits order.
And after that’s complete, there’s one final requirement:
- We must keep a trace of 0 in numbers, each 0 must be replaced with char “*“
Attempting to do that without guidance gets quite tricky indeed. Try doing it without tests and you’re very likely to get things wrong, or to give up in the attempt, especially with the “*” requirement.
Getting started
We can start this off with a simple index.html page, that requests the code script and a test script.
<!DOCTYPE html>
<html>
<head>
<title>FooBarQix Kata</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>FooBarQix Kata - 2018-01-02</h1>
<script src="foobarqix.js"></script>
<script src="foobarqix.test.js"></script>
<script>
</script>
</body>
</html>
We’ll add something into style.css later, and we’ll also add some code in the script area to loop through some values and show them on the page, but that can occur after we have some values coming from the foobarqix() function.
Test with an expect function
Without using any external libraries, we can create our own custom-made expect function.
These can be made to be nice and colorful in the browser console, but the code can get to be a bit complex and bulky, so this is a fairly minimal approach instead that gets us going nice and quickly,
foobarqix.test.js
function expect(actual, expected, msg) {
console.log(msg);
if (actual !== expected) {
console.error(" Expected " + expected + " but got " + actual);
}
}
That’s all you need to get started with testing. Other things can be added on from here, which is why there’s a wide range of testing libraries out there, but just checking that one value equals another, is the core of testing.
First test
According to the rules on the page, the foobarqix() is to accept a string and to return a string.
The three laws of test-driven development are of good value to know, but I like to simplify them to:
- Write a failing test
- with the least code to make it pass
- then refactor
That forms a nice tight loop, that results in working code that works better and better each time.
We can start our first test by writing a simple test below the expect function in the test code.
foobarqix.test.js
expect(typeof foobarqix, "function", "The foobarqix function exists");
With the index.html page loaded and the browser console open, reloading the index page shows our first test in the console area.
The test fails, as it properly should do, and tells us that it expects a function. Let’s give it one.
foobarqix.js
function foobarqix() {
}
And on reloading the page, the test passes. This is a good first test as it helps to ensure that the filenames are all spelled correctly, and that everything is plumbed together properly.
I don’t want to have to reload the index page manually myself every time myself after every test and after writing code, so let’s have the page reload itself. That way when we save the file, the web page will automatically update and show us the result. I tried doing the update every 1 second but the flicker became too distracting, so 2 seconds seems about right.
function expect(actual, expected, msg) {
...
}
setTimeout(() => window.location = window.location, 2000);
Test for no input
The next test helps us to deal with no input to the function.
expect(foobarqix(), "", "No arguments should give us an empty string");
Then check the index.html page, to make sure that the console is correctly showing an error. If it doesn’t show an error then we are testing the wrong thing, and cannot know if the code that we write actually helped. Making the test pass helps us to know that our code has been beneficial.
In this case, we can return an empty string to make the test pass:
function foobarqix() {
return "";
}
We could carry on testing for things that shouldn’t occur, which is the thorns around the gold idea, but that’s something that can be done on a future project when there’s a more useful benefit to be gained in protecting people from bad behaviour.
Next up though, we’ll begin testing what the foobarqix() function is supposed to achieve.