/var/log/messages

Jun 9, 2018 - 5 minute read - Comments - Angular

Testing Components

以下なドキュメント機械翻訳控えを投入。

Testing Components

Learning Objectives

  • どのようにコンポーネントの入力だけでなく、その出力をテストする。
  • コンポーネントビューと対話する方法。

Test setup

LoginComponentをテストする例を続けます。 入力、出力、ドメインモデル、フォームを使って、より複雑なバージョンにコンポーネントを変更します:

import {Component, EventEmitter, Input, Output} from '@angular/core';

export class User {  // 1.
  constructor(public email: string, public password: string) {
  }
}

@Component({
  selector: 'app-login',
  template: `
<form>
  <label>Email</label>
  <input type="email"
         #email>
  <label>Password</label>
  <input type="password"
         #password>
  <button type="button"  // 2.
          (click)="login(email.value, password.value)"
          [disabled]="!enabled">Login
  </button>
</form>
`
})
export class LoginComponent {
  @Output() loggedIn = new EventEmitter<User>();  // 3.
  @Input() enabled = true;  // 4.

  login(email, password) {  // 5.
    console.log(`Login ${email} ${password}`);
    if (email && password) {
      console.log(`Emitting`);
      this.loggedIn.emit(new User(email, password));
    }
  }
}
  1. ログインしたユーザーのモデルを保持するUserクラスを作成します。
  2. 有効な入力プロパティ値と、ログイン機能と呼ばれるボタンをクリックすると、ボタンが無効になることがあります。
  3. コンポーネントにはloggedInという出力イベントがあります。
  4. コンポーネントには、enabledという入力プロパティがあります。
  5. ログイン関数では、loggedInイベントで新しいユーザーモデルを発行します。

コンポーネントはより複雑で、入力、出力を使用し、出力イベントでドメインモデルを出力します。

注 これ以上AuthServiceを使用していません。

また、テストスイートファイルを次のようにブートストラップします。

describe('Component: Login', () => {

  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let submitEl: DebugElement;
  let loginEl: DebugElement;
  let passwordEl: DebugElement;

  beforeEach(() => {

    TestBed.configureTestingModule({
      declarations: [LoginComponent]
    });

    // create component and test fixture
    fixture = TestBed.createComponent(LoginComponent);

    // get test component from the fixture
    component = fixture.componentInstance;

    submitEl = fixture.debugElement.query(By.css('button'));
    loginEl = fixture.debugElement.query(By.css('input[type=email]'));
    passwordEl = fixture.debugElement.query(By.css('input[type=password]'));
  });
});

私たちはテストスイートにいくつかのデバッグ要素を格納しておき、テスト仕様で検査または対話を行います。

Testing @Inputs

入力をテストするには、処理が必要です。

  1. コンポーネントで有効になっている入力プロパティを変更できる必要があります。
  2. 入力プロパティの値に応じて、ボタンが有効か無効かをチェックする必要があります。

最初の問題を解決するのは実際にはとても簡単です。

ただそれは@Inputであるという事実を変えるものではありません。まだ単純なプロパティなので、他のプロパティと同様に変更することができます:

it('Setting enabled to false disables the submit button', () => {
  component.enabled = false;
});

2番目の場合は、ボタンのDOM要素の無効なプロパティ値を次のようにチェックする必要があります:

it('Setting enabled to false disables the submit button', () => {
    component.enabled = false;
    fixture.detectChanges();
    expect(submitEl.nativeElement.disabled).toBeTruthy();
});

注 fixture.detectChanges()を呼び出して変更検出をトリガーし、ビューを更新する必要もあります。

Testing @Outputs

出力のテストは、特にビューからテストする場合は、やや難解です。

まず、出力イベントによって生成されたものをどのように追跡し、それに対していくつかの期待を追加する方法を見てみましょう。

it('Entering email and password emits loggedIn event', () => {
  let user: User;

  component.loggedIn.subscribe((value) => user = value);

  expect(user.email).toBe("test@example.com");
  expect(user.password).toBe("123456");
});

上記のキーになるラインは

component.loggedIn.subscribe((value) => user = value);

出力イベントは実際にObservableなので、それを subscribe して、放出されたすべてのアイテムのコールバックを取得することができます。

放出された値をユーザーオブジェクトに格納し、ユーザーオブジェクトにいくつかの期待値を追加します。

実際にイベントを発生させるにはどうすればいいですか? 私たちはcomponent.login(…)関数を自分自身で呼び出すことができますが、この講義の目的のために、ビューから関数をトリガーしたいと考えています。

まず、ビューの電子メールとパスワードの入力コントロールにいくつかの値を設定します。 私たちは既にセットアップ機能の両方のフィールドへの参照を持っているので、次のような値を設定します:

loginEl.nativeElement.value = "test@example.com";
passwordEl.nativeElement.value = "123456";

次に、送信ボタンのクリックをトリガーしますが、私たちはobservableにサブスクライブした後にこれを実行します。

it('Entering email and password emits loggedIn event', () => {
  let user: User;
  loginEl.nativeElement.value = "test@example.com";  // 1.
  passwordEl.nativeElement.value = "123456";

  component.loggedIn.subscribe((value) => user = value);

  submitEl.triggerEventHandler('click', null);  // 2.

  expect(user.email).toBe("test@example.com");
  expect(user.password).toBe("123456");
});
  1. 入力コントロールのデータを設定します。
  2. 送信ボタンのクリックをトリガします。これは、サブスクライブ・コールバック内のユーザオブジェクトを同期的に発行します。

Summary

コンポーネント入力プロパティの値を設定するだけで入力をテストできます。

EventEmittersオブザーバブルにサブスクライブし、出力された値をローカル変数に格納することによって、出力をテストできます。

前の講義と入力と出力をテストする能力と組み合わせて、コンポーネントをAngularでテストするために必要なすべての情報を取得する必要があります。

次の講義では、ディレクティブをテストする方法を見ていきます。

Listing

http://plnkr.co/edit/N95Scj9LcUbxaLhZismT?p=preview Listing 1. login.component.ts

import {Component, EventEmitter, Input, Output} from '@angular/core';

export class User {
  constructor(public email: string, public password: string) {
  }
}

@Component({
  selector: 'app-login',
  template: `
<form>
  <label>Email</label>
  <input type="email"
         #email>
  <label>Password</label>
  <input type="password"
         #password>
  <button type="button"
          (click)="login(email.value, password.value)"
          [disabled]="!enabled">Login
  </button>
</form>
`
})
export class LoginComponent {
  @Output() loggedIn = new EventEmitter<User>();
  @Input() enabled = true;

  login(email, password) {
    console.log(`Login ${email} ${password}`);
    if (email && password) {
      console.log(`Emitting`);
      this.loggedIn.emit(new User(email, password));
    }
  }
}

Listing 2. login.component.spec.ts

/* tslint:disable:no-unused-variable */
import {TestBed, ComponentFixture, inject, async} from '@angular/core/testing';
import {LoginComponent, User} from './login.component';
import {Component, DebugElement} from "@angular/core";
import {By} from "@angular/platform-browser";


describe('Component: Login', () => {

  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let submitEl: DebugElement;
  let loginEl: DebugElement;
  let passwordEl: DebugElement;

  beforeEach(() => {

    // refine the test module by declaring the test component
    TestBed.configureTestingModule({
      declarations: [LoginComponent]
    });


    // create component and test fixture
    fixture = TestBed.createComponent(LoginComponent);

    // get test component from the fixture
    component = fixture.componentInstance;

    submitEl = fixture.debugElement.query(By.css('button'));
    loginEl = fixture.debugElement.query(By.css('input[type=email]'));
    passwordEl = fixture.debugElement.query(By.css('input[type=password]'));
  });

  it('Setting enabled to false disabled the submit button', () => {
    component.enabled = false;
    fixture.detectChanges();
    expect(submitEl.nativeElement.disabled).toBeTruthy();
  });

  it('Setting enabled to true enables the submit button', () => {
    component.enabled = true;
    fixture.detectChanges();
    expect(submitEl.nativeElement.disabled).toBeFalsy();
  });

  it('Entering email and password emits loggedIn event', () => {
    let user: User;
    loginEl.nativeElement.value = "test@example.com";
    passwordEl.nativeElement.value = "123456";

    // Subscribe to the Observable and store the user in a local variable.
    component.loggedIn.subscribe((value) => user = value);

    // This sync emits the event and the subscribe callback gets executed above
    submitEl.triggerEventHandler('click', null);

    // Now we can check to make sure the emitted value is correct
    expect(user.email).toBe("test@example.com");
    expect(user.password).toBe("123456");
  });
})
;

Testing Dependency Injection Testing Directives

comments powered by Disqus