K KodePressdocumentation
Laravel 11 · MySQL 8 Specification Built 2026-10-10

15 — Testing and QA#

15.1 Strategy#

Level Tool What it covers Share
Feature Pest (Laravel) HTTP + Livewire + database behaviour: the bulk of the suite ~70 %
Unit Pest pure logic with branches worth isolating: PartResolver, SchemaValidator, Sanitizer, RedirectMatcher, TokenCompiler, path building ~20 %
Browser Playwright the handful of flows that only exist in a real browser: drag and drop, autosave, mega-menu hover, drawer, lightbox ~10 %

Principles:

  1. Reproduce first. A bug gets a failing test before a fix. Then re-break the fix and confirm the test catches it. A test that has never been seen to fail proves nothing.
  2. One report is a bug class. When a bug is found in one place, grep for the pattern and fix every sibling in the same commit, with a test covering the class (e.g. every date render, not just the one that was reported).
  3. Both sides of a duplicated rule. Server validation and client hints, renderer and editor, pages and template_parts — a rule that exists twice is changed twice, in one commit.
  4. Test what the user does. Livewire::test() for component logic is fine, but a flow that a user performs (log in, create, publish, view) is tested through real HTTP requests and real routes.
  5. Tests never depend on each other or on execution order. RefreshDatabase everywhere.
  6. Factories produce valid content trees via a TreeFactory helper, so a test never hand-writes 40 lines of JSON.

15.2 Feature-test map#

Area Must-have tests
Install kodepress:install on an empty database; idempotent re-run; non-interactive flags; seeded roles, theme, templates, default header/footer
Auth login, logout, reset, named throttle, 2FA enrol and challenge, 4-digit email code, changed admin path
Authorization the full role sweep over every admin route (11)
Blocks registry discovery; a block added at runtime appears; invalid schema skipped and logged; context filtering; tree validation; sanitisation; upcaster renders a v1 document
Editor create from template; edit a block; autosave writes draft only; conflict modal path; undo/redo state; publish validation failures named; device preview token
Publish version row created; current_version_id set; cache cleared for that page only; public URL shows the new content; unpublish removes it
Versions list, restore into draft, publish creates a new version, retention prune keeps labelled versions
Pages list filters, search (Bengali), duplicate, trash, restore, permanent delete, hierarchy path rewrite with 301s for descendants, homepage switch
Blog post uses the same pipeline; scheduling publishes on cron; archives (index, nested category, tag, author); RSS validity; post_list filters, pagination and noindex past page 1
SEO meta output and fallbacks; hreflang; JSON-LD on a post; sitemap contents and noindex exclusion; sitemap index past 5,000; robots in maintenance mode
Redirects auto 301 on slug change; manual rules; regex rules; loop refusal; hop limit; query preservation; hit counting throttled
Menus the list in 07
Header/footer the list in 08
Theme the list in 09
Media & forms the list in 10
i18n the list in 12
Cache the list in 13
Global blocks editing one updates every page that uses it; usage count; warning before publish
Approval submit, approve, request changes, Writer blocked from publishing while pending
Audit a row per logged action, scalar diffs only, read-only screen, prune
Backup chunked run resumes; restore refuses a newer manifest; archive not web-reachable
Doctor fails on APP_DEBUG=true, a missing cron tick, a world-readable .env

15.3 Browser tests#

Playwright, against a seeded local install. Workers = 1 (shared database).

Spec Flow
smoke.spec homepage, inner page, post, 404, header/footer present, no console errors
onboarding.spec fresh install -> tour -> pick template -> edit text -> publish -> view site, asserting 10 clicks or fewer
editor-dnd.spec drag a block between columns, reorder sections, duplicate, delete with the modal
autosave.spec type, wait, reload, the draft survived; the unload warning appears while dirty
megamenu.spec hover opens the panel, the diagonal path does not close it, keyboard opens and Escape closes, mobile width shows the accordion
header-sticky.spec sticky after scroll, shrink, hide-on-scroll-down
media.spec drag-drop upload, alt text prompt, insert into a block, replace
form.spec submit the contact form, see the success message, the submission appears in the admin
roles.spec Writer cannot see Publish; Designer cannot see Blog
inline-edit.spec logged-in public page shows Edit, in-place text edit, publish banner

Every manual test round ends by turning what was tested into one of these specs. A bug found by clicking is fixed and gets a spec in the same commit — otherwise the next regression is found by clicking again.

15.4 Final acceptance checklist#

The gate for calling KodePress done. Each row is a command or a scripted flow, not an opinion.

Check Passes when
New user publishes in 10 minutes from a template, no training, no documentation; onboarding.spec asserts ≤ 10 clicks
Add a new block type one new folder; git diff touches nothing under app/Livewire or resources/views/admin
3-level menu + mega menu panel on desktop, accordion on mobile, keyboard-operable
Header and footer preset switch, condition-based assignment, draft, preview on any page, version restore
Public page load cached page under 1 second TTFB on the target host, zero queries
Shared cPanel deploy SSH only: git pull, composer install, migrate, kodepress:install; doctor green
Roles and permissions Writer cannot publish; Designer touches design only; the sweep test is green
Bengali every screen in bn, no missing keys, fonts render, dates in Bengali months
All tests php artisan test green; npx playwright test green
Security kodepress:doctor green in production; no .env, .git or storage reachable over HTTP

15.5 Running the suites#

php artisan test                        # everything
php artisan test --filter=PartResolver  # one area
php artisan test --parallel             # local only; the browser suite stays serial

npx playwright test                     # all browser specs
npx playwright test megamenu --headed   # watch one

php artisan kodepress:doctor            # environment, local or production

CI (GitHub Actions) on every push and PR: PHP 8.3 + MySQL 8 service, composer install, php artisan test, npm ci && npm run build, then Playwright against the built app. A red suite blocks merge. Asset build in CI is a check that the committed public/build is current — CI fails if building produces a diff, which is how we keep a committed build honest.

15.6 Test data#

15.7 What is deliberately not tested#

Not tested Why
Third-party library internals trust the dependency; test our usage
Exact rendered CSS values brittle; we test that a token change produces a new hash and a new linked file
Visual appearance pixel-by-pixel no screenshot diffing in core; the budget tests and the browser smoke cover regressions that matter
Every block's markup in detail one render test per block asserting its key output, not its whole HTML
Shared-host-specific quirks cannot be reproduced in CI; covered by doctor and the post-deploy checklist

KodePress documentation · generated from the Markdown sources by tools/build-docs-site.py · internal preview, not indexed.