For unit testing with QUnit, see: Manual:JavaScript unit testing.
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
For improved security and consistency with production CI, consider using Fresh to run NPM commands.

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
See also: Vue.js/Testing

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]

 N 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 ] );

Notes

edit

See also

edit