4.8 KiB
Testing
We take very seriously code quality. Tests is an important part of a solid and
robust application. Each feature should be (if reasonable) tested properly, in
the QUnit test suite (available in the route /wowl/tests
)
In a few sentences, here is how the test suite is organized:
- tests are written in the
static/tests
folder. - the main entry point for the suite is
static/tests/main.ts
, which is the code that setup the test suite environment. - some helpers are available in
static/tests/helpers.ts
. - to access the test suite, one needs to have an odoo server running and then
open
/wowl/tests
in a browser
The test suite file structure looks like this:
static/
...
tests/
components/
navbar_tests.ts
...
services/
router_tests.ts
...
helpers.ts <-- helpers that will probably be imported in each test file
main.ts <-- main file, used to generate the test bundle
qunit.ts <-- qunit config file. No test should import this
Test helpers
-
mount(SomeComponent, {env, target})
: create a component with theenv
provided, and mount it to thetarget
html element. This method is asynchronous, and returns the instance of the component -
makeTestEnv(params?: Params)
: create asynchronously a test environment. By default, a test environment has no service, components or browser access. It can be optionally customized with theparams
argument:services (optional, Registry<Service>)
: a registry of servicesComponents (optional, Registry<Component>)
) main component registrybrowser (optional, object)
: the browser object that will be used for the test environment.
-
getFixture(): HTMLElement
: return an html element to use as a DOM node for tests (only applies to code that needs to interact with the DOM, obviously). -
nextTick(): Promise<void>
: helper to wait for the next animation frame. This is extremely useful while writing tests involving components updating the DOM. -
click(el: HTMLElement, selector?: string): Promise<void>
: helper to click on an element, given the element itself, or an element and a selector that matches a single element inside it. The helper will crash when called with a selector that have no match, or more than 1 match. It returns a promise resolved after the next animation frame, i.e. after potential DOM updates have been applied.
QUnit custom assertions
QUnit provides several built-in assertions,
available on the QUnit.assert
object. Alongside them, we provide custom
assertions.
-
assert.containsN(el: HTMLElement, selector: string, n: number, msg?: string)
: check that a target elementel
contains exactlyn
matches for the givenselector
, withmsg
being an optional short description of the assertion -
assert.containsNone(el: HTMLElement, selector: string, msg?: string)
: check that a target elementel
contains no match for the givenselector
-
assert.containsOnce(el: HTMLElement, selector: string, msg?: string)
: check that a target elementel
contains exactly one match for the givenselector
-
assert.hasClass(el: HTMLElement, classNames: string, msg?: string)
: check that a target elementel
has the givenclassNames
-
assert.doesNotHaveClass(el: HTMLElement, classNames: string, msg?: string)
: check that a target elementel
does not have the givenclassNames
.
Adding a new test
To add a new test file to the QUnit suite, the following steps need to be done:
- create a new file named
something_test.ts
in thestatic/tests
folder - import your file in
static/tests/main.ts
(so it will be added to the test bundle) - add your tests inside your new file.
Here is a simple example of a test file to test a component:
import * as QUnit from "qunit";
import { MyComponent } from "../../src/components/...";
import { getFixture, makeTestEnv, mount, OdooEnv } from "../helpers";
let target: HTMLElement;
let env: OdooEnv;
QUnit.module("MyComponent", {
beforeEach() {
target = getFixture();
env = makeTestEnv();
}
});
QUnit.test("can be rendered", async (assert) => {
assert.expect(1);
const myComponent = await mount(MyComponent, { env, target });
// perform some assertion/actions
});
Debugging a test
Sometimes, changes in the code make tests fail. Understanding why assertions
fail reading the logs might be tedious. Hopefully, one can use our custom
QUnit.debug
function instead of QUnit.test
(basically, rename ŧest
into
debug
for the failing test). With this, the target returned by getFixture
will be document.body
, so that what has been inserted into the DOM is visible,
and can be directly interacted with.