DEV Community

Styrow.dev
Styrow.dev

Posted on Originally published at styrow.dev

How would you design a robust Playwright E2E test suite to verify client-side routing and deep linking in a complex Sing

πŸ”₯ Playwright Challenge of the Day:
How do you robustly verify complex client-side routing and deep linking in an SPA with dynamic content and varying auth?

πŸ“Œ Problem Statement
Complex Single-Page Applications (SPAs) make E2E testing routing a challenge.
β€’ Authentication Overhead: Re-logging in for every test slows down suites and increases flakiness.
β€’ Dynamic URLs: Routes with parameters (e.g., /users/{id}/profile) require careful handling.
β€’ Async Content Loading: SPA content loads asynchronously; tests must wait for full render.
β€’ Data Dependencies: Setting up specific backend data via UI before each test is inefficient.
β€’ Client-Side Redirections: Verifying internal redirects (e.g., / to /dashboard if authenticated) is crucial.

πŸ’‘ Solution & Code Walkthrough
A production-grade Playwright solution combines session persistence, direct navigation, API-based state manipulation, and resilient waiting strategies.

βœ… Persistent Authentication via storageState: Log in once, save the browser state (cookies, local storage), and reuse it across multiple tests. This dramatically reduces setup time.

// playwright/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.fill('#username', 'testuser');
  await page.fill('#password', 'password123');
  await page.click('button[type="submit"]');
  // Ensure a successful login indicator is visible
  await expect(page.locator('.user-profile')).toBeVisible();
  await page.context().storageState({ path: authFile });
});
Enter fullscreen mode Exit fullscreen mode

Then, configure playwright.config.ts to use authFile in your test projects to load the session state.

βœ… Direct Navigation & API Seeding: Navigate directly to deep links (e.g., /products/123). For data-dependent routes, use Playwright's page.request to seed test data via API calls before navigating, bypassing slow UI setup.

βœ… Resilient Assertions: Utilize page.waitForURL() for client-side route changes and locator.waitFor() or expect(locator).toBeVisible() to ensure dynamic content related to the route is fully rendered. Avoid brittle page.waitForTimeout().

πŸ”‘ Key Takeaways
β€’ Prioritize storageState for efficient authentication management in SPAs, boosting speed.
β€’ Leverage direct URL navigation and API requests for fast, reliable data setup.
β€’ Employ Playwright's robust waiting mechanisms for accurate async content verification.
β€’ Always assert the final URL or specific elements to confirm successful routing and redirects.

❓ Quick Summary Q&A
Q: Why is storageState crucial for SPA routing tests?
A: It saves and reuses login sessions, drastically speeding up tests and reducing flakiness.
Q: How to handle dynamic URLs like /users/{id}?
A: Construct the full URL with specific IDs, then navigate directly.

TAGS: playwright, e2e testing, spa, routing, authentication, automation

────────────────────────────────────────
Improve your dev skills daily. Download 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_20260926

🍎 𝐀𝐩𝐩 π’π­π¨π«πž (π’πŽπ’):
https://apps.apple.com/app/id6786760948?pt=128640464&ct=devto_selenium_20260926&mt=8

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

Top comments (0)