Based on the application presented previously, we can start writing acceptance criteria that define investment:
Using the standalone distribution downloaded in the previous chapter, the first thing we need to do is create a new spec file. This file can be created anywhere, but it is a good idea to stick to a convention, and Jasmine already has a good one: specs should be in the /spec
folder. Create an InvestmentSpec.js
file and add the following lines:
describe("Investment", function() { });
The describe
function is a global Jasmine function used to define test contexts. When used as the first call in a spec, it creates a new test suite (a collection of test cases). It accepts two parameters, which are as follows:
Investment
function
that will contain all its specsThen, to translate the first acceptance criterion (given an investment, it should be of a stock) into a Jasmine spec (or test case), we are going to use another global Jasmine function called it
:
describe("Investment", function() { it("should be of a stock", function() { }); });
It also accepts two parameters, which are as follows:
should be of a stock
To run this spec, add it to the runner, as follows:
<!-- include spec files here... -->
<script type="text/javascript" src="spec/InvestmentSpec.js"></script>
Execute the spec by opening the runner on the browser. The following output can be seen:
It might sound strange to have an empty spec passing, but in Jasmine, as with other test frameworks, a failed assertion is required to make the spec fail.
An assertion (or expectation) is a comparison between two values that must result in a boolean value. The assertion is only considered a success if the result of the comparison is true.
In Jasmine, assertions are written using the global Jasmine function expect
, along with a matcher that indicates what comparison must be made with the values.
Regarding the current spec (it is expected that the investment is of a stock), in Jasmine this translates to the following code:
describe("Investment", function() {
it("should be of a stock", function() {
expect(investment.stock).toBe(stock);
});
});
Add the preceding highlighted code to the InvestmentSpec.js
file. The expect
function takes only one parameter, which defines the actual value, or in other words, what is going to be tested—investment.stock
—and expects the chaining call to a matcher function, which in this case is toBe
. That defines the expected value, stock
, and the comparison method to be performed (to be the same).
Behind the scenes, Jasmine makes a comparison to check whether the actual value (investment.stock
) and expected value (stock
) are the same, and if they are not, the test fails.
With the assertion written, the spec that previously passed has now failed, as shown in the following screenshot:
This spec failed because, as the error message states, investment is not defined
.
The idea here is to do only what the error is indicating us to do, so although you might feel the urge to write something else, for now let's just create this investment
variable with an Investment
instance in the InvestmentSpec.js
file, as follows:
describe("Investment", function() {
it("should be of a stock", function() {
var investment = new Investment();
expect(investment.stock).toBe(stock);
});
});
Don't worry that the Investment()
function doesn't exist yet; the spec is about to ask for it on the next run, as follows:
You can see that the error has changed to Investment is not defined
. It now asks for the Investment
function. So, create a new Investment.js
file in the src
folder and add it to the runner, as shown in the following code:
<!-- include source files here... --> <script type="text/javascript" src="src/Investment.js"></script>
To define Investment
, write the following constructor function in the Investment.js
file inside the src
folder:
function Investment () {};
This makes the error change. It now complains about the missing stock
variable, as shown in the following screenshot:
One more time, we feed the code it is asking for into the InvestmentSpec.js
file, as shown in the following code:
describe("Investment", function() {
it("should be of a stock", function() {
var stock = new Stock();
var investment = new Investment();
expect(investment.stock).toBe(stock);
});
});
The error changes again; this time it is about the missing Stock
function:
Create a new file in the src
folder, name it Stock.js
, and add it to the runner. Since the Stock
function is going to be a dependency of Investment
, we should add it just before Investment.js
:
<!-- include source files here... -->
<script type="text/javascript" src="src/Stock.js"></script>
<script type="text/javascript" src="src/Investment.js"></script>
Write the Stock
constructor function to the Stock.js
file:
function Stock () {};
Finally, the error is about the expectation, as shown in the following screenshot:
To fix this and complete this exercise, open the Investment.js
file inside the src
folder, and add the reference to the stock
parameter:
function Investment (stock) {
this.stock = stock;
};
In the spec file, pass stock
as a parameter to the Investment
function:
describe("Investment", function() {
it("should be of a stock", function() {
var stock = new Stock();
var investment = new Investment(stock);
expect(investment.stock).toBe(stock);
});
});
Finally, you will have a passing spec:
This exercise was meticulously conducted to show how a developer works by feeding the spec with what it wants when doing test-first development.