Jest
MediaWiki version: | ≥ 1.43 |
As of MediaWiki 1.43, Core ships with the Jest JavaScript testing framework. If you need to test Vue.js components, Jest is recommended for unit testing.
Usage
[edit]Running tests
[edit]This runs the Jest tests for MediaWiki Core in a headless Node.js environment:
$ npm run jest
> jest
> jest --config tests/jest/jest.config.js
PASS tests/jest/mediawiki.special.block/SpecialBlock.test.js
SpecialBlock
✓ should show a submit button with the correct text (98 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.561 s, estimated 1 s
Ran all test suites.
You can run specific Jest tests by passing the path to a file or directory:
$ npm run jest tests/nothing-exists-here
> jest
> jest --config tests/jest/jest.config.js tests/nothing-exists-here
No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
In /mediawiki
24316 files checked.
testMatch: /mediawiki/tests/jest/**/*.test.js - 1 match
testPathIgnorePatterns: /node_modules/, /vendor/, /skins/, /extensions/, /tests/qunit/ - 2913 matches
testRegex: - 0 matches
Pattern: tests/nothing-exists-here - 0 matches
You can use npm run jest -- --watch
to watch all associated files, and automatically re-run tests when those files change.
Features
[edit]Mocked mw global object
[edit]Jest tests are ran outside of MediaWiki in a headless Node.js environment. As such, globals like mw need to be mocked. Core's Jest setup mocks much of mw
for you using Jest mocked functions. This means unless your test relies on mw
methods and properties behaving a specific way, you don't need to mock them yourself.
You can add additional mocks as needed, either to the Core jest.setup.js or in your own test. For example, the following would mock the return value of mw.user.getName()
:
mw.user.getName = jest.fn().mockReturnValue( 'Foobar' );
Using Codex icons
[edit]
Core's Jest config maps modules ending with icons.json
to the @wikimedia/codex-icons package. If your component makes use of Codex icons, first make the module available to your code with a virtual file in the ResourceLoader configuration:
// Resources.php
'packageFiles' => [
'resources/init.js',
'resources/MyComponent.vue',
[
'name' => 'resources/icons.json',
'callback' => 'MediaWiki\\ResourceLoader\\CodexModule::getIcons',
'callbackParam' => [
'cdxIconEdit',
'cdxIconSearch'
],
]
]
// extension.json
"ext.MyExtension": {
"packageFiles": [
"resources/init.js",
"resources/MyComponent.vue",
{
"name": "resources/icons.json",
"callback": "MediaWiki\\ResourceLoader\\CodexModule::getIcons",
"callbackParam": [
"CdxIconEdit",
"CdxIconSearch"
]
}
]
}
Then in your Vue component, you require the icons module with a relative path:
// MyComponent.vue
const { cdxIconEdit, cdxIconSearch } = require( './icons.json' );
Because of the automatic mapping in the Core Jest config, you won't need to mock this module or any specific icons in your tests.
Writing unit tests
[edit]Jest test files should live under the tests/jest/
directory and be of the form MyComponent.test.js
. Jest will treat any file ending with .test.js
in this directory as a Jest test.
Components
[edit]To make a component testable by Jest, the module.exports
property is replaced by a new object (your component), so the Node.js modules API requires we also assign the module to the exports
variable.[1]
Not testable by Jest | Testable by Jest |
---|---|
module.exports = defineComponent( {
// …
} );
|
module.exports = exports = defineComponent( {
// …
} );
|
Failure to do so may result in warnings like:
[Vue warn]: Component is missing template or render function.
at <MyChildComponent some-attribute="Foobar" >
at <MyParentComponent ref="VTU_COMPONENT" >
at <VTUROOT>
Mocking
[edit]
Here is an example of how to mock the implementation of mw.config.get
:
// MyComponent.test.js
const mockConfig = {
wgRelevantUserName: 'Example',
wgPageName: 'Example'
};
mw.config.get.mockImplementation( ( key ) => mockConfig[ key ] );