はじめに
この記事はHubble Advent Calendar 2023の7日目1の記事です。
Hubbleのフロントエンドチームではユニットテストに重きを置いていて、ほとんどのテストをユニットテストで書いています。
また、Presentationalコンポーネントでは、Testing Libraryを用いてテストを書いています。
Presentationalコンポーネントから親コンポーネントへの@Outputイベントをモックするのに少し手間取った経験があるため、方法を書き残します。
実際のコード例
todo.component.ts
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
Output,
} from '@angular/core';
import { Todo } from '../../models';
@Component({
selector: 'app-todo',
standalone: true,
imports: [CommonModule],
template: `
<ul>
@for (todo of todos; track todo.id) {
<li>
<span>Title: {{ todo.title }} | Completed: {{ todo.completed }}</span>
|
<button (click)="toggleStatusEvent.emit(todo.id)">Toggle Status</button>
</li>
} @empty {
<p>No todos found</p>
}
</ul>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TodoComponent {
@Input({ required: true }) todos: Todo[] = [];
@Output() toggleStatusEvent = new EventEmitter<number>();
}
todo.component.spec.ts
import { render } from '@testing-library/angular';
import userEvent from '@testing-library/user-event';
import { TodoComponent } from './todo.component';
import { Todo } from '../../models';
it('should emit toggleStatusEvent when button is clicked', async () => {
const todos: Todo[] = [{ id: 1, title: 'Test Todo', completed: false }];
const { component, user, mockToggleStatusEvent } = await setup({ todos });
const toggleButton = component.getByRole('button', {
name: /Toggle Status/i,
});
await user.click(toggleButton);
expect(mockToggleStatusEvent.emit).toHaveBeenCalledWith(1);
});
async function setup(props?: Partial<TodoComponent>) {
const mockToggleStatusEvent = new EventEmitter<number>();
jest.spyOn(mockToggleStatusEvent, 'emit');
const component = await render(TodoComponent, {
componentProperties: {
todos: props?.todos ?? [],
toggleStatusEvent: mockToggleStatusEvent
},
});
return {
component,
user: userEvent.setup(),
mockToggleStatusEvent,
};
}
解説
ポイント1: @Outputイベントをモックする
ts
@Output() toggleStatusEvent = new EventEmitter<number>();
spec.ts
// emit関数をモックする
const mockToggleStatusEvent = new EventEmitter<number>();
jest.spyOn(mockToggleStatusEvent, 'emit');
spec.ts
// componentPropertiesにセットしたモックイベントをreturnする
return {
// ...
mockToggleStatusEvent,
};
ポイント2: ボタン要素を取得し、クリックイベントを発火させる
ts
<button (click)="toggleStatusEvent.emit(todo.id)">Toggle Status</button>
spec.ts
const toggleButton = component.getByRole('button', {
name: /Toggle Status/i,
});
await user.click(toggleButton);
まとめ
このような形で、親コンポーネントへのイベントをモックし、テストすることができました。
明日は @embokoirさんです!
-
平日のみの投稿なので、投稿日は11日ですが7日目の記事としています。 ↩