简体   繁体   中英

Jasmine, karma, TypeError: Cannot read property 'returnValue' of undefined

I am trying to implement a unit test on a component with Jasmine and Karma.I am using Angular 10. The component I am testing is HomeComponent . I do a test on retrieving courses that are for beginners

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

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

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

  beforeEach(async(() => {
    const 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;
        courseService = TestBed.inject(CoursesService);
      });
  }));

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

  it('should display only beginner courses', () => {
    // pending();
     courseService.findAllCourses.and.returnValue(of(beginnerCourses));

     fixture.detectChanges();
  });

Of course I googled a lot, but couldn't find anything useful.

I still get this error:

TypeError: Cannot read property 'returnValue' of undefined
    at <Jasmine>
    at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/src/app/courses/home/home.component.spec.ts:51:39)
    at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:364:1)
    at ProxyZoneSpec.push../node_modules/zone.js/dist/proxy.js.ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/proxy.js:117:1)
    at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:363:1)
    at Zone.run (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:123:1)
    at runInTestZone (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/jasmine-patch.js:176:1)
    at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/jasmine-patch.js:191:1)
    at <Jasmine>

I don't know what I have to change? Thank you.

You have to define courseServiceSpy outside of the beforeEach block, so that the rest of the code can access the variable.

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;

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

  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', () => {
    // pending();
    // Mock the spy here
    courseServiceSpy.findAllCourses.and.returnValue(of(beginnerCourses));

    fixture.detectChanges();
  });
});

In your earlier example the definition of courseService was only "visible" within the beforeEach block. Read up here to understand the scope of var , let and const .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM