-1

I try to test a component with a amount of courses. So I try to do a unit test that there are more then 0 courses available. So I have this:

it('should display only beginner courses', () => {

    courseServiceSpy.findAllCourses.and.returnValue(of(beginnerCourses));

    fixture.detectChanges();

    const tabs = el.queryAll(By.css('.mat-tab-label'));

    expect(tabs.length).toBe(1, 'found in tabs found');
  });

And this is the template:

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

But I still get this error:

Expected 0 to be 1, 'found in tabs found'.
Error: Expected 0 to be 1, 'found in tabs found'.
    at <Jasmine>
    at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/src/app/courses/home/home.component.spec.ts:60:25)
    at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:364:1)
    at ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/proxy.js:117:1)

So what I have to change?

Thank you

This is my total class:

describe('HomeComponent', () => {
  let fixture: ComponentFixture<HomeComponent>;
  let component: HomeComponent;
  let el: DebugElement;
  let courseServiceSpy: SpyObj<CoursesService>; // Declare the spy here

  const beginnerCourses = setupCourses().filter(course => course.category === 'BEGINNER');
  const advancedCourses = setupCourses().filter(course => course.category === 'ADVANCED');

  beforeEach(async(() => {
    // Initialize the spy here
    courseServiceSpy = jasmine.createSpyObj('CoursesService', [
      'findAllCourses',
    ]);

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

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

  it('should display only beginner courses', () => {

    courseServiceSpy.findAllCourses.and.returnValue(of(beginnerCourses));

    fixture.detectChanges();

    const tabs = el.queryAll(By.css('.mat-tab-label'));

    expect(tabs.length).toBe(1, 'found in tabs found');
  });

  it('should display only advanced courses', () => {
    courseServiceSpy.findAllCourses.and.returnValue(of(advancedCourses));

    fixture.detectChanges();

    const tabs = el.queryAll(By.css('.mat-tab-label'));

    expect(tabs.length).toBe(1, 'found in tabs found');
  });

});

and this is the method:

  findAllCourses(): Observable<Course[]> {
        return this.http.get('/api/courses')
            .pipe(
                map(res => res['payload']), shareReplay()
            );
    }

2 Answers2

0

A spy only simulates an action but doesn't really act on your component. You need to mock your service to return of(beginnerCourses);

Create a mock class :

class CourseServiceMock {
  findAllCourses() {
    return of(beginnerCourses);
  }
}

and declare it as the class used for the provider (and remove your spy):

TestBed.configureTestingModule({
      imports: [CoursesModule, HttpClientTestingModule, NoopAnimationsModule],
      providers: [{provide: CoursesService, usevalue: CourseServiceMock}],
    })
Gérôme Grignon
  • 3,859
  • 1
  • 6
  • 18
  • Thank you of course. But I already have a mock: let courseServiceSpy: SpyObj; // Declare the spy here: courseServiceSpy = jasmine.createSpyObj('CoursesService', [ 'findAllCourses', ]); – NiceTobeBottleInfinity Sep 11 '20 at 10:00
  • And toBe accepts two arguments: toBe(expected: Expected, expectationFailOutput?: any): boolean; – NiceTobeBottleInfinity Sep 11 '20 at 10:01
  • a spy isn't a mock : there are two different things. The goal of a mock is to provide custom class for your test environment not to call external dependencies (and to avoid making an http call in your situation). The goal of a spy is to watch other actions, without really triggering action itself. – Gérôme Grignon Sep 11 '20 at 10:03
  • Eh, to mock sometihing, you are using a jasmine.spy: see:https://codecraft.tv/courses/angular/unit-testing/mocks-and-spies/. But of course I appreciate you enthusiasm. So thank you for that. But I solved at the correct way. Have a nice day – NiceTobeBottleInfinity Sep 11 '20 at 11:04
  • @Grignon. See my ans ware. So you can learn something about it :) – NiceTobeBottleInfinity Sep 12 '20 at 14:56
0

I fixed, this works:

import { filter } from 'rxjs/operators';
import {setupCourses} from '../common/setup-test-data';
import {
  async,
  ComponentFixture,
  TestBed,
} from '@angular/core/testing';
import { CoursesModule } from '../courses.module';
import { DebugElement } from '@angular/core';

import { HomeComponent } from './home.component';
import {
  HttpClientTestingModule,
} from '@angular/common/http/testing';
import { CoursesService } from '../services/courses.service';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { of } from 'rxjs';
import SpyObj = jasmine.SpyObj;
import { By } from '@angular/platform-browser';

describe('HomeComponent', () => {
  let fixture: ComponentFixture<HomeComponent>;
  let component: HomeComponent;
  let el: DebugElement;
  let coursesService: any;

  const beginnerCourses = setupCourses().filter(course => course.category === 'BEGINNER');
  const advancedCourses = setupCourses().filter(course => course.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.inject(CoursesService);
        });

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

  it('should display only beginner courses', () => {

    coursesService.findAllCourses.and.returnValue(of(beginnerCourses));

    fixture.detectChanges();

    const tabs = el.queryAll(By.css('.mat-tab-label'));

    expect(tabs.length).toBe(1);
  });

  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).toBe(1, 'found in tabs found');
  });

  it('should display both tabs', () => {
    pending();
  }); 
});

So this:

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

is creating the mock. So a seperate mock is not necessarily