Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Tidy up your tests using component test harnesses

Alisa
November 29, 2021

Tidy up your tests using component test harnesses

For context and write-up, visit my article series on https://dev.to/alisaduncan.

This presentation is from ngRome 2021.

Do your component tests feel "cluttered"? Do you wish for tests that are easier to write and maintain, and focused on testing behavior without worrying about having to always query the template to interact with components? This is possible when you tidy up your test using Angular CDK's test harnesses. In this talk, we'll cover what test harnesses are, using Angular Material component test harnesses for immediate results, and how you can extend from the CDK test harness API to create custom component test harnesses. With the magical power of testing harnesses, you'll be able to write tests that bring you joy. ✨

Alisa

November 29, 2021
Tweet

More Decks by Alisa

Other Decks in Programming

Transcript

  1. @AlisaDuncan Tidy up your tests TIDY UP YOUR TESTS use

    component harnesses to write tests that bring you joy ALISA DUNCAN
  2. ALISA DUNCAN Software Architect | Co-organizer | Core Team |

    Angular GDE Loves learning about, discussing, and writing automated tests Enjoys reading a book and drinking a glass of wine on the porch @ALISADUNCAN AngularKC ngGirls
  3. TESTS THAT DON'T BRING US JOY Do your component tests

    feel "cluttered"? Is it difficult to read and understand your component unit tests at a glance?
  4. TESTS THAT DON'T BRING US JOY Do your component tests

    feel "cluttered"? Is it difficult to read and understand your component unit tests at a glance? Do you want tests to focus on testing behavior without having to deal with querying the DOM?
  5. WHAT ARE COMPONENT TEST HARNESSES? Test harnesses are a set

    of APIs in Angular CDK that support testing interactions with components
  6. WHAT ARE COMPONENT TEST HARNESSES? Test harnesses are a set

    of APIs in Angular CDK that support testing interactions with components All Angular Material components have test harnesses built-in in v12
  7. WHY IS THIS USEFUL? Tests that are easier to read

    Tests that use an API to interact with a component
  8. WHY IS THIS USEFUL? Tests that are easier to read

    Tests that use an API to interact with a component Allows you and your team to write tests that focus on behavior
  9. A TIDY LIST TODO APP Consider the tests you'd write

    for an app like this. We'll look at a task view.
  10. THE CODE WE'LL TEST <div class="tidy-task"> <mat-checkbox color="accent" [checked]="tidyTask.completed" (change)="onChecked()"

    [ngClass]="tidyTask.completed ? 'tidy-task-completed' : ''"> {{tidyTask.description}} </mat-checkbox> <div class="actions"> <mat-icon matBadge="{{tidyTask.rating}}" matBadgeColor="primary">favorite_border</mat-icon> <button mat-icon-button color="accent" (click)="onDeleted()"> <mat-icon>delete</mat-icon> </button> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  11. THE CODE WE'LL TEST <div class="tidy-task"> <mat-checkbox color="accent" [checked]="tidyTask.completed" (change)="onChecked()"

    [ngClass]="tidyTask.completed ? 'tidy-task-completed' : ''"> {{tidyTask.description}} </mat-checkbox> <div class="actions"> <mat-icon matBadge="{{tidyTask.rating}}" matBadgeColor="primary">favorite_border</mat-icon> <button mat-icon-button color="accent" (click)="onDeleted()"> <mat-icon>delete</mat-icon> </button> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [ngClass]="tidyTask.completed ? 'tidy-task-completed' : ''"> <div class="tidy-task"> 1 <mat-checkbox color="accent" 2 [checked]="tidyTask.completed" 3 (change)="onChecked()" 4 5 {{tidyTask.description}} 6 </mat-checkbox> 7 <div class="actions"> 8 <mat-icon matBadge="{{tidyTask.rating}}" matBadgeColor="primary">favorite_border</mat-icon> 9 <button mat-icon-button color="accent" (click)="onDeleted()"> 10 <mat-icon>delete</mat-icon> 11 </button> 12 </div> 13 </div> 14
  12. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  13. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); it('should apply completed class to match task completion', () => { 1 2 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18
  14. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); it('should apply completed class to match task completion', () => { 1 2 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 5 6 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18
  15. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); it('should apply completed class to match task completion', () => { 1 2 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 5 6 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18
  16. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); it('should apply completed class to match task completion', () => { 1 2 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 5 6 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 10 11 12 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18
  17. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); it('should apply completed class to match task completion', () => { 1 2 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 5 6 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 10 11 12 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 expect(cbEl.nativeElement.checked).toBe(true); expect(component.tidyTask.completed).toBeTrue(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 17 }); 18
  18. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); it('should apply completed class to match task completion', () => { 1 2 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 5 6 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 10 11 12 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 expect(cbEl.nativeElement.checked).toBe(true); expect(component.tidyTask.completed).toBeTrue(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 17 }); 18 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 16 17 }); 18
  19. EXAMPLE TEST it('should apply completed class to match task completion',

    () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); it('should apply completed class to match task completion', () => { 1 2 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 5 6 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); it('should apply completed class to match task completion', () => { 1 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 10 11 12 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 expect(component.tidyTask.completed).toBeTrue(); 17 }); 18 expect(cbEl.nativeElement.checked).toBe(true); expect(component.tidyTask.completed).toBeTrue(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 15 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); 16 17 }); 18 expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); it('should apply completed class to match task completion', () => { 1 const matCb = fixture.debugElement.query(By.css('mat-checkbox')); 2 expect(matCb).toBeTruthy(); 3 4 const cbEl = matCb.query(By.css('input')); 5 expect(cbEl).toBeTruthy(); 6 expect(cbEl.nativeElement.checked).toBe(false); 7 expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); 8 9 const cbClickEl = 10 fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); 11 cbClickEl.nativeElement.click(); 12 fixture.detectChanges(); 13 14 expect(cbEl.nativeElement.checked).toBe(true); 15 16 17 }); 18 it('should apply completed class to match task completion', () => { const matCb = fixture.debugElement.query(By.css('mat-checkbox')); expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('tidy-task-completed'); const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inner-container')); cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-task-completed'); expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  20. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  21. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 it('should apply completed class to match task completion', async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12
  22. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 it('should apply completed class to match task completion', async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 const cb = await loader.getHarness(MatCheckboxHarness); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12
  23. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 it('should apply completed class to match task completion', async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 const cb = await loader.getHarness(MatCheckboxHarness); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); it('should apply completed class to match task completion', async () => { 1 2 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12
  24. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 it('should apply completed class to match task completion', async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 const cb = await loader.getHarness(MatCheckboxHarness); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); it('should apply completed class to match task completion', async () => { 1 2 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 5 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12
  25. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 it('should apply completed class to match task completion', async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 const cb = await loader.getHarness(MatCheckboxHarness); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); it('should apply completed class to match task completion', async () => { 1 2 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 5 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 await cb.toggle(); it('should apply completed class to match task completion', async () => { 1 const cb = await loader.getHarness(MatCheckboxHarness); 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12
  26. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 it('should apply completed class to match task completion', async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 const cb = await loader.getHarness(MatCheckboxHarness); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); it('should apply completed class to match task completion', async () => { 1 2 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 5 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 await cb.toggle(); it('should apply completed class to match task completion', async () => { 1 const cb = await loader.getHarness(MatCheckboxHarness); 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 expect(await cb.isChecked()).toBeTrue(); it('should apply completed class to match task completion', async () => { 1 const cb = await loader.getHarness(MatCheckboxHarness); 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12
  27. EXAMPLE TEST it('should apply completed class to match task completion

    const matCb = fixture.debugElement.query(By.css('mat-ch expect(matCb).toBeTruthy(); const cbEl = matCb.query(By.css('input')); expect(cbEl).toBeTruthy(); expect(cbEl.nativeElement.checked).toBe(false); expect(matCb.nativeElement.classList).not.toContain('ti const cbClickEl = fixture.debugElement.query(By.css('.mat-checkbox-inne cbClickEl.nativeElement.click(); fixture.detectChanges(); expect(cbEl.nativeElement.checked).toBe(true); expect(matCb.nativeElement.classList).toContain('tidy-t expect(component.tidyTask.completed).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 it('should apply completed class to match task completion', async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12 const cb = await loader.getHarness(MatCheckboxHarness); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); it('should apply completed class to match task completion', async () => { 1 2 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 const cb = await loader.getHarness(MatCheckboxHarness); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); it('should apply completed class to match task completion', async () => { 1 2 expect(await cb.isChecked()).toBeFalse(); 3 4 5 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 await cb.toggle(); it('should apply completed class to match task completion', async () => { 1 const cb = await loader.getHarness(MatCheckboxHarness); 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 8 9 expect(await cb.isChecked()).toBeTrue(); 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 expect(await cb.isChecked()).toBeTrue(); it('should apply completed class to match task completion', async () => { 1 const cb = await loader.getHarness(MatCheckboxHarness); 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 10 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); 11 }); 12 expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); it('should apply completed class to match task completion', async () => { 1 const cb = await loader.getHarness(MatCheckboxHarness); 2 expect(await cb.isChecked()).toBeFalse(); 3 4 const cbHost = await cb.host(); 5 expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); 6 7 await cb.toggle(); 8 9 expect(await cb.isChecked()).toBeTrue(); 10 11 }); 12
  28. EXAMPLE TEST it('should apply completed class to match task completion',

    async () => { const cb = await loader.getHarness(MatCheckboxHarness); expect(await cb.isChecked()).toBeFalse(); const cbHost = await cb.host(); expect(await cbHost.hasClass('tidy-task-completed')).not.toBeTrue(); await cb.toggle(); expect(await cb.isChecked()).toBeTrue(); expect(await cbHost.hasClass('tidy-task-completed')).toBeTrue(); }); 1 2 3 4 5 6 7 8 9 10 11 12
  29. GET A HARNESSLOADER FOR YOUR ENVIRONMENT import { HarnessLoader }

    from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; describe('Tidy Test', () => { let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({...}); fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); }); }); 1 2 3 4 5 6 7 8 9 10 11 12
  30. GET A HARNESSLOADER FOR YOUR ENVIRONMENT import { HarnessLoader }

    from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; describe('Tidy Test', () => { let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({...}); fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); }); }); 1 2 3 4 5 6 7 8 9 10 11 12 import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 1 2 3 describe('Tidy Test', () => { 4 let loader: HarnessLoader; 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 fixture = TestBed.createComponent(TidyTestComponent); 9 loader = TestbedHarnessEnvironment.loader(fixture); 10 }); 11 }); 12
  31. GET A HARNESSLOADER FOR YOUR ENVIRONMENT import { HarnessLoader }

    from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; describe('Tidy Test', () => { let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({...}); fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); }); }); 1 2 3 4 5 6 7 8 9 10 11 12 import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 1 2 3 describe('Tidy Test', () => { 4 let loader: HarnessLoader; 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 fixture = TestBed.createComponent(TidyTestComponent); 9 loader = TestbedHarnessEnvironment.loader(fixture); 10 }); 11 }); 12 let loader: HarnessLoader; import { HarnessLoader } from '@angular/cdk/testing'; 1 import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 2 3 describe('Tidy Test', () => { 4 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 fixture = TestBed.createComponent(TidyTestComponent); 9 loader = TestbedHarnessEnvironment.loader(fixture); 10 }); 11 }); 12
  32. GET A HARNESSLOADER FOR YOUR ENVIRONMENT import { HarnessLoader }

    from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; describe('Tidy Test', () => { let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({...}); fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); }); }); 1 2 3 4 5 6 7 8 9 10 11 12 import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 1 2 3 describe('Tidy Test', () => { 4 let loader: HarnessLoader; 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 fixture = TestBed.createComponent(TidyTestComponent); 9 loader = TestbedHarnessEnvironment.loader(fixture); 10 }); 11 }); 12 let loader: HarnessLoader; import { HarnessLoader } from '@angular/cdk/testing'; 1 import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 2 3 describe('Tidy Test', () => { 4 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 fixture = TestBed.createComponent(TidyTestComponent); 9 loader = TestbedHarnessEnvironment.loader(fixture); 10 }); 11 }); 12 fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); import { HarnessLoader } from '@angular/cdk/testing'; 1 import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 2 3 describe('Tidy Test', () => { 4 let loader: HarnessLoader; 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 9 10 }); 11 }); 12
  33. GET A HARNESSLOADER FOR YOUR ENVIRONMENT import { HarnessLoader }

    from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; describe('Tidy Test', () => { let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({...}); fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); }); }); 1 2 3 4 5 6 7 8 9 10 11 12 import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 1 2 3 describe('Tidy Test', () => { 4 let loader: HarnessLoader; 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 fixture = TestBed.createComponent(TidyTestComponent); 9 loader = TestbedHarnessEnvironment.loader(fixture); 10 }); 11 }); 12 let loader: HarnessLoader; import { HarnessLoader } from '@angular/cdk/testing'; 1 import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 2 3 describe('Tidy Test', () => { 4 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 fixture = TestBed.createComponent(TidyTestComponent); 9 loader = TestbedHarnessEnvironment.loader(fixture); 10 }); 11 }); 12 fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); import { HarnessLoader } from '@angular/cdk/testing'; 1 import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; 2 3 describe('Tidy Test', () => { 4 let loader: HarnessLoader; 5 6 beforeEach(() => { 7 TestBed.configureTestingModule({...}); 8 9 10 }); 11 }); 12 import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; describe('Tidy Test', () => { let loader: HarnessLoader; beforeEach(() => { TestBed.configureTestingModule({...}); fixture = TestBed.createComponent(TidyTestComponent); loader = TestbedHarnessEnvironment.loader(fixture); }); }); 1 2 3 4 5 6 7 8 9 10 11 12
  34. GET HARNESSES const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); const btns:

    MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 1 2 3 4 5 6
  35. GET HARNESSES const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); const btns:

    MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 1 2 3 4 5 6 const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); 3 4 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); 5 const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 6
  36. GET HARNESSES const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); const btns:

    MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 1 2 3 4 5 6 const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); 3 4 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); 5 const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 6 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 3 4 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); 5 const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 6
  37. GET HARNESSES const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); const btns:

    MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 1 2 3 4 5 6 const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); 3 4 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); 5 const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 6 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 3 4 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); 5 const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 6 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); 3 4 5 6
  38. GET HARNESSES const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); const btns:

    MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 1 2 3 4 5 6 const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); 3 4 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); 5 const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 6 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 3 4 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); 5 const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 6 const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); 1 2 const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); 3 4 5 6 const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness); const btns: MatButtonHarness[] = await loader.getAllHarnesses(MatButtonHarness); const childLoader: HarnessLoader = await loader.getChildLoader('.my-selector'); const childBtn: MatButtonHarness = await childLoader.getHarness(MatButtonHarness); 1 2 3 4 5 6
  39. ACCESS THE HOST ELEMENT const btn: MatButtonHarness = await loader.getHarness(MatButtonHarness);

    const btnHost: TestElement = await btn.host(); await btnHost.hover(); 1 2 3
  40. OPTIMIZE MULTIPLE ACTIONS const checkbox: MatCheckboxHarness = await loader.getHarness(MatCheckboxHarness); const

    [checked, label] = await parallel(() => [ checkbox.isChecked(), checkbox.getLabelText() ]); 1 2 3 4 5
  41. A TIDY LIST TODO APP Take a look at the

    sentiment rating. We'll write a test harness for the component.
  42. THE COMPONENT WE'LL WRITE A HARNESS FOR @Component({ selector: 'app-sentiment-rating',

    template: ` <button mat-icon-button *ngFor="let rating of sentimentRating; index as i" (click)="onRating(rating)" [color]="rate > i ? 'accent' : ''"> <mat-icon *ngIf="i >= rate">favorite_border</mat-icon> <mat-icon *ngIf="rate > i">favorite</mat-icon> </button> ` }) export class SentimentRatingComponent{ public sentimentRating = [1, 2, 3, 4, 5]; @Input() public rate = 0; @Output() public changed = new EventEmitter<number>(); public onRating(rating: number): void { this.rate = rating; this.changed.emit(rating); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
  43. THE COMPONENT WE'LL WRITE A HARNESS FOR @Component({ selector: 'app-sentiment-rating',

    template: ` <button mat-icon-button *ngFor="let rating of sentimentRating; index as i" (click)="onRating(rating)" [color]="rate > i ? 'accent' : ''"> <mat-icon *ngIf="i >= rate">favorite_border</mat-icon> <mat-icon *ngIf="rate > i">favorite</mat-icon> </button> ` }) export class SentimentRatingComponent{ public sentimentRating = [1, 2, 3, 4, 5]; @Input() public rate = 0; @Output() public changed = new EventEmitter<number>(); public onRating(rating: number): void { this.rate = rating; this.changed.emit(rating); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 selector: 'app-sentiment-rating', @Component({ 1 2 template: ` 3 <button mat-icon-button 4 *ngFor="let rating of sentimentRating; index as i" 5 (click)="onRating(rating)" 6 [color]="rate > i ? 'accent' : ''"> 7 8 <mat-icon *ngIf="i >= rate">favorite_border</mat-icon> 9 <mat-icon *ngIf="rate > i">favorite</mat-icon> 10 </button> 11 ` 12 }) 13 export class SentimentRatingComponent{ 14 public sentimentRating = [1, 2, 3, 4, 5]; 15 @Input() public rate = 0; 16 @Output() public changed = new EventEmitter<number>(); 17 18 public onRating(rating: number): void { 19 this.rate = rating; 20 this.changed.emit(rating); 21 } 22 } 23
  44. THE COMPONENT WE'LL WRITE A HARNESS FOR @Component({ selector: 'app-sentiment-rating',

    template: ` <button mat-icon-button *ngFor="let rating of sentimentRating; index as i" (click)="onRating(rating)" [color]="rate > i ? 'accent' : ''"> <mat-icon *ngIf="i >= rate">favorite_border</mat-icon> <mat-icon *ngIf="rate > i">favorite</mat-icon> </button> ` }) export class SentimentRatingComponent{ public sentimentRating = [1, 2, 3, 4, 5]; @Input() public rate = 0; @Output() public changed = new EventEmitter<number>(); public onRating(rating: number): void { this.rate = rating; this.changed.emit(rating); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 selector: 'app-sentiment-rating', @Component({ 1 2 template: ` 3 <button mat-icon-button 4 *ngFor="let rating of sentimentRating; index as i" 5 (click)="onRating(rating)" 6 [color]="rate > i ? 'accent' : ''"> 7 8 <mat-icon *ngIf="i >= rate">favorite_border</mat-icon> 9 <mat-icon *ngIf="rate > i">favorite</mat-icon> 10 </button> 11 ` 12 }) 13 export class SentimentRatingComponent{ 14 public sentimentRating = [1, 2, 3, 4, 5]; 15 @Input() public rate = 0; 16 @Output() public changed = new EventEmitter<number>(); 17 18 public onRating(rating: number): void { 19 this.rate = rating; 20 this.changed.emit(rating); 21 } 22 } 23 <button mat-icon-button <mat-icon *ngIf="i >= rate">favorite_border</mat-icon> <mat-icon *ngIf="rate > i">favorite</mat-icon> </button> @Component({ 1 selector: 'app-sentiment-rating', 2 template: ` 3 4 *ngFor="let rating of sentimentRating; index as i" 5 (click)="onRating(rating)" 6 [color]="rate > i ? 'accent' : ''"> 7 8 9 10 11 ` 12 }) 13 export class SentimentRatingComponent{ 14 public sentimentRating = [1, 2, 3, 4, 5]; 15 @Input() public rate = 0; 16 @Output() public changed = new EventEmitter<number>(); 17 18 public onRating(rating: number): void { 19 this.rate = rating; 20 this.changed.emit(rating); 21 } 22 } 23
  45. DEFINE THE FILTERS INTERFACE TO SUPPORT QUERYING import { BaseHarnessFilters

    } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { rate?: number; } 1 2 3 4 5
  46. DEFINE THE FILTERS INTERFACE TO SUPPORT QUERYING import { BaseHarnessFilters

    } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { rate?: number; } 1 2 3 4 5 import { BaseHarnessFilters } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { 1 2 3 rate?: number; 4 } 5
  47. DEFINE THE FILTERS INTERFACE TO SUPPORT QUERYING import { BaseHarnessFilters

    } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { rate?: number; } 1 2 3 4 5 import { BaseHarnessFilters } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { 1 2 3 rate?: number; 4 } 5 rate?: number; import { BaseHarnessFilters } from '@angular/cdk/testing'; 1 2 export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { 3 4 } 5
  48. DEFINE THE FILTERS INTERFACE TO SUPPORT QUERYING import { BaseHarnessFilters

    } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { rate?: number; } 1 2 3 4 5 import { BaseHarnessFilters } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { 1 2 3 rate?: number; 4 } 5 rate?: number; import { BaseHarnessFilters } from '@angular/cdk/testing'; 1 2 export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { 3 4 } 5 import { BaseHarnessFilters } from '@angular/cdk/testing'; export interface SentimentRatingHarnessFilters extends BaseHarnessFilters { rate?: number; } 1 2 3 4 5
  49. IMPLEMENT YOUR COMPONENT TEST HARNESS import { ComponentHarness } from

    '@angular/cdk/testing'; export class SentimentRatingHarness extends ComponentHarness { } 1 2 3 4 5
  50. IMPLEMENT YOUR COMPONENT TEST HARNESS static hostSelector = 'app-sentiment-rating'; import

    { ComponentHarness } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 4 } 5
  51. IMPLEMENT YOUR COMPONENT TEST HARNESS private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button');

    import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 6 7 public async getRate(): Promise<number> { 8 9 } 10 11 public async setRate(rate: number): Promise<void> { 12 13 } 14 } 15
  52. IMPLEMENT YOUR COMPONENT TEST HARNESS private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button');

    import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 6 7 public async getRate(): Promise<number> { 8 9 } 10 11 public async setRate(rate: number): Promise<void> { 12 13 } 14 } 15 public async getRate(): Promise<number> { } import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 8 9 10 11 public async setRate(rate: number): Promise<void> { 12 13 } 14 } 15
  53. IMPLEMENT YOUR COMPONENT TEST HARNESS private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button');

    import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 6 7 public async getRate(): Promise<number> { 8 9 } 10 11 public async setRate(rate: number): Promise<void> { 12 13 } 14 } 15 public async getRate(): Promise<number> { } import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 8 9 10 11 public async setRate(rate: number): Promise<void> { 12 13 } 14 } 15 public async setRate(rate: number): Promise<void> { } import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 9 } 10 11 12 13 14 } 15
  54. IMPLEMENT YOUR COMPONENT TEST HARNESS private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button');

    import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 6 7 public async getRate(): Promise<number> { 8 9 } 10 11 public async setRate(rate: number): Promise<void> { 12 13 } 14 } 15 public async getRate(): Promise<number> { } import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 8 9 10 11 public async setRate(rate: number): Promise<void> { 12 13 } 14 } 15 public async setRate(rate: number): Promise<void> { } import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 9 } 10 11 12 13 14 } 15 import { AsyncFactoryFn, ComponentHarness, TestElement } from '@angular/cdk/testing'; export class SentimentRatingHarness extends ComponentHarness { static hostSelector = 'app-sentiment-rating'; private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); public async getRate(): Promise<number> { } public async setRate(rate: number): Promise<void> { } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  55. IMPLEMENT YOUR COMPONENT TEST HARNESS public async getRate(): Promise<number> {

    const btns = await this._rateButtons(); return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); } import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 8 9 10 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16
  56. IMPLEMENT YOUR COMPONENT TEST HARNESS public async getRate(): Promise<number> {

    const btns = await this._rateButtons(); return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); } import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 8 9 10 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16 const btns = await this._rateButtons(); import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16
  57. IMPLEMENT YOUR COMPONENT TEST HARNESS public async getRate(): Promise<number> {

    const btns = await this._rateButtons(); return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); } import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 8 9 10 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16 const btns = await this._rateButtons(); import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16
  58. IMPLEMENT YOUR COMPONENT TEST HARNESS public async getRate(): Promise<number> {

    const btns = await this._rateButtons(); return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); } import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 8 9 10 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16 const btns = await this._rateButtons(); import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 } 15 } 16 import { AsyncFactoryFn, ComponentHarness, parallel, TestElement } from '@angular/cdk/testing'; export class SentimentRatingHarness extends ComponentHarness { static hostSelector = 'app-sentiment-rating'; private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); public async getRate(): Promise<number> { const btns = await this._rateButtons(); return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc : acc, 0); } public async setRate(rate: number): Promise<void> { } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
  59. IMPLEMENT YOUR COMPONENT TEST HARNESS public async setRate(rate: number): Promise<void>

    { if (rate <= 0) throw Error('Rate is invalid'); const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); return (await btns[rate - 1]).click(); } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 13 14 15 16 17 18 19 } 20
  60. IMPLEMENT YOUR COMPONENT TEST HARNESS public async setRate(rate: number): Promise<void>

    { if (rate <= 0) throw Error('Rate is invalid'); const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); return (await btns[rate - 1]).click(); } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 13 14 15 16 17 18 19 } 20 if (rate <= 0) throw Error('Rate is invalid'); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 15 const btns = await this._rateButtons(); 16 if (btns.length < rate) throw Error('Rate exceeds supported rate options'); 17 return (await btns[rate - 1]).click(); 18 } 19 } 20
  61. IMPLEMENT YOUR COMPONENT TEST HARNESS public async setRate(rate: number): Promise<void>

    { if (rate <= 0) throw Error('Rate is invalid'); const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); return (await btns[rate - 1]).click(); } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 13 14 15 16 17 18 19 } 20 if (rate <= 0) throw Error('Rate is invalid'); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 15 const btns = await this._rateButtons(); 16 if (btns.length < rate) throw Error('Rate exceeds supported rate options'); 17 return (await btns[rate - 1]).click(); 18 } 19 } 20 const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 if (rate <= 0) throw Error('Rate is invalid'); 14 15 16 17 return (await btns[rate - 1]).click(); 18 } 19 } 20
  62. IMPLEMENT YOUR COMPONENT TEST HARNESS public async setRate(rate: number): Promise<void>

    { if (rate <= 0) throw Error('Rate is invalid'); const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); return (await btns[rate - 1]).click(); } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 13 14 15 16 17 18 19 } 20 if (rate <= 0) throw Error('Rate is invalid'); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 15 const btns = await this._rateButtons(); 16 if (btns.length < rate) throw Error('Rate exceeds supported rate options'); 17 return (await btns[rate - 1]).click(); 18 } 19 } 20 const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 if (rate <= 0) throw Error('Rate is invalid'); 14 15 16 17 return (await btns[rate - 1]).click(); 18 } 19 } 20 return (await btns[rate - 1]).click(); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 if (rate <= 0) throw Error('Rate is invalid'); 14 15 const btns = await this._rateButtons(); 16 if (btns.length < rate) throw Error('Rate exceeds supported rate options'); 17 18 } 19 } 20
  63. IMPLEMENT YOUR COMPONENT TEST HARNESS public async setRate(rate: number): Promise<void>

    { if (rate <= 0) throw Error('Rate is invalid'); const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); return (await btns[rate - 1]).click(); } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 13 14 15 16 17 18 19 } 20 if (rate <= 0) throw Error('Rate is invalid'); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 14 15 const btns = await this._rateButtons(); 16 if (btns.length < rate) throw Error('Rate exceeds supported rate options'); 17 return (await btns[rate - 1]).click(); 18 } 19 } 20 const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 if (rate <= 0) throw Error('Rate is invalid'); 14 15 16 17 return (await btns[rate - 1]).click(); 18 } 19 } 20 return (await btns[rate - 1]).click(); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 export class SentimentRatingHarness extends ComponentHarness { 3 static hostSelector = 'app-sentiment-rating'; 4 5 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 6 7 public async getRate(): Promise<number> { 8 const btns = await this._rateButtons(); 9 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 10 } 11 12 public async setRate(rate: number): Promise<void> { 13 if (rate <= 0) throw Error('Rate is invalid'); 14 15 const btns = await this._rateButtons(); 16 if (btns.length < rate) throw Error('Rate exceeds supported rate options'); 17 18 } 19 } 20 import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; export class SentimentRatingHarness extends ComponentHarness { static hostSelector = 'app-sentiment-rating'; private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); public async getRate(): Promise<number> { const btns = await this._rateButtons(); return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); } public async setRate(rate: number): Promise<void> { if (rate <= 0) throw Error('Rate is invalid'); const btns = await this._rateButtons(); if (btns.length < rate) throw Error('Rate exceeds supported rate options'); return (await btns[rate - 1]).click(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  64. IMPLEMENT YOUR COMPONENT TEST HARNESS import { SentimentRatingHarnessFilters } from

    './sentiment-rating-harness-filters'; import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24
  65. IMPLEMENT YOUR COMPONENT TEST HARNESS import { SentimentRatingHarnessFilters } from

    './sentiment-rating-harness-filters'; import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24
  66. IMPLEMENT YOUR COMPONENT TEST HARNESS import { SentimentRatingHarnessFilters } from

    './sentiment-rating-harness-filters'; import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 return new HarnessPredicate(SentimentRatingHarness, options) .addOption('rate', options.rate, ); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 8 9 async (harness, rate) => await harness.getRate() === rate 10 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24
  67. IMPLEMENT YOUR COMPONENT TEST HARNESS import { SentimentRatingHarnessFilters } from

    './sentiment-rating-harness-filters'; import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 return new HarnessPredicate(SentimentRatingHarness, options) .addOption('rate', options.rate, ); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 8 9 async (harness, rate) => await harness.getRate() === rate 10 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 async (harness, rate) => await harness.getRate() === rate import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 10 ); 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24
  68. IMPLEMENT YOUR COMPONENT TEST HARNESS import { SentimentRatingHarnessFilters } from

    './sentiment-rating-harness-filters'; import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { } import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 async (harness, rate) => await harness.getRate() === rate 10 ); 11 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 return new HarnessPredicate(SentimentRatingHarness, options) .addOption('rate', options.rate, ); import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 8 9 async (harness, rate) => await harness.getRate() === rate 10 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 async (harness, rate) => await harness.getRate() === rate import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; 1 import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; 2 3 export class SentimentRatingHarness extends ComponentHarness { 4 static hostSelector = 'app-sentiment-rating'; 5 6 static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { 7 return new HarnessPredicate(SentimentRatingHarness, options) 8 .addOption('rate', options.rate, 9 10 ); 11 } 12 13 private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); 14 15 public async getRate(): Promise<number> { 16 const btns = await this._rateButtons(); 17 return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); 18 } 19 20 public async setRate(rate: number): Promise<void> { 21 if (rate <= 0) throw Error('Rate is invalid'); 22 23 const btns = await this._rateButtons(); 24 import { AsyncFactoryFn, ComponentHarness, HarnessPredicate, parallel, TestElement } from '@angular/cdk/testing'; import { SentimentRatingHarnessFilters } from './sentiment-rating-harness-filters'; export class SentimentRatingHarness extends ComponentHarness { static hostSelector = 'app-sentiment-rating'; static with(options: SentimentRatingHarnessFilters): HarnessPredicate<SentimentRatingHarness> { return new HarnessPredicate(SentimentRatingHarness, options) .addOption('rate', options.rate, async (harness, rate) => await harness.getRate() === rate ); } private _rateButtons: AsyncFactoryFn<TestElement[]> = this.locatorForAll('button'); public async getRate(): Promise<number> { const btns = await this._rateButtons(); return (await parallel(() => btns.map(b => b.text()))).reduce((acc, curr) => curr === 'favorite' ? ++acc: acc, 0); } public async setRate(rate: number): Promise<void> { if (rate <= 0) throw Error('Rate is invalid'); const btns = await this._rateButtons(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
  69. TEST YOUR COMPONENT TEST HARNESS Don't forget to test your

    harness - treat it like publishing an API
  70. TEST YOUR COMPONENT TEST HARNESS Don't forget to test your

    harness - treat it like publishing an API Create a test host for your component and write tests utilizing your component test harness
  71. WANT TO LEARN MORE? Slides Tidy Task Todo App Using

    Angular Material component harnesses guide on Test harness API docs on @ALISADUNCAN alisaduncan.github.io/component-harness https://github.com/alisaduncan/component-harness-code material.angular.io material.angular.io