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’??).