Skip to content

Instantly share code, notes, and snippets.

@kaplan81
Last active August 8, 2022 19:27

Revisions

  1. kaplan81 revised this gist Apr 26, 2021. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -18,7 +18,7 @@ import { MyService } from './my.service';
    Use stub components for shallow testing.
    Do not use NO_ERRORS_SCHEMA.
    */
    const optionsDataMock: { [key: string]: any } = {
    const optionsDataMock: Record<string, string> = {
    option1: 'option1',
    option2: 'option2',
    option3: 'option3',
    @@ -31,15 +31,15 @@ class ChildStubComponent {

    @Injectable()
    class MyAsyncServiceMock extends MyAsyncService {
    myAsyncServiceMethod: () => Observable<any[]> = jest.fn(() => of([]));
    myAsyncServiceMethod: jest.Mock<Observable<any[]>> = jest.fn(() => of([]));
    }

    @Injectable()
    class MyFromModuleServiceMock extends MyFromModuleService {
    observableMethod: () => Observable<any[]> = jest.fn(() => of([]));
    optionsObj = optionsDataMock;
    promiseMethod: () => Promise<any[]> = jest.fn(() => Promise.resolve([]));
    voidMethod: () => void = jest.fn();
    observableMethod: jest.Mock<Observable<any[]>> = jest.fn(() => of([]));
    optionsObj: Record<string, string> = optionsDataMock;
    promiseMethod: jest.Mock<Promise<any[]>> = jest.fn(() => Promise.resolve([]));
    voidMethod: jest.Mock<void> = jest.fn();
    }

    /* HERE YOUR SUITES (describe) */
  2. kaplan81 revised this gist Jun 22, 2020. 1 changed file with 1 addition and 6 deletions.
    7 changes: 1 addition & 6 deletions sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -49,13 +49,8 @@ describe('MyComponent', () => {
    let els: ComponentSuiteElements<MyComponent>;
    let page: Page;
    let myService: MyService;
    // Methods from mocked services.
    let myAsyncServiceMethod: any;
    // Other values.
    let myValue: string;

    beforeEach(async(() => {
    /* Initialized here variables that are not depending on the fixture. */ // OLD
    // myAsyncServiceMethod = new myAsyncService().myAsyncServiceMethod; // OLD
    // myValue = 'myValue'; // OLD
    TestBed.configureTestingModule({
    @@ -78,7 +73,7 @@ describe('MyComponent', () => {
    We can also have non-mocked services here.
    For mocked services we directly test on their mocked methods.
    */
    myService = debugEl.injector.get(MyService);
    myService = TestBed.inject(MyService);
    });
    }));

  3. kaplan81 revised this gist Jun 22, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -18,7 +18,7 @@ import { MyService } from './my.service';
    Use stub components for shallow testing.
    Do not use NO_ERRORS_SCHEMA.
    */
    const optionsDataMock = {
    const optionsDataMock: { [key: string]: any } = {
    option1: 'option1',
    option2: 'option2',
    option3: 'option3',
  4. kaplan81 revised this gist Jun 22, 2020. 1 changed file with 23 additions and 21 deletions.
    44 changes: 23 additions & 21 deletions sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -18,27 +18,29 @@ import { MyService } from './my.service';
    Use stub components for shallow testing.
    Do not use NO_ERRORS_SCHEMA.
    */
    @Component({ selector: 'child-comp', template: '' })
    const optionsDataMock = {
    option1: 'option1',
    option2: 'option2',
    option3: 'option3',
    };

    @Component({ selector: 'pfx-child', template: '' })
    class ChildStubComponent {
    @Input() prop: string;
    }

    const myAsyncService = jest.fn<MyAsyncService>(() => ({
    myAsyncServiceMethod: jest.fn(() => of([]))
    }));

    const optionsMock = {
    option1: 'option1',
    option2: 'option2',
    option3: 'option3'
    };
    @Injectable()
    class MyAsyncServiceMock extends MyAsyncService {
    myAsyncServiceMethod: () => Observable<any[]> = jest.fn(() => of([]));
    }

    const myFromModuleServiceMock = jest.fn<MyFromModuleService>(() => ({
    optionsObj: optionsMock,
    promiseMethod: jest.fn(() => Promise.resolve()),
    observableMethod: jest.fn(() => of([])),
    voidMethod: jest.fn()
    }));
    @Injectable()
    class MyFromModuleServiceMock extends MyFromModuleService {
    observableMethod: () => Observable<any[]> = jest.fn(() => of([]));
    optionsObj = optionsDataMock;
    promiseMethod: () => Promise<any[]> = jest.fn(() => Promise.resolve([]));
    voidMethod: () => void = jest.fn();
    }

    /* HERE YOUR SUITES (describe) */
    describe('MyComponent', () => {
    @@ -53,17 +55,17 @@ describe('MyComponent', () => {
    let myValue: string;

    beforeEach(async(() => {
    /* Initialized here variables that are not depending on the fixture. */
    myAsyncServiceMethod = new myAsyncService().myAsyncServiceMethod;
    myValue = 'myValue';
    /* Initialized here variables that are not depending on the fixture. */ // OLD
    // myAsyncServiceMethod = new myAsyncService().myAsyncServiceMethod; // OLD
    // myValue = 'myValue'; // OLD
    TestBed.configureTestingModule({
    imports: [CoreModule],
    declarations: [MyComponent, ChildStubComponent],
    providers: [MyService, { provide: MyAsyncService, useValue: myAsyncService }]
    providers: [MyService, { provide: MyAsyncService, useClass: MyAsyncServiceMock }]
    })
    .overrideComponent(MyComponent, {
    set: {
    providers: [{ provide: MyFromModuleService, useClass: myFromModuleServiceMock }]
    providers: [{ provide: MyFromModuleService, useClass: MyFromModuleServiceMock }]
    }
    })
    .compileComponents()
  5. kaplan81 revised this gist Oct 19, 2018. 1 changed file with 0 additions and 128 deletions.
    128 changes: 0 additions & 128 deletions http-hero.service.spec.ts
    Original file line number Diff line number Diff line change
    @@ -1,128 +0,0 @@
    /* FILE TYPE: HERO SERVICE TEST */

    /**
    * Test the HeroService when implemented with the OLD HttpModule
    */
    import {
    async, inject, TestBed
    } from '@angular/core/testing';

    import {
    MockBackend,
    MockConnection
    } from '@angular/http/testing';

    import {
    HttpModule, Http, XHRBackend, Response, ResponseOptions
    } from '@angular/http';

    import { of } from 'rxjs';

    import { Hero } from './hero';
    import { HttpHeroService } from './http-hero.service';

    const makeHeroData = () => [
    { id: 1, name: 'Windstorm' },
    { id: 2, name: 'Bombasto' },
    { id: 3, name: 'Magneta' },
    { id: 4, name: 'Tornado' }
    ] as Hero[];

    //////// Tests /////////////
    describe('HttpHeroService (using old HttpModule)', () => {
    let backend: MockBackend;
    let service: HttpHeroService;

    beforeEach( () => {
    TestBed.configureTestingModule({
    imports: [ HttpModule ],
    providers: [
    HttpHeroService,
    { provide: XHRBackend, useClass: MockBackend }
    ]
    });
    });

    it('can instantiate service via DI', () => {
    service = TestBed.get(HttpHeroService);
    expect(service instanceof HttpHeroService).toBe(true);
    });

    it('can instantiate service with "new"', () => {
    const http = TestBed.get(Http);
    expect(http).not.toBeNull('http should be provided');
    let service = new HttpHeroService(http);
    expect(service instanceof HttpHeroService).toBe(true, 'new service should be ok');
    });

    it('can provide the mockBackend as XHRBackend', () => {
    const backend = TestBed.get(XHRBackend);
    expect(backend).not.toBeNull('backend should be provided');
    });

    describe('when getHeroes', () => {
    let fakeHeroes: Hero[];
    let http: Http;
    let response: Response;

    beforeEach(() => {

    backend = TestBed.get(XHRBackend);
    http = TestBed.get(Http);

    service = new HttpHeroService(http);
    fakeHeroes = makeHeroData();
    let options = new ResponseOptions({status: 200, body: {data: fakeHeroes}});
    response = new Response(options);
    });

    it('should have expected fake heroes (then)', () => {
    backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));

    service.getHeroes().toPromise()
    // .then(() => Promise.reject('deliberate'))
    .then(heroes => {
    expect(heroes.length).toBe(fakeHeroes.length,
    'should have expected no. of heroes');
    })
    .catch(fail);
    });

    it('should have expected fake heroes (Observable tap)', () => {
    backend.connections.subscribe((c: MockConnection) => c.mockRespond(response));

    service.getHeroes().subscribe(
    heroes => {
    expect(heroes.length).toBe(fakeHeroes.length,
    'should have expected no. of heroes');
    },
    fail
    );
    });


    it('should be OK returning no heroes', () => {
    let resp = new Response(new ResponseOptions({status: 200, body: {data: []}}));
    backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp));

    service.getHeroes().subscribe(
    heroes => {
    expect(heroes.length).toBe(0, 'should have no heroes');
    },
    fail
    );
    });

    it('should treat 404 as an Observable error', () => {
    let resp = new Response(new ResponseOptions({status: 404}));
    backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp));

    service.getHeroes().subscribe(
    heroes => fail('should not respond with heroes'),
    err => {
    expect(err).toMatch(/Bad response status/, 'should catch bad response status code');
    return of(null); // failure is the expected test result
    });
    });
    });
    });
  6. kaplan81 revised this gist Oct 19, 2018. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions http-client.spec.ts
    Original file line number Diff line number Diff line change
    @@ -50,9 +50,6 @@ describe('HttpClient testing', () => {
    // Respond with mock data, causing Observable to resolve.
    // Subscribe callback asserts that correct data was returned.
    req.flush(testData);

    // Finally, assert that there are no outstanding requests.
    httpTestingController.verify();
    });
    it('can test HttpClient.get with matching header', () => {
    const testData: Data = { name: 'Test Data' };
  7. kaplan81 revised this gist Sep 28, 2018. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions router-link-directive-stub.ts
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,7 @@ export { RouterLink } from '@angular/router';
    @Directive({
    selector: '[routerLink]'
    })
    export class RouterLinkDirectiveStub {
    export class RouterLinkStubDirective {
    navigatedTo: any = null;
    @Input()
    routerLink: any;
    @@ -20,6 +20,6 @@ export class RouterLinkDirectiveStub {
    }

    @NgModule({
    declarations: [RouterLinkDirectiveStub]
    declarations: [RouterLinkStubDirective]
    })
    export class RouterStubsModule {}
  8. kaplan81 revised this gist Sep 18, 2018. 1 changed file with 9 additions and 15 deletions.
    24 changes: 9 additions & 15 deletions router-link-directive-stub.ts
    Original file line number Diff line number Diff line change
    @@ -1,31 +1,25 @@
    /* FILE TYPE: TEST HELPER */

    import { Directive, Input } from '@angular/core';
    import { Directive, HostListener, Input, NgModule } from '@angular/core';

    // export for convenience.
    export { RouterLink} from '@angular/router';
    export { RouterLink } from '@angular/router';

    /* tslint:disable:directive-class-suffix */
    // #docregion router-link
    @Directive({
    selector: '[routerLink]',
    host: { '(click)': 'onClick()' }
    selector: '[routerLink]'
    })
    export class RouterLinkDirectiveStub {
    @Input('routerLink') linkParams: any;
    navigatedTo: any = null;

    @Input()
    routerLink: any;
    @HostListener('click')
    onClick() {
    this.navigatedTo = this.linkParams;
    this.navigatedTo = this.routerLink;
    }
    }
    // #enddocregion router-link
    /// Dummy module to satisfy Angular Language service. Never used.
    import { NgModule } from '@angular/core';

    @NgModule({
    declarations: [
    RouterLinkDirectiveStub
    ]
    declarations: [RouterLinkDirectiveStub]
    })
    export class RouterStubsModule {}
    export class RouterStubsModule {}
  9. kaplan81 revised this gist Sep 18, 2018. 1 changed file with 15 additions and 9 deletions.
    24 changes: 15 additions & 9 deletions router-link-directive-stub.ts
    Original file line number Diff line number Diff line change
    @@ -1,25 +1,31 @@
    /* FILE TYPE: TEST HELPER */

    import { Directive, HostListener, Input, NgModule } from '@angular/core';
    import { Directive, Input } from '@angular/core';

    // export for convenience.
    export { RouterLink } from '@angular/router';
    export { RouterLink} from '@angular/router';

    /* tslint:disable:directive-class-suffix */
    /* tslint:disable:directive-selector */
    // #docregion router-link
    @Directive({
    selector: '[routerLink]'
    selector: '[routerLink]',
    host: { '(click)': 'onClick()' }
    })
    export class RouterLinkDirectiveStub {
    @Input() routerLink: any;
    @Input('routerLink') linkParams: any;
    navigatedTo: any = null;
    @HostListener('click')

    onClick() {
    this.navigatedTo = this.routerLink;
    this.navigatedTo = this.linkParams;
    }
    }
    // #enddocregion router-link
    /// Dummy module to satisfy Angular Language service. Never used.
    import { NgModule } from '@angular/core';

    @NgModule({
    declarations: [RouterLinkDirectiveStub]
    declarations: [
    RouterLinkDirectiveStub
    ]
    })
    export class RouterStubsModule {}
    export class RouterStubsModule {}
  10. kaplan81 revised this gist Sep 6, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion _testing.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,3 @@
    # Testing

    > Helper classes and example specs for unit testing purposes on Angular applications and libraries.
    > Helpers and examples for unit testing on Angular applications and libraries.
  11. kaplan81 revised this gist Sep 6, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion _testing.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,3 @@
    # testing
    # Testing

    > Helper classes and example specs for unit testing purposes on Angular applications and libraries.
  12. kaplan81 revised this gist Sep 6, 2018. 2 changed files with 3 additions and 1 deletion.
    1 change: 0 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    Hello World
    3 changes: 3 additions & 0 deletions _testing.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    # testing

    > Helper classes and example specs for unit testing purposes on Angular applications and libraries.
  13. kaplan81 revised this gist Sep 6, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    Hello World
  14. kaplan81 revised this gist Sep 6, 2018. 1 changed file with 13 additions and 11 deletions.
    24 changes: 13 additions & 11 deletions component-suite.ts
    Original file line number Diff line number Diff line change
    @@ -5,11 +5,11 @@ import { ComponentFixture } from '@angular/core/testing';
    import { By } from '@angular/platform-browser';

    export interface ComponentSuiteElements<H, N = any> {
    host: ComponentTestingElements<H>;
    nested?: ComponentTestingElements<N>;
    host: ComponentTestingElement<H>;
    nested?: ComponentTestingElement<N>;
    }

    export interface ComponentTestingElements<T> {
    export interface ComponentTestingElement<T> {
    component: T;
    debugEl: DebugElement;
    nativeEl: Element | HTMLElement;
    @@ -22,7 +22,7 @@ export class ComponentSuite<H, N = any> {
    this.setElements();
    }

    private getHost(): ComponentTestingElements<H> {
    private getHost(): ComponentTestingElement<H> {
    const component: H = this.fixture.componentInstance;
    const debugEl: DebugElement = this.fixture.debugElement;
    const nativeEl: Element | HTMLElement = debugEl.nativeElement;
    @@ -31,16 +31,16 @@ export class ComponentSuite<H, N = any> {
    }

    private getIntegrationElements(): ComponentSuiteElements<H, N> {
    const host: ComponentTestingElements<H> = this.getHost();
    const nested: ComponentTestingElements<N> = this.getNested(host.debugEl);
    const host: ComponentTestingElement<H> = this.getHost();
    const nested: ComponentTestingElement<N> = this.getNested(host.debugEl);

    return {
    host,
    nested
    };
    }

    private getNested(hostDebugEl: DebugElement): ComponentTestingElements<N> {
    private getNested(hostDebugEl: DebugElement): ComponentTestingElement<N> {
    const debugEl: DebugElement = hostDebugEl.query(By.css(this.selector));
    const component: N = debugEl.componentInstance;
    const nativeEl: Element | HTMLElement = debugEl.nativeElement;
    @@ -53,8 +53,10 @@ export class ComponentSuite<H, N = any> {
    }

    private setElements(): void {
    this.elements = this.selector
    ? this.getIntegrationElements()
    : (this.elements = this.getShallowElements());
    if (this.selector) {
    this.elements = this.getIntegrationElements();
    } else {
    this.elements = this.getShallowElements();
    }
    }
    }
    }
  15. kaplan81 revised this gist Sep 5, 2018. 1 changed file with 3 additions and 5 deletions.
    8 changes: 3 additions & 5 deletions component-suite.ts
    Original file line number Diff line number Diff line change
    @@ -53,10 +53,8 @@ export class ComponentSuite<H, N = any> {
    }

    private setElements(): void {
    if (this.selector) {
    this.elements = this.getIntegrationElements();
    } else {
    this.elements = this.getShallowElements();
    }
    this.elements = this.selector
    ? this.getIntegrationElements()
    : (this.elements = this.getShallowElements());
    }
    }
  16. kaplan81 revised this gist Sep 5, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -95,7 +95,7 @@ describe('MyComponent', () => {
    it('should generate as many titles as contents', () => {
    fixture.detectChanges();

    const titles: number = els.host.debugEl.queryAll(By.css('.label')).length;
    const titles: number = els.host.debugEl.queryAll(By.css('.title')).length;
    const contents: number = els.host.component.contents.toArray().length;

    expect(titles).toEqual(contents);
  17. kaplan81 revised this gist Sep 5, 2018. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -107,11 +107,11 @@ describe('MyComponent', () => {
    myAsyncServiceMethod.and.returnValue(q$);

    fixture.detectChanges(); // ngOnInit()
    expect(nativeEl.textContent).toBe('...');
    expect(els.host.nativeEl.textContent).toBe('...');

    getTestScheduler().flush(); // flush the observables

    fixture.detectChanges(); // update view
    expect(nativeEl.textContent).toBe(myValue);
    expect(els.host.nativeEl.textContent).toBe(myValue);
    });
    });
  18. kaplan81 revised this gist Sep 5, 2018. 1 changed file with 14 additions and 12 deletions.
    26 changes: 14 additions & 12 deletions sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,8 @@ import { Component, DebugElement, Input } from '@angular/core';
    import { ComponentFixture, TestBed, async } from '@angular/core/testing';
    // Use Typescript path mapping to import test helpers.
    import { CoreModule } from '@app/core/core.module';
    import { Page } from '@testing/page';
    import { Page } from '@testing';
    import { ComponentSuite, ComponentSuiteElements } from '@testing';
    import { cold, getTestScheduler } from 'jasmine-marbles';
    import { of } from 'rxjs/observable/of';
    import { MyAsyncService } from './my-async.service';
    @@ -43,9 +44,7 @@ const myFromModuleServiceMock = jest.fn<MyFromModuleService>(() => ({
    describe('MyComponent', () => {
    /* Declare all variables that you need for your specs. */
    let fixture: ComponentFixture<MyComponent>;
    let component: MyComponent;
    let debugEl: DebugElement;
    let nativeEl: Element | HTMLElement;
    let els: ComponentSuiteElements<MyComponent>;
    let page: Page;
    let myService: MyService;
    // Methods from mocked services.
    @@ -70,14 +69,7 @@ describe('MyComponent', () => {
    .compileComponents()
    .then(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    /*
    Always declare the debug element because of 2 reasons:
    1) It wrappes the native element in a platformBrowser way.
    2) It contains methods that you will want to use in many tests.
    */
    debugEl = fixture.debugElement;
    nativeEl = debugEl.nativeElement;
    els = new ComponentSuite<MyComponent>(fixture).elements;
    /* User the Page class (or extend it) to encapsulate component's complexity. */
    page = new Page(component, debugEl, nativeEl);
    /*
    @@ -98,6 +90,16 @@ describe('MyComponent', () => {
    /* We use Jest snapshot testing instead of the usual matcher. */
    expect(fixture).toMatchSnapshot();
    });

    /* Shallow test example with ComponentSuite helper class */
    it('should generate as many titles as contents', () => {
    fixture.detectChanges();

    const titles: number = els.host.debugEl.queryAll(By.css('.label')).length;
    const contents: number = els.host.component.contents.toArray().length;

    expect(titles).toEqual(contents);
    });

    /* Work with jasmine marbles to test observables. */
    it('should test with jasmine marbles', () => {
  19. kaplan81 revised this gist Sep 5, 2018. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions component-suite.ts
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    /* FILE TYPE: TEST HELPER */

    import { DebugElement } from '@angular/core';
    import { ComponentFixture } from '@angular/core/testing';
    import { By } from '@angular/platform-browser';
  20. kaplan81 revised this gist Sep 5, 2018. 1 changed file with 60 additions and 0 deletions.
    60 changes: 60 additions & 0 deletions component-suite.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    import { DebugElement } from '@angular/core';
    import { ComponentFixture } from '@angular/core/testing';
    import { By } from '@angular/platform-browser';

    export interface ComponentSuiteElements<H, N = any> {
    host: ComponentTestingElements<H>;
    nested?: ComponentTestingElements<N>;
    }

    export interface ComponentTestingElements<T> {
    component: T;
    debugEl: DebugElement;
    nativeEl: Element | HTMLElement;
    }

    export class ComponentSuite<H, N = any> {
    elements: ComponentSuiteElements<H, N>;

    constructor(private fixture: ComponentFixture<H>, private selector?: string) {
    this.setElements();
    }

    private getHost(): ComponentTestingElements<H> {
    const component: H = this.fixture.componentInstance;
    const debugEl: DebugElement = this.fixture.debugElement;
    const nativeEl: Element | HTMLElement = debugEl.nativeElement;

    return { component, debugEl, nativeEl };
    }

    private getIntegrationElements(): ComponentSuiteElements<H, N> {
    const host: ComponentTestingElements<H> = this.getHost();
    const nested: ComponentTestingElements<N> = this.getNested(host.debugEl);

    return {
    host,
    nested
    };
    }

    private getNested(hostDebugEl: DebugElement): ComponentTestingElements<N> {
    const debugEl: DebugElement = hostDebugEl.query(By.css(this.selector));
    const component: N = debugEl.componentInstance;
    const nativeEl: Element | HTMLElement = debugEl.nativeElement;

    return { component, debugEl, nativeEl };
    }

    private getShallowElements(): ComponentSuiteElements<H> {
    return { host: this.getHost() };
    }

    private setElements(): void {
    if (this.selector) {
    this.elements = this.getIntegrationElements();
    } else {
    this.elements = this.getShallowElements();
    }
    }
    }
  21. kaplan81 revised this gist Sep 5, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion sample.component.spec.ts
    Original file line number Diff line number Diff line change
    @@ -96,7 +96,7 @@ describe('MyComponent', () => {
    */
    fixture.detectChanges();
    /* We use Jest snapshot testing instead of the usual matcher. */
    expect(component).toMatchSnapshot();
    expect(fixture).toMatchSnapshot();
    });

    /* Work with jasmine marbles to test observables. */
  22. kaplan81 revised this gist Jun 20, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions router-link-directive-stub.ts
    Original file line number Diff line number Diff line change
    @@ -6,6 +6,7 @@ import { Directive, HostListener, Input, NgModule } from '@angular/core';
    export { RouterLink } from '@angular/router';

    /* tslint:disable:directive-class-suffix */
    /* tslint:disable:directive-selector */
    @Directive({
    selector: '[routerLink]'
    })
  23. kaplan81 revised this gist Jun 20, 2018. 1 changed file with 3 additions and 4 deletions.
    7 changes: 3 additions & 4 deletions activated-route-stub.ts
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // export for convenience.
    export { ActivatedRoute } from '@angular/router';
    import { convertToParamMap, Data, ParamMap, Params } from '@angular/router';
    import { Observable, of, ReplaySubject } from 'rxjs';
    import { Observable, of, BehaviorSubject } from 'rxjs';

    export interface ActivatedRouteSnapshotStub {
    data?: Data;
    @@ -20,9 +20,8 @@ export class ActivatedRouteStub {
    data: Observable<Data>;
    snapshot: ActivatedRouteSnapshotStub;
    readonly paramMap: Observable<ParamMap>;
    // Use a ReplaySubject to share previous values with subscribers
    // and pump new values into the `paramMap` observable
    private subject = new ReplaySubject<ParamMap>();
    // ReplaySubject is not compatible with snapshot testing since it produces a window timestamp.
    private subject = new BehaviorSubject<ParamMap>(null);

    constructor(init: ActivatedRouteProps = {}) {
    this.paramMap = this.subject.asObservable();
  24. kaplan81 revised this gist Jun 20, 2018. No changes.
  25. kaplan81 revised this gist Jun 13, 2018. 1 changed file with 6 additions and 2 deletions.
    8 changes: 6 additions & 2 deletions activated-route-stub.ts
    Original file line number Diff line number Diff line change
    @@ -25,12 +25,16 @@ export class ActivatedRouteStub {
    private subject = new ReplaySubject<ParamMap>();

    constructor(init: ActivatedRouteProps = {}) {
    this.data = of(init.initialData);
    this.paramMap = this.subject.asObservable();
    this.setParamMap(init.initialParams);
    if (init.initialSnapshot) this.snapshot = init.initialSnapshot;
    if (init.initialData) {
    this.data = of(init.initialData);
    this.setParamMap(init.initialParams);
    }
    }

    setParamMap(params?: Params) {
    this.subject.next(convertToParamMap(params));
    }
    }

  26. kaplan81 revised this gist Jun 13, 2018. 1 changed file with 0 additions and 27 deletions.
    27 changes: 0 additions & 27 deletions async-observable-helpers.ts
    Original file line number Diff line number Diff line change
    @@ -1,27 +0,0 @@
    /* FILE TYPE: TEST HELPER */

    /*
    * Mock async observables that return asynchronously.
    * The observable either emits once and completes or errors.
    *
    * Must call `tick()` when test with `fakeAsync()`.
    *
    * THE FOLLOWING DON'T WORK
    * Using `of().delay()` triggers TestBed errors;
    * see https://github.com/angular/angular/issues/10127 .
    *
    * Using `asap` scheduler - as in `of(value, asap)` - doesn't work either.
    */
    import { defer } from 'rxjs';

    /** Create async observable that emits-once and completes
    * after a JS engine turn */
    export function asyncData<T>(data: T) {
    return defer(() => Promise.resolve(data));
    }

    /** Create async observable error that errors
    * after a JS engine turn */
    export function asyncError<T>(errorObject: any) {
    return defer(() => Promise.reject(errorObject));
    }
  27. kaplan81 revised this gist Jun 13, 2018. 1 changed file with 12 additions and 11 deletions.
    23 changes: 12 additions & 11 deletions activated-route-stub.ts
    Original file line number Diff line number Diff line change
    @@ -2,33 +2,34 @@

    // export for convenience.
    export { ActivatedRoute } from '@angular/router';
    import { convertToParamMap, ParamMap, Params } from '@angular/router';
    import { convertToParamMap, Data, ParamMap, Params } from '@angular/router';
    import { Observable, of, ReplaySubject } from 'rxjs';

    export interface ActivatedRouteSnapshotStub {
    data?: Data;
    paramMap?: ParamMap;
    }

    export interface ActivatedRouteProps {
    initialData?: Data;
    initialSnapshot?: ActivatedRouteSnapshotStub;
    initialParams?: Params;
    initialData?: any;
    }

    /**
    * An ActivateRoute test double with a `paramMap` observable.
    * Use the `setParamMap()` method to add the next `paramMap` value.
    */
    export class ActivatedRouteStub {
    /** The mock paramMap observable */
    readonly paramMap: Observable<any>;
    readonly data: Observable<any>;
    data: Observable<Data>;
    snapshot: ActivatedRouteSnapshotStub;
    readonly paramMap: Observable<ParamMap>;
    // Use a ReplaySubject to share previous values with subscribers
    // and pump new values into the `paramMap` observable
    private subject = new ReplaySubject<ParamMap>();

    constructor(init: ActivatedRouteProps = {}) {
    this.paramMap = this.subject.asObservable();
    this.data = of(init.initialData);
    this.paramMap = this.subject.asObservable();
    this.setParamMap(init.initialParams);
    }

    /** Set the paramMap observables's next value */
    setParamMap(params?: Params) {
    this.subject.next(convertToParamMap(params));
    }
  28. kaplan81 revised this gist Jun 12, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion async-observable-helpers.ts
    Original file line number Diff line number Diff line change
    @@ -12,7 +12,7 @@
    *
    * Using `asap` scheduler - as in `of(value, asap)` - doesn't work either.
    */
    import { defer } from 'rxjs/observable/defer';
    import { defer } from 'rxjs';

    /** Create async observable that emits-once and completes
    * after a JS engine turn */
  29. kaplan81 revised this gist Jun 12, 2018. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions activated-route-stub.ts
    Original file line number Diff line number Diff line change
    @@ -3,9 +3,7 @@
    // export for convenience.
    export { ActivatedRoute } from '@angular/router';
    import { convertToParamMap, ParamMap, Params } from '@angular/router';
    import { Observable } from 'rxjs/Observable';
    import { of } from 'rxjs/observable/of';
    import { ReplaySubject } from 'rxjs/ReplaySubject';
    import { Observable, of, ReplaySubject } from 'rxjs';

    export interface ActivatedRouteProps {
    initialParams?: Params;
  30. kaplan81 revised this gist Jun 12, 2018. 1 changed file with 15 additions and 7 deletions.
    22 changes: 15 additions & 7 deletions activated-route-stub.ts
    Original file line number Diff line number Diff line change
    @@ -2,26 +2,34 @@

    // export for convenience.
    export { ActivatedRoute } from '@angular/router';

    import { ParamMap, Params, convertToParamMap } from '@angular/router';
    import { convertToParamMap, ParamMap, Params } from '@angular/router';
    import { Observable } from 'rxjs/Observable';
    import { of } from 'rxjs/observable/of';
    import { ReplaySubject } from 'rxjs/ReplaySubject';

    export interface ActivatedRouteProps {
    initialParams?: Params;
    initialData?: any;
    }

    /**
    * An ActivateRoute test double with a `paramMap` observable.
    * Use the `setParamMap()` method to add the next `paramMap` value.
    */
    export class ActivatedRouteStub {
    /** The mock paramMap observable */
    readonly paramMap: Observable<any>;
    readonly data: Observable<any>;
    // Use a ReplaySubject to share previous values with subscribers
    // and pump new values into the `paramMap` observable
    private subject = new ReplaySubject<ParamMap>();

    constructor(initialParams?: Params) {
    this.setParamMap(initialParams);
    constructor(init: ActivatedRouteProps = {}) {
    this.paramMap = this.subject.asObservable();
    this.data = of(init.initialData);
    this.setParamMap(init.initialParams);
    }

    /** The mock paramMap observable */
    readonly paramMap = this.subject.asObservable();

    /** Set the paramMap observables's next value */
    setParamMap(params?: Params) {
    this.subject.next(convertToParamMap(params));