SauceDemo Automation Suite
A Playwright + TypeScript test automation framework for SauceDemo, 71 tests across 15 spec files, page object model with fixture composition, tagged CI gating across three browser engines, and a documented decision log for every non-obvious call.
The problem
Most QA automation portfolios show tests passing: They don’t show why the tests are structured the way they are, what happens when a locator changes, or how someone decided what was worth automating and what wasn’t.
I built this suite to put ten years of software engineering behind test automation. Instead of a folder of standalone test scripts, it needed to read like a framework a team would inherit: page objects instead of pasted locators, fixtures that compose instead of a beforeEach repeated in every file, and a written reason for every decision that isn’t obvious from the code alone.
A reader skimming a repo full of green checkmarks has no way to tell whether the person behind it thought about maintenance cost, flake reduction, or CI gating, which is what the actual QA job implies.
What I built
The suite tests SauceDemo, Sauce Labs’ practice storefront, across Chromium, Firefox, and WebKit: 71 tests across 15 spec files, split between functional specs (one file per page or feature: auth, cart, checkout, inventory, navigation) and full multi-page e2e journeys through the checkout flow.
Every test carries a tag (@smoke, @regression, @e2e, @a11y, @visual, @security, @performance, @problematic), so CI runs a different slice depending on the trigger: lint, typecheck, and a chromium-only smoke check on every push; the regression + e2e + a11y gate on push to main; the full suite minus @problematic, across all three engines, on every pull request into main.
Auth runs once per user profile (standard, performance, problem) as a Playwright setup project that saves storage state, so none of the tests re-authenticate on their own. A second setup project seeds a three-item cart on top of that session for the specs that need one already populated.
13 defects are logged against the app itself: 11 functional, 2 accessibility. Each one is a test.skip with the full reproduction steps left intact and a matching entry in a defect log.
Technical highlights
- Page object model with typed components: one
<Page>class per page, plus reusable<Component>classes for repeating elements like cart rows and inventory items. These are built once, reused wherever that element shows up. - Fixture composition:
mergeTests()merges page-object and helper fixtures into a singletest/expectevery spec imports from, one clean entry point instead of setup logic repeated per file. - Path aliases over relative imports:
@pages/*,@fixtures/*,@app-types/*, and more. Every import states what it is, not where it happens to sit in the folder tree, avoiding relative-path hell - Evidence-based multi-profile coverage: a user persona only gets its own test where its behavior is confirmed to diverge from the baseline. No test duplication for personas that behave identically.
- Known-bug capture pattern: real defects become
test.skipcases asserting the correct behavior, with full reproduction steps intact and a matching defect log entry (bugs stay executable, not just noted). - Lint rules tied to specific flake sources:
no-wait-for-timeoutforces web-first waiting instead of hard sleeps,no-floating-promisescatches unawaited page-object calls before they cause race conditions,no-raw-locatorspushes towardgetByRole/getByTestIdover CSS selectors that break on a restyle. - Hydration-aware accessibility scans: page objects wait on a real container element after navigation, not just
domcontentloaded. This avoids a context-destroyed race condition that hit Firefox and WebKit hardest. - Append-only decision log: every non-obvious call gets one dated entry, newest first, so the reasoning survives past the person who made it.