nwb uses Karma as a test runner, with Webpack to bundle test code and a Babel plugin to instrument it for code coverage reporting.
Karma runs tests in Chrome, which must be installed on the machine the tests are running on.
To configure this, provide
karma.browsers
config
Mocha is configured as the default test framework - its BDD testing interface is available globally in tests.
To configure this, provide
karma.frameworks
config
A suitable reporter for Mocha is configured as the default if you don't configure the test framework, otherwise the Karma dots
reporter is used.
To configure this, provide
karma.reporters
config
expect v1 is made available by default for assertions and spies without having to install it in your own devDependencies
- just import it when you need it:
import expect from 'expect'
In the project skeletons created by nwb's new
and init
commands, the sample unit test is in a *.test.js
file in the tests/
directory.
However, the default configuration supports having tests in any file which ends with one of the following suffixes, anywhere underneath a src/
, test/
or tests/
directory:
.test.js
.spec.js
This supports having your tests in a separate top-level directory or co-located with the code they're testing, or both (e.g. co-located unit tests, separate integration tests).
To configure this, provide
karma.testFiles
config
This is an example of a minimal unit test which will run with nwb test
straight out of the box:
import expect from 'expect'
describe('Minimal unit test', () => {
it('informs the reader', () => {
expect('tautology').toEqual('tautology')
})
})
Default test Webpack config is configured to alias src
to the src/
directory, allowing you to write tests which use directory-independent import paths, no matter where you choose to put your test files.
If you're using a separate test directory, the src
alias allows you to organise your tests whichever way you want without having to adjust how you import the code to be tested, for example if you start out with a flat structure which you later want to organise using directories as the number of tests grows, by using the alias you won't have to change how you import the code being tested.
e.g., if the following directory structure exists in your project:
src/
components/
MyComponent.js
Then your tests can import this component like so:
import MyComponent from 'src/components/MyComponent'
If your tests are co-located with the modules they test, either as siblings or in __tests__
directories, tests will usually move too during any reorganisation, but you may find the src
alias useful for shared test utilities:
e.g. if you set up the following directory structure:
src/
__tests__/
utils.js
Then all your co-located tests can import shared utilities like so, no matter where they are in the tree, and the utilities will be excluded from code coverage:
import utils from src/__tests__/utils
If you need to run some code before any of your tests run, the recommended approach is to create a context module for Webpack to load and use karma.testContext
config to point to it.
You will need to use require.context()
in this module to specify which test files to run, e.g.:
// tests.webpack.js
let context = require.context('./src', true, /\.spec\.js$/)
context.keys().forEach(context)
// nwb.js
module.exports = {
karma: {
testContext: 'tests.webpack.js'
}
}
Note: if you provide karma.testContext
and your tests would not have been picked up by the [default test files][#test-files] config, you will also need to provide a suitable karma.testFiles
config so your tests can be excluded from code coverage.
Use a context module you need to configure testing libraries before running any tests. E.g. if you're using Enzyme to test some React code...
import Enzyme from 'enzyme'
import Adapter from 'enzyme-adapter-react-15'
Enzyme.configure({adapter: new Adapter()})
let context = require.context('./src', true, /\.spec\.js$/)
context.keys().forEach(context)
A Webpack context module is also a suitable place for before/after hooks which should apply to all tests.
For example, if you want to make use of Expect's spies to fail tests by default if any unexpected error logging is performed, you could use a context module like this:
import expect from 'expect'
beforeEach(() => {
expect.spyOn(console, 'error').andCall(msg => {
let expected = false
console.error.expected.forEach(about => {
if (msg.indexOf(about) !== -1) {
console.error.warned[about] = true
expected = true
}
})
if (expected) return
console.error.threw = true
throw new Error(msg)
})
console.error.expected = []
console.error.warned = Object.create(null)
console.error.threw = false
})
afterEach(() => {
let {threw, expected, warned} = console.error
console.error.restore()
if (!threw) {
expected.forEach(about => {
expect(warned[about]).toExist(`Missing expected warning: ${about}`)
})
}
})
let context = require.context('./src', true, /-test\.js$/)
context.keys().forEach(context)
Passing a --coverage
flag when running tests will generate a code coverage report in coverage/
.
Coverage will be measured automatically when your tests are run on Travis CI, or any other environment where a CONTINUOUS_INTEGRATION
environment variable is set to true
.
All project skeletons come with a .travis.yml
which will post coverage results to codecov.io and coveralls after a successful build.
node_modules/
, test files and test context modules are automatically excluded from code coverage.
Use karma.excludeFromCoverage
config to specify additional paths which should be excluded from coverage reporting.
By default, this is configured to ignore code in a few common directory conventions for test code:
[
'test/',
'tests/',
'src/**/__tests__/',
]