Jest – JavaScript Testing Framework
Jest is a delightful JavaScript testing framework with a focus on simplicity.
Vortex comes with pre-configured Jest setup for testing JavaScript in custom Drupal modules.
For writing tests, mocking Drupal globals, and test templates, see the Jest development guide.
Usage
- Ahoy
- Docker Compose
ahoy test-js # Run all Jest tests.
docker compose exec cli bash -c "yarn test" # Run all Jest tests.
Running tests matching a pattern
- Ahoy
- Docker Compose
ahoy test-js -- --testPathPattern=ys_demo
docker compose exec cli bash -c "yarn test --testPathPattern=ys_demo"
Running a specific test by name
- Ahoy
- Docker Compose
ahoy test-js -- -t "should increment the value"
docker compose exec cli bash -c "yarn test -t 'should increment the value'"
Configuration
See Jest configuration reference.
All global configuration takes place in the jest.config.js file.
By default, Jest will discover and run test files in web/modules/custom/*/js/
directories. Test files must use the .test.js extension and be co-located
alongside the source files they test.
The configuration uses the jsdom test environment to provide browser globals
like document, window, and localStorage.
Test discovery
The jest.config.js file dynamically scans web/modules/custom/ for modules
that contain a js/ directory, and adds each as a root for test discovery. This
means adding a new custom module with JavaScript tests requires no configuration
changes.
Writing tests
Test files are placed next to the source file they test:
web/modules/custom/my_module/
└── js/
├── my_module.js # Source file
└── my_module.test.js # Test file
Loading Drupal behaviors
Drupal JavaScript uses the IIFE pattern with Drupal as a global. Tests load
the source file using eval() after setting up the global:
/**
* @jest-environment jsdom
*/
const fs = require('fs');
const path = require('path');
describe('Drupal.behaviors.myModule', () => {
beforeEach(() => {
localStorage.clear();
global.Drupal = { behaviors: {} };
const filePath = path.resolve(__dirname, 'my_module.js');
const code = fs.readFileSync(filePath, 'utf8');
eval(code);
});
afterEach(() => {
delete global.Drupal;
});
it('should attach behavior', () => {
document.body.innerHTML = '<div data-my-module></div>';
Drupal.behaviors.myModule.attach(document);
const el = document.querySelector('[data-my-module]');
expect(el.classList.contains('processed')).toBe(true);
});
});
Key patterns
global.Drupal = { behaviors: {} }inbeforeEachprovides the Drupal global that the IIFE receives as a parameter.eval(fs.readFileSync(...))loads and executes the source file, which registers the behavior onDrupal.behaviors.delete global.DrupalinafterEachensures test isolation.document.body.innerHTMLsets up the DOM for each test using jsdom.jest.useFakeTimers()controlssetTimeoutandsetIntervalfor testing timed behavior.
ESLint configuration
The .eslintrc.json file includes an override for *.test.js files that
enables the jest environment and disables no-eval to allow the source
loading pattern:
{
"overrides": [
{
"files": ["*.test.js"],
"env": { "jest": true },
"rules": {
"no-eval": "off",
"max-nested-callbacks": ["warn", 5],
"jsdoc/check-tag-names": "off"
}
}
]
}
Ignoring fail in continuous integration pipeline
This tool runs in continuous integration pipeline by default and fails the build if there are any violations.
Set VORTEX_CI_JEST_IGNORE_FAILURE environment variable to 1 to ignore
failures. The tool will still run and report violations, if any.