Fix memory and performance issues in Karma test suite
This commit is contained in:
parent
71d53ebcf8
commit
6b1e4ad5e8
|
@ -1,8 +1,16 @@
|
|||
var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
var argumentsParser = require('commander');
|
||||
var webpackConfig = require('./webpack.config.js');
|
||||
var ROOT_PATH = path.resolve(__dirname, '..');
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const chalk = require('chalk');
|
||||
const webpack = require('webpack');
|
||||
const argumentsParser = require('commander');
|
||||
const webpackConfig = require('./webpack.config.js');
|
||||
|
||||
const ROOT_PATH = path.resolve(__dirname, '..');
|
||||
|
||||
function fatalError(message) {
|
||||
console.error(chalk.red(`\nError: ${message}\n`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// remove problematic plugins
|
||||
if (webpackConfig.plugins) {
|
||||
|
@ -15,33 +23,70 @@ if (webpackConfig.plugins) {
|
|||
});
|
||||
}
|
||||
|
||||
var testFiles = argumentsParser
|
||||
const specFilters = argumentsParser
|
||||
.option(
|
||||
'-f, --filter-spec [filter]',
|
||||
'Filter run spec files by path. Multiple filters are like a logical OR.',
|
||||
(val, memo) => {
|
||||
memo.push(val);
|
||||
(filter, memo) => {
|
||||
memo.push(filter, filter.replace(/\/?$/, '/**/*.js'));
|
||||
return memo;
|
||||
},
|
||||
[]
|
||||
)
|
||||
.parse(process.argv).filterSpec;
|
||||
|
||||
webpackConfig.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.TEST_FILES': JSON.stringify(testFiles),
|
||||
})
|
||||
);
|
||||
if (specFilters.length) {
|
||||
const specsPath = /^(?:\.[\\\/])?spec[\\\/]javascripts[\\\/]/;
|
||||
|
||||
webpackConfig.devtool = process.env.BABEL_ENV !== 'coverage' && 'cheap-inline-source-map';
|
||||
// resolve filters
|
||||
let filteredSpecFiles = specFilters.map(filter =>
|
||||
glob
|
||||
.sync(filter, {
|
||||
root: ROOT_PATH,
|
||||
matchBase: true,
|
||||
})
|
||||
.filter(path => path.endsWith('spec.js'))
|
||||
);
|
||||
|
||||
// flatten
|
||||
filteredSpecFiles = Array.prototype.concat.apply([], filteredSpecFiles);
|
||||
|
||||
// remove duplicates
|
||||
filteredSpecFiles = [...new Set(filteredSpecFiles)];
|
||||
|
||||
if (filteredSpecFiles.length < 1) {
|
||||
fatalError('Your filter did not match any test files.');
|
||||
}
|
||||
|
||||
if (!filteredSpecFiles.every(file => specsPath.test(file))) {
|
||||
fatalError('Test files must be located within /spec/javascripts.');
|
||||
}
|
||||
|
||||
const newContext = filteredSpecFiles.reduce((context, file) => {
|
||||
const relativePath = file.replace(specsPath, '');
|
||||
context[file] = `./${relativePath}`;
|
||||
return context;
|
||||
}, {});
|
||||
|
||||
webpackConfig.plugins.push(
|
||||
new webpack.ContextReplacementPlugin(
|
||||
/spec[\\\/]javascripts$/,
|
||||
path.join(ROOT_PATH, 'spec/javascripts'),
|
||||
newContext
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
webpackConfig.entry = undefined;
|
||||
webpackConfig.devtool = 'cheap-inline-source-map';
|
||||
|
||||
// Karma configuration
|
||||
module.exports = function(config) {
|
||||
process.env.TZ = 'Etc/UTC';
|
||||
|
||||
var progressReporter = process.env.CI ? 'mocha' : 'progress';
|
||||
const progressReporter = process.env.CI ? 'mocha' : 'progress';
|
||||
|
||||
var karmaConfig = {
|
||||
const karmaConfig = {
|
||||
basePath: ROOT_PATH,
|
||||
browsers: ['ChromeHeadlessCustom'],
|
||||
customLaunchers: {
|
||||
|
|
|
@ -69,6 +69,9 @@ const config = {
|
|||
test: /\.js$/,
|
||||
exclude: /(node_modules|vendor\/assets)/,
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: path.join(ROOT_PATH, 'tmp/cache/babel-loader'),
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
|
|
|
@ -62,6 +62,7 @@ describe('.methodName', () => {
|
|||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### Testing promises
|
||||
|
||||
When testing Promises you should always make sure that the test is asynchronous and rejections are handled.
|
||||
|
@ -69,9 +70,9 @@ Your Promise chain should therefore end with a call of the `done` callback and `
|
|||
|
||||
```javascript
|
||||
// Good
|
||||
it('tests a promise', (done) => {
|
||||
it('tests a promise', done => {
|
||||
promise
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
expect(data).toBe(asExpected);
|
||||
})
|
||||
.then(done)
|
||||
|
@ -79,10 +80,10 @@ it('tests a promise', (done) => {
|
|||
});
|
||||
|
||||
// Good
|
||||
it('tests a promise rejection', (done) => {
|
||||
it('tests a promise rejection', done => {
|
||||
promise
|
||||
.then(done.fail)
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
expect(error).toBe(expectedError);
|
||||
})
|
||||
.then(done)
|
||||
|
@ -91,38 +92,37 @@ it('tests a promise rejection', (done) => {
|
|||
|
||||
// Bad (missing done callback)
|
||||
it('tests a promise', () => {
|
||||
promise
|
||||
.then((data) => {
|
||||
expect(data).toBe(asExpected);
|
||||
})
|
||||
promise.then(data => {
|
||||
expect(data).toBe(asExpected);
|
||||
});
|
||||
});
|
||||
|
||||
// Bad (missing catch)
|
||||
it('tests a promise', (done) => {
|
||||
it('tests a promise', done => {
|
||||
promise
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
expect(data).toBe(asExpected);
|
||||
})
|
||||
.then(done)
|
||||
.then(done);
|
||||
});
|
||||
|
||||
// Bad (use done.fail in asynchronous tests)
|
||||
it('tests a promise', (done) => {
|
||||
it('tests a promise', done => {
|
||||
promise
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
expect(data).toBe(asExpected);
|
||||
})
|
||||
.then(done)
|
||||
.catch(fail)
|
||||
.catch(fail);
|
||||
});
|
||||
|
||||
// Bad (missing catch)
|
||||
it('tests a promise rejection', (done) => {
|
||||
it('tests a promise rejection', done => {
|
||||
promise
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
expect(error).toBe(expectedError);
|
||||
})
|
||||
.then(done)
|
||||
.then(done);
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -139,7 +139,7 @@ documentation for these methods can be found in the [jasmine introduction page](
|
|||
Sometimes you may need to spy on a method that is directly imported by another
|
||||
module. GitLab has a custom `spyOnDependency` method which utilizes
|
||||
[babel-plugin-rewire](https://github.com/speedskater/babel-plugin-rewire) to
|
||||
achieve this. It can be used like so:
|
||||
achieve this. It can be used like so:
|
||||
|
||||
```javascript
|
||||
// my_module.js
|
||||
|
@ -181,8 +181,8 @@ See this [section][vue-test].
|
|||
`rake karma` runs the frontend-only (JavaScript) tests.
|
||||
It consists of two subtasks:
|
||||
|
||||
- `rake karma:fixtures` (re-)generates fixtures
|
||||
- `rake karma:tests` actually executes the tests
|
||||
* `rake karma:fixtures` (re-)generates fixtures
|
||||
* `rake karma:tests` actually executes the tests
|
||||
|
||||
As long as the fixtures don't change, `rake karma:tests` (or `yarn karma`)
|
||||
is sufficient (and saves you some time).
|
||||
|
@ -217,6 +217,14 @@ yarn karma-start --filter-spec profile/account/components/
|
|||
yarn karma-start -f vue_shared -f vue_mr_widget
|
||||
```
|
||||
|
||||
You can also use glob syntax to match files. Remember to put quotes around the
|
||||
glob otherwise your shell may split it into multiple arguments:
|
||||
|
||||
```bash
|
||||
# Run all specs named `file_spec` within the IDE subdirectory
|
||||
yarn karma -f 'spec/javascripts/ide/**/file_spec.js'
|
||||
```
|
||||
|
||||
## RSpec feature integration tests
|
||||
|
||||
Information on setting up and running RSpec integration tests with
|
||||
|
@ -231,14 +239,14 @@ supported by the PhantomJS test runner which is used for both Karma and RSpec
|
|||
tests. We polyfill some JavaScript objects for older browsers, but some
|
||||
features are still unavailable:
|
||||
|
||||
- Array.from
|
||||
- Array.first
|
||||
- Async functions
|
||||
- Generators
|
||||
- Array destructuring
|
||||
- For..Of
|
||||
- Symbol/Symbol.iterator
|
||||
- Spread
|
||||
* Array.from
|
||||
* Array.first
|
||||
* Async functions
|
||||
* Generators
|
||||
* Array destructuring
|
||||
* For..Of
|
||||
* Symbol/Symbol.iterator
|
||||
* Spread
|
||||
|
||||
Until these are polyfilled appropriately, they should not be used. Please
|
||||
update this list with additional unsupported features.
|
||||
|
@ -295,11 +303,11 @@ Scenario: Developer can approve merge request
|
|||
[jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html
|
||||
[jasmine-jquery]: https://github.com/velesin/jasmine-jquery
|
||||
[karma]: http://karma-runner.github.io/
|
||||
[vue-test]:https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components
|
||||
[RSpec]: https://github.com/rspec/rspec-rails#feature-specs
|
||||
[Capybara]: https://github.com/teamcapybara/capybara
|
||||
[Karma]: http://karma-runner.github.io/
|
||||
[Jasmine]: https://jasmine.github.io/
|
||||
[vue-test]: https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components
|
||||
[rspec]: https://github.com/rspec/rspec-rails#feature-specs
|
||||
[capybara]: https://github.com/teamcapybara/capybara
|
||||
[karma]: http://karma-runner.github.io/
|
||||
[jasmine]: https://jasmine.github.io/
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -98,10 +98,11 @@
|
|||
"devDependencies": {
|
||||
"axios-mock-adapter": "^1.10.0",
|
||||
"babel-eslint": "^8.0.2",
|
||||
"babel-plugin-istanbul": "^4.1.5",
|
||||
"babel-plugin-istanbul": "^4.1.6",
|
||||
"babel-plugin-rewire": "^1.1.0",
|
||||
"babel-template": "^6.26.0",
|
||||
"babel-types": "^6.26.0",
|
||||
"chalk": "^2.4.1",
|
||||
"commander": "^2.15.1",
|
||||
"eslint": "^3.18.0",
|
||||
"eslint-config-airbnb-base": "^10.0.1",
|
||||
|
@ -116,13 +117,13 @@
|
|||
"istanbul": "^0.4.5",
|
||||
"jasmine-core": "^2.9.0",
|
||||
"jasmine-jquery": "^2.1.1",
|
||||
"karma": "^2.0.0",
|
||||
"karma": "^2.0.2",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "^1.4.1",
|
||||
"karma-coverage-istanbul-reporter": "^1.4.2",
|
||||
"karma-jasmine": "^1.1.1",
|
||||
"karma-mocha-reporter": "^2.2.5",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "2.0.7",
|
||||
"karma-webpack": "3.0.0",
|
||||
"nodemon": "^1.15.1",
|
||||
"prettier": "1.11.1",
|
||||
"webpack-dev-server": "^2.11.2"
|
||||
|
|
|
@ -84,21 +84,11 @@ beforeEach(() => {
|
|||
|
||||
const axiosDefaultAdapter = getDefaultAdapter();
|
||||
|
||||
let testFiles = process.env.TEST_FILES || [];
|
||||
if (testFiles.length > 0) {
|
||||
testFiles = testFiles.map(path => path.replace(/^spec\/javascripts\//, '').replace(/\.js$/, ''));
|
||||
console.log(`Running only tests matching: ${testFiles}`);
|
||||
} else {
|
||||
console.log('Running all tests');
|
||||
}
|
||||
|
||||
// render all of our tests
|
||||
const testsContext = require.context('.', true, /_spec$/);
|
||||
testsContext.keys().forEach(function(path) {
|
||||
try {
|
||||
if (testFiles.length === 0 || testFiles.some(p => path.includes(p))) {
|
||||
testsContext(path);
|
||||
}
|
||||
testsContext(path);
|
||||
} catch (err) {
|
||||
console.error('[ERROR] Unable to load spec: ', path);
|
||||
describe('Test bundle', function() {
|
||||
|
|
Loading…
Reference in New Issue