• 4 hours
  • Easy

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 2/7/20

Test, code, repeat

In the last chapter, you wrote your first test, including little bits of nonsense code (likegame.roll, which technically doesn't exist anywhere yet). You did this in the  BowlingGameSpec.js file in the  spec folder.

It's time to write JavaScript code that accompanies the test! 💻 #JS4ever

Open the file you created called  BowlingGame.js  (in the  src  folder of your Jasmine directory).

 Reminder, here's the contents of your test file:

describe("Bowling game", function() {
    
    it("should properly calculate a gutter game", function() {
        game.roll(20, 0);
        expect(game.score()).toEqual(0);
    });
    
    it("should properly calculate a strike", function () {
        // test
    });
    
    it("should properly calculate a spare", function () {
        // test
    });
        
});

Running your test

You've written the test but haven't actually run it to see if it will pass or fail.

Of course, the test will fail at first because you haven't written any code to support it. In TDD, it's still important to see your test fail the first time though.

Open up the file called  SpecRunner.html  included in the Jasmine standalone package or in the files you downloaded at the beginning of the second course part. 

SpecRunner.html shows which tests pass and fail
SpecRunner.html shows which tests pass and fail

From the above test, we know we need to define multiple entities in our actual JavaScript code.

  • the idea of a  BowlingGame 

  • a function of rolling many times or at all, ex.  roll  and   rollMany 

  • the notion of a  game  

  • the notion of a  score 

For example, introduce the notion of a  BowlingGame   first. It's as simple as adding this to your  BowlingGame.js  file :

var BowlingGame = function() {
};

Remember, you're only coding just enough to make the test pass! Since your first error was the  BowlingGame   doesn't exist, all you did was add that.

Refresh the  SpecRunner.html  page. Now you'll see:

Running the test a second time
Running the test a second time

Ok,  game  isn't defined. Fair enough! Define it.

Since you'll need to define a new  game   for every test that is run (so as not to combine the results of multiple, separate games), we can do a bit of setup in the tests themselves.

Back in the  BowlingGameSpec  file, add a line above your tests saying to create a new instance of  BowlingGame   for each test, and assign it to a  game  variable. 

In  BowlingGameSpec (your test file):

describe("BowlingGame", function() {
	var game;

	beforeEach(function(){
		game = new BowlingGame();
	});
// ...

Save your changes, and refresh  SpecRunner.html  again.

Running the test a third time
Running the test a third time

You have another error now, which says  game.roll is not a function ("TypeError: game.roll is not a function").  

This means  BowlingGame   needs a function called  roll  that is more action-oriented. Define this in the code, rerun the test, and see what error you get next.

Do this enough times, and here's the code you might end up with. Even if this is your final code, code one step at a time! ☝️

Here's what  BowlingGame.js  looks like: 

var BowlingGame = function() {
    this.rolls = [];
    this.currentRoll = 0;
};

BowlingGame.prototype.roll = function(pins) {
    this.rolls[this.currentRoll++] = pins;
};

BowlingGame.prototype.score = function() {
    var score = 0;
    var frameIndex = 0;
    var self = this;

    function sumOfBallsInFrame() {
        return self.rolls[frameIndex] + self.rolls[frameIndex + 1];
    }

    for (var frame = 0; frame < 10; frame++) {
        score += sumOfBallsInFrame();
        frameIndex += 2;
    }
    return score;
};

And here's  BowlingGameSpec.js :

describe("BowlingGame", function() {
    var game;

    beforeEach(function(){
        game = new BowlingGame();
    });

    function rollMany (n, pins) {
        for (var i = 0; i < n; i++) {
            game.roll(pins)
        }
    }

    it("should handle a gutter game", function() {
        rollMany(20, 0);
        expect(game.score()).toEqual(0);
    });
    
    it("should properly calculate a strike", function () {
        // test
    });
    
    it("should properly calculate a spare", function () {
        // test
    });

});

 You've written enough code in your source and spec files to make your first test pass. Look at all that green in  SpecRunner.html ! ✅🍏📗💚

Your first test is passing!
Your first test is passing!

Only now can you attack writing the code for your second test:

it("should properly calculate a strike", function () {
    // test
});

You'll write code associated with rolling strikes and spares while making sure to not break your other code. You'll know you've broken something in a previous test if that test starts erroring, when previously it was passing. 

This is the classic TDD cycle.

  1. Write the basic test.

  2. Run the test.

  3. Write the simplest code to fix the first error.

  4. Rerun the test.

  5. Write the simplest code to fix the next error.

  6. Repeat until all the tests pass.

Nailed it!
Nailed it!

Next up, you'll get to put this workflow into practice in an activity: build a candy store! 🍬🍭🍫

Example of certificate of achievement
Example of certificate of achievement