Angular 8 Jasmine 和业力测试:mocked ngonit promise 值未在 DOM 中呈现

Angular 8 Jasmine and karma testing: mocked ngonit promise value is not rendered in the DOM

我在测试中的模拟数据在 运行 测试时不会显示在标记中。无论我尝试什么(fakeasync、完成、存根),承诺的内容都不会在 运行 测试后在标记中呈现。

谁能告诉我为什么这个模拟的 promise 数据不会显示在 dom 中。我几乎在这上面花了 2 天时间,但无论我尝试什么,它都不起作用。我正在使用 angular 8 并开始认为这是框架中的错误。

我有以下标记:

<div>
    <div class="pt-8">
        <!-- Displays -->
        <ul>
            <li *ngFor="let worker of workers">{{worker.getName()}}</li>
        </ul>

        <!-- DOES NOT DISPLAY -->
        <ol>
            <li *ngFor="let centre of centres">{{centre.name}}</li>
        </ol>
    </div>
</div>

这是class:

import { Component, OnInit, Input, Inject } from '@angular/core';
import { WorkcentersService } from 'app/services/workcenters.service';
import { Workcenter } from 'app/model/workcenter';
import { User } from 'app/model/user';

@Component({
  selector: 'test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
  workers: User[];
  centres: Workcenter[];

  constructor(private workcentersService: WorkcentersService) { }

  ngOnInit(): void {
    let user1 = new User(); user1.name = "worker 1"; user1.surname = "surname1";
    let user2 = new User(); user2.name = "worker 2"; user2.surname = "surname2";
    let user3 = new User(); user3.name = "worker 3"; user3.surname = "surname3";
    this.workers = [user1, user2, user3];
    this.workcentersService.getWorkcentersList().then(wc => this.centres = wc);
  }
}

这是测试:

import { ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
import { WorkcentersService } from 'app/services/workcenters.service';
import { Workcenter } from 'app/model/workcenter';
import { TestComponent } from './test.component';

fdescribe('TestComponent', () => {
  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;

  beforeEach(async () => {
    const mockCentres = createMockCentres();
    const mockWorkcentersService = jasmine.createSpyObj(["getWorkcentersList"]);
    mockWorkcentersService.getWorkcentersList.and.returnValue(Promise.resolve(mockCentres));

    TestBed.configureTestingModule({
      declarations: [TestComponent],
      imports: [],
      providers: [
        { provide: WorkcentersService, useValue: mockWorkcentersService }
      ]
    });

    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    await fixture.whenStable();
    fixture.detectChanges();
  });

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

  // Passes
  it('should render users', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll("ul li");
    expect(displayedUsers.length).toEqual(3);
  });

  // Fails
  it('should render centres', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll("ol li");
    expect(displayedUsers.length).toEqual(2);
  });

  // Fails
  it('should display "hello"', fakeAsync(() => {
    fixture.detectChanges();
    tick();
    const displayedUsers = fixture.nativeElement.querySelectorAll("ol li");
    expect(displayedUsers.length).toEqual(2);
  }));

  function createMockCentres(): Workcenter[] {
    const mockCentre1 = new Workcenter();mockCentre1.id = 1;mockCentre1.name = "Test centre 1";
    const mockCentre2 = new Workcenter();mockCentre2.id = 2;mockCentre2.name = "Test centre 2";
    return [mockCentre1, mockCentre2];
  }
});
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';

import { AppComponent } from './app.component';
import { WorkCenter } from './workCenter';
import { WorkcentersService } from './workcenters.service';

fdescribe('TestComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;
  let mockWorkcentersService: WorkcentersService;
  beforeEach(async () => {
    const mockCentres = createMockCentres();
    TestBed.configureTestingModule({
      declarations: [AppComponent],
      imports: [],
      providers: [
        WorkcentersService
      ]
    });

    fixture = TestBed.createComponent(AppComponent);
    mockWorkcentersService = TestBed.get(WorkcentersService);
    spyOn(mockWorkcentersService, 'getWorkcentersList').and.returnValue(new Promise((resolve, reject) => resolve(mockCentres)));
    component = fixture.componentInstance;
    await fixture.whenStable();
    fixture.detectChanges();
  });

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

  // Passes
  it('should render users', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll('ul li');
    expect(displayedUsers.length).toEqual(3);
  });

  // Fails
  it('should render centres', async () => {
    expect(mockWorkcentersService.getWorkcentersList).toHaveBeenCalled();
    fixture.detectChanges();
    await fixture.whenStable();
    const displayedUsers = fixture.nativeElement.querySelectorAll('ol li');
    expect(displayedUsers.length).toEqual(2);
  });

  // Fails
  it('should display "hello"', fakeAsync(() => {
    fixture.detectChanges();
    tick();
    const displayedUsers = fixture.nativeElement.querySelectorAll('ol li');
    expect(displayedUsers.length).toEqual(2);
  }));

  function createMockCentres(): WorkCenter[] {
    const mockCentre1 = new WorkCenter(); mockCentre1.id = 1; mockCentre1.name = 'Test centre 1';
    const mockCentre2 = new WorkCenter(); mockCentre2.id = 2; mockCentre2.name = 'Test centre 2';
    return [mockCentre1, mockCentre2];
  }
});

这对我有用

证明:-

还尝试了 运行 单个测试用例来向您展示测试中心现在正在显示:-

@Aakash Garg 我接受了你的回答,因为你答对了。

在这方面花费(还)更多时间后,我发现我们以不同方式创建间谍这一事实并没有产生任何影响。

关键事实是你转身 fixture.detectChanges(); 等待 fixture.whenStable(); 我把它们反过来了。

您还在测试本身中添加了一个 fixture.detectChanges() ,这也是必要的。附加的 whenStable 调用似乎没有任何区别。

最后我使用了 fixture.autoDetectChanges() 使得它在没有 fixture.whenStable 调用的情况下工作,如下所示:

beforeEach(async () => {
    const mockCentres = createMockCentres();
    const workers = { workers: createMockWorkers(), companyId: 22 };
    const mockWorkcentersService = jasmine.createSpyObj(["getWorkcentersList"]);
    mockWorkcentersService.getWorkcentersList.and.returnValue(Promise.resolve(mockCentres));

    TestBed.configureTestingModule({
      declarations: [CentreAssociateComponent],
      imports: [],
      providers: [
        //WorkcentersService,
        { provide: WorkcentersService, useValue: mockWorkcentersService },
        { provide: MAT_DIALOG_DATA, useValue: workers },
        { provide: MatDialogRef, useValue: {} }
      ]
    });

    fixture = TestBed.createComponent(CentreAssociateComponent);
    fixture.autoDetectChanges();
    component = fixture.componentInstance;

    await fixture.whenStable();
  });

  it('should render centres', async () => {
    const displayedUsers = fixture.nativeElement.querySelectorAll("ol li");
    expect(displayedUsers.length).toEqual(2);
  });