Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
gitlab-ce
Commits
6b1e4ad5
Commit
6b1e4ad5
authored
May 01, 2018
by
Mike Greiling
Committed by
Clement Ho
May 01, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix memory and performance issues in Karma test suite
parent
71d53ebc
Changes
6
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
280 additions
and
452 deletions
+280
-452
config/karma.config.js
config/karma.config.js
+61
-16
config/webpack.config.js
config/webpack.config.js
+3
-0
doc/development/testing_guide/frontend_testing.md
doc/development/testing_guide/frontend_testing.md
+41
-33
package.json
package.json
+5
-4
spec/javascripts/test_bundle.js
spec/javascripts/test_bundle.js
+1
-11
yarn.lock
yarn.lock
+169
-388
No files found.
config/karma.config.js
View file @
6b1e4ad5
var
path
=
require
(
'
path
'
);
const
path
=
require
(
'
path
'
);
var
webpack
=
require
(
'
webpack
'
);
const
glob
=
require
(
'
glob
'
);
var
argumentsParser
=
require
(
'
commander
'
);
const
chalk
=
require
(
'
chalk
'
);
var
webpackConfig
=
require
(
'
./webpack.config.js
'
);
const
webpack
=
require
(
'
webpack
'
);
var
ROOT_PATH
=
path
.
resolve
(
__dirname
,
'
..
'
);
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
// remove problematic plugins
if
(
webpackConfig
.
plugins
)
{
if
(
webpackConfig
.
plugins
)
{
...
@@ -15,33 +23,70 @@ if (webpackConfig.plugins) {
...
@@ -15,33 +23,70 @@ if (webpackConfig.plugins) {
});
});
}
}
var
testFile
s
=
argumentsParser
const
specFilter
s
=
argumentsParser
.
option
(
.
option
(
'
-f, --filter-spec [filter]
'
,
'
-f, --filter-spec [filter]
'
,
'
Filter run spec files by path. Multiple filters are like a logical OR.
'
,
'
Filter run spec files by path. Multiple filters are like a logical OR.
'
,
(
val
,
memo
)
=>
{
(
filter
,
memo
)
=>
{
memo
.
push
(
val
);
memo
.
push
(
filter
,
filter
.
replace
(
/
\/?
$/
,
'
/**/*.js
'
)
);
return
memo
;
return
memo
;
},
},
[]
[]
)
)
.
parse
(
process
.
argv
).
filterSpec
;
.
parse
(
process
.
argv
).
filterSpec
;
webpackConfig
.
plugins
.
push
(
if
(
specFilters
.
length
)
{
new
webpack
.
DefinePlugin
({
const
specsPath
=
/^
(?:\.[\\\/])?
spec
[\\\/]
javascripts
[\\\/]
/
;
'
process.env.TEST_FILES
'
:
JSON
.
stringify
(
testFiles
),
// 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
.
devtool
=
process
.
env
.
BABEL_ENV
!==
'
coverage
'
&&
'
cheap-inline-source-map
'
;
webpackConfig
.
entry
=
undefined
;
webpackConfig
.
devtool
=
'
cheap-inline-source-map
'
;
// Karma configuration
// Karma configuration
module
.
exports
=
function
(
config
)
{
module
.
exports
=
function
(
config
)
{
process
.
env
.
TZ
=
'
Etc/UTC
'
;
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
,
basePath
:
ROOT_PATH
,
browsers
:
[
'
ChromeHeadlessCustom
'
],
browsers
:
[
'
ChromeHeadlessCustom
'
],
customLaunchers
:
{
customLaunchers
:
{
...
...
config/webpack.config.js
View file @
6b1e4ad5
...
@@ -69,6 +69,9 @@ const config = {
...
@@ -69,6 +69,9 @@ const config = {
test
:
/
\.
js$/
,
test
:
/
\.
js$/
,
exclude
:
/
(
node_modules|vendor
\/
assets
)
/
,
exclude
:
/
(
node_modules|vendor
\/
assets
)
/
,
loader
:
'
babel-loader
'
,
loader
:
'
babel-loader
'
,
options
:
{
cacheDirectory
:
path
.
join
(
ROOT_PATH
,
'
tmp/cache/babel-loader
'
),
},
},
},
{
{
test
:
/
\.
vue$/
,
test
:
/
\.
vue$/
,
...
...
doc/development/testing_guide/frontend_testing.md
View file @
6b1e4ad5
...
@@ -62,6 +62,7 @@ describe('.methodName', () => {
...
@@ -62,6 +62,7 @@ describe('.methodName', () => {
});
});
});
});
```
```
#### Testing promises
#### Testing promises
When testing Promises you should always make sure that the test is asynchronous and rejections are handled.
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 `
...
@@ -69,9 +70,9 @@ Your Promise chain should therefore end with a call of the `done` callback and `
```
javascript
```
javascript
// Good
// Good
it
(
'
tests a promise
'
,
(
done
)
=>
{
it
(
'
tests a promise
'
,
done
=>
{
promise
promise
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
expect
(
data
).
toBe
(
asExpected
);
expect
(
data
).
toBe
(
asExpected
);
})
})
.
then
(
done
)
.
then
(
done
)
...
@@ -79,10 +80,10 @@ it('tests a promise', (done) => {
...
@@ -79,10 +80,10 @@ it('tests a promise', (done) => {
});
});
// Good
// Good
it
(
'
tests a promise rejection
'
,
(
done
)
=>
{
it
(
'
tests a promise rejection
'
,
done
=>
{
promise
promise
.
then
(
done
.
fail
)
.
then
(
done
.
fail
)
.
catch
(
(
error
)
=>
{
.
catch
(
error
=>
{
expect
(
error
).
toBe
(
expectedError
);
expect
(
error
).
toBe
(
expectedError
);
})
})
.
then
(
done
)
.
then
(
done
)
...
@@ -91,38 +92,37 @@ it('tests a promise rejection', (done) => {
...
@@ -91,38 +92,37 @@ it('tests a promise rejection', (done) => {
// Bad (missing done callback)
// Bad (missing done callback)
it
(
'
tests a promise
'
,
()
=>
{
it
(
'
tests a promise
'
,
()
=>
{
promise
promise
.
then
(
data
=>
{
.
then
((
data
)
=>
{
expect
(
data
).
toBe
(
asExpected
);
expect
(
data
).
toBe
(
asExpected
);
})
});
});
});
// Bad (missing catch)
// Bad (missing catch)
it
(
'
tests a promise
'
,
(
done
)
=>
{
it
(
'
tests a promise
'
,
done
=>
{
promise
promise
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
expect
(
data
).
toBe
(
asExpected
);
expect
(
data
).
toBe
(
asExpected
);
})
})
.
then
(
done
)
.
then
(
done
)
;
});
});
// Bad (use done.fail in asynchronous tests)
// Bad (use done.fail in asynchronous tests)
it
(
'
tests a promise
'
,
(
done
)
=>
{
it
(
'
tests a promise
'
,
done
=>
{
promise
promise
.
then
(
(
data
)
=>
{
.
then
(
data
=>
{
expect
(
data
).
toBe
(
asExpected
);
expect
(
data
).
toBe
(
asExpected
);
})
})
.
then
(
done
)
.
then
(
done
)
.
catch
(
fail
)
.
catch
(
fail
)
;
});
});
// Bad (missing catch)
// Bad (missing catch)
it
(
'
tests a promise rejection
'
,
(
done
)
=>
{
it
(
'
tests a promise rejection
'
,
done
=>
{
promise
promise
.
catch
(
(
error
)
=>
{
.
catch
(
error
=>
{
expect
(
error
).
toBe
(
expectedError
);
expect
(
error
).
toBe
(
expectedError
);
})
})
.
then
(
done
)
.
then
(
done
)
;
});
});
```
```
...
@@ -181,8 +181,8 @@ See this [section][vue-test].
...
@@ -181,8 +181,8 @@ See this [section][vue-test].
`rake karma`
runs the frontend-only (JavaScript) tests.
`rake karma`
runs the frontend-only (JavaScript) tests.
It consists of two subtasks:
It consists of two subtasks:
-
`rake karma:fixtures`
(re-)generates fixtures
*
`rake karma:fixtures`
(re-)generates fixtures
-
`rake karma:tests`
actually executes the tests
*
`rake karma:tests`
actually executes the tests
As long as the fixtures don't change,
`rake karma:tests`
(or
`yarn karma`
)
As long as the fixtures don't change,
`rake karma:tests`
(or
`yarn karma`
)
is sufficient (and saves you some time).
is sufficient (and saves you some time).
...
@@ -217,6 +217,14 @@ yarn karma-start --filter-spec profile/account/components/
...
@@ -217,6 +217,14 @@ yarn karma-start --filter-spec profile/account/components/
yarn karma-start
-f
vue_shared
-f
vue_mr_widget
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
## RSpec feature integration tests
Information on setting up and running RSpec integration tests with
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
...
@@ -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
tests. We polyfill some JavaScript objects for older browsers, but some
features are still unavailable:
features are still unavailable:
-
Array.from
*
Array.from
-
Array.first
*
Array.first
-
Async functions
*
Async functions
-
Generators
*
Generators
-
Array destructuring
*
Array destructuring
-
For..Of
*
For..Of
-
Symbol/Symbol.iterator
*
Symbol/Symbol.iterator
-
Spread
*
Spread
Until these are polyfilled appropriately, they should not be used. Please
Until these are polyfilled appropriately, they should not be used. Please
update this list with additional unsupported features.
update this list with additional unsupported features.
...
@@ -295,11 +303,11 @@ Scenario: Developer can approve merge request
...
@@ -295,11 +303,11 @@ Scenario: Developer can approve merge request
[
jasmine-focus
]:
https://jasmine.github.io/2.5/focused_specs.html
[
jasmine-focus
]:
https://jasmine.github.io/2.5/focused_specs.html
[
jasmine-jquery
]:
https://github.com/velesin/jasmine-jquery
[
jasmine-jquery
]:
https://github.com/velesin/jasmine-jquery
[
karma
]:
http://karma-runner.github.io/
[
karma
]:
http://karma-runner.github.io/
[
vue-test
]:
https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components
[
vue-test
]:
https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components
[
RS
pec
]:
https://github.com/rspec/rspec-rails#feature-specs
[
rs
pec
]:
https://github.com/rspec/rspec-rails#feature-specs
[
C
apybara
]:
https://github.com/teamcapybara/capybara
[
c
apybara
]:
https://github.com/teamcapybara/capybara
[
K
arma
]:
http://karma-runner.github.io/
[
k
arma
]:
http://karma-runner.github.io/
[
J
asmine
]:
https://jasmine.github.io/
[
j
asmine
]:
https://jasmine.github.io/
---
---
...
...
package.json
View file @
6b1e4ad5
...
@@ -98,10 +98,11 @@
...
@@ -98,10 +98,11 @@
"devDependencies"
:
{
"devDependencies"
:
{
"
axios-mock-adapter
"
:
"
^1.10.0
"
,
"
axios-mock-adapter
"
:
"
^1.10.0
"
,
"
babel-eslint
"
:
"
^8.0.2
"
,
"
babel-eslint
"
:
"
^8.0.2
"
,
"
babel-plugin-istanbul
"
:
"
^4.1.
5
"
,
"
babel-plugin-istanbul
"
:
"
^4.1.
6
"
,
"
babel-plugin-rewire
"
:
"
^1.1.0
"
,
"
babel-plugin-rewire
"
:
"
^1.1.0
"
,
"
babel-template
"
:
"
^6.26.0
"
,
"
babel-template
"
:
"
^6.26.0
"
,
"
babel-types
"
:
"
^6.26.0
"
,
"
babel-types
"
:
"
^6.26.0
"
,
"
chalk
"
:
"
^2.4.1
"
,
"
commander
"
:
"
^2.15.1
"
,
"
commander
"
:
"
^2.15.1
"
,
"
eslint
"
:
"
^3.18.0
"
,
"
eslint
"
:
"
^3.18.0
"
,
"
eslint-config-airbnb-base
"
:
"
^10.0.1
"
,
"
eslint-config-airbnb-base
"
:
"
^10.0.1
"
,
...
@@ -116,13 +117,13 @@
...
@@ -116,13 +117,13 @@
"
istanbul
"
:
"
^0.4.5
"
,
"
istanbul
"
:
"
^0.4.5
"
,
"
jasmine-core
"
:
"
^2.9.0
"
,
"
jasmine-core
"
:
"
^2.9.0
"
,
"
jasmine-jquery
"
:
"
^2.1.1
"
,
"
jasmine-jquery
"
:
"
^2.1.1
"
,
"
karma
"
:
"
^2.0.
0
"
,
"
karma
"
:
"
^2.0.
2
"
,
"
karma-chrome-launcher
"
:
"
^2.2.0
"
,
"
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-jasmine
"
:
"
^1.1.1
"
,
"
karma-mocha-reporter
"
:
"
^2.2.5
"
,
"
karma-mocha-reporter
"
:
"
^2.2.5
"
,
"
karma-sourcemap-loader
"
:
"
^0.3.7
"
,
"
karma-sourcemap-loader
"
:
"
^0.3.7
"
,
"
karma-webpack
"
:
"
2.0.7
"
,
"
karma-webpack
"
:
"
3.0.0
"
,
"
nodemon
"
:
"
^1.15.1
"
,
"
nodemon
"
:
"
^1.15.1
"
,
"
prettier
"
:
"
1.11.1
"
,
"
prettier
"
:
"
1.11.1
"
,
"
webpack-dev-server
"
:
"
^2.11.2
"
"
webpack-dev-server
"
:
"
^2.11.2
"
...
...
spec/javascripts/test_bundle.js
View file @
6b1e4ad5
...
@@ -84,21 +84,11 @@ beforeEach(() => {
...
@@ -84,21 +84,11 @@ beforeEach(() => {
const
axiosDefaultAdapter
=
getDefaultAdapter
();
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
// render all of our tests
const
testsContext
=
require
.
context
(
'
.
'
,
true
,
/_spec$/
);
const
testsContext
=
require
.
context
(
'
.
'
,
true
,
/_spec$/
);
testsContext
.
keys
().
forEach
(
function
(
path
)
{
testsContext
.
keys
().
forEach
(
function
(
path
)
{
try
{
try
{
if
(
testFiles
.
length
===
0
||
testFiles
.
some
(
p
=>
path
.
includes
(
p
)))
{
testsContext
(
path
);
testsContext
(
path
);
}
}
catch
(
err
)
{
}
catch
(
err
)
{
console
.
error
(
'
[ERROR] Unable to load spec:
'
,
path
);
console
.
error
(
'
[ERROR] Unable to load spec:
'
,
path
);
describe
(
'
Test bundle
'
,
function
()
{
describe
(
'
Test bundle
'
,
function
()
{
...
...
yarn.lock
View file @
6b1e4ad5
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment