這次我們來測試 angular directive 元件。一樣我們要先產生一個 directive 這邊我們會使用 angular 官方的教學文件範例來做測試。
我們會在 src/app 下看到兩個 angular cli 產生的 directive 檔案。
hover-focus.directive.spec.ts
在這個測試檔下是會測試失敗的!因為我們的 hover-focus 在 constructor() 裡面有加入一個 private el: ElementRef 的預設 member 所以在 const directive = new HoverFocusDirective() 會失敗。
所以這邊我們給他一個 new directive 參數就可以使用就能通過這個測試。
hover-focus.directive.spce.ts
不過別忘了要 import ElementRef
hover-focus.directive.spec.ts
但是上述的測試只是單純驗證這個 directive 到底有沒有存在,但是對於這個 directive 到底有沒有在滑鼠游標移在我們指定的 dom 上面時把背景改成黃色呢?因此我們必須在測試的時候產生一個有 html dom 的測試環境來針對我們的 directive 做測試。
首先我們必須產生一個有 html dom 的 template 物件,然後在這個物件上面的加入 directive 來做測試驗證
hover-focus.directive.spec.ts
因為我們用到 Component 的 decorator 因此要 import Compnent 進來。
hover-focus.directive.spec.ts
接著我們撰寫測試 login component spec 的方式在建立 TestBed 並且使用一個新的 describe()。
hover-focus.directive.spec.ts
當然要把建立 TestBed 的 module 與 library import 進來。
hover-focus.directive.spec.ts
這邊要注意的是 titleEl 我們用的 angular 提供 By 的方式來抓取在 html 上的 title 而非之前我們使用 ElementRef 的 querySelector() 這是因為我們在後續 it() 使用 triggerEventHandler() 的 function。
再來是 it() 部份的程式碼如下:
hover-focus.directive.spec.ts
這邊說明一下我們為什麼要使用 By.css() 來抓取我們要測試的目標。
另外我自己在這邊有遇到一個很奇怪的問題:
當我使用 mouseover 的時候測試會失敗,錯誤訊息是 backgroundColor 值為 '空' 值。但是在 ng test 啟用的 Chrome 瀏覽器上面的畫面自己移動滑鼠上去 title 的時候,背景是有變黃色。但是改用 mouseenter 卻有正確在測試通過。這個問題我目前還是不知道為什麼,提供給大家我遇到很奇怪的問題。
login.component.spec.ts
一樣寫一個新的 describe() 與包含 HoverFocusDirective 的測試環境。
login.component.spec.ts
測試 spec 上面的程式碼會跟我們做 directive unit test 很像:
login.component.spec.ts
可以加上 f 讓 Jasmine 只做這個測試。
結果:
---- 待續
新增 directive
# ng g d hoverfocus我們會在 src/app 下看到兩個 angular cli 產生的 directive 檔案。
- hover-Focus.directive.ts
- hover-Focus.directive.spec.ts
撰寫 Directive:
我們先修改 hover-Focus.directive.ts 檔案,撰寫一個『當滑鼠游標移到這個 directive 標注的 dom 上面』就把背景顏色改成黃色。
hover-Focus.directive.ts
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[appHoverFocus]'
})
export class HoverFocusDirective {
constructor(private el: ElementRef) { }
@HostListener('mouseenter') onMouseEnter() {
this.highlight('yellow');
}
@HostListener('mouseleave') onMouseLeave() {
this.highlight(null);
}
private highlight(color: string) {
this.el.nativeElement.style.backgroundColor = color;
}
}
我們可以在 login.component.html 的『登入帳號』的 dom 裡面加入這個 directive 就可以看到當滑鼠移入這個名字上,這個 h4 的 tag 背景就會被改成黃色。
login.component.html
login.component.html
<h4 class="" appHoverFocus>登入帳號</h4>
撰寫測試:
我們先看 angular cli 幫我們產生好的 hover focus 的測試檔內容。hover-focus.directive.spec.ts
import { HoverFocusDirective } from './hover-focus.directive';
describe('HoverFocusDirective', () => {
it('should create an instance', () => {
const directive = new HoverFocusDirective();
expect(directive).toBeTruthy();
});
});
在這個測試檔下是會測試失敗的!因為我們的 hover-focus 在 constructor() 裡面有加入一個 private el: ElementRef 的預設 member 所以在 const directive = new HoverFocusDirective() 會失敗。
所以這邊我們給他一個 new directive 參數就可以使用就能通過這個測試。
hover-focus.directive.spce.ts
describe('HoverFocusDirective', () => {
let el: ElementRef;
it('should create an instance', () => {
const directive = new HoverFocusDirective(el);
expect(directive).toBeTruthy();
});
});
不過別忘了要 import ElementRef
hover-focus.directive.spec.ts
import { ElementRef } from '@angular/core';
但是上述的測試只是單純驗證這個 directive 到底有沒有存在,但是對於這個 directive 到底有沒有在滑鼠游標移在我們指定的 dom 上面時把背景改成黃色呢?因此我們必須在測試的時候產生一個有 html dom 的測試環境來針對我們的 directive 做測試。
首先我們必須產生一個有 html dom 的 template 物件,然後在這個物件上面的加入 directive 來做測試驗證
hover-focus.directive.spec.ts
@Component ({
template: `
Hello World
`
})
class TestHoverFocusComponent {}
因為我們用到 Component 的 decorator 因此要 import Compnent 進來。
hover-focus.directive.spec.ts
import { Component } from '@angular/core';
接著我們撰寫測試 login component spec 的方式在建立 TestBed 並且使用一個新的 describe()。
hover-focus.directive.spec.ts
describe('Directive: HoverFocus', () => {
let component: TestHoverFocusComponent;
let fixture: ComponentFixture<TestHoverFocusComponent>;
let titleEl: DebugElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
TestHoverFocusComponent,
HoverFocusDirective]
});
fixture = TestBed.createComponent(TestHoverFocusComponent);
component = fixture.componentInstance;
// 這邊注意!改用 By 這個angular 提供的套件。
titleEl = fixture.debugElement.query(By.css('#title'));
});
});
當然要把建立 TestBed 的 module 與 library import 進來。
hover-focus.directive.spec.ts
import { By } from '@angular/platform-browser';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
這邊要注意的是 titleEl 我們用的 angular 提供 By 的方式來抓取在 html 上的 title 而非之前我們使用 ElementRef 的 querySelector() 這是因為我們在後續 it() 使用 triggerEventHandler() 的 function。
再來是 it() 部份的程式碼如下:
hover-focus.directive.spec.ts
it('hovering over title.', () => {
titleEl.triggerEventHandler('mouseenter', null);
fixture.detectChanges();
expect(titleEl.nativeElement.style.backgroundColor).toBe('yellow');
titleEl.triggerEventHandler('mouseleave', null);
fixture.detectChanges();
expect(titleEl.nativeElement.style.backgroundColor).toBe('');
});
這邊說明一下我們為什麼要使用 By.css() 來抓取我們要測試的目標。
- 因為 triggerEventHandler() 是我們用來要求 angular 來做 mouse enter 的行為,但是這個 triggerEventHandler() 是屬於 angular 提供的功能而非 HTML Dom 本身的功能。所以如果我們使用 fixture.debugElement.nativeElement.querySelector() 來抓 title 的話。會因為 DOM 本身沒有 triggerEventHandler() 的功能變成測試產生錯誤!
當我使用 mouseover 的時候測試會失敗,錯誤訊息是 backgroundColor 值為 '空' 值。但是在 ng test 啟用的 Chrome 瀏覽器上面的畫面自己移動滑鼠上去 title 的時候,背景是有變黃色。但是改用 mouseenter 卻有正確在測試通過。這個問題我目前還是不知道為什麼,提供給大家我遇到很奇怪的問題。
套用到 login component 上的測試
首先我們要先 import By 進來。login.component.spec.ts
import { By } from '@angular/platform-browser';
一樣寫一個新的 describe() 與包含 HoverFocusDirective 的測試環境。
login.component.spec.ts
describe('Test directive in LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let service: DemoService;
let el: DebugElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
LoginComponent, HoverFocusDirective],
imports: [ ReactiveFormsModule ],
providers: [ DemoService ]
});
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
service = TestBed.get(DemoService);
el = fixture.debugElement;
fixture.detectChanges();
});
});
測試 spec 上面的程式碼會跟我們做 directive unit test 很像:
login.component.spec.ts
it('test hover focus directive on LoginComponent', () => {
let titleEl = el.query(By.css('h4'));
titleEl.triggerEventHandler('mouseenter', null);
fixture.detectChanges();
expect(titleEl.nativeElement.style.backgroundColor).toBe('yellow');
titleEl.triggerEventHandler('mouseleave', null);
fixture.detectChanges();
expect(titleEl.nativeElement.style.backgroundColor).toBe('');
});
可以加上 f 讓 Jasmine 只做這個測試。
結果:
---- 待續
REF:
留言
張貼留言