環境
- Angular CLI: 7.3.1
たぶん他のバージョンでも動く
準備
事前準備
テキストエリアやボタンを使うのにFormsModule必要です。
app.modules.ts
import { FormsModule } from '@angular/forms';
// ...
imports: [
FormsModule,
// ...
app.component.spec.ts
beforeEach(async(() => {
TestBed.configureTestingModule({
// ...
imports: [
FormsModule
// ...
HTMLとTypeScriptの準備
app.component.html
<div id="message">{{message}}</div>
<textarea [(ngModel)]="input"></textarea>
<button (click)="postMessage(input)">書く</button>
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
message = '';
input = '';
postMessage(message: string) {
this.message = message;
this.input = '';
}
}
あると便利なもの
app.component.spec.ts
beforeEach(async(() => {
TestBed.configureTestingModule({
// ...
providers: [
{ provide: ComponentFixtureAutoDetect, useValue: true }
// ...
CompoentFixtureAutoDetectはある程度コンポーネント変更検知を自動検知してくれる。
何度もdetectChanges()書かなくて済む
まぁ、DOMイベントは自動検知してくれないけど(以下のサンプルでは必須)。
本題
inputイベントが発行されたことをテストする
app.compoent.spec.ts
it('should input to textarea', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
const htmlElement: HTMLElement = fixture.debugElement.nativeElement;
const textarea = htmlElement.querySelector('textarea');
textarea.value = 'なんか書いた'; // 注目
textarea.dispatchEvent(new Event('input')); // 注目
fixture.detectChanges(); // 注目
expect(app.message).toBe('なんか書いた');
});
ちなみにquerySelectorに渡す文字列はCSSのセレクターの指定の仕方と同じ
ボタンをクリックをテストする
app.component.spec.ts
it('should post message by clicking button', () => {
const fixture = TestBed.createComponent(AppComponent);
const htmlElement: HTMLElement = fixture.debugElement.nativeElement;
const textarea = htmlElement.querySelector('textarea');
const button = htmlElement.querySelector('button');
const message = htmlElement.querySelector('div#message');
textarea.value = 'なんか書いた';
textarea.dispatchEvent(new Event('input'));
button.dispatchEvent(new Event('click')); // 注目
fixture.detectChanges();
expect(message.htmlContent).toBe('なんか書いた');
});
エンターキーで投稿できるようにする
keydown.enterのコールバックを指定する
app.component.html
<div id="message">{{message}}</div>
<textarea [(ngModel)]="input" (keydown.enter)="postMessage(input)"></textarea>
<button (click)="postMessage(input)">書く</button>
KeyboardEventを発行してテストする
app.component.spec.ts
it('should post message by pressing enter key', () => {
const fixture = TestBed.createComponent(AppComponent);
const htmlElement: HTMLElement = fixture.debugElement.nativeElement;
const textarea = htmlElement.querySelector('textarea');
const message = htmlElement.querySelector('div#message');
textarea.value = 'なんか書いた';
textarea.dispatchEvent(new Event('input'));
textarea.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'})); // 注目
fixture.detectChanges();
expect(message.htmlContent).toBe('なんか書いた');
});
参考記事
- Angular 日本語ドキュメンテーション - テスト
- HTMLElement - MDN - Mozilla
- HTMLTextAreaElement - MDN - Mozilla
- HTMLButtonElement - MDN - Mozilla
- KeyboardEvent - MDN - Mozilla
- JavaScriptでキーボードの入力値を別の値しようとしたらめちゃめちゃ苦しんだ話
間違いなどありましたら気兼ねなくご指摘ください