【问题标题】:Unable to get Jest test to pass in Angular无法让 Jest 测试通过 Angular
【发布时间】:2019-06-05 17:05:31
【问题描述】:

这看起来很简单,我知道我一定做错了什么,但我已经做了一整天,仍然无法通过一个简单的测试。我的组件使用第三方库 JQWidgets,部分问题是测试报告了该库中的错误,但测试失败的另一部分显然是我的模拟数据应该加载到组件中的属性中没有进入那里。

我正在尝试使用 Jest 模拟,但即使我现在已经阅读了十几次文档,我仍然不确定我是否做得对。有时我需要一个间谍,有时我只希望模拟函数(通常是服务函数)返回一些虚拟数据。我觉得我可能只是不了解 Jest 的一些嘲弄魔法。

对于任何含糊之处,我深表歉意,我希望有人在我的工作中可以问,但没有,所以我很谦虚地寻求帮助。

编辑:模拟整个服务这似乎工作得更好,因为我的测试断言通过了,但由于第三方模块中的错误,测试仍然失败。我试过添加 NO_ERRORS_SCHEMA 但没有帮助:

TypeError: bA.getPropertyValue is not a function
      at R (node_modules/jqwidgets-scripts/jqwidgets/jqxcore.js:14:36743)

组件的 ngOnInit()

ngOnInit() {
    this._dataService.getData().subscribe(
      data => {
        this.populate(data); // <--this line appears not to be running, as this function populates this.source.localdata with this data
        this.dataAdapter = new jqx.dataAdapter(this.source);
      },
      error => {
        console.error(error);
      }
    );
  }

我的测试

import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { jqxGridComponent } from 'jqwidgets-scripts/jqwidgets-ts/angular_jqxgrid';
import { ProgressComponent } from './progress.component';
import { ProgressGridDataService } from './progress.service';
import { WorkingFileService } from 'src/app/services/working-file/working-file.service';
import { IProgressData } from './progress.interfaces';
import { of } from 'rxjs';

describe('ProgressComponent', () => {
  let component: ProgressComponent;
  let fixture: ComponentFixture<ProgressComponent>;

  class ProgressServiceSpy {
    testHistory: IProgressData = {
      recordId: 1,
      product: 'A',
    };
    getData = jest.fn().mockImplementation(() => of(Object.assign({}, this.testHistory)));

    restartLoad = jest.fn();
  }
  beforeEach(
    async(() => {
      TestBed.configureTestingModule({
        declarations: [ProgressComponent, jqxGridComponent],
        providers: [
          WorkingFileService,
          { provide: ProgressGridDataService, useValue: {} },
        ],
      })
      .overrideComponent(ProgressComponent, {
        set: {
          providers: [
            { provide: ProgressGridDataService, useClass: ProgressServiceSpy },
          ],
        },
      })
      .compileComponents();
      fixture = TestBed.createComponent(ProgressComponent);
      component = fixture.componentInstance;
      fixture.detectChanges();
    })
  );

  describe('retry button', () => {
    it('should call the restartLoad service and pass a record ID', () => {
      component.ngOnInit();
     expect(component.source).toHaveProperty('localdata');
      expect(component.source.localdata).toEqual(testHistory);
    });
  });
});

【问题讨论】:

  • 请给minimal reproducible example。一方面,您似乎怀疑您使用的是真正的合作者,并且在测试 组件而不是服务时显然需要使用HttpClientTestingModule
  • @jonrsharpe 即使这也让我有点过头了。以前我试图按照一些 Angular 文档示例来测试服务,而这只是留在那里。我切换到 HttpClientModule

标签: angular unit-testing mocking jestjs jqwidget


【解决方案1】:

通过进一步的挖掘,我设法弄清楚了。我按照Angular Stackblitz Hero app 的例子完全模拟了我的整个服务,因为它并没有真正接受测试。我不明白为什么必须使用overrideComponent 来设置间谍服务,而不仅仅是在TestBed 配置中这样做,但我认为这是因为我的组件在它自己的providers 数组(docs)中有该服务。

至于奇怪的bA.getPropertyValue is not a function 错误,this Github issue 让我走上了正确的轨道,这样我就可以将这个 sn-p 添加到jestGlobalMocks.ts,最后我的测试通过了!

我希望我能更清楚自己在 Angular 中使用 Jest 进行测试的目的是什么,因为花了整整 8 个小时来让这个微小的测试运行并通过,这正是我的应用程序缺乏测试覆盖率的原因。

Object.defineProperty(window, 'getComputedStyle', {
  value: () => ({
    getPropertyValue: prop => {
      return '';
    },
  }),
})

【讨论】:

    【解决方案2】:

    您应该从 TestBed 获取服务引用,然后对其进行模拟或 SpyOn:

        import { ComponentFixture, TestBed } from '@angular/core/testing';
    import { By } from '@angular/platform-browser';
    import { jqxGridComponent } from 'jqwidgets-scripts/jqwidgets-ts/angular_jqxgrid';
    import { ProgressComponent } from './progress.component';
    import { ProgressGridDataService } from './progress.service';
    import { HttpClientTestingModule } from '@angular/common/http/testing';
    import { HttpClient } from '@angular/common/http';
    import { IProgressData } from './progress.interfaces';
    import { of } from 'rxjs';
    
    describe('ProgressComponent', () => {
      let component: ProgressComponent;
      let progressService: ProgressGridDataService;
      let fixture: ComponentFixture<ProgressComponent>;
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          declarations: [ProgressComponent, jqxGridComponent],
          imports: [HttpClientTestingModule],
          providers: [ProgressGridDataService, WorkingFileService],
        });
        fixture = TestBed.createComponent(ProgressComponent);
        component = fixture.componentInstance;
        progressService = TestBed.get(ProgressGridDataService); // Here get the service
        fixture.detectChanges();
      });
    
      describe('component load', () => {
        let testHistory: IProgressData;
    
        beforeEach(() => {
          testHistory = {
            recordId: 1,
            product: 'A',
            fileId: 'A',     
          };
        });
        it('should pull the data from the service into a component property', () => {
         //I'm trying to use a Jest mock function, but I'm not sure I'm using it right 
    
      //Mock and Spy now....
    
          jest.spyOn(progressService, 'getData').mockImplementation(() => of(testHistory));
          component.ngOnInit();
    
          expect(component.source).toHaveProperty('localdata');
          expect(component.source.localdata).toEqual(testHistory)
          //would love to have an expectation that the service was called properly, but not sure how to do Jest spies on that function correctly.
           });
          });
        });
    

    【讨论】:

    • 在我的组件中,虽然我在providers 中有服务(虽然我不太确定为什么除了它有效),并且在 Angular 文档 (angular.io/guide/testing#get-injected-services) 中他们说要得到在这种情况下,来自组件的注入器的服务。
    • 没关系。您正在此处配置您的 TestModule,因此您应该从 TestBed 获得服务。根据文档:您还可以通过TestBed.get() 从根注入器获取服务。这更容易记住并且不那么冗长。但它仅在 Angular 在测试的根注入器中使用服务实例注入组件时才有效。
    猜你喜欢
    • 2019-10-21
    • 2022-08-07
    • 1970-01-01
    • 2017-07-15
    • 1970-01-01
    • 2021-06-17
    • 2017-11-23
    • 1970-01-01
    • 2021-07-07
    相关资源
    最近更新 更多