Skip to content

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 remote
    shell
    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?

javascript
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:

javascript
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.

shell
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.

shell
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

dockerfile
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.

shell
npm run editor:test:debug

You should see something similar to this in the browser:

chrome inspect

wfcms/standard tests

The code in wfcms/standard is also covered by tests. To run them, first

shell
cd vendor/wfcms/standard/Wf/Bundle/CmsBaseAssetsBundle/

Test in wfcms/standard are split between editor and wf-directives:

shell
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.

shell
npm run wf-directives:test

Similarly to the commands described in Command types section, there are also watch and debug versions available

shell
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:

shell
npm run editor:test -- --testPathPattern my_feature

or by specifying a pattern for the test name (what you put inside test("__TEST_NAME__", callback)):

shell
npm run editor:test -- --testNamePattern "my feature should work"

Of course, the two above can also be combined.