Commit a9fe3c0a authored by Robert Knight's avatar Robert Knight

Reduce test startup time when running a subset of tests

Change the way that the `FILTER` option works in `make test FILTER=<pattern>`
(or equivalently the `--grep` option if using `gulp test --grep
<pattern>`) to control which test files are executed rather than
matching test descriptions.

This enables the test configuration function in `src/karma.config.js` to
limit the test bundle to only the matching files and their dependencies.
This can make the initial bundling much faster and bundle updates (when
using `make servetests`) somewhat faster.

On my system, `make test FILTER=menu-item` takes ~40s on master but only
~7s on this branch.

As before, the filename filter can be combined with the `.only` modifier
on `description` or `it` calls to do more fine-grained filtering of
tests within matching files.

 - Change `--grep` option to gulp to filter test files as part of the
   test bundling process instead of setting the `grep` mocha option

 - Make `make servetests` accept a `FILTER` argument for consistency
   with `make test`

 - Simplify code in gulpfile.js for launching Karma

 - Update documentation for `make test`
parent b0cd5378
...@@ -29,7 +29,11 @@ endif ...@@ -29,7 +29,11 @@ endif
.PHONY: servetests .PHONY: servetests
servetests: node_modules/.uptodate servetests: node_modules/.uptodate
ifdef FILTER
node_modules/.bin/gulp test-watch --grep $(FILTER)
else
node_modules/.bin/gulp test-watch node_modules/.bin/gulp test-watch
endif
.PHONY: lint .PHONY: lint
lint: node_modules/.uptodate lint: node_modules/.uptodate
......
...@@ -110,8 +110,7 @@ Hypothesis uses Karma and mocha for testing. To run all the tests once, run: ...@@ -110,8 +110,7 @@ Hypothesis uses Karma and mocha for testing. To run all the tests once, run:
make test make test
You can filter the tests which are run by running ``make test FILTER=<pattern>``. You can filter the tests which are run by running ``make test FILTER=<pattern>``.
See the documentation for Mocha's Only test files matching ``<pattern>`` will be executed.
`grep <https://mochajs.org/#g---grep-pattern>`_ option.
To run tests and automatically re-run them whenever any source files change, run: To run tests and automatically re-run them whenever any source files change, run:
...@@ -121,7 +120,7 @@ To run tests and automatically re-run them whenever any source files change, run ...@@ -121,7 +120,7 @@ To run tests and automatically re-run them whenever any source files change, run
This command will also serve the tests on localhost (typically `http://localhost:9876`) This command will also serve the tests on localhost (typically `http://localhost:9876`)
so that break points can be set and the browser's console can be used for interactive so that break points can be set and the browser's console can be used for interactive
debugging. debugging.
Code Style Code Style
......
...@@ -36,15 +36,12 @@ let liveReloadChangedFiles = []; ...@@ -36,15 +36,12 @@ let liveReloadChangedFiles = [];
function parseCommandLine() { function parseCommandLine() {
commander commander
// Test configuration. .option(
// See https://github.com/karma-runner/karma-mocha#configuration '--grep [pattern]',
.option('--grep [pattern]', 'Run only tests matching a given pattern') 'Run only tests where filename matches a pattern'
)
.parse(process.argv); .parse(process.argv);
if (commander.grep) {
gulpUtil.log(`Running tests matching pattern /${commander.grep}/`);
}
return { return {
grep: commander.grep, grep: commander.grep,
}; };
...@@ -384,37 +381,20 @@ gulp.task( ...@@ -384,37 +381,20 @@ gulp.task(
) )
); );
function runKarma(baseConfig, opts, done) { function runKarma({ singleRun }, done) {
// See https://github.com/karma-runner/karma-mocha#configuration
const cliOpts = {
client: {
mocha: {
grep: taskArgs.grep,
},
},
};
const karma = require('karma'); const karma = require('karma');
new karma.Server( new karma.Server(
Object.assign( {
{}, configFile: path.resolve(__dirname, './src/karma.config.js'),
{ grep: taskArgs.grep,
configFile: path.resolve(__dirname, baseConfig), singleRun,
}, },
cliOpts,
opts
),
done done
).start(); ).start();
} }
gulp.task('test', function(callback) { gulp.task('test', done => runKarma({ singleRun: true }, done));
runKarma('./src/karma.config.js', { singleRun: true }, callback); gulp.task('test-watch', done => runKarma({ singleRun: false }, done));
});
gulp.task('test-watch', function(callback) {
runKarma('./src/karma.config.js', {}, callback);
});
gulp.task( gulp.task(
'upload-sourcemaps', 'upload-sourcemaps',
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
const path = require('path'); const path = require('path');
const envify = require('loose-envify/custom'); const envify = require('loose-envify/custom');
const glob = require('glob');
let chromeFlags = []; let chromeFlags = [];
process.env.CHROME_BIN = require('puppeteer').executablePath(); process.env.CHROME_BIN = require('puppeteer').executablePath();
...@@ -50,6 +51,22 @@ if (process.env.RUNNING_IN_DOCKER) { ...@@ -50,6 +51,22 @@ if (process.env.RUNNING_IN_DOCKER) {
} }
module.exports = function(config) { module.exports = function(config) {
let testFiles = [
'annotator/**/*-test.coffee',
'**/test/*-test.js',
'**/integration/*-test.js',
];
if (config.grep) {
const allFiles = testFiles
.map(pattern => glob.sync(pattern, { cwd: __dirname }))
.flat();
testFiles = allFiles.filter(path => path.match(config.grep));
// eslint-disable-next-line no-console
console.log(`Running tests matching pattern "${config.grep}": `, testFiles);
}
config.set({ config.set({
// base path that will be used to resolve all patterns (eg. files, exclude) // base path that will be used to resolve all patterns (eg. files, exclude)
basePath: './', basePath: './',
...@@ -66,31 +83,13 @@ module.exports = function(config) { ...@@ -66,31 +83,13 @@ module.exports = function(config) {
// Empty HTML file to assist with some tests // Empty HTML file to assist with some tests
{ pattern: './annotator/test/empty.html', watched: false }, { pattern: './annotator/test/empty.html', watched: false },
// Karma watching is disabled for these files because they are // Test modules.
// bundled with karma-browserify which handles watching itself via ...testFiles.map(pattern => ({
// watchify pattern,
// Unit tests // Disable watching because karma-browserify handles this.
{
pattern: 'annotator/**/*-test.coffee',
watched: false,
included: true,
served: true,
},
{
pattern: '**/test/*-test.js',
watched: false, watched: false,
included: true, })),
served: true,
},
// Integration tests
{
pattern: '**/integration/*-test.js',
watched: false,
included: true,
served: true,
},
], ],
// list of files to exclude // list of files to exclude
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment