I am testing a Chrome extension (Manifest V3) using Jest and Puppeteer. The extension uses Firebase Authentication and Firestore.
The Goal:
My test needs to register a new user, wait for a backend Cloud Function to create their profile document in Firestore, and then perform actions as that user.
The Problem:
My onUserCreate Cloud Function runs successfully when a user is registered (I have verified this manually and by checking the Firestore database โ the /Users/{uid} document is created correctly).
However, my test script’s polling loop, which repeatedly calls a getUserProfile function to check for this document, consistently fails to find it and eventually times out.
Why would a client-side .get() request from within a Puppeteer test fail to find a document that was successfully created by a Cloud Function moments before? Could this be a Firestore consistency issue that is specific to a test environment, or a problem with how auth state is handled by the client SDK in this context?
I have confirmed that billing is enabled for my Google Cloud project and the project is on the Blaze plan.
I have already tried implementing a polling loop to wait for the document, as suggested in similar questions, but the test still times out.
Here is the relevant code:
- The Cloud Function (functions/index.js):
exports.initializeNewUser = functions.auth.user().onCreate(async (user) => {
const db = admin.firestore();
const settingsDoc = await db.collection("settings").doc("trustScoreRules").get();
const initialScore = settingsDoc.exists ? settingsDoc.data().initialScoreTom : 3;
const newUserProfile = {
email: user.email,
trustScore: initialScore,
// ... other fields
};
return db.collection("Users").doc(user.uid).set(newUserProfile);
});
- The Test Script Polling Logic (tests/extension.test.js):
// This happens inside a beforeAll block
// ... after user is successfully registered and signed in ...
let userProfile = null;
for (let i = 0; i < 10; i++) {
const response = await worker.evaluate(async () => {
return new Promise((resolve) => {
chrome.runtime.sendMessage(
{ type: 'getUserProfile', target: 'background' },
(response) => { resolve(response); }
);
});
});
if (response && response.success) {
userProfile = response.profile;
break;
}
await new Promise(resolve => setTimeout(resolve, 1000));
}
if (!userProfile) {
throw new Error("Timed out waiting for user profile to be created...");
}
- The Client-Side Fetch Logic (offscreen.js):
case 'getUserProfile': {
const unsubscribe = auth.onAuthStateChanged(user => {
unsubscribe();
if (user) {
db.collection('Users').doc(user.uid).get()
.then(doc => {
if (doc.exists) {
sendResponse({ success: true, profile: doc.data() });
} else {
sendResponse({ success: false, error: "User profile not found." });
}
})
} else {
sendResponse({ success: false, error: "User not authenticated." });
}
});
return true;
}
The result was that the New User was indeed created in Firestore and Firebase Authentication, but it is failing two of the three tests. Here is the terminal output:
> [email protected] test
> NODE_OPTIONS=--experimental-vm-modules jest
(node:2283) ExperimentalWarning: VM Modules is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
FAIL tests/extension.test.js (12.447 s)
Anotato Extension Tests
Extension Loading
โ should load the extension and find the service worker (2 ms)
User Actions
โ should show a signed-in state in the popup
โ should allow a signed-in user to create an annotation
โ Anotato Extension Tests โบ User Actions โบ should show a signed-in state in the popup
Timed out waiting for user profile to be created by Cloud Function.
83 | }
84 | if (!userProfile) {
> 85 | throw new Error("Timed out waiting for user profile to be created by Cloud Function.");
| ^
86 | }
87 | });
88 |
at Object.<anonymous> (tests/extension.test.js:85:15)
โ Anotato Extension Tests โบ User Actions โบ should allow a signed-in user to create an annotation
Timed out waiting for user profile to be created by Cloud Function.
83 | }
84 | if (!userProfile) {
> 85 | throw new Error("Timed out waiting for user profile to be created by Cloud Function.");
| ^
86 | }
87 | });
88 |
at Object.<anonymous> (tests/extension.test.js:85:15)
Test Suites: 1 failed, 1 total
Tests: 2 failed, 1 passed, 3 total
Snapshots: 0 total
Time: 14.223 s
Ran all test suites.