Stencil — это современный фреймворк для создания веб-компонентов, который использует возможности стандартов Web Components. Одной из ключевых особенностей работы с компонентами является обработка событий. Тестирование событий в Stencil требует учета нескольких факторов, таких как асинхронность, реакция на пользовательские действия и взаимодействие компонентов. В этом разделе рассматриваются основные подходы и инструменты для тестирования событий в приложениях, построенных на Stencil.
В Stencil компоненты могут генерировать и слушать события, которые
играют важную роль в взаимодействии с другими частями приложения.
События могут быть как кастомными (созданными вручную), так и
стандартными (например, click, change,
input).
С помощью Stencil можно создать кастомные события, используя синтаксис, схожий с нативным Jav * aScript:
@Component({
tag: 'my-component',
shadow: true,
})
export class MyComponent {
@Event() myEvent: EventEmitter;
triggerEvent() {
this.myEvent.emit({ data: 'some data' });
}
}
В данном примере, когда вызывается метод triggerEvent,
генерируется кастомное событие myEvent. Такие события можно
слушать внутри других компонентов или на уровне DOM.
Stencil использует Jest для тестирования. Для имитации взаимодействия с событиями и компонентов используется несколько ключевых инструментов:
Stencil предоставляет утилиту для рендеринга компонентов в тестах. Используя эту утилиту, можно тестировать обработку событий с помощью нескольких простых шагов.
Рассмотрим пример компонента, который генерирует событие по клику на кнопку.
@Component({
tag: 'my-button',
shadow: true,
})
export class MyButton {
@Event() buttonClicked: EventEmitter;
handleClick() {
this.buttonClicked.emit('clicked');
}
render() {
return (
<button onCl ick={() => this.handleClick()}>Click Me</button>
);
}
}
В этом примере компонент генерирует событие
buttonClicked при клике на кнопку. Теперь можно написать
тест для проверки того, что событие действительно эмиттируется.
import { newSpecPage } from '@stencil/core/testing';
import { MyButton } from './my-button';
describe('my-button', () => {
it('emits buttonClicked event on click', async () => {
const page = await newSpecPage({
components: [MyButton],
html: `<my-button></my-button>`,
});
const spy = jest.fn();
page.root.addEventListener('buttonClicked', spy);
const button = page.root.shadowRoot.querySelector('button');
button.click();
expect(spy).toHaveBeenCalled();
expect(spy).toHaveBeenCalledWith(expect.objectContaining({
detail: 'clicked',
}));
});
});
Этот тест выполняет несколько шагов:
my-button с помощью
newSpecPage.buttonClicked.detail.В Stencil можно работать с асинхронными событиями. Это полезно в случае, когда необходимо протестировать события, которые происходят с задержкой, например, при вызове API или асинхронной операции.
Пример компонента, который генерирует асинхронное событие:
@Component({
tag: 'async-button',
shadow: true,
})
export class AsyncButton {
@Event() asyncEvent: EventEmitter;
async handleClick() {
const result = await new Promise((resolve) => setTimeout(() => resolve('done'), 1000));
this.asyncEvent.emit(result);
}
render() {
return (
<button onCl ick={() => this.handleClick()}>Click Me</button>
);
}
}
Теперь можно протестировать асинхронное событие:
describe('async-button', () => {
it('emits asyncEvent with result after delay', async () => {
const page = await newSpecPage({
components: [AsyncButton],
html: `<async-button></async-button>`,
});
const spy = jest.fn();
page.root.addEventListener('asyncEvent', spy);
const button = page.root.shadowRoot.querySelector('button');
button.click();
await new Promise(resolve => setTimeout(resolve, 1100)); // Ожидаем завершения асинхронной операции
expect(spy).toHaveBeenCalled();
expect(spy).toHaveBeenCalledWith(expect.objectContaining({
detail: 'done',
}));
});
});
В этом тесте:
setTimeout.В некоторых случаях, например, при интеграционном тестировании, может потребоваться мокирование событий или их поведения. Jest предоставляет удобные средства для создания моков и шпионов, что позволяет изолировать тесты и убедиться, что события обрабатываются правильно.
Пример мокирования:
it('mocks event listener', async () => {
const page = await newSpecPage({
components: [MyButton],
html: `<my-button></my-button>`,
});
const mock = jest.fn();
const spy = jest.spyOn(page.root, 'dispatchEvent').mockImplementation(mock);
const button = page.root.shadowRoot.querySelector('button');
button.click();
expect(mock).toHaveBeenCalled();
});
В этом примере используется jest.spyOn для того, чтобы
отслеживать вызовы dispatchEvent и мокировать его
поведение. Это полезно для тестирования, когда нужно проверить, были ли
сгенерированы события в определенных ситуациях.
В Stencil можно использовать пользовательские события, которые
предоставляют дополнительную гибкость при тестировании. Такие события
могут не только передавать данные через detail, но и иметь
дополнительные параметры, такие как bubbles,
cancelable и т. д.
Пример создания события с дополнительными параметрами:
@Component({
tag: 'custom-button',
shadow: true,
})
export class CustomButton {
@Event() customEvent: EventEmitter;
handleClick() {
const event = new CustomEvent('customEvent', {
bubbles: true,
cancelable: true,
detail: { customData: 'data' },
});
this.customEvent.emit(event);
}
render() {
return (
<button onCl ick={() => this.handleClick()}>Click Me</button>
);
}
}
Тестирование пользовательского события:
it('emits custom event with custom data', async () => {
const page = await newSpecPage({
components: [CustomButton],
html: `<custom-button></custom-button>`,
});
const spy = jest.fn();
page.root.addEventListener('customEvent', spy);
const button = page.root.shadowRoot.querySelector('button');
button.click();
expect(spy).toHaveBeenCalledWith(expect.objectContaining({
detail: { customData: 'data' },
}));
});
В этом примере тестируется, что событие содержит нужные данные и имеет правильные параметры.
Тестирование событий в Stencil требует внимательного подхода, особенно когда речь идет о кастомных и асинхронных событиях. С помощью инструментов Stencil и Jest можно эффективно создавать тесты, которые проверяют правильность эмитации событий, их обработку и взаимодействие с другими компонентами. Важно учитывать особенности работы с асинхронностью и мокированием, чтобы создать надежные и воспроизводимые тесты.