Skip to content

YogiAdv/playwright-ui-audit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

playwright-ui-audit

Full-page screenshots of every route in your web app — at desktop and mobile — with a single command. Generates a browsable HTML report.

Use this to:

  • Review your UI before a demo or deploy
  • Catch visual regressions after big changes
  • Share a visual overview of your app with collaborators or stakeholders
  • Spot mobile layout issues without manually resizing your browser

What it looks like

Run npm run screenshot → open screenshots/report.html → see this:

Page Desktop 1280px Mobile 390px
Homepage (screenshot) (screenshot)
Login (screenshot) (screenshot)
Projects list (screenshot) (screenshot)

Each screenshot is clickable to open full-size. Auth-required pages are captured after a configurable login step.


Setup

Requirements: Node.js 18+

# 1. Clone
git clone https://github.com/YOUR_USERNAME/playwright-ui-audit.git
cd playwright-ui-audit

# 2. Install dependencies
npm install

# 3. Install the Chromium browser Playwright uses
npm run setup

Usage

# Your dev server must be running first (e.g. npm run dev in your app)

npm run screenshot                                    # localhost:3000, desktop + mobile
npm run screenshot:mobile                             # mobile only
npm run screenshot:desktop                            # desktop only
npm run screenshot -- --url https://staging.myapp.com          # against any URL
npm run screenshot -- --url https://myapp.com --only mobile    # deployed + mobile only

Then open the report:

open screenshots/report.html     # macOS
xdg-open screenshots/report.html # Linux
start screenshots/report.html    # Windows

Configuration

Everything you need to change is in config.ts. The engine (screenshot.ts) never needs editing.

1. Set your base URL

export const BASE_URL = "http://localhost:3000"; // change this

Override at runtime without editing the file:

npm run screenshot -- --url https://staging.myapp.com

2. Define your routes

export const ROUTES: Route[] = [
  {
    path: "/",
    label: "Homepage",
    auth: "public",   // no login needed
    waitFor: "main",  // CSS selector — wait for this before screenshotting
  },
  {
    path: "/dashboard",
    label: "Dashboard",
    auth: "user",     // login() will be called first
    waitFor: "main",
  },
  // add as many as you need
];

auth values:

  • "public" — screenshot without logging in
  • "user" — calls your login() function first (once, then reuses the session)

waitFor: A CSS selector the tool waits for before taking the screenshot. Prevents capturing loading spinners. Use "main" as a safe default for most apps.

3. Implement login (if you have auth-required pages)

In config.ts, fill in the login() function. Three options are pre-written — uncomment the one that fits:

Option A — Dev bypass button (Next.js + Supabase pattern)

export async function login(page: Page, baseUrl: string): Promise<boolean> {
  const res = await page.request.post(`${baseUrl}/api/dev-login`);
  if (!res.ok()) return false;
  await page.goto(`${baseUrl}/login`, { waitUntil: "networkidle" });
  const btn = page.locator("button", { hasText: /skip login/i }).first();
  if (!(await btn.isVisible({ timeout: 3_000 }).catch(() => false))) return false;
  await btn.click();
  await page.waitForURL((url) => !url.pathname.startsWith("/login"), { timeout: 8_000 }).catch(() => {});
  return !page.url().includes("/login");
}

Option B — Email + password

export async function login(page: Page, baseUrl: string): Promise<boolean> {
  await page.goto(`${baseUrl}/login`, { waitUntil: "networkidle" });
  await page.fill("input[type='email']", "test@example.com");
  await page.fill("input[type='password']", "your-test-password");
  await page.click("button[type='submit']");
  await page.waitForNavigation({ waitUntil: "networkidle", timeout: 8_000 });
  return !page.url().includes("/login");
}

Option C — No auth

export async function login(): Promise<boolean> {
  return false; // mark all routes as auth: "public"
}

4. Customize viewports

export const VIEWPORTS = {
  desktop: { width: 1280, height: 900,  label: "Desktop 1280px" },
  mobile:  { width: 390,  height: 844,  label: "Mobile 390px" },
  // add tablet: { width: 768, height: 1024, label: "Tablet 768px" }
};

Output

screenshots/
  desktop/
    homepage.png
    login.png
    projects-list.png
    …
  mobile/
    homepage.png
    login.png
    …
  report.html     ← open this

screenshots/ is gitignored — it's output, not source.


How to add dynamic routes (e.g. /products/[id])

If your app has routes with database-driven IDs, fetch the ID before adding the route. Example for a Supabase app:

// At the bottom of config.ts, before exporting ROUTES:
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_KEY!);
const { data } = await supabase.from("products").select("id").limit(1).single();
const productId = data?.id ?? "fallback-id";

export const ROUTES: Route[] = [
  // ...static routes...
  {
    path: `/products/${productId}`,
    label: "Product detail",
    auth: "public",
    waitFor: "main",
  },
];

Workflow

Make UI changes in your app
         ↓
npm run screenshot
         ↓
open screenshots/report.html
         ↓
Spot issues → fix in your code
         ↓
Repeat

For teams: run before every PR merge or before every deploy to staging. Paste the report (or specific screenshots) into your PR description.


Why not Stagehand / Cypress / Playwright Test?

Tool Best for
This tool Fast visual review, pre-deploy sanity check, sharing with non-engineers
Playwright Test Functional correctness — "does the button work?"
Cypress E2E test suites with assertions
Stagehand AI-driven exploration of unknown flows

This tool is intentionally simple — it doesn't assert, it doesn't click around. It just shows you what every page looks like. Fast to set up, zero maintenance.


Tech

  • Playwright — headless browser automation
  • tsx — run TypeScript directly, no build step
  • Chromium (installed via npm run setup)

Contributing

PRs welcome. Keep it simple — the goal is a tool that takes 5 minutes to set up and never needs updating.

Ideas welcome:

  • --diff flag to compare against a previous run
  • Slack/Discord webhook to post report after CI runs
  • Lighthouse score per page alongside the screenshot

Made while building CoBuilt — a platform where builders form teams and share revenue.

About

small tool: one command, and you get full-page screenshots of every route in your app — at desktop and mobile — with a browsable HTML report.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors