在 describe 中定义的变量在 angular 测试 (jest/jasmine) 的外部函数中是 "undefined"

Variables defined in describe is "undefined" in outer functions in angular test (jest/jasmine)

我有这样的代码:

// imports
    
describe('AdminGetRightsComponent', () => {
    
  // Declare variables to be re-initialized before each test suite
  let fixture: ComponentFixture<AdminGetRightsComponent>;
  let component: AdminGetRightsComponent;
  let router: Router;
  let location: Location;
  let debugElement: DebugElement;


  window.alert = jest.fn();

  // Create service stubs
  let nxDialogServiceStub: Partial<NxDialogService>;
  nxDialogServiceStub = {};

  let ServicesRmAdminServiceStub: Partial<ServicesRmAdminService>;
  ServicesRmAdminServiceStub = {

    // Simulate API call, wait for 1000 milliseconds
    async getRights(contactIds: string[]) {
      await new Promise(resolve => setTimeout(resolve, 0));
      return {
        body: TEST_API_RESPONES_BODY
      }
    }
  };

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ AdminGetRightsComponent ],
      imports: [
        RouterTestingModule.withRoutes([{ path: '', component: AdminGetRightsComponent }]),
        HttpClientTestingModule,
        BrowserAnimationsModule,
        modulesForTests
      ],
      providers: [
        { provide: NxDialogService },
        { provide: ServicesRmAdminService, useValue : ServicesRmAdminServiceStub},
        { provide: ServicesFileManagementService }
      ]
    })
    .compileComponents();
  });


  beforeEach(() => {
    router = TestBed.inject(Router);
    location = TestBed.inject(Location);
    fixture = TestBed.createComponent(AdminGetRightsComponent);
    component = fixture.componentInstance;
    component.downloadCSV = jest.fn(() => {
      component.fileUploaderComponent.removeFile(component.files[0]);
    });
    debugElement = fixture.debugElement;
    fixture.ngZone.run(() => {
      router.initialNavigation();
    });
    fixture.detectChanges();
  });


  describe('When uploaded a file', () => {


    beforeEach((done) => {
      fixture.detectChanges();
      uploadFileToComponent(component);
      setTimeout(done, TEST_DEFAULT_TIMEOUT);
    });

    afterEach((done) => {
      fixture.detectChanges();
      // Remove the file
      component.files.length > 0 && component.fileUploaderComponent.fileDeleted.emit(component.files[0]);

      setTimeout(done, TEST_DEFAULT_TIMEOUT);
    });

    it('should have the right UI elements', () => {

      fixture.detectChanges();

      expect(...).toBe(...);
    });

    describe('When clicked on the delete file button', () => {


      beforeEach((done) => {
        fixture.detectChanges();
        getNativeElement('nx-file-upload-delete button', debugElement).click();
        setTimeout(done, TEST_DEFAULT_TIMEOUT);
      });

      it('should remove the right UI elements', () => {
        fixture.detectChanges();
        expect(...).toBe(...);
      });

    });

    // other code

  });

});

在我的代码中,我有很多这样的 beforeEach(至少 8 或 9 个地方):

beforeEach((done) => {
  fixture.detectChanges();
  getNativeElement('nx-file-upload-delete button', debugElement).click();
  setTimeout(done, TEST_DEFAULT_TIMEOUT);
});

fixture.detectChanges()setTimeout(...) 是重复的代码,我不想要它。


一开始我是这样写的:

function _beforeEach(callback) {
  eval('fixture.detectChanges()');
  beforeEach((done) => {
    callback();
    setTimeout(done, TEST_DEFAULT_TIMEOUT);
  })
}

然后我用这个_beforeEach替换了之前的所有beforeEach,这可以帮助我减少每次调用的2行代码。但它说 ReferenceError: fixture is not defined.


然后我尝试了这样的事情:

function _beforeEach(
  callback,
  fixture: ComponentFixture<AdminGetRightsComponent>
) {
  fixture.detectChanges();
  beforeEach((done) => {
    callback();
    setTimeout(done, TEST_DEFAULT_TIMEOUT);
  });
}

并且我用上面的 _beforeEach 替换了之前的所有 beforeEach,当我用 ng test 启动测试时,我得到了错误 TypeError: Cannot read property 'detectChanges' of undefined.


有人知道为什么会这样吗?

我想你尝试归档这个:

function _beforeEach(
  callback
) {
  fixture.detectChanges();
  beforeEach((done) => {
    callback();
    setTimeout(done, TEST_DEFAULT_TIMEOUT);
  });
}

虽然我看不到 fixture.detectChanges(); 这行的必要性。似乎只是从根 beforeEach.

复制相同的代码

我也会避免 setTimeout(done, TEST_DEFAULT_TIMEOUT); 会减慢测试 运行 执行时间。在大多数情况下 await fixture.whenStable() 解决等待异步操作完成的问题。如果还不够,那么 fakeAsyncctickjasmine.clock 可能是一个解决方案。虽然它并不总是有效,但我也偶尔会放弃并使用超时解决方案。