Automated testing (Jest)
Intro
Jest is an open-source JavaScript testing framework maintained by Facebook. It is widely used for testing JavaScript code, including both frontend and backend applications. Jest is known for its simplicity, speed, and developer-friendly features.
Key features of Jest include:
- Zero Configuration: Jest requires minimal configuration, making it easy to set up and use.
- Built-in Testing Utilities: It provides built-in testing utilities for various types of tests, including unit tests, integration tests, and end-to-end tests.
- Mocking: Jest simplifies mocking by allowing you to easily mock dependencies and functions.
- Parallel Test Execution: Jest can run tests in parallel, speeding up the test suite's execution.
- Snapshot Testing: Snapshot testing allows you to capture the output of a component or function and compare it to a saved snapshot to detect changes.
- Watch Mode: Jest's watch mode enables real-time testing, automatically re-running tests when code changes are detected.
- Jest Extensions: Jest has a rich ecosystem of extensions and plugins for various testing needs.
Config
- add the skeleton repository as a remoteshell
git remote add skeleton git@git.xalok.com:HML/skeleton-2021.git git fetch skeleton
- cherry pick the commits that configure Jest in the project:shell
git cherry-pick 70bc1dec371083e1dd10c81d1355f9c999aae78b git cherry-pick 200572f4a12dec550dcf5307666867959e2e8f8f
Test types
Xalok has two types of test:
Editor type
This is used to write tests for the vuex events, for example what happen when we add a module and this have a wf-max directive?
const { loadTemplateConfig, createStore } = require("./util/jest");
const expandCompositeConfig = require("./util/expand_composite_config");
const expandCompositeData = require("./util/expand_composite_data");
const sampleData = require("./util/test_sample_data");
const {
INITIALIZE,
MODULE_ADD,
MODULE_DELETE,
MODULE_CONFIG_PARTIAL_UPDATE,
} = require("./util/constants");
describe("wf-max for current page", () => {
const {
INITIALIZE,
MODULE_ADD,
MODULE_DELETE,
} = require("wfed/wfvue/store/util/constants");
let store;
beforeEach(() => {
store = createStore();
});
const initialize = async (templateConfig, moduleData, _store = store) => {
return _store.dispatch(INITIALIZE, {
title: "test",
module: moduleData && expandCompositeData(moduleData),
config: expandCompositeConfig(templateConfig),
});
};
test("adding a simple module with max directive", async () => {
await initialize(
{
test: {
__config: {
allowAdd: ["test"],
allowDelete: true,
max: 2,
},
},
},
{
test: {},
}
);
await store.dispatch(MODULE_ADD, {
wfRolePath: ["test"],
role: "test",
});
const testData = store.state.templateConfig.test.__config;
expect(testData.allowAdd).toStrictEqual(false);
});
});
The initialize
function creates a mock page model based on the parameters defined in the test description. Once this dummy module is initialized, we can trigger various Vuex events, such as MODULE_ADD
.
In this specific example, we are simulating the behavior of a wf-max
directive, which restricts the maximum number of allowable modules to 2. To replicate this functionality, we also set the allowAdd
and allowDelete
directives, often referred to as wf-allow
directive.
Given that we initially have one module, denoted as test, when we dispatch an event to add another module, the wf-max
directive comes into play. It prevents the addition of another module, resulting in the allowAdd
property being set to false
. This test effectively validates that the wf-max
directive functions as expected, limiting the number of modules that can be added.
wf-directive type
Wf-Directive type tests focus on the functionality of directives in the SSR (Server-Side Rendering) part of the application. For instance, you can test scenarios where two modules have the same role. Here's an example of a Wf-Directive type test:
const { parse } = require("./util/jest");
describe("wf-role", () => {
test("throws error for two modules having the same role", () => {
expect(() =>
parse(`
<div>
<a wf-module="wfed/composite/module" wf-role="test"></a>
<a wf-module="wfed/composite/module" wf-role="test"></a>
</div>
`)
).toThrowError("already contains a module");
});
});
In this example, the test ensures that an error is thrown when two modules with the same role are detected. It tests the functionality of the wf-role
directive.
Command types
Note: This is only and example for editor tests command, this is the same with the wf-directives
commands (e.g.: npm run wf-directives:test
)
Default
This command runs Jest tests using the configuration from jest.editor.config.js
.
npm run editor:test
Watch
This command runs Jest tests in watch mode. It will automatically re-run tests when you make changes to your code or test files.
npm run editor:test:watch
Debug
Note: To be able to see this on chrome://inspect/#devices first you should expose the por 9229 in docker, change docker-compose.yml
and add this on the php container
ports:
- '9229:9229'
Use this command to run Jest tests in debug mode, allowing you to inspect and debug your tests using a debugger like Chrome DevTools. It listens on all available network interfaces (0.0.0.0) on port 9229.
npm run editor:test:debug
You should see something similar to this in the browser:
wfcms/standard tests
The code in wfcms/standard
is also covered by tests. To run them, first
cd vendor/wfcms/standard/Wf/Bundle/CmsBaseAssetsBundle/
Test in wfcms/standard
are split between editor
and wf-directives
:
WF_CLEAN=1 npm run editor:test
Note: The editor:test
command checks the WF_CLEAN
environment variable, as in the example above. Set this if you make changes to the unit test HTMLs or to source JS files (JS files inside XalokNext, the JS code of the tests is automatically reloaded by Jest). The compilation step is required by JS code related to wf components. When changing this, it's not possible to work with npm run editor:test:watch
, the compilation happens only at start time, not before every rerun.
npm run wf-directives:test
Similarly to the commands described in Command types section, there are also watch and debug versions available
npm run editor:test:watch
npm run editor:test:debug
npm run wf-directives:watch
npm run wf-directives:debug
Filtering tests
When working on a specific feature, you can run only the tests related to that feature. One way to do this is by specifying a pattern for the test filenames:
npm run editor:test -- --testPathPattern my_feature
or by specifying a pattern for the test name (what you put inside test("__TEST_NAME__", callback))
:
npm run editor:test -- --testNamePattern "my feature should work"
Of course, the two above can also be combined.