• [Unit testing Angular] Complete component code


    The component we test against:

    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) )
          );
        }
    
    }

    Template:

    <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>

    Testing code:

    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 { CoursesService } from "../services/courses.service";
    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";
    
    describe("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.findAllCourses.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");
      });
    
      /**
       *
       * async vs fakeAsync
       *
       * Depends on whether you need to call real http, if yes, then async
       * Otherwise, always fakeAsync
       */
      it("should display advanced courses when tab clicked - fakeAsync", fakeAsync(() => {
        coursesService.findAllCourses.and.returnValue(of(setupCourses()));
        fixture.detectChanges();
        const tabs = el.queryAll(By.css(".mat-tab-label"));
        click(tabs[1]);
        fixture.detectChanges();
        flush();
        const cardTitles = el.queryAll(By.css(".mat-card-title"));
        expect(cardTitles.length).toBeGreaterThan(0, "Could not find card titles");
        expect(textContent(cardTitles[0])).toContain("Angular Security Course");
      }));
    
      it("should display advanced courses when tab clicked - async", async(() => {
        coursesService.findAllCourses.and.returnValue(of(setupCourses()));
        fixture.detectChanges();
        const tabs = el.queryAll(By.css(".mat-tab-label"));
        click(tabs[1]);
        fixture.detectChanges();
        // async will tigger whenStable callback
        fixture.whenStable().then(() => {
          const cardTitles = el.queryAll(By.css(".mat-card-title"));
          expect(cardTitles.length).toBeGreaterThan(
            0,
            "Could not find card titles"
          );
          expect(textContent(cardTitles[0])).toContain("Angular Security Course");
        });
      }));
    });
  • 相关阅读:
    万字总结:学习MySQL优化原理,这一篇就够了!
    sql中自连接的使用
    SQL 优化原则
    Thumbnailator java图片压缩,加水印,批量生成缩略图
    java使用Thumbnailator处理图片
    Mysql优化原则_小表驱动大表IN和EXISTS的合理利用
    MySQL千万级多表关联SQL语句调优
    了解MySQL联表查询中的驱动表,优化查询,以小表驱动大表
    【explain】MySQL联表查询中的驱动表
    pyCharm最新2018激活码
  • 原文地址:https://www.cnblogs.com/Answer1215/p/12363450.html
Copyright © 2020-2023  润新知