Skip to content

afishingday/fiskr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fiskr

Demo sport fishing store (rods, reels, lures, line and accessories) built with vanilla HTML, CSS and JavaScript, no frameworks or dependencies. It's meant as a practice ground for UI test automation with Playwright: it covers everything from basic interactions to the framework's advanced capabilities (network, downloads, uploads, dialogs, iframes, Shadow DOM, drag & drop, languages and regions), with deterministic text and documented intentional bugs.

Created by Luis Montoya · @afishingday. Fiskr comes from Old Norse fiskr: "fish".

Test site — not a real store. Orders, payments and the user account are simulated; nothing is sent to any server.

What you can automate (Playwright capability map)

Capability Where it lives on the site
Navigation, forms, asserts The whole site (getByRole, getByLabel, getByTestId)
Live search/filters/sort Catalog (search-input, category-filter, sort-select)
Network interception (page.route, waitForResponse) The catalog loads via fetch from assets/data/products.json; can be mocked, delayed or broken
Downloads (waitForEvent("download")) Knots guide (static), catalog CSV, per-product spec sheet, per-order receipt
Upload (setInputFiles) My account → "Request a return" (validates JPG/PNG/PDF type and ≤ 2 MB size)
Native dialog (page.on("dialog")) Cart → "Clear cart" uses confirm()
Tooltip (hover()) Cart → "?" icon next to Shipping (hover and focus)
iframe (frameLocator) Homepage → store map (store-map, with an interactive button inside)
Shadow DOM Floating help widget on every page (help-widget, custom element with an open shadow root)
Drag & drop (dragTo) My account → "My favorite techniques" (reorderable list with aria-live status)
Languages (context locale) ES/EN: the initial language comes from navigator.language; there's also a header selector (language-select)
Multi-country / currency Country selector (country-select): CO (COP), MX (MXN), ES (EUR), US (USD) with fixed rates
Dependent dropdowns Checkout: the city select is enabled and populated based on the country
Deterministic waits Simulated payment: exactly 2000 ms; toasts: auto-dismiss at 4000 ms
Keyboard / accessibility Arrow-key tabs, ARIA on toasts/steps/errors, aria-invalid, aria-live

Multi-language and multi-country

  • Language (ES/EN): defaults to navigator.language (es* → Spanish, anything else → English), ideal for testing with browser.newContext({ locale: "es-CO" }). Can also be changed with the language-select in the header (reloads the page).
  • Country: country-select sets the displayed currency. Base prices are in USD and converted with fixed rates (deterministic): COP ×4000 (no decimals, "." thousands separator), MXN ×17 (MX$), EUR ×0.9 (" €" suffix, European format), USD ×1.
  • If the locale carries a known region (es-MX → MX, es-ES → ES), the initial country adjusts itself; otherwise ES→Colombia and EN→United States.
  • The preference lives in sessionStorage (key fiskr-locale).
  • Product reviews are not translated (just like on a real store).
  • The catalog CSV always exports prices in USD, so the download stays stable regardless of the active country.

Test data

Data Value
Demo account sofia@fiskr.shop / Pesca2026!
Card that approves 4111 1111 1111 1111 (any future date and CVV)
Card that declines 4000 0000 0000 0002
Valid coupon BIENVENIDA10 → −10% (always recalculated)
Valid coupon (with a bug) PESCADOR15 → −15% (see BUG-03)
Expired coupon PROMO2024
Out-of-stock product "Glaciar 45 L marine cooler" (nevera-marina)
Low-stock product "EcoScan portable sounder with GPS" (sonda-gps, 3 units)
Free shipping Orders from $150 USD (otherwise $9.90 USD)
Tax 8% on the discounted subtotal
Countries / cities CO, MX, ES, US — 5 cities each (checkout)

Included automation suite

The repo ships the full suite under tests/: Playwright + TypeScript, Page Object Model, 71 tests with per-viewport projects (mobile, tablet, desktop, 2K and 4K), a self-contained dashboard (tests/dashboard/index.html) and a GitHub Actions workflow that deploys to Pages and runs the suite against the published site. The defects the suite detects are documented in tests/BUGS.md.

Intentional bugs

Six real, reproducible defects, meant for writing tests that must fail (or that document the bug with test.fail()):

ID Where Expected behavior Actual behavior
BUG-01 Catalog · search Searching cana or senuelo (no accent/ñ) should find "Cañas" and "Señuelos" Doesn't normalize accents: returns 0 results (reproducible in ES)
BUG-02 Catalog · "price: low to high" sort Ascending numeric order Sorts as text: the $9.50 hooks end up last
BUG-03 Cart · PESCADOR15 coupon The 15% discount should recalculate when the cart changes The amount stays "frozen" at the moment it was applied
BUG-04 Cart · + button Should not allow exceeding the available stock Allows ordering more units than there are
BUG-05 Checkout · zip code Should require digits only Accepts any non-empty text
BUG-06 Product · "Reviews" tab The counter should match the listed reviews Shows one review too many (off-by-one)

Automation conventions

  • data-testid on every interactive or assertable element. Dynamic ids derive from the product id or the order id: add-to-cart-cana-spinning, qty-plus-kit-senuelos, remove-sonda-gps, order-FSK-1042, download-receipt-FSK-1042.
  • Correct ARIA: tabs with role="tab" and arrow-key navigation, toasts with role="status", tooltip with role="tooltip", errors with aria-invalid + aria-describedby, drag & drop order announced via aria-live.
  • Deterministic text: same data and language, same text. Currency formatting is manual (doesn't depend on Intl or the browser version).
  • Fixed timings: simulated payment 2000 ms; toasts 4000 ms.
  • State in sessionStorage: cart, coupon, session, orders and language/country survive navigation, but every new browser context (every test) starts from a clean store.
  • Deterministic downloads: catalogo-fiskr.csv, ficha-cana-spinning.txt, comprobante-FSK-1042.txt, guia-nudos.txt.
  • Observable network: GET assets/data/products.json on every page; great for page.route() (mock an empty catalog, altered prices, a 500 error…).

Running the site

It's a 100% static site with relative paths, ready for GitHub Pages. Since the catalog loads via fetch, you need a local server (it won't work by opening the file directly):

# Python
python -m http.server 8080

# Node
npx serve .

Then open http://localhost:8080.

Structure

fiskr/
├── index.html              # Homepage: hero, favorites, promos, map iframe
├── pages/
│   ├── products.html       # Catalog with search, filter, sort and CSV
│   ├── product.html        # Detail: photo, stock, tabs, spec sheet
│   ├── cart.html            # Cart: coupons, tooltip, confirm() on clear
│   ├── checkout.html       # Shipping (country→city) → simulated payment → confirmation
│   └── account.html        # Login, orders, return (upload), drag & drop
└── assets/
    ├── css/styles.css      # Single design system (light/dark)
    ├── data/products.json  # Bilingual catalog served via fetch
    ├── img/                # Hero photo and product photos
    ├── downloads/          # Static downloadable files
    ├── frames/mapa.html    # iframe content
    └── js/
        ├── i18n.js         # Languages, countries, currencies and DOM translation
        ├── store.js        # Catalog (fetch), cart, coupons, session, orders
        ├── main.js         # Shell: language/country, theme, nav, toasts, badge
        ├── widget.js       # Help widget with Shadow DOM
        └── *.js            # One module per page

About

Test site — not a real store

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages