🦉 How to test Components 🦉
Содержание
Введение
Очень хорошей практикой является тестирование приложения и компонентов для того чтобы убедиться что они ведут себя так, как ожидается. Есть множество способов для того, чтобы протестировать пользовательский интерфейс: ручное тестирование, интеграционные тесты, юнит тесты и т.д.
В этом разделе, мы будем обсуждать как писать юнит тесты для компонентов.
Юнинт тесты
Написание юнит тестов для Owl компонентов зависит от фреймворка тестирования который вы используете в проекте. Но обычно это зависит от нескольких шагов:
- создание файла теста: например
SomeComponent.test.js
, - в этом файле импортируйте код из
SomeComponent
, - добавьте тестовый кейс:
- создайте реальный DOM элемент чтобы использовать его как тестовую фикстуру
- создайте тестовое окружение
- создайте экземпляр
SomeComponent
, прмонтируйте его к фикстуре - взаимодействуйте с компонентом и установике проверки его свойств.
Чтобы помочь в этом, полезно иметь файл helper.js
, который будет содержать в себе
некоторые общие служебные функции:
export function makeTestFixture() {
let fixture = document.createElement("div");
document.body.appendChild(fixture);
return fixture;
}
export function nextTick() {
let requestAnimationFrame = owl.Component.scheduler.requestAnimationFrame;
return new Promise(function(resolve) {
setTimeout(() => requestAnimationFrame(() => resolve()));
});
}
export function makeTestEnv() {
// application specific. It needs a way to load actual templates
const templates = ...;
return {
qweb: new QWeb(templates),
..., // each service can be mocked here
};
}
С таким файлом типичный набор тестов для Jest будет выглядеть так:
// в SomeComponent.test.js
import { SomeComponent } from "../../src/ui/SomeComponent";
import { nextTick, makeTestFixture, makeTestEnv} from '../helpers';
//------------------------------------------------------------------------------
// Setup
//------------------------------------------------------------------------------
let fixture: HTMLElement;
let env: Env;
beforeEach(() => {
fixture = makeTestFixture();
env = makeTestEnv();
// мы устанавливаем здесь окружение по умолчанию для каждого компонента, созданного в тесте
Component.env = env;
});
afterEach(() => {
fixture.remove();
});
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
describe("SomeComponent", () => {
test("component behaves as expected", async () => {
const props = {...}; // зависит от компонента
const comp = await mount(SomeComponent, { target: fixture, props });
// делаем проверки
expect(...).toBe(...);
fixture.querySelector('button').click();
await nextTick();
// далаем другие проверки
expect(...).toBe(...);
});
});
Обратите внимание что Owl ожидает следующий кадр анимации для того, чтобы обновить
DOM. Вот почему необходимо явно включать ожидание с помощью nextTick
(или других методов)
чтобы убедиться что DOM обновился.
Иногда бывает полезно подождать, пока Owl полностью завершит обновление компонентов (в частности, если у нас высокопараллельный пользовательский интерфейс). Следующий помощник просто опрашивает каждые 20 мс внутреннюю очередь задач Owl и возвращает промис, который разрешается, когда он пуст:
function afterUpdates() {
return new Promise((resolve, reject) => {
let timer = setTimeout(poll, 20);
let counter = 0;
function poll() {
counter++;
if (owl.Component.scheduler.tasks.length) {
if (counter > 10) {
reject(new Error("timeout"));
} else {
timer = setTimeout(poll);
}
} else {
resolve();
}
}
});
}