首页 > 解决方案 > 测试时在 *ngIf 语句中找不到按钮,因为语句涉及模拟类

问题描述

我正在构建一个应用程序,人们可以在其中使用 Angular 中的 Github 进行身份验证。我已经建立了一个按钮来做到这一点。尝试测试此按钮时,测试似乎找不到该按钮。我认为它与 *ngIf 语句有关。

login.component.spec.ts:

    class MockAuthService implements Partial<AuthService> {
  isAuthenticated() {
    return 'Mocked';
  }


  loginwithGithubProvider() {
    return new Promise((resolve, reject) => resolve());
  }

  logout(): Promise<boolean | Observable<never> | never> {
    return new Promise(function(resolve, reject) { resolve(); });
  }
}


describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let componentService: AuthService;
  const routerSpy = jasmine.createSpyObj('Router', ['navigate']);
  const ghServiceSpy = jasmine.createSpyObj('GithubService', ['methodName']);

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        MatCardModule,
        AngularFireModule.initializeApp(environment.firebase),
        RouterModule.forRoot([{path: '', component: LoginComponent}]),
      ],
      declarations: [
        LoginComponent
      ],
      providers: [
        AuthService,
        AngularFirestore,
        AngularFireAuth,
        HttpClient,
        HttpHandler
      ]
    });
    TestBed.overrideComponent(LoginComponent, {
      set: {
        providers: [
          {provide: AuthService, useClass: MockAuthService},
          {provide: Router, useValue: routerSpy},
          {provide: GithubService, useValue: ghServiceSpy},
        ]
      }
    });

    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;
    componentService = fixture.debugElement.injector.get(AuthService);
  }));

  it('Logginbutton calls signInWithGithub', async(() => {
    spyOn(component, 'signInWithGithub');
    const button =  fixture.debugElement.nativeElement.querySelector('#signInWithGithub');
    button.click();
    fixture.whenStable().then(() => {
      expect(component.signInWithGithub).toHaveBeenCalled();
    });
  }));

login.component.html:

 <div *ngIf="authService.isLoggedIn; else loginTemplate">
    <h1>Welcome {{authService?.username}}</h1>
    <img src="{{ authService?.userDetails?.photoURL }} ">
    <br />
    <button mat-flat-button class="btn-github" id="logout" (click)="logout()">
      <i class="fab fa-github"></i> Stop authentication Github
    </button>
  </div>

  <ng-template #loginTemplate>
    <h1>FullProjectCloner</h1>
    <button mat-flat-button class="btn-github" id="signInWithGithub" (click)="signInWithGithub()">
      <i class="fab fa-github"></i> Authenticate with github
    </button>
    <p class="authError">{{this?.loginError}}</p>
  </ng-template> 

我得到的错误:

TypeError: Cannot read property 'click' of null

标签: angulartesting

解决方案


问题是您已经设置了所有内容,但在测试之前没有调用让 Angular 实际渲染任何内容所需的生命周期更改。

简单的解决方法是fixture.detectChanges()在您 spyOn 组件后调用。

我把它放在一个Stackblitz中,以确保它对你有用。在那个 Stackblitz 中,只需注释掉fixture.detectChanges(),你就会看到问题。

这是 Stackblitz 的规范:

it('Logginbutton calls signInWithGithub', async(() => {
  spyOn(component, 'signInWithGithub');
  fixture.detectChanges();
  const button =  fixture.debugElement.nativeElement.querySelector('#signInWithGithub');
  button.click();
  expect(component.signInWithGithub).toHaveBeenCalled();
}));

您会注意到我也删除了对的调用,whenStable()因为这也不需要。


推荐阅读