I am trying to run unit tests for a few portions of my Firebase web app, but I am running into issues with authentication. I have the mock authentication working (triggering onAuthStateChanged as expected). The problem I am having is that it seems the Firebase SDK is holding onto the auth object I pass in first, which makes sense other than I can’t seem to sign out or reset the auth object in between tests.
My onAuthStateChanged observer:
onAuthStateChanged(auth, async (user) => {
console.log('onAuthStateChanged', auth, user);
if (!user || (user && !user.currentUser.emailVerified)) {
window.location.href = 'index.html';
} else {
await showInputs();
}
});
My first test is:
const mockAuth = { currentUser: { uid: true, emailVerified: true } };
getAuth.mockReturnValue(mockAuth);
require('./register.js');
await onAuthStateChanged.mock.calls[0][1](mockAuth);
As expected, console.log prints
onAuthStateChanged
auth: { currentUser: { uid: true, emailVerified: true } }
user: { currentUser: { uid: true, emailVerified: true } }
But, on the next test mockAuth is set to
const mockAuth = { currentUser: { uid: true, emailVerified: false } };
^^^^^
and console.log prints:
onAuthStateChanged
auth: { currentUser: { uid: true, emailVerified: true } }
user: { currentUser: { uid: true, emailVerified: false } }
Clearly, the SDK is holding onto the auth state, (again, this makes sense given I haven’t logged out), but I have tried getAuth.mockReset(), signOut(getAuth()), getAuth.mockReturnValue(null), and a few others to no avail.
It isn’t so much that I need to sign out, as much as I need to alter the auth object for other tests. These tests are merely checking authentication and are working as expected (they are simply easy examples to illustrate my problem).
I need to be able to add/update the auth.currentUser.email field for later tests. Since the SDK is hanging on to the auth object I initially provide (ignoring getAuth.mockReturnValue(mockAuth) on subsequent calls), I cannot test my code fully.
For this particular test, in my beforeEach call, I have:
getAuth.mockReset();
mockAuth = { currentUser: { uid: true, emailVerified: true, email: "[email protected]" } };
getAuth.mockReturnValue(mockAuth);
But, when executed, auth.currentUser.email is undefined.
The problem function:
onValue(child(firebaseRef, `items`), items => {
document.getElementById('itemList').innerHTML = '';
// fill item list
if (auth.currentUser) {
items.forEach(i => {
if (i.child('seller').val() === auth.currentUser.email && !i.hasChild('inactive')) {
addItemToList(i);
}
});
}
});
auth.currentUser.email is always undefined because when it is set in my first authentication test, I do not need nor provide an email property, but that is the auth object used for the entirety of the test run. If I change the mockAuth object and re-run the test, auth will have the new values (so maybe it doesn’t have anything to do with ‘signing out’??).