Slide 1

Slide 1 text

Piotr Lewandowski Good testing hygiene Piotr Lewandowski

Slide 2

Slide 2 text

piotrl.net 2 • JavaScript tes-ng is great, but not bullet proof • When the app scales, some prac-ces needs to be adjusted Lighiting Talk – 15min 3 #ps for today

Slide 3

Slide 3 text

3 piotrl.net Testing Modules

Slide 4

Slide 4 text

piotrl.net 4 What testing modules do we know? • HttpClientTestingModule • RouterTestingModule • BrowserTestingModule • NoopAnimationsModule Goal? • Avoid imperative mocking • Deliver predefined mocks and used modules • Cut Dependency Injection tree @NgModule({ providers: [ IconRegistryMock, { provide: IconRegistry, useExisting: IconRegistryMock, }, ], }) export class IconTestingModule { } @Injectable() export class IconRegistryMock { getIcon(name: string): Observable { return of(''); } }

Slide 5

Slide 5 text

piotrl.net 5 Configurable testing modules? TestBed.configureTestingModule({ imports: [ FeatureFlagsTestingModule.with({ angularEnabled: true, }), ], }); Especially useful for Shared services Shared direc2ves

Slide 6

Slide 6 text

piotrl.net 6 Configurable testing modules? @NgModule() export class FeatureFlagsTestingModule { static with(config) { return { ngModule: FeatureFlagsTestingModule, providers: [ { provide: FeatureFlagsService, useFactory: () => new FeatureFlagsServiceMock(config), }, ], }; } }

Slide 7

Slide 7 text

7 piotrl.net Shallow testing but when?

Slide 8

Slide 8 text

piotrl.net 8 What is shallow testing? {{ someCode | json }}
{{ someCode | json }}
page-xyz.component.html huge component WHAT IF? Our page have 100 huge components And their children have 100 huge components And so on ... schemas: [NO_ERRORS_SCHEMA],

Slide 9

Slide 9 text

piotrl.net 9 When? Testing huge components page-xyz.component.spec.ts TestBed.configureTestingModule( { declarations: [ ComponentWeTest, MockOfChildComponent1, MockOfChildComponent2, MockOfChildComponent3, // and so on for up to MockOfChildComponent4, // 10, 20 mocked child components MockOfChildComponent5, MockOfChildComponent6, ], imports: [ YourModuleWrappingAllDependenciesForAllModules, ButtonComponentModule, // + other design components DependentModule1, DependentModule2, DependentModule3, DependentModule4, // and so on for up to DependentModule1, // 10, 20 imported modules ], }) EFFECT Single test suite 20s+ Modified shared direc2ve = broken test Dependency mess. Hard to maintain.

Slide 10

Slide 10 text

piotrl.net 10 Apply shallow testing page-xyz.component.spec.ts TestBed.configureTestingModule({ schemas: [NO_ERRORS_SCHEMA], declarations: [ ComponentWeTest, ], imports: [ // only TestingModules // for direct dependencies of ComponentWeTest ], providers: [ // only mocks for direct dependencies of ComponentWeTest // or mocks that we modify for test behaviour ], }); EFFECT Single test suite 200ms Modified shared directive = not affecting test Truly unit test. No maintanance effort Cannot do integra2on tes2ng

Slide 11

Slide 11 text

11 piotrl.net avoid done() together with real asynchronousity

Slide 12

Slide 12 text

12 When do we deal with asynchronous code in tests? • async/await • async functions • waitForAsync() • observables with done() Avoid all in tests: • Race condi-ons • Slow tests because we’re wai-ng for real events • Always green tests if we’re not careful

Slide 13

Slide 13 text

13 Async with done() is it really bad? better approach? Rx marbles fakeAsync() it('should refresh after 1s', (done) => { // given // when serviceWithTimeout().subscribe((el) { // then expect(el).toBeTruthy(); done(); }); });

Slide 14

Slide 14 text

14 RxJs and fakeAsync() it('should be green for async', fakeAsync(() => { // given const result = []; // when interval(1000).subscribe((el) => result.push(el)); tick(2000); // then expect(result).toEqual([0, 1]); })); fakeAsync() > waitForAsync() piotrl.net

Slide 15

Slide 15 text

piotrl.net 15 Questions?