I am working through Angular 2 testing examples here https://angular.io/docs/ts/latest/guide/testing.html
Welcome component
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'app-welcome',
template: '<h3 class="welcome" ><i>{{welcome}}</i></h3>'
})
export class WelcomeComponent implements OnInit {
welcome = '-- not initialized yet --';
constructor(private userService: UserService) {
}
ngOnInit(): void {
this.welcome = this.userService.isLoggedIn ?
'Welcome, ' + this.userService.user.name :
'Please log in.';
}
}
Test spec
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { WelcomeComponent } from './welcome.component';
import { UserService } from './user.service';
describe('WelcomeComponent', () => {
let component: WelcomeComponent;
let fixture: ComponentFixture<WelcomeComponent>;
let de: DebugElement;
let el: HTMLElement;
let userServiceStub: UserService;
let userService:UserService;
beforeEach(async(() => {
// Declare stub UserService for test purposes
let userServiceStub = {
isLoggedIn: true,
user: { name: 'Test User'}
};
TestBed.configureTestingModule({
declarations: [ WelcomeComponent ],
providers: [ {provide: UserService, useValue: userServiceStub } ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(WelcomeComponent);
component = fixture.componentInstance;
//userService = TestBed.get(UserService);
userService = fixture.debugElement.injector.get(UserService);
// get the "welcome" element by CSS selector (e.g., by class name)
de = fixture.debugElement.query(By.css('.welcome'));
el = de.nativeElement;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should welcome the user', () => {
fixture.detectChanges();
const content = el.textContent;
expect(content).toContain('Welcome', '"Welcome ..."');
expect(content).toContain('Test User', 'expected name');
});
it('should welcome "Bubba"', () => {
userService.user.name = 'Bubba';
fixture.detectChanges();
expect(el.textContent).toContain('Bubba');
});
it('should request login if not logged in', () => {
userService.isLoggedIn = false;
fixture.detectChanges();
const content = el.textContent;
expect(content).not.toContain('Welcome', 'not welcomed');
expect(content).toMatch(/log in/i, '"log in"');
});
});
The last 2 it() tests failed because the service stub values didn't change after
userService.user.name = 'Bubba';
fixture.detectChanges();
and
userService.isLoggedIn = false;
fixture.detectChanges();
Any idea why Angular test module failed to detect change?
Uodate
I found it. fixture.detectChanges()
triggers ngOnInit()
.
fixture.detectChanges()
in beforeEach()
is the culprit. Because it has initialized the component, the fixture.detectChanges()
in it()
won't initialized the component again. So by removing fixture.detectChanges()
from beforeEach()
the fixture.detectChanges()
in it()
will have the chance to trigger ngOnInit()
and all tests pass through.
beforeEach(() => {
fixture = TestBed.createComponent(WelcomeComponent);
component = fixture.componentInstance;
//userService = TestBed.get(UserService);
userService = fixture.debugElement.injector.get(UserService);
// get the "welcome" element by CSS selector (e.g., by class name)
de = fixture.debugElement.query(By.css('.welcome'));
el = de.nativeElement;
// fixture.detectChanges(); // this is the culprit.
});
Try to initilize your service at your "it"
it('should welcome "Bubba"' , inject([UserService], (userService: UserService) => {
userService.user.name = 'Bubba';
fixture.detectChanges();
expect(el.textContent).toContain('Bubba');
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With