[Angular 8 Unit testing] Testing a smart component with service injection -- 1


The smart component we want to test:

import {Component, OnInit} from '@angular/core';
import {Course} from "../model/course";
import {Observable} from "rxjs";
import {CoursesService} from "../services/courses.service";
import {map} from "rxjs/operators";
import {sortCoursesBySeqNo} from './sort-course-by-seq';

@Component({
    selector: 'home',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

    beginnerCourses$: Observable<Course[]>;

    advancedCourses$: Observable<Course[]>;

    constructor(private coursesService: CoursesService) {

    }

    ngOnInit() {

      this.reloadCourses();

    }


    reloadCourses() {

      const courses$ = this.coursesService.findAllCourses();

      this.beginnerCourses$ = this.filterByCategory(courses$, 'BEGINNER');

      this.advancedCourses$ = this.filterByCategory(courses$, 'ADVANCED');

    }

    filterByCategory(courses$: Observable<Course[]>, category:string) {
      return courses$.pipe(
        map(courses => courses.filter(course => course.category === category).sort(sortCoursesBySeqNo) )
      );
    }

}

html:

<div class="container">

    <h3>All Courses</h3>

    <mat-tab-group>


      <ng-container *ngIf="(beginnerCourses$ | async) as beginnerCourses">

        <mat-tab label="Beginners" *ngIf="beginnerCourses?.length > 0">

          <courses-card-list (courseEdited)="reloadCourses()"
                             [courses]="beginnerCourses">

          </courses-card-list>

        </mat-tab>

      </ng-container>


      <ng-container  *ngIf="(advancedCourses$ | async) as advancedCourses">

        <mat-tab label="Advanced" *ngIf="advancedCourses?.length > 0">

          <courses-card-list (courseEdited)="reloadCourses()"
                             [courses]="advancedCourses">


          </courses-card-list>

        </mat-tab>

      </ng-container>

    </mat-tab-group>

</div>

  

Let's also setup some test-utils methods we need to use:

import {DebugElement} from '@angular/core';

export const ButtonClickEvents = {
  left:  { button: 0 },
  right: { button: 2 }
};


export function click(el: DebugElement | HTMLElement,
                      eventObj: any = ButtonClickEvents.left): void {

  if (el instanceof HTMLElement) {
    el.click();
  } else {
    el.triggerEventHandler('click', eventObj);
  }
}

export function textContent(el: DebugElement | HTMLElement): string {
  if (el instanceof HTMLElement) {
    return el.textContent;
  } else {
    return el.nativeElement.textContent;
  }
}

 

spec for component:

Basic setup for a test, we create a Spy for the service and provide in test config module

  beforeEach(async(() => {

    const coursesServiceSpy = jasmine.createSpyObj('CoursesService', ['findAllCourses']); 
    TestBed.configureTestingModule({
        imports: [
            CoursesModule,
            NoopAnimationsModule
        ],
        providers: [
            {provide: CoursesService, useValue: coursesServiceSpy}
        ]
    })
        .compileComponents()
        .then(() => {
            fixture = TestBed.createComponent(HomeComponent);
            component = fixture.componentInstance;
            el = fixture.debugElement;
            coursesService = TestBed.get(CoursesService);
        })
  }));

 

According to HTML layout, we want to test, when only beginner course is available, there should be only one tab;

the same for only advanced course available, we should also see only one tab

And if all boths types of courses are available, we display to tabs.

  it("should create the component", () => {
    expect(component).toBeTruthy();
  });


  it("should display only beginner courses", () => {
    
    coursesService.findAllCoursesT.and.returnValue(of(beginnerCourses));
    fixture.detectChanges();

    // only one tab available
    const tabs = el.queryAll(By.css('.mat-tab-label'));
    expect(tabs.length).toEqual(1, "Unexpect number of tabs");
  });


  it("should display only advanced courses", () => {

     coursesService.findAllCourses.and.returnValue(of(advancedCourses))
     fixture.detectChanges()

     const tabs = el.queryAll(By.css('.mat-tab-label'))
     expect(tabs.length).toEqual(1, "Unexpect number of tabs")

  });


  it("should display both tabs", () => {

    coursesService.findAllCourses.and.returnValue(of(setupCourses()))
    fixture.detectChanges()

    const tabs = el.queryAll(By.css('.mat-tab-label'))
    expect(tabs.length).toEqual(2, "Unexpect number of tabs")
  });

 

Tests:

import {async, ComponentFixture, fakeAsync, flush, flushMicrotasks, TestBed, tick} from '@angular/core/testing';
import {CoursesModule} from '../courses.module';
import {DebugElement} from '@angular/core';

import {HomeComponent} from './home.component';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {CoursesService} from '../services/courses.service';
import {HttpClient} from '@angular/common/http';
import {COURSES} from '../../../../server/db-data';
import {setupCourses} from '../common/setup-test-data';
import {By} from '@angular/platform-browser';
import {of} from 'rxjs';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {click, textContent} from '../common/test-utils';

fdescribe('HomeComponent', () => {

    let fixture: ComponentFixture<HomeComponent>,
    component: HomeComponent,
    el: DebugElement,
    coursesService: any; // TestBed.inject(CoursesService) will fix type issue
    const beginnerCourses = setupCourses().filter(cs => cs.category === 'BEGINNER');
    const advancedCourses = setupCourses().filter(cs => cs.category === 'ADVANCED');

  beforeEach(async(() => {

    const coursesServiceSpy = jasmine.createSpyObj('CoursesService', ['findAllCourses']);

    TestBed.configureTestingModule({
        imports: [
            CoursesModule,
            NoopAnimationsModule
        ],
        providers: [
            {provide: CoursesService, useValue: coursesServiceSpy}
        ]
    })
        .compileComponents()
        .then(() => {
            fixture = TestBed.createComponent(HomeComponent);
            component = fixture.componentInstance;
            el = fixture.debugElement;
            coursesService = TestBed.get(CoursesService);
        })
  }));

  it("should create the component", () => {
    expect(component).toBeTruthy();
  });


  it("should display only beginner courses", () => {
    coursesService.findAllCoursesT.and.returnValue(of(beginnerCourses));
    fixture.detectChanges();
    // only one tab available
    const tabs = el.queryAll(By.css('.mat-tab-label'));
    expect(tabs.length).toEqual(1, "Unexpect number of tabs");
  });


  it("should display only advanced courses", () => {
     coursesService.findAllCourses.and.returnValue(of(advancedCourses))
     fixture.detectChanges()
     const tabs = el.queryAll(By.css('.mat-tab-label'))
     expect(tabs.length).toEqual(1, "Unexpect number of tabs")
  });


  it("should display both tabs", () => {
    coursesService.findAllCourses.and.returnValue(of(setupCourses()))
    fixture.detectChanges()
    const tabs = el.queryAll(By.css('.mat-tab-label'))
    expect(tabs.length).toEqual(2, "Unexpect number of tabs")
  });

});

  


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM