Throughout most chapters, there are quizzes and exercises. These are a paid feature, but a comprehensive preview is available. This chapter explains how to get started with them.
Installation:
impatient-js-quiz.zip
Running the quiz app:
impatient-js-quiz/index.html
in a web browserTo install the exercises:
impatient-js-code.zip
README.txt
exercises/quizzes-exercises/first_module_test.mjs
All exercises in this book are tests that are run via the test framework AVA. This section gives a brief introduction.
Typical test code is split into two parts:
Take, for example, the following two files:
id.mjs
(code to be tested)id_test.mjs
(tests)The code itself resides in id.mjs
:
The key thing here is: everything you want to test must be exported. Otherwise, the test code can’t access it.
Don’t worry about the exact details of tests
You don’t need to worry about the exact details of tests: They are always implemented for you. Therefore, you only need to read them, but not write them.
The tests for the code reside in id_test.mjs
:
import test from 'ava'; // (A)
import {strict as assert} from 'assert'; // (B)
import {id} from './id.mjs'; // (C)
test('My test', t => { // (D)
assert.equal(id('abc'), 'abc'); // (E)
});
The core of this test file is line E – an assertion: assert.equal()
specifies that the expected result of id('abc')
is 'abc'
.
As for the other lines:
assert
lets us remain compatible with plain Node.js.test()
:
t
gives us access to AVA’s testing API (assertions etc.).To run the test, we execute the following in a command line:
npm t demos/quizzes-exercises/id_test.mjs
The t
is an abbreviation for test
. That is, the long version of this command is:
npm test demos/quizzes-exercises/id_test.mjs
Exercise: Your first exercise
The following exercise gives you a first taste of what exercises are like:
exercises/quizzes-exercises/first_module_test.mjs
Reading
You can postpone reading this section until you get to the chapters on asynchronous programming.
Writing tests for asynchronous code requires extra work: The test receives its results later and has to signal to AVA that it isn’t finished, yet, when it returns. The following subsections examine three ways of doing so.
If we call test.cb()
instead of test()
, AVA switches to callback-based asynchronicity. When we are done with our asynchronous work, we have to call t.end()
:
test.cb('divideCallback', t => {
divideCallback(8, 4, (error, result) => {
if (error) {
t.end(error);
} else {
assert.strictEqual(result, 2);
t.end();
}
});
});
If a test returns a Promise, AVA switches to Promise-based asynchronicity. A test is considered successful if the Promise is fulfilled and failed if the Promise is rejected.
test('dividePromise 1', t => {
return dividePromise(8, 4)
.then(result => {
assert.strictEqual(result, 2);
});
});
Async functions always return Promises. Therefore, an async function is a convenient way of implementing an asynchronous test. The following code is equivalent to the previous example.
test('dividePromise 2', async t => {
const result = await dividePromise(8, 4);
assert.strictEqual(result, 2);
// No explicit return necessary!
});
You don’t need to explicitly return anything: The implicitly returned undefined
is used to fulfill the Promise returned by this async function. And if the test code throws an exception then the async function takes care of rejecting the returned Promise.