DEV Community

Styrow.dev
Styrow.dev

Posted on Originally published at styrow.dev

How do you effectively test an application's reliance on browser history (back/forward buttons) and history API state ma

🤯 SPA Navigation Nightmares? 99% of Devs Miss This Playwright Trick!
How do you truly test your Single Page Application's reliance on browser history (back/forward) and History API state without full page reloads?

📌 Problem Statement
SPAs use History API (pushState) for client-side navigation. Back/forward buttons don't always trigger full reloads. Verifying only the URL is insufficient. You must confirm the application's internal state and rendered UI. Traditional tests often fail here.

💡 Solution & Code Walkthrough
Playwright's page.goBack() and page.goForward() mimic browser button clicks. These async methods await navigation completion, allowing assertions on both URL and dynamic UI. For deeper validation, page.evaluate(() => history.state) can inspect raw History API state.

import { test, expect } from '@playwright/test';

test('should handle browser history navigation in an SPA', async ({ page }) => {
  // 1. Navigate to initial product list
  await page.goto('http://localhost:3000/products');
  await expect(page).toHaveURL(/products$/);
  await expect(page.locator('h1')).toHaveText('Product List');

  // 2. Navigate to a product detail page
  await page.locator('a:has-text("Product A")').click();
  await expect(page).toHaveURL(/products\/product-a$/);
  await expect(page.locator('h1')).toHaveText('Product A Detail');

  // 3. Simulate browser back button
  await page.goBack();
  await expect(page).toHaveURL(/products$/);
  await expect(page.locator('h1')).toHaveText('Product List');

  // 4. Simulate browser forward button
  await page.goForward();
  await expect(page).toHaveURL(/products\/product-a$/);
  await expect(page.locator('h1')).toHaveText('Product A Detail');
  // Consider checking history.state for advanced SPA logic
  // const state = await page.evaluate(() => history.state);
  // expect(state).toHaveProperty('productViewed', 'product-a');
});
Enter fullscreen mode Exit fullscreen mode

🔑 Key Takeaways
• Use page.goBack() & page.goForward() for authentic browser navigation.
• Always verify both URL (toHaveURL) and rendered UI content (toHaveText).
• Consider page.evaluate(() => history.state) for deep client-side state validation.
❌ Relying solely on URL changes for SPA history tests is a common pitfall.

❓ Quick Summary Q&A
Q: How to simulate back/forward in Playwright?
A: Use page.goBack() and page.goForward().
Q: What to verify in SPA history navigation?
A: URL, visible UI content, and potentially the history.state object.

TAGS: playwright, testing, spa, automation, javascript, webdev

────────────────────────────────────────
👉 Master Playwright & Automation with our App!
────────────────────────────────────────

📲 𝐅𝐑𝐄𝐄 𝐌𝐎𝐁𝐈𝐋𝐄 𝐀𝐏𝐏 — 𝟔𝟎𝟎+ 𝐒𝐃𝐄𝐓 𝐐&𝐀𝐬
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_20261113

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

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

Top comments (0)