Create and Debug Tests
Testing can be a complex system itself. Depending on your test case, you may need to set up data before running each test or the test suite. A setup step can be creating a test user. Another step may be the cleanup after test runs. This document shows you how to create useful tests in Supercharge.
Create Tests
Supercharge comes with a base-test
utility that is a class you can build on. The suggested way to create tests in Supercharge is to write a class that extends the base-test
. A base test example looks like this:
const BaseTest = require('@supercharge/framework/base-test')
class TestCase extends BaseTest {
/**
* A passing test example.
*/
async testMethod (t) {
t.pass()
}
}
module.exports = new TestCase()
Each test method accepts the t
parameter from AVA. Use t
for assertions or to store context data for the test suite.
Export a new instance of the TestCase
class so that Supercharge knows how to handle it. Supercharge will pick up all test methods and pass them down to AVA for test runs. The following section shows you how to modify the handling of each test method using keywords.
Lifecycle Hooks
Lifecycle hooks are a powerful way to run methods before or after test cases. The supported lifecycle methods in Supercharge are:
before
: runs before all tests in the suitebeforeEach
: runs before each test caseafterEach
: runs after each test caseafter
: runs after all tests in the suitealwaysAfter
: runs after all tests in the suite, even if a test fails
The order of the lifecycle hooks above matches the execution plan in AVA.
Implement lifecycle hoooks as methods in your test class:
const BaseTest = require('@supercharge/framework/base-test')
class TestWithLifecycleHooks extends BaseTest {
async before (t) {}
async beforeEach (t) {}
async afterEach (t) {}
async after (t) {}
async alwaysAfter (t) {}
}
The alwaysAfter
hook will always run as soon as your tests complete. It will also run if your suite includes failing tests and makes it a good place for cleanup tasks.
Test Context
Lifecycle hooks are a common place to create dummy data for your tests. For example, if you need a user instance in each test method, you can create a fake user before each test and save it in the test context. The test context is available at t.context
.
const BaseTest = require('@supercharge/framework/base-test')
class ContextData extends BaseTest {
async beforeEach (t) {
t.context.user = await this.fakeUser()
}
async testMethod (t) {
const user = t.context.user
t.pass()
}
async alwaysAfter (t) {
await this.deleteUsers()
}
}
Each test method has access to the test context via the t
parameter. The context object is a convenient place if you need to pass data through the test suite.
Assertions
Each test method receives the t
parameter which makes assertions directly available.
const BaseTest = require('@supercharge/framework/base-test')
class Assertions extends BaseTest {
async assertions (t) {
t.is(1, 1)
// many more assertions
t.pass()
}
}
Here’s a list of available assertions:
t.pass()
: passing assertiont.fail()
: failing assertiont.truthy(value)
: assert thatvalue
is truthyt.falsy(value)
: assert thatvalue
is falsyt.true(value)
: assert thatvalue
istrue
t.false(value)
: assert thatvalue
isfalse
t.is(value, expected)
: assert thatvalue
is the same asexpected
t.not(value, expected)
: assert thatvalue
is not the same asexpected
t.deepEqual(value, expected)
: assert thatvalue
is deeply equal toexpected
t.notDeepEqual(value, expected)
: assert thatvalue
is not deeply equal toexpected
t.throws(fn, [expected])
: assert that an error is thrownt.throwsAsync(thrower, [expected])
: assert that an error is thrownt.notThrows(fn)
: assert that no error is thrown.t.notThrowsAsync(nonThrower)
: assert that no error is thrown. Like the.throwsAsync()
assertion, you must wait for the assertion to completet.regex(contents, regex)
: assert thatcontents
matchesregex
t.notRegex(contents, regex)
: assert thatcontents
does not matchregex
t.snapshot(expected)
: compareexpected
with a previously recorded snapshott.snapshot(expected, [options])
: snapshots are stored and assigned to a single test which requires unique test names. You can pass in a custom identifier via theoptions
object: { id: 'my-snapshot-id' }. Find our more details on snapshot testing in the AVA docs
Each assertion accepts a message
as the last parameter. The message is a nice way if you need to print an additional message for an assertion.
Here are examples for custom messages: t.pass('Successful assertion')
or t.is(1, 1, 'Yep, 1 is 1')
.
Run Specific Tests
In a large test class you might want to run only a subset of all test cases.
Prefix test methods with only
to run only these methods.
const BaseTest = require('@supercharge/framework/base-test')
class Only extends BaseTest {
async onlyTest (t) {
// this runs
}
async anotherTest (t) {
// this won’t
}
}
Notice: the “only” prefix is applicable in a single test file. Using npm test
will run all your test files which might cause a lot more tests to run than you want. If you want to run a single test, you should use the NPM command npm run test-single <testCase>
.
Skip Tests
Skipping tests allows you you to simply ignore these (failing) test cases.
Prefix test methods with skip
to skip these methods.
const BaseTest = require('@supercharge/framework/base-test')
class Skip extends BaseTest {
async skipTest (t) {
// skipped
}
async doNotSkip (t) {
// not skipped
}
}
Skipped tests are reported in the test result.
Notice: you cannot skip tests from inside the test method.
Tests as “Todo”
Planning out test cases (without writing them yet) can be easily with the “todo” modifier.
Prefix test methods with todo
to mark them as placeholders.
const BaseTest = require('@supercharge/framework/base-test')
class Todo extends BaseTest {
async todoTest (t) {
// marked as TODO
}
}
Test cases marked “todo” are reported in the test result.
Run Tests Serially
Tests in Supercharge run concurrently by default. Test cases that can't run concurrently can be marked to run serially.
Prefix test methods with serial
to run them sequentially before the concurrent test cases run.
const BaseTest = require('@supercharge/framework/base-test')
class Serial extends BaseTest {
async serialFirst (t) {
// runs first
}
async serialSecond (t) {
// runs second, after first finished
}
}
Unfortunately, you can’t combine the skip
, todo
and serial
modifier for a test. You can only use one of them. This method name is currently not available: serialTodoOnlyTest
.
Debug Tests
AVA runs tests in parallel using child processes. That’s why you need a workaround to attach a debugger to code in your tests.
Please follow the advice on debugging with AVA given in the readme. You’ll find tips for populare IDEs and editors, like WebStorm and Visual Studio Code.