问题描述
我正在为我的 Angular Web 应用程序编写测试,该应用程序包含一个带有 firebase UI 元素的页面。有两项测试,一项确保页面加载,一项确保 firebaseui 组件正确加载:
authentication.component.spec.ts
/*eslint-env jasmine*/
import { ComponentFixture,Testbed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { AuthenticationComponent } from './authentication.component';
import { FirebaseService } from '../services/firebase.service';
describe('AuthenticationComponent_Logged_Out',() => {
let component: AuthenticationComponent;
let fixture: ComponentFixture<AuthenticationComponent>;
let service;
beforeEach(async () => {
await Testbed.configureTestingModule({
declarations: [ AuthenticationComponent ],schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents();
service = Testbed.inject(FirebaseService);
fixture = Testbed.createComponent(AuthenticationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create',() => {
expect(component).toBeTruthy();
});
it('should render auth ui',() => {
const compiled = fixture.nativeElement;
expect(compiled.querySelector("#firebaseui_auth_container")).toBeTruthy();
});
afterEach(async () => {
service.ui.reset();
});
});
并带有以下模板文件:
<script src="https://www.gstatic.com/firebasejs/ui/4.8.0/firebase-ui-auth.js"></script>
<link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.8.0/firebase-ui-auth.css" />
<div id="authentication-wrapper">
<h1>Please sign in below to access your quotes!</h1>
<div id="firebaseui_auth_container"></div>
<div id="loader">Loading...</div>
</div>
和一类:
import { Component } from '@angular/core';
import { FirebaseService } from '../services/firebase.service';
@Component({
selector: 'app-authentication',templateUrl: './authentication.component.html',styleUrls: ['./authentication.component.css']
})
export class AuthenticationComponent {
constructor (private fbService: FirebaseService) {
sessionStorage.removeItem('displayed_random');
// If user logged in,redirect to Feed
if (fbService.currentUser) {
window.location.href = "/Feed";
} else {
this.fbService.instantiateUi();
}
}
}
实际加载 firebase ui 的服务是:
firebase.service.ts
import { Injectable } from '@angular/core';
import firebase from "firebase/app";
import * as firebaseui from "firebaseui";
import { config } from './config';
import 'firebase/database';
import 'firebase/auth';
firebase.initializeApp(config);
@Injectable({
providedIn: 'root'
})
export class FirebaseService {
currentUser: string;
auth = firebase.auth();
ui = firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(this.auth);
constructor () {
const username = sessionStorage.getItem('username');
if (username) {
this.currentUser = username;
}
}
signoutUser () {
this.auth.signOut();
this.currentUser = undefined;
if (sessionStorage.getItem('username')) {
sessionStorage.removeItem('username');
}
}
getRef (path) {
return firebase.database().ref(path);
}
instantiateUi () {
this.ui.start("#firebaseui_auth_container",{
callbacks: {
signInSuccessWithAuthResult: (authResult) => {
// Save username in storage
sessionStorage.setItem('username',authResult.user.displayName);
return true;
},uiShown: () => {
// The widget is rendered,hide the loader.
document.getElementById('loader').style.display = 'none';
}
},// Will use popup for IDP Providers sign-in flow instead of the default,redirect.
signInFlow: 'popup',signInSuccessUrl: 'Feed',signInoptions: [
{
provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,customParameters: {
prompt: 'select_account' // Forces account selection even when only one account is available.
}
},firebase.auth.EmailAuthProvider.PROVIDER_ID
]
});
}
}
现在,在正常的开发服务器环境(即 ng serve
)中运行应用程序,UI 按预期创建。但是,在测试中,由于某种原因无法正常生成,并且无法创建UI。
我应该怎么做才能让测试框架找到 firebaseui auth 容器?我显然尝试多次注入服务并在每次测试后重置 UI,但没有任何乐趣。我猜这与 compiled
出于某种原因未定义有关,这也很奇怪,因为该逻辑适用于我的其他测试。
解决方法
根据您提供的文件,在这种情况下,我们可以采用几种方法来测试您的组件。我将模拟您的 FirebaseService,因为我们应该相信此外部依赖项运行良好。
我们应该编写 unite test 来锁定代码,如果我们源代码上的其他更改会破坏测试。
测试范围
我们应该编写最少的大约四个测试来锁定 àuthentication.component.ts
- 它应该创建
- 它应该是来自 sessionStorage 的display_random 值的空
- 当 currentUser 为真时执行 location href。
- 当 currentUser 为假时调用 fbService 函数。
constructor (private fbService: FirebaseService) {
sessionStorage.removeItem('displayed_random');
// If user logged in,redirect to feed
if (fbService.currentUser) {
window.location.href = "/feed";
} else {
this.fbService.instantiateUi();
}
}
当前用户为真时
在您的authentication.component.spec.ts
内
describe('AuthenticationComponent with current user',() => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AuthenticationComponent ],providers: [
{
provide: FirebaseService,useValue: {
currentUser: true,instantiateUi: () => null
}
}
],schemas: [ NO_ERRORS_SCHEMA ]
}).compileComponents();
service = TestBed.inject(FirebaseService);
fixture = TestBed.createComponent(AuthenticationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create',() => {
expect(component).toBeTruthy();
});
it('should be session storage displayed_random empty on start',() => {
expect(sessionStorage.getItem('displayed_random').toBeFalsy();
});
it('should change href value to feed',() => {
expect(window.location.href).toBe('/feed');
});
当前用户为false时
在您的authentication.component.spec.ts
内
describe('AuthenticationComponent without current user',useValue: {
currentUser: false,() => {
expect(component).toBeTruthy();
});
it('should call instantiateUI when no current user',() => {
const instantiateUiSpy = spyOn(service,'instantiateUi');
expect(instantiateUiSpy).toHaveBeenCalled();
});