close

DEV Community

Cover image for Every Dev Re-Tests the Whole App Before Release. Here's the One-Time Setup That Ends That.
Suresh
Suresh

Posted on

Every Dev Re-Tests the Whole App Before Release. Here's the One-Time Setup That Ends That.

I'd used Jest for years. Great for unit tests and React components, but it doesn't run a real browser. The moment I hit a Safari-specific bug that never appeared in Chrome, I realized I needed something different.

That's the gap Playwright is built for. It drives an actual browser - Chrome, Firefox, WebKit — and runs the same test in each one. The bug that only shows up in Safari shows up in the test run too, before it ships.

The project.
Secure Share is a file-sharing app I built — small enough to put together quickly, but complex enough to cover authentication, uploads, downloads, protected routes, and share-link generation.

User (Browser)
   ↓
React.js — Dashboard UI
   ↓
Node.js API — JWT Auth
   ↓
MongoDB — Users & Files
   ↓
Storage — Documents
Enter fullscreen mode Exit fullscreen mode

Secure sharing workflow:


Login →  Upload File →  Generate Link →  Set Expiry →  Share URL → Protected Download

Enter fullscreen mode Exit fullscreen mode

Every one of those six steps used to mean a manual click-through across two or three browsers before a release. That's what got automated.

Testing across browsers. Playwright defines browsers as projects in config. One test file, run once per browser listed:

// playwright.config.js
export default defineConfig({
  testDir: './tests',
  reporter: 'html',
  use: { baseURL: 'http://localhost:5173' },

  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit',   use: { ...devices['Desktop Safari'] } },
  ],
});

Enter fullscreen mode Exit fullscreen mode
npx playwright test                    # all three browsers
npx playwright test --project=webkit   # just Safari's engine

Enter fullscreen mode Exit fullscreen mode

What this caught: a Safari click-handler bug. Chrome passed, WebKit failed on the same spec, and the report named the exact line. That's the kind of bug that lives entirely in the browser layer — invisible to anything running in Node.

Validating login.

test('user can login', async ({ page }) => {
  await page.goto('/login');
  await page.fill('#email', 'test@gmail.com');
  await page.fill('#password', 'Password123');
  await page.click('button[type="submit"]');

  const token = await page.evaluate(() => localStorage.getItem('token'));
  expect(token).not.toBeNull();
});

Enter fullscreen mode Exit fullscreen mode

Not just "did the page redirect" — checking the JWT actually landed in storage. A redirect can fire before the token write finishes; checking the token is what catches that.

Validating the rest, briefly.

// wrong password → correct error
await page.fill('#email', 'wrong@test.com');
await page.fill('#password', 'WrongPassword');
await page.click('button[type="submit"]');
await expect(page.getByText('Invalid email or password')).toBeVisible();

// upload → confirmation
await page.locator('input[type="file"]').setInputFiles('tests/files/sample.pdf');
await expect(page.getByText(/uploaded successfully/i)).toBeVisible({ timeout: 20000 });

// share link → copy confirmation
await page.click('text=Generate URL');
await page.click('text=Generate & Copy Link');
await expect(page.getByText(/link copied/i)).toBeVisible();

// download → real file, not a broken stream
const downloadPromise = page.waitForEvent('download');
await page.click('text=Download');
const download = await downloadPromise;
expect(download.suggestedFilename()).toBeTruthy();

Enter fullscreen mode Exit fullscreen mode

Each test is small on purpose — one user action, one thing it should be true after. Stacked together, they cover the same path the manual checklist used to.

The HTML report.

reporter: 'html' generates a report after every run that shows pass/fail per browser, per test, with a trace of exactly where it broke. It's caught more than one selector that Safari resolves differently — something that would never show up in a Jest test.

One-time setup, then it's just a command.

git clone <repo>
cd e2e
npm install
npx playwright install
Enter fullscreen mode Exit fullscreen mode

Before Playwright: 15–20 minutes of clicking through the app before every release. After Playwright: one command (npx playwright test) and a report in under a minute.

The report tells you — before a user does — whether login, upload, sharing, and download still work everywhere they need to.

I still use Jest for unit tests. Playwright didn't replace it. It solved a different problem: validating that the entire application works the way a real user expects. For this project, that meant fewer repetitive checks, faster releases, and more confidence that a change in one area didn't quietly break another.

Code and live demo:

Top comments (2)

Collapse
 
espoirsamah profile image
HopeGeek

Great...

Collapse
 
frank_signorini profile image
Frank

How do you handle end-to-end tests with this setup, or is that still a manual process? I've struggled to integrate them with Jest. Would love to hear your thoughts on this.