Slim.js — это легковесная библиотека для создания веб-компонентов, ориентированная на реактивное управление состоянием и эффективное связывание данных с DOM. В современных приложениях асинхронные операции встречаются повсеместно: загрузка данных с сервера, обработка событий, таймеры и промисы. Правильное тестирование таких сценариев критически важно для стабильности приложения.
В Slim.js изменения состояния компонентов автоматически отражаются в DOM через реактивную систему. Это включает в себя и асинхронные операции. Рассмотрим пример:
class AsyncComponent extends Slim {
constructor() {
super();
this.data = null;
}
get template() {
return `<div>{{data}}</div>`;
}
async fetchData() {
const response = await fetch('/api/data');
const json = await response.json();
this.data = json.value;
}
}
customElements.define('async-component', AsyncComponent);
В этом примере data обновляется только после завершения
асинхронного запроса. Тестирование должно учитывать задержку между
вызовом метода и фактическим изменением DOM.
Для проверки асинхронного поведения необходимо использовать промисы и
ожидание их завершения. В Jest это делается с помощью
async/await:
test('fetchData обновляет состояние компонента', async () => {
const component = document.createElement('async-component');
document.body.appendChild(component);
// Подмена fetch для тестирования
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ value: 'Тестовое значение' }),
})
);
await component.fetchData();
expect(component.data).toBe('Тестовое значение');
expect(component.shadowRoot.innerHTML).toContain('Тестовое значение');
});
Важно дождаться завершения асинхронной функции перед проверкой состояния компонента. Без этого тест может проверять DOM до обновления, что приведет к ложным отрицательным результатам.
Slim.js обновляет DOM не мгновенно, а через реактивную очередь изменений. Иногда необходимо дождаться следующего цикла обновления:
await new Promise(resolve => setTimeout(resolve, 0));
Это гарантирует, что все реактивные изменения, связанные с присвоением значений свойствам, будут применены к DOM перед проверкой.
Асинхронные операции часто сопровождаются генерацией пользовательских событий. В Slim.js можно слушать события компонента и проверять их корректность:
class EventComponent extends Slim {
constructor() {
super();
this.data = null;
}
get template() {
return `<button on-click="loadData">Загрузить</button>`;
}
async loadData() {
this.data = await Promise.resolve('Значение');
this.dispatchEvent(new CustomEvent('data-loaded', { detail: this.data }));
}
}
customElements.define('event-component', EventComponent);
test('loadData генерирует событие data-loaded', async () => {
const component = document.createElement('event-component');
document.body.appendChild(component);
const listener = jest.fn();
component.addEventListener('data-loaded', listener);
await component.loadData();
expect(listener).toHaveBeenCalledWith(expect.objectContaining({
detail: 'Значение'
}));
});
Использование событий в тестах позволяет убедиться, что асинхронная логика корректно уведомляет другие части приложения.
Для изоляции компонентов в тестах важно использовать моки. Fetch-запросы, таймеры и другие внешние ресурсы можно подменять на контролируемые объекты. Например, таймеры можно тестировать через Jest Fake Timers:
jest.useFakeTimers();
test('отложенное обновление данных', () => {
const component = document.createElement('async-component');
document.body.appendChild(component);
component.data = 'Начальное';
setTimeout(() => {
component.data = 'Обновленное';
}, 1000);
jest.advanceTimersByTime(1000);
expect(component.data).toBe('Обновленное');
});
Это позволяет мгновенно симулировать прохождение времени без реальной задержки.
await для асинхронных функций.Асинхронное тестирование в Slim.js требует понимания реактивной природы компонентов и правильного управления промисами и событиями. Систематическое применение описанных подходов обеспечивает точные и надежные проверки поведения компонентов.