E2E (Playwright, motir-marketing) + acceptance video — a tenant host and a customer host render the project, the canonical names the primary, and the non-primary address redirects
Opened by Zhu Yue ·
The browser walk of the public half of the story's verification recipe — a visitor arrives on a tenant subdomain and on a customer domain, reads the project, follows a link and stays on that host, and a request on a non-primary address lands on the primary — recorded at a pace a person can watch, and published to this card. motir-marketing's Playwright lane exists (MOTIR-4112): playwright.config.ts builds the app against e2e/stub/publicApiStub.ts and records video; the agent publishes the clip over the MCP (attach_file) — CI does not upload it, by decision.
The harness this needs, verified before a line is written
- Tenant hosts in the lane: Chromium resolves any
*.localhostname to loopback, so the stub site is reachable asacme.localhost:<SITE_PORT>androadmap.localhost:<SITE_PORT>with no/etc/hostschange — the router card records this ine2e/stub/origin.ts. Read that file first; if the constant is not there, the router card did not finish and this card stops. - The stub answers the host contract:
publicApiStub.tsgains routes forGET /api/public/hosts/{host}returning the three DTO shapes for the two hosts above and an alias host, plusaddresseson the subject fixture andprimaryHoston the index fixture — recorded frommotir-core's OpenAPI document, the way the existinge2e/fixtures/*.jsonwere. - The base domain at build time: the lane's
webServercommand setsNEXT_PUBLIC_MOTIR_TENANT_DOMAIN=localhost:<SITE_PORT>(or the shape the router card's accessor accepts for tests) alongside the app origin it already sets.
The spec — e2e/specs/acceptance-public-address.spec.ts
- Open
http://acme.localhost:<port>/— the workspace's public-project list renders inside the site chrome; click the project card →/<identifier>renders the Overview; the tab bar's hrefs are host-relative; open Board and Items, page Items once — every navigation stays onacme.localhost. - Open
http://roadmap.localhost:<port>/board— the project's Board renders at the root of a custom domain; the canonical<link>andog:urlname the primary host the fixture declares. - Open
http://acme.localhost:<port>/<identifier>when the fixture says the primary is the custom domain → the browser lands onroadmap.localhost:<port>/(a301, asserted from the response chain), path preserved for a tab. - Open an alias host (
old.localhost:<port>/<identifier>) →301to the live subdomain, path preserved. GET /sitemap.xmland/robots.txton each host — the sitemap lists only that host's URLs, robots names that host's sitemap.- The empty, loading and error states: the workspace list with zero public projects; the ERROR state when the stub's host resolution answers
500(never a 404 for an outage); the not-found page for an unknown host. - The recording of steps 1–4 is paced for a person (the lane's
slowMo/ explicit pauses at each landing), and the agent attaches the video to this card withattach_file.
Waits are on authoritative signals (the landmark, the canonical tag present, the response status) — never on timers, per the E2E discipline in motir-core/CLAUDE.md this lane inherited.
Acceptance criteria
- The spec passes in the
e2eCI job on the PR, walking all seven steps above against the stub, with the video and trace artefacts produced. - Steps 1–4 assert from the response chain that every cross-host move is a
301and every same-host move is a200, and that no href rendered on a tenant host names/p/ormotir.co. - Step 5 asserts the sitemap's and robots' host per host kind; step 6 distinguishes the error state from the not-found page.
- The stub's new routes and fixtures are recorded from the OpenAPI document (the recording command is in the PR body), not typed by hand.
- The acceptance video is attached to this card, and its recorded happy path shows each landing long enough to read.
- No file outside
motir-marketingis touched.
Context refs
motir-marketing/playwright.config.ts(the build-in-webServernote,video: 'on', the no-uploader decision) ·e2e/stub/origin.ts·e2e/stub/publicApiStub.ts·e2e/fixtures/·e2e/specs/acceptance-public-project.spec.ts— the precedent walk- the router · the canonical card — the behaviour under test; the host contract — the DTO the stub records
motir-core/docs/decisions/acceptance-video.md— the agent publishes the clip; MOTIR-4122 — the previous story's acceptance walk on this host- MOTIR-3878 — the verification recipe, steps 1 and 3
Discussion
No comments yet.
Adding to this discussion signs you in on app.motir.co and brings you back to this request.