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
Running tests
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
Mocked mw global object
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
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
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.
Register a test suite
New Jest suites must be added to the jest.config.js file, under the roots
property:
module.exports = {
// …
// A list of paths to directories that Jest should use to search for files in
roots: [
'<rootDir>/tests/jest',
'<rootDir>/resources/src/mediawiki.special.block',
+ '<rootDir>/resources/src/path/to/my/test/suite'
],
Components
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]
![]() |
![]() |
---|---|
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
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 ] );