I am writing tests for my angular web application that contains a page with a firebase UI element. There are two tests, one that ensures the page loads and one that ensures the firebaseUI component loads correctly:
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();
});
});
and with a template file of:
<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>
and a class of:
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();
}
}
}
The service that actually loads the firebase ui is:
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
]
});
}
}
Now, running the application in a normal dev server environment (i.e. ng serve
), the UI is created as expected. However, in the test, it does not get generated properly for some reason and the UI fails to be created.
What should I be doing to allow the test framework to find the firebaseui auth container? I have obviously tried to inject the service multiple times and reset the UI after each test but with no joy. I'm guessing that it's to do with compiled
being undefined for some reason, which is also strange as that logic works on my other tests.
Based on your provided files, we can make a few approaches to test your component in this case. I will mock up your FirebaseService because we should trust that this external dependency is working well.
We should write unite test to lock the code, and if something else on our source code change will break the tests.
Tests scope
We should write minimal around four tests to lock
àuthentication.component.ts
when the current user is true
Inside your
authentication.component.spec.ts
when the current user is false
Inside your
authentication.component.spec.ts