JavaScript unit testing with Jasmine
Magento uses a custom Grunt task named spec
to run Jasmine tests. The task collects the tests from <magento_root_dir>dev/tests/js/jasmine/tests
and can be run for all tests, a theme, or a single test.
Prepare environment
Step 1. Install Node.js.
Step 2. Install grunt-cli.
Step 3. In <magento_root_dir>
, create Gruntfile.js
and copy Gruntfile.js.sample
into it.
Step 4. In <magento_root_dir>
, create package.json
and copy package.json.sample
into it.
Step 5. In <magento_root_dir>
, install all dependencies:
1
npm install
Step 6. In <magento_root_dir>
, generate static view files in Magento that are going to be tested
1
bin/magento setup:static-content:deploy -f
Note that normally you don’t have permissions to <magento_root_dir>/app/code/
, in fact the generated static view file is being tested.
For CentOS and Ubuntu users
If the command fails with the error message:
1
/var/www/html/magento2ce/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory
Install fontconfig library:
-
CentOS:
1
yum install fontconfig
-
Ubuntu:
1
apt-get install fontconfig
Learn more in Deploy static view files.
Run tests
Gruntfile.js
contains the test run task, so you can run all tests using the following command in the Magento root directory:
1
grunt spec:<THEME>
Example:
1
grunt spec:backend
or for the frontend area:
1
grunt spec:luma
You can also run a single test:
1
grunt spec:backend --file="/path/to/the/test.js"
or for the frontend area:
1
grunt spec:luma --file="/path/to/the/test.js"
Write a test
All tests are distributed through modules stored in <magento_root_dir>/dev/tests/js/jasmine/tests
. Let’s see how to write a test using an example of an existing test:
app/code/Magento/Ui/base/js/grid/columns/actions.test.js
which tests a JS module:
<magento_root_dir>/app/code/Magento/Ui/view/base/web/js/grid/columns/actions.js
in its static representations generated in Step 6 previously:
<magento_root_dir>/pub/static/<area>/<theme>/<localisation>/Magento_Ui/js/columns/actions.js
.
Step 1. Create a new file with name <fileName>.test.js
in an appropriate module directory.
For convenience, we can reflect the directory structure of a file to test.
A path to JS module that we want to cover with tests: app/code/Magento/Ui/view/base/web/js/grid/columns/actions.js
A path to a test of the module: app/code/Magento/Ui/base/js/grid/columns/actions.test.js
In <magento_root_dir>/dev/tests/js/jasmine/tests
create the test with appropriate path.
Step 2. Require a file that you want to test.
For our example we need to cover all static view files ending with Magento_Ui/js/grid/columns/actions
.
1
2
3
4
5
6
7
8
define([
'Magento_Ui/js/grid/columns/actions'
], function (Actions) {
'use strict';
//Test code
//...
});
Step 3. Write your Jasmine test code.
A Jasmine test consists of main two parts:
describe
blocksit
blocks
Both the describe
and it
functions contains two parameters:
- a text string with description of what is going to be done
- a function with block of code implementing described action
In describe
you can use beforeEach
and afterEach
functions performing a preparation of what must be done before and after every it
test followed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
define([
'underscore',
'Magento_Ui/js/grid/columns/actions'
], function (_, Actions) {
'use strict';
describe('ui/js/grid/columns/actions', function () {
var model,
action;
beforeEach(function () {
model = new Actions({
index: 'actions',
name: 'listing_action',
indexField: 'id',
dataScope: '',
rows: [{
identifier: 'row'
}]
});
action = {
index: 'delete',
hidden: true,
rowIndex: 0,
callback: function() {
return true;
}
};
});
it('Check addAction function', function () {
expect(model.addAction('delete', action)).toBe(model);
});
it('Check getAction function', function () {
var someAction = _.clone(action);
someAction.index = 'edit';
model.addAction('edit', someAction);
expect(model.getAction(0, 'edit')).toEqual(someAction);
});
it('Check getVisibleActions function', function () {
var someAction = _.clone(action);
someAction.hidden = false;
someAction.index= 'view';
model.addAction('delete', action);
model.addAction('view', someAction);
expect(model.getVisibleActions('0')).toEqual([someAction]);
});
it('Check updateActions function', function () {
expect(model.updateActions()).toEqual(model);
});
it('Check applyAction function', function () {
model.addAction('delete', action);
expect(model.applyAction('delete', 0)).toEqual(model);
});
it('Check isSingle and isMultiple function', function () {
var someAction = _.clone(action);
action.hidden = false;
model.addAction('delete', action);
expect(model.isSingle(0)).toBeTruthy();
someAction.hidden = false;
someAction.index = 'edit';
model.addAction('edit', someAction);
expect(model.isSingle(0)).toBeFalsy();
expect(model.isMultiple(0)).toBeTruthy();
});
it('Check isActionVisible function', function () {
expect(model.isActionVisible(action)).toBeFalsy();
action.hidden = false;
expect(model.isActionVisible(action)).toBeTruthy();
});
});
});
This topic doesn’t provide Jasmine test writing methodology.
Learn more about testing with Jasmine.
Debug tests
Jasmine tests can be debugged in a browser using the following steps:
To keep the webserver running, set keepalive
setting to true
in the dev/tests/js/jasmine/spec_runner/settings.json
file.
Launch the tests with the grunt spec:luma
CLI command. Now the webserver should be started and waiting, _SpecRunner.html
file should be generated in the project root.
Go to http://localhost:8000/_SpecRunner.html
and use the developer console to debug the tests.
The array of the tests can be edited in the _SpecRunner.html
file to include only necessary files.
Known issues and solutions
Error: Cannot find module ‘<module>’
Issue:
An error message appears:
1
2
3
4
5
Loading "Gruntfile.js" tasks...ERROR
>> Error: Cannot find module '<module>'
Warning: Task "spec" not found. Use --force to continue.
Solution:
- Make sure your Node.js version is up-to-date.
- Remove
package.json
,Gruntfile.js
. - Copy
package.json
,Gruntfile.js
frompackage.json.sample
,Gruntfile.js.sample
. - Delete the
node_modules
directory. - Run
npm install
in your terminal.
Warning: Cannot read property ‘pid’ of undefined
Issue:
An error message appears:
1
2
3
Warning: Cannot read property 'pid' of undefined
Use --force to continue. Aborted due to warnings.
Solution:
Run in your terminal:
1
cd <magento_root>/node_modules/grunt-contrib-jasmine
1
npm install