/* 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/page'; 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 component: MyComponent; let debugEl: DebugElement; let nativeEl: Element | HTMLElement; 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); 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; /* 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(component).toMatchSnapshot(); }); /* 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(nativeEl.textContent).toBe('...'); getTestScheduler().flush(); // flush the observables fixture.detectChanges(); // update view expect(nativeEl.textContent).toBe(myValue); }); });