playwright
Technical notes on web development, DevOps, and AI integration.
11 articles
- 13:27testing
The Test That Counts Requests, Not Pixels
A Playwright test that intercepts network traffic to prove a form blocks submission client-side, plus a date-filter edge case that almost slipped through.
TL;DR: The test checks that submitting without a service pillar shows an inline error and sends no network request, verified via Playwright route interception. It fills all other fields and handles dev-only login plus a required phone setup wizard beforehand. It also adds coverage for a date filter edge case, ensuring today-to-today includes today using an exclusive bound the next day.
#playwright#testing#e2e - 08:17testing
Admin E2E: Testing Role and Bidang Guards Through the UI
Three Playwright specs for the admin area: login through the real UI, CRUD down to permanent delete with API verification, and role/bidang guards tested up to the server's 403.
TL;DR: We moved admin E2E tests beyond happy paths to guardrails, logging in via UI and reusing the localStorage token. It covers full CRUD in the Tiptap editor and trash flow, verifying permanent deletes via API not just UI. It also validates authorization, hiding user management from editors and blocking bidang users with a 403.
#playwright#e2e#testing - 04:19testing
E2E Tests You Can Re-run by Module Name
Forgetting spec filenames whenever one page needs testing? A thin resolver plus an honest coverage ledger.
TL;DR: A 73-line bash script maps module names to Playwright specs so you can rerun one page instead of the whole suite. It checks folders, matches spec files, forwards flags like headed mode, and lists modules from describe blocks. A companion ledger tracks coverage per feature and requires new code to update its row, keeping gaps visible.
#testing#playwright#e2e - 04:18testing
Unit Testing Whose Contents Are Not Just Unit Tests
One script per test tier: vet, integration against real MySQL, a smoke gate, up to Playwright E2E.
TL;DR: Scattered manual tests were often skipped, so they were consolidated into four strict scripts for backend, frontend, E2E and smoke. Backend handles Docker and runs integration tests serially on real MySQL, while smoke validates deployment endpoints and E2E wraps Playwright with retries. README now defines what to run when, so a passing backend script signals the shared team contract.
#testing#bash#go - 22:20tooling
When Browser Automation Selectors Break on Locale Switches
My automation browser profile leaked an id-ID locale, the UI rendered Tanya Qwen instead of Ask Qwen, and every exact-label selector quietly broke. Here is the two-layer fix.
TL;DR: An automation suite broke because the browser profile's id-ID locale made the target site render UI text in Indonesian, so exact-match selectors like "Ask Qwen" failed. The fix: regex alternation accepting both languages, plus pinning the locale via context emulation. A small assert-based test guards against regressions.
#automation#playwright#regex - 18:55devops
Healthy Container, Dead Browser: A Compose Migration Trap
Five hours of 'healthy' while the browser inside the container had been dead since minute one. Notes on user, HOME, and shallow healthchecks.
#docker#playwright#debugging - 11:37tooling
DeepSeek Login Died Between Sessions. Three Scripts Fixed It.
Re-logging into DeepSeek via VNC every week got old. I transferred the whole session into Camofox instead: cookies, token, keepalive.
TL;DR: DeepSeek sessions in Camofox died because logging in means two layers: HttpOnly cookies and a localStorage userToken for Bearer API calls. Importing cookies alone patched half the state, so the login page persisted. Three scripts merge cookies into Playwright's storage-state.json, inject the wrapped token, and poll every five minutes to confirm the session.
#automation#playwright#deepseek - 22:45frontend
I Filled the Textarea, React Never Noticed
The text visibly entered the textarea, yet React never saw a change. Why plain assignment fails on controlled components and how the native prototype setter fixes it.
TL;DR: Automating React apps like DeepSeek fails when you set textarea.value directly, because React replaces the setter on each element instance and swallows non-user input events. The fix: grab the native setter from HTMLTextAreaElement.prototype, call it with your text, then dispatch a bubbling input event. Since the icon-only send button has no label, press Enter instead.
#deepseek#react#automation - 04:50ai
My Scraper Kept Catching My Own Prompt Echo
An accessibility snapshot caught my own prompt instead of the AI answer. The fix: echo rejection, clipboard-first extraction, and a recover subcommand.
TL;DR: Chat scrapers fail when the answer anchor matches the user's own echoed prompt, so the fix filters template markers and length. Virtualized rendering hides offscreen text anyway, making clipboard reads via the Copy button the reliable data path over DOM snapshots. A .url sidecar written before polling lets the script recover finished answers without resending.
#automation#playwright#qwen