/* FILE TYPE: JEST COMPONENT TEST SAMPLE */ 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'; import { ComponentSuite, ComponentSuiteElements } from '@testing'; import { cold, getTestScheduler } from 'jasmine-marbles'; import { of } from 'rxjs/observable/of'; import { MyAsyncService } from './my-async.service'; import { MyFromModuleService } from './my-from-module.service'; import { MyComponent } from './my.component'; import { MyService } from './my.service'; /* HERE YOUR STUBS AND MOCKS */ /* Use stub components for shallow testing. Do not use NO_ERRORS_SCHEMA. */ @Component({ selector: 'child-comp', template: '' }) class ChildStubComponent { @Input() prop: string; } const myAsyncService = jest.fn<MyAsyncService>(() => ({ myAsyncServiceMethod: jest.fn(() => of([])) })); const optionsMock = { option1: 'option1', option2: 'option2', option3: 'option3' }; const myFromModuleServiceMock = jest.fn<MyFromModuleService>(() => ({ optionsObj: optionsMock, promiseMethod: jest.fn(() => Promise.resolve()), observableMethod: jest.fn(() => of([])), voidMethod: jest.fn() })); /* HERE YOUR SUITES (describe) */ describe('MyComponent', () => { /* Declare all variables that you need for your specs. */ let fixture: ComponentFixture<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. */ myAsyncServiceMethod = new myAsyncService().myAsyncServiceMethod; myValue = 'myValue'; TestBed.configureTestingModule({ imports: [CoreModule], declarations: [MyComponent, ChildStubComponent], providers: [MyService, { provide: MyAsyncService, useValue: myAsyncService }] }) .overrideComponent(MyComponent, { set: { providers: [{ provide: MyFromModuleService, useClass: myFromModuleServiceMock }] } }) .compileComponents() .then(() => { fixture = TestBed.createComponent(MyComponent); els = new ComponentSuite<MyComponent>(fixture).elements; /* User the Page class (or extend it) to encapsulate component's complexity. */ page = new Page(component, debugEl, nativeEl); /* We can also have non-mocked services here. For mocked services we directly test on their mocked methods. */ myService = debugEl.injector.get(MyService); }); })); /* HERE YOUR SPECS (it -> expect) */ it('should create', () => { /* Detect changes on every spec and not on the beforeEach() since you might also want to check some logic on the component's constructor(). */ fixture.detectChanges(); /* 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('.title')).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', () => { const q$ = cold('---x|', { x: myValue }); myAsyncServiceMethod.and.returnValue(q$); fixture.detectChanges(); // ngOnInit() expect(els.host.nativeEl.textContent).toBe('...'); getTestScheduler().flush(); // flush the observables fixture.detectChanges(); // update view expect(els.host.nativeEl.textContent).toBe(myValue); }); });