12 new Playwright tests closing the UI coverage gap in the collective
lifecycle (onboarding → invitation → admin manage). Writing them surfaced
three product-code bugs that have silently been present since Fase 1;
fixed as part of this phase.
Tests:
- tests/e2e/onboarding.test.ts O-01..O-03 (Eva auto-redirect, happy
path create, empty-name submit-disabled)
- tests/e2e/invitation.test.ts I-01..I-05 (token generation, accept
logged-out + logged-in, expired, used)
- tests/e2e/manage-collective.test.ts MC-02..MC-05 (promote, demote, remove
member, generate pending invite)
- tests/fixtures/db.ts resetEva, seedExpiredInvitation,
seedUsedInvitation, restoreSeedMembership,
countMembership — all via raw SQL so they
don't depend on SUPABASE_SERVICE_ROLE_KEY
Bugs found & fixed:
- supabase/migrations/012_create_collective_rpc.sql: atomic
`create_collective(name, emoji)` SECURITY DEFINER RPC. Fase 1 onboarding
used `.insert(...).select().single()` which triggers the SELECT policy on
the fresh row — creator isn't a member yet, so the INSERT was rejected with
"row-level security" even though the INSERT policy passed. onboarding now
calls the RPC which inserts both the collective AND the creator-as-admin
membership in one transaction, bypassing RLS. F-08 in rls-isolation.test.ts
has been silently masking this bug (only the spoof branch was asserted).
- routes/+layout.svelte: post-login redirect now reads sessionStorage
`pendingInvitationToken` and routes back to /invitation/<token> instead of
defaulting to /onboarding or /lists. The invitation page already stashed
the token before kicking off Keycloak, but nothing read it back.
- routes/(app)/collective/manage/+page.svelte: loadMembers now subscribes
to currentCollective so it re-runs when the store resolves after cold
navigation. onMount alone races with the auth listener's first emit and
the member list stayed empty on direct URL hits.
- routes/invitation/[token]/+page.svelte: awaits authLoading before deciding
whether to redirect to login. Previously raced with the auth listener and
triggered a redundant Keycloak round-trip for freshly-authenticated users.
Stable selectors added (Playwright):
- Onboarding: onboarding-create-tab, onboarding-join-tab,
collective-name-input, collective-submit
- Manage: member-row-<uid>, role-select-<uid>, remove-member-<uid>,
generate-invite, invite-link
- Invitation: invitation-accept, invitation-error (+ data-error-key attr)
Scope dropped from the plan — UI does not exist, would be feature work:
- O-04: "+ new collective" affordance in the sidebar.
- MC-01: rename-collective input in /collective/manage.
Both flagged as follow-ups in plan/fase-7-collective-flow-tests.md.
Test totals: 34 pgTAP + 140 Vitest integration + 15 Vitest unit + 58
Playwright + 1 gated rate-limit. 3 skipped (2 Realtime presence, 1 gated).
54 lines
1.6 KiB
JSON
54 lines
1.6 KiB
JSON
{
|
|
"name": "@colectivo/web",
|
|
"private": true,
|
|
"version": "0.0.1",
|
|
"type": "module",
|
|
"scripts": {
|
|
"dev": "vite dev",
|
|
"build": "vite build",
|
|
"preview": "vite preview",
|
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
"lint": "prettier --check . && eslint .",
|
|
"format": "prettier --write .",
|
|
"test:unit": "vitest run",
|
|
"test:e2e": "playwright test",
|
|
"test:e2e:headed": "playwright test --headed"
|
|
},
|
|
"dependencies": {
|
|
"@colectivo/types": "workspace:*",
|
|
"@inlang/paraglide-sveltekit": "^0.16.1",
|
|
"@supabase/supabase-js": "^2.46.2",
|
|
"cropperjs": "^1.6.2",
|
|
"idb": "^8.0.1",
|
|
"lucide-svelte": "^1.0.1",
|
|
"svelte-dnd-action": "^0.9.51"
|
|
},
|
|
"devDependencies": {
|
|
"@colectivo/test-utils": "workspace:*",
|
|
"@playwright/test": "^1.50.0",
|
|
"@sveltejs/adapter-node": "^5.2.11",
|
|
"@sveltejs/kit": "^2.15.1",
|
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
|
"@vite-pwa/sveltekit": "^0.6.6",
|
|
"@vitest/ui": "^4.1.4",
|
|
"autoprefixer": "^10.4.20",
|
|
"eslint": "^9.18.0",
|
|
"eslint-plugin-svelte": "^2.46.1",
|
|
"fake-indexeddb": "^6.2.5",
|
|
"jsdom": "^29.0.2",
|
|
"postcss": "^8.5.1",
|
|
"prettier": "^3.4.2",
|
|
"prettier-plugin-svelte": "^3.3.2",
|
|
"prettier-plugin-tailwindcss": "^0.6.9",
|
|
"svelte": "^5.17.3",
|
|
"svelte-check": "^4.1.1",
|
|
"tailwindcss": "^3.4.17",
|
|
"typescript": "^5.7.3",
|
|
"vite": "^6.0.7",
|
|
"vitest": "^2.1.8",
|
|
"workbox-precaching": "^7.4.0",
|
|
"workbox-window": "^7.3.0"
|
|
}
|
|
}
|