slides.com/gerardsans | @gerardsans
850
1K
Angular In Flip Flops
Unit Tests
Assertion Libraries
Spies, Stubs
Test
Automation
Browsers
Coverage Reports
e2e Tests
Test
Runner
WebDriverJS
Selenium
Protractor
Unit tests
e2e Tests
Acceptance Tests
$ npm run tests $ npm run e2e
let calculator = {
add: (a, b) => a + b
};
describe('Calculator', () => {
it('should add two numbers', () => {
expect(calculator.add(1,1)).toBe(2);
})
})
fail(msg), pending(msg)
xdescribe, xit
fdescribe, fit
Test double functions that record calls, arguments and return values
describe('Spies', () => {
let calculator = { add: (a,b) => a+b };
it('should track calls but NOT call through', () => {
spyOn(calculator, 'add');
let result = calculator.add(1,1);
expect(calculator.add).toHaveBeenCalled();
expect(calculator.add).toHaveBeenCalledTimes(1);
expect(calculator.add).toHaveBeenCalledWith(1,1);
expect(result).not.toEqual(2);
})
})
describe('Spies', () => {
it('should call through', () => {
spyOn(calculator, 'add').and.callThrough();
let result = calculator.add(1,1);
expect(result).toEqual(2);
//restore stub behaviour
calculator.add.and.stub();
expect(calculator.add(1,1)).not.toEqual(2);
})
})
describe('Spies', () => {
it('should return value with 42', () => {
spyOn(calculator, 'add').and.returnValue(42);
let result = calculator.add(1,1);
expect(result).toEqual(42);
})
it('should return values 1, 2, 3', () => {
spyOn(calculator, 'add').and.returnValues(1, 2, 3);
expect(calculator.add(1,1)).toEqual(1);
expect(calculator.add(1,1)).toEqual(2);
expect(calculator.add(1,1)).toEqual(3);
})
})
describe('Spies', () => {
it('should throw with error', () => {
spyOn(calculator, 'add').and.throwError("Ups");
expect(() => calculator.add(1,1)).toThrowError("Ups");
})
})
describe('Spies', () => {
it('should be able to create a spy manually', () => {
let add = jasmine.createSpy('add');
add();
expect(add).toHaveBeenCalled();
})
})
// usage: create spy to use as a callback
// setTimeout(add, 100);
describe('Spies', () => {
it('should be able to create multiple spies manually', () => {
let calculator = jasmine.createSpyObj('calculator', ['add']);
calculator.add.and.returnValue(42);
let result = calculator.add(1,1);
expect(calculator.add).toHaveBeenCalled();
expect(result).toEqual(42);
})
})
import { TestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
import {Injectable} from '@angular/core';
@Injectable()
export class LanguagesService {
get() {
return ['en', 'es', 'fr'];
}
}
describe('Service: LanguagesService', () => {
//setup
beforeEach(() => TestBed.configureTestingModule({
providers: [ LanguagesService ]
}));
//specs
it('should return available languages', inject([LanguagesService], service => {
let languages = service.get();
expect(languages).toContain('en');
expect(languages).toContain('es');
expect(languages).toContain('fr');
expect(languages.length).toEqual(3);
});
});
describe('Service: LanguagesService', () => {
let service;
beforeEach(() => TestBed.configureTestingModule({
providers: [ LanguagesService ]
}));
beforeEach(inject([LanguagesService], s => {
service = s;
}));
it('should return available languages', () => {
let languages = service.get();
expect(languages).toContain('en');
expect(languages).toContain('es');
expect(languages).toContain('fr');
expect(languages.length).toEqual(3);
});
});
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class LanguagesServiceHttp {
constructor(private http:Http) { }
get(){
return this.http.get('api/languages.json')
.map(response => response.json());
}
}
describe('MockBackend: LanguagesServiceHttp', () => {
let mockbackend, service;
beforeEach(() => TestBed.configureTestingModule({
providers: [
BaseRequestOptions,
MockBackend,
{ provide: Http,
useFactory: (backend, options) => new Http(backend, options),
deps: [MockBackend, BaseRequestOptions] },
LanguagesServiceHttp
]
}));
beforeEach(inject([MockBackend, LanguagesServiceHttp], (m, s) => {
mockbackend = m;
service = s;
}))
it('should return mocked response (sync)', () => {
//setup mock response
let response = ["ru", "es"];
mockbackend.connections.subscribe(connection => {
connection.mockRespond(new Response({body: JSON.stringify(response)}));
});
//check expectations
service.get().subscribe(languages => {
expect(languages).toContain('ru');
expect(languages).toContain('es');
expect(languages.length).toBe(2);
});
});
import {Component, Input} from '@angular/core';
@Component({
selector: 'greeter', // <greeter name="Igor"></greeter>
template: `<h1>Hello {{name}}!</h1>`
})
export class Greeter {
@Input() name;
}
describe('Component: Greeter', () => {
let fixture, greeter, element, de;
//setup
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ Greeter ]
});
fixture = TestBed.createComponent(Greeter);
greeter = fixture.componentInstance;
element = fixture.nativeElement;
de = fixture.debugElement;
});
}
describe('Component: Greeter', () => {
let fixture, greeter, element, de;
//setup
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ Greeter ],
})
.compileComponents() // compile external templates and css
.then(() => {
fixture = TestBed.createComponent(Greeter);
greeter = fixture.componentInstance;
element = fixture.nativeElement;
de = fixture.debugElement;
});
))
});
describe('Component: Greeter', () => {
it('should render `Hello World!`', async(() => {
greeter.name = 'World';
//trigger change detection
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(element.querySelector('h1').innerText).toBe('Hello World!');
expect(de.query(By.css('h1')).nativeElement.innerText).toBe('Hello World!');
});
}));
}
describe('Component: Greeter', () => {
it('should render `Hello World!`', fakeAsync(() => {
greeter.name = 'World';
//trigger change detection
fixture.detectChanges();
//execute all pending asynchronous calls
tick();
expect(element.querySelector('h1').innerText).toBe('Hello World!');
expect(de.query(By.css('h1')).nativeElement.innerText).toBe('Hello World!');
}));
}
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ MyComponent ],
schemas: [ NO_ERRORS_SCHEMA ]
})
});
Components, Directives, Pipes
Services, Http, MockBackend
Router, Observables
Spies