⚡️ Offline-First Apps: How do you TEST the "impossible"?
Designing an end-to-end test for a complex web app's offline capabilities with Playwright, focusing on Service Workers, IndexedDB, and data sync, demands a sophisticated strategy.

📌 Problem Statement
Our field technician SPA needs robust offline-first validation:
• Create/edit reports while offline.
• Automatic backend sync on reconnect.
• Data consistency across sessions (offline, close, reopen).
• Accurate UI status for offline/syncing.

💡 Solution & Code Walkthrough
Playwright offers powerful APIs for network control and browser context interaction.

✅ Simulate Network Changes:
Use setOffline() to toggle connectivity.

// Go offline await page.context().setOffline(true); // Go online await page.context().setOffline(false); 

✅ Verify Service Worker (SW) Registration:
Ensure the SW is active and controlling the page.

const serviceWorker = (await page.context().serviceWorkers())[0]; expect(serviceWorker).toBeDefined(); // SW registered // await serviceWorker.evaluate(() => self.registration.scope); // Evaluate SW state 

✅ Inspect IndexedDB Data:
Access IndexedDB via page.evaluate() to assert local data state.

const localData = await page.evaluate(async () => { const db = await new Promise(resolve => { const request = indexedDB.open('MyAppDB', 1); request.onsuccess = () => resolve(request.result); }); const transaction = db.transaction(['reports'], 'readonly'); const store = transaction.objectStore('reports'); return new Promise(resolve => store.getAll().onsuccess = e => resolve(e.target.result)); }); expect(localData).toContainEqual({ id: 'report-123', status: 'pending' }); 

✅ Trigger & Monitor Data Synchronization:
Toggle network, then wait for UI feedback or direct IndexedDB updates.

// Perform offline action (e.g., create report) await page.context().setOffline(true); await page.locator('#create-report').click(); // Go online to trigger sync await page.context().setOffline(false); // Wait for sync completion UI element await expect(page.locator('.sync-status')).toHaveText('Synced!'); 

✅ Handle Race Conditions:
Use waitForFunction or waitForResponse to await specific state changes.

// Wait for IDB update after sync await page.waitForFunction(async () => { // Assume getDbConnection() is a helper for IndexedDB connection const db = await getDbConnection(); const transaction = db.transaction(['reports'], 'readonly'); const store = transaction.objectStore('reports'); const reports = await new Promise(resolve => store.getAll().onsuccess = e => resolve(e.target.result)); return reports.some(r => r.status === 'synced'); }, { timeout: 10000 }); 

🔑 Key Takeaways
• page.context().setOffline() is crucial for network simulation.
• page.context().serviceWorkers() provides direct SW access.
• page.evaluate() bridges Playwright to browser-side APIs (IndexedDB).
• Strategic use of waitFor methods prevents flaky tests due to async operations.

❓ Quick Summary Q&A
Q: How to simulate offline? A: page.context().setOffline(true).
Q: How to check IndexedDB? A: Use page.evaluate() to run browser-side IDB code.
Q: Why waitForFunction? A: To reliably await dynamic, asynchronous state changes.

TAGS: playwright, e2e testing, offline-first, service workers, indexeddb, automation, web testing

────────────────────────────────────────
Download our app for more dev insights & interview prep!
────────────────────────────────────────

📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&𝐀𝐬
Practice real-world interview scenarios offline on the free QA Automation & SDET Prep app:

🤖 𝐆𝐨𝐨𝐠𝐥𝐞 𝐏𝐥𝐚𝐲 (𝐀𝐧𝐝𝐫𝐨𝐢𝐝):
https://play.google.com/store/apps/details?id=com.app.seleniuminterviewquestions&referrer=utm_source%3Ddevto%26utm_medium%3Darticle%26utm_campaign%3Dselenium_20261012

🍎 𝐀𝐩𝐩 𝐒𝐭𝐨𝐫𝐞 (𝐢𝐎𝐒):
https://apps.apple.com/app/id6786760948?pt=128640464&ct=devto_selenium_20261012&mt=8

────────────────────────────────────────
────────────────────────────────────────