Skip to content

End-to-End Test Flows

Updated: 23/03/2026

Comprehensive test flows for Knowledge Hub pre-pilot quality gate. Each flow is a numbered sequence with preconditions, steps, expected outcomes, and pass/fail criteria.

Test environment: http://localhost:3000 with bun dev running. Auth: All flows require authenticated session (admin role by default). Config: playwright.config.ts — 2 browser projects (Desktop Chrome, Pixel 5 mobile).

Test data setup: Before running Flows 4-7, create test data using the E2E Test Data Setup Runbook. This covers bid creation, question insertion, response creation without AI, and cleanup procedures. Flows 6 (Export) and 7 (Template Completion) can be tested with zero AI API calls by inserting responses directly via SQL.

15 spec files in e2e/tests/, each covering one or more manual flows. Worker-scoped fixtures seed test data per worker to avoid cross-test interference.

#Spec FileManual FlowDescription
1auth.spec.tsFlow 0Authentication: unauthenticated redirect, login page elements, session persistence
2browse-search.spec.tsFlow 2Browse page: grid/list views, filters, sorting; Search page: semantic search, results
3item-detail.spec.tsFlow 3Item detail: page loading, metadata sidebar, content sections, breadcrumbs, mobile
4qa-library.spec.tsFlow 12Q&A Library: browsing, search, filtering, domain groups, virtualised list
5coverage-page.spec.tsFlow 13Coverage dashboard: summary cards, domain sections, gap identification
6bid-pipeline.spec.tsFlow 4Bid pipeline: bid list, bid detail, status filters, creation form, mobile
7governance-review.spec.tsFlow 8Review queue: loading, speed-review cards, verify/flag/skip, progress
8settings.spec.tsFlow 9Settings: sidebar navigation, section content, admin-only sections
9role-gating.spec.tsFlow 9Role-based gating: viewer/editor/admin nav items, settings visibility
10layer-suggestion.spec.tsLayer suggestion: banner on create page, layer filter, layer badges
11entity-filters.spec.tsEntity filters: type/name filtering on browse, co-occurrence, badges
12wave1-cert-renew.spec.tsCertification renewal: Renew button on cert/framework cards, dashboard links
13wave1-dashboard-expiry.spec.tsDashboard expiry: ExpiringContentSection, ComplianceStatusSection, urgency badges
14wave1-guide-sections.spec.tsGuide sections: GuideSectionBanner on create page, match strength, dismiss
15wave1-item-detail-dates.spec.tsItem detail dates: ExpiryDateDisplay, TemporalReferencesSection, UK date format

Shared utilities in e2e/helpers/:

FilePurpose
dev-overlays.tsHide CopilotKit Web Inspector, stub /api/copilotkit/ requests, dismiss error banners
responsive.tsViewport detection (isMobileViewport), header navigation (navigateViaHeader), search helpers
data-factory.tsCreate test items (createTestItem), Q&A pairs (createTestQAPair), bids (createTestBid)
selectors.tsShared selectors for nav, search, browse, and common UI components

Worker-scoped fixtures in e2e/fixtures/:

FilePurpose
index.tsMain fixture export — extends Playwright test with authenticatedPage, viewerPage, workerData
auth.tsAuthentication fixture — login with test user credentials
supabase.tsSupabase service client for data seeding
test-data-fixture.tsWorker-scoped data fixture — seeds content items, Q&A pairs, bids per worker
test-data.tsTest data definitions — IDs and content for seeded items

Preconditions: Dev server running (bun dev), valid Supabase user exists. Spec: auth.spec.ts

#StepExpected OutcomePass/Fail Criteria
0.1Navigate to http://localhost:3000Redirected to /login (unauthenticated) or home page (authenticated)Page loads without errors
0.2On /login, enter valid email, click “Continue”Email accepted, method selection shown”Sign in with password” and “Send magic link” options visible
0.3Click “Sign in with password”, enter password, click “Sign in”Redirect to / (home page)URL changes to /, dashboard content visible
0.4Verify session persists across page navigationNavigate to /browse, /bid, /settings — all load without re-authNo redirect to /login
0.5Test invalid credentialsEnter wrong password, click “Sign in”Error message: “That email and password combination didn’t work. Please try again.”
0.6Test magic link flowEnter email, click “Continue”, then “Send magic link”Success: heading “Check your email” with message “We sent a sign-in link to {email}”

Error states:

  • Empty email: HTML5 validation prevents submission
  • Network error: Error message displayed

Preconditions: Authenticated session, content items exist in database.

#StepExpected OutcomePass/Fail Criteria
1.1Navigate to /Home page loads with hero search bar and dashboard sectionsReorient Me, Needs Attention, Active Bids, Content Health, Recent Activity sections render
1.2Verify Reorient Me section3 sub-sections: “Needs your attention” (bid deadlines, expired content, pending reviews, quality flags, unread notifications), “Since you were away” (grouped team changes), “Pick up where you left off” (user’s recent work, max 3 items)All sub-sections render with relevant data or empty states
1.3Dismiss Reorient Me sectionClick dismiss buttonSection hides for current session, reappears on next visit
1.4Verify Content Health stripFreshness counts (Fresh/Aging/Stale/Expired), Active Bids count, Unread countNumbers match DB reality
1.5Verify Needs Attention sectionUnverified items count with Review link, quality flags with Browse linkLinks navigate to /review and /browse?quality_issues=true
1.6Verify Active Bids sectionActive bid cards with name, buyer, status, deadline, progressAt least one bid card if bids exist
1.7Verify Recent Activity sectionActivity feed with timestamped eventsEvents listed chronologically
1.8Verify Expiring Content sectionItems expiring within 30 days with urgency badgesColour coding uses freshness semantic tokens
1.9Verify Compliance Status sectionCertification and framework summary cards with expiry badgesCards show certification/framework/registration status
1.10Click a Needs Attention linkNavigate to /review or /browse?quality_issues=trueTarget page loads
1.11Click an Active Bid cardNavigate to /bid/{id}Bid detail page loads
1.12Type a query in hero search bar, press EnterNavigate to /search?q={query}Search results page loads

Preconditions: Authenticated, content items exist across multiple domains. Spec: browse-search.spec.ts

#StepExpected OutcomePass/Fail Criteria
2.1Navigate to /browseBrowse page loads with content grid and filter controlsGrid renders, filter bar visible, item count shown
2.2Switch from grid view to list viewContent displayed as list rowsView toggle works, items re-render
2.3Switch back to grid viewContent displayed as grid cardsToggle persists layout change
2.4Apply domain filter (select a domain)Grid filters to show only items in selected domainItem count decreases, all visible items match domain
2.5Apply content type filterGrid filters furtherCombined filters work correctly
2.6Apply entity type filterGrid filters to items mentioning entities of that typeEntity filter section expands, filter badge shown
2.7Apply layer filterGrid filters to items with selected layerLayer badges match filter
2.8Clear all filtersFull content list restoredItem count returns to unfiltered total
2.9Use pagination (if >20 items)Next page loads, different items shownPage indicator updates
2.10Click a content itemNavigate to /item/{id}Item detail page loads
2.11Navigate to /search directlySearch page loads with search barEmpty state or prompt to search
2.12Enter a search query (e.g., “project management”)Search results appear with similarity scoresResults are relevant, similarity badges shown
2.13Click a search resultNavigate to /item/{id}Item detail page loads

Preconditions: Authenticated with editor role, at least one content item exists. Spec: item-detail.spec.ts

#StepExpected OutcomePass/Fail Criteria
3.1Navigate to /item/{id} for a known itemDetail page loads with title, metadata, contentTitle, domain, content type, date all visible
3.2Verify metadata displayDomain badge, content type icon, author, source, date, quality score badgeAll metadata fields render correctly
3.3Verify AI summary sectionAI summary shown if availableSummary text visible or “No summary” placeholder
3.4Verify related items sectionRelated items displayed at bottomCards shown with similarity scores
3.5Verify breadcrumb navigationBreadcrumb shows Browse link for articles, Library for Q&ACorrect parent link based on content type
3.6Edit priority (set to “high”)Priority selector updatesPriority persists after page refresh
3.7Add item to a workspaceWorkspace assignment updatesWorkspace tag visible on item
3.8Verify reader viewContent displayed in reader formatReader HTML renders without broken layout
3.9Verify expiry date display (if present)ExpiryDateDisplay shows DD/MM/YYYY with urgency badgeDate format is UK English
3.10Verify temporal references (if present)Collapsible section with extracted datesDates show context type and confidence

Flow 4: Bid Creation and Question Extraction

Section titled “Flow 4: Bid Creation and Question Extraction”

Preconditions: Authenticated with editor role. A .docx or .pdf tender document available locally. Spec: bid-pipeline.spec.ts

#StepExpected OutcomePass/Fail Criteria
4.1Navigate to /bidBids list page loadsPage renders, “New Bid” button visible for editors
4.2Click “New Bid” buttonBid creation dialog opensForm with name, buyer, deadline fields
4.3Fill in bid name “Test E2E Bid”, buyer “Test Corp”, deadline tomorrowForm validates inputsAll fields accept input
4.4Submit the formRedirect to /bid/{new-id}Bid detail page loads, state is “draft”
4.5Verify bid headerName, buyer, deadline, state badge all correctData matches what was entered
4.6Verify tabs: Overview, Questions, Responses, DocumentsAll 4 tabs render and are clickableTab switching works
4.7Click Documents tabDocuments section shown, upload area visibleTenderUpload component renders
4.8Upload a .docx tender documentUpload progress shown, extraction beginsFile accepted, processing indicator visible
4.9After extraction completesQuestion review dialog appearsExtracted questions listed with sections
4.10Review extracted questions — confirm individual questionsCheckmarks toggle on/off per questionIndividual question accept/reject works
4.11Click “Confirm” to accept questionsQuestions saved, dialog closesQuestions tab shows extracted questions
4.12Switch to Questions tabQuestions listed with section groupingQuestion text, word limits, categories visible
4.13Add a manual questionClick “Add Question”, enter text, saveNew question appears in list
4.14Navigate back to /bidBids list shows the new bidBid card visible with correct name and state

Error states:

  • Upload invalid file type (e.g., .txt): Error message shown
  • Upload empty file: Error message shown
  • Create bid with empty name: Validation prevents submission

Preconditions: Authenticated, bid exists with at least 3 confirmed questions. ANTHROPIC_API_KEY set.

#StepExpected OutcomePass/Fail Criteria
5.1Navigate to /bid/{id}Bid detail loads with questionsQuestions tab accessible
5.2Click “Match KB” buttonQuestions matched against knowledge baseToast shows match count
5.3Click “Draft All” buttonCost estimate dialog may appearDrafting begins for unmatched questions
5.4Wait for drafting to completeToast shows “Drafted N responses”Response count updates
5.5Navigate to /bid/{id}/sessionCopilotKit session page loadsChat interface and response panel visible
5.6Use CopilotKit to draft a specific responseAI generates a responseResponse text appears in editor
5.7Review the response in the Tiptap editorRich text editor with response contentText is editable, formatting preserved
5.8Edit the response textText changes reflected in editorModifications persist
5.9Approve the responseResponse status changes to “approved”Status indicator updates
5.10Verify response versioningEdit approved response and saveVersion number increments

Error states:

  • Draft without API key: Clear error message
  • Draft with no questions: Appropriate warning

Preconditions: Bid exists with at least 2 approved responses.

#StepExpected OutcomePass/Fail Criteria
6.1Navigate to /bid/{id}Bid detail loadsExport button visible in header
6.2Click Export menuDropdown with “Export as Word” and “Export as Excel”Both options visible
6.3Click “Export as Word”.docx file downloadsFile downloads with bid name in filename
6.4Open downloaded .docxDocument contains bid name, questions, and responsesAll approved responses present, formatted correctly
6.5Click “Export as Excel”.xlsx file downloadsFile downloads with bid name in filename
6.6Open downloaded .xlsxSpreadsheet contains questions and responses in columnsData matches bid content

Error states:

  • Export bid with no responses: Warning or empty document generated
  • Download fails: Error toast shown

Preconditions: Authenticated, bid exists with confirmed questions and approved responses. Python worker running (PYTHONUNBUFFERED=1 python3 scripts/bid_worker.py).

#StepExpected OutcomePass/Fail Criteria
7.1Navigate to /bid/{id}/templatesTemplates page loadsUpload area visible, existing templates listed (if any)
7.2Enter template name “Test Template” and descriptionFields accept inputName field required, description optional
7.3Upload a .docx template file (drag-and-drop or click)Upload progress shownFile accepted, template appears in list
7.4Click “Analyse” on the uploaded templateAnalysis job queued, progress shownStatus changes to “analysing”
7.5Wait for analysis to completeTemplate fields identified and listedStatus changes to “analysed”, field count shown
7.6Click to review fieldsField review table opensAll identified fields listed with field text
7.7Click “Auto-Map” to match fields to bid questionsFields mapped to questions via text similarityMapping confidence shown, matched questions displayed
7.8Review mappings — confirm correct ones (Enter key)Field status changes to “confirmed”Keyboard shortcut works
7.9Reject incorrect mappings (r key)Field status changes to “rejected”Rejected fields visually distinct
7.10Navigate fields with j/k keysSelection moves up/downKeyboard navigation works
7.11Use bulk reject with checkboxesMultiple fields rejected at onceBulk action button works
7.12Click “Fill Template”Fill job queued, progress bar shownStatus changes to “filling”
7.13Wait for fill to completeCompletion summary shownFilled count, error count, truncation warnings
7.14Download completed document.docx file downloadsFile downloads successfully
7.15Open downloaded .docxResponses filled in correct cells, formatting preservedContent matches approved responses
7.16Verify retry button on fill errorIf fill fails, retry button shownButton triggers new fill job

Error states:

  • Upload non-.docx file: Error message
  • Upload password-protected .docx: Clear error (WP5)
  • Analyse without Python worker: Job stays queued, timeout message
  • Fill with no confirmed mappings: Validation prevents fill

Preconditions: Authenticated with editor role, content items exist. Spec: governance-review.spec.ts

#StepExpected OutcomePass/Fail Criteria
8.1Navigate to /reviewReview queue loadsSpeed-review cards visible
8.2Review a content item — click ApproveItem marked as reviewedCard advances to next item
8.3Review a content item — click RejectItem marked for follow-upCard advances to next item
8.4Skip a content itemItem skipped, next item shownSkip doesn’t change item status
8.5Verify review statsStats bar shows reviewed/pending countsNumbers update after each action
8.6Navigate to /browseBrowse page loadsFreshness indicators visible on items
8.7Check freshness badgesItems show fresh/aging/stale/expired statusColour coding uses semantic freshness tokens
8.8Navigate to /settings, Governance tabGovernance settings visibleFreshness thresholds configurable (admin only)

Error states:

  • Viewer role accessing /review: Redirected to /browse with notice
  • Empty review queue: Empty state message shown

Preconditions: Authenticated with admin role. Specs: settings.spec.ts, role-gating.spec.ts

#StepExpected OutcomePass/Fail Criteria
9.1Navigate to /settingsSettings page loads with sidebar navigation7 sections visible (admin): Profile, Integrations, Taxonomy, Tags, Team, Governance, Activity. Non-admins see: Profile, Integrations only
9.2Profile sectionUser profile info displayedEmail, display name, role badge, password change visible
9.3Integrations sectionMCP server connection detailsConnection URL, auth instructions, connector status
9.4Taxonomy sectionDomain/subtopic configurationDomain list with edit capability
9.5Tags sectionTag managementTag list with create/rename/merge
9.6Team section (admin only)User management interfaceList of users with roles, invite button
9.7Governance section (admin only)Governance configurationFreshness thresholds, review posture per domain
9.8Activity sectionActivity feed displayedRecent actions listed chronologically
9.9Invite a new userClick invite, enter email, select roleInvitation dialog functional
9.10Change a user’s roleSelect new role from dropdown, confirmRole updated, badge changes
9.11Test appearance settings (site header)Click gear icon in site header — toggle dark/light/system mode, accessibility switchesTheme changes instantly. Dyslexia-friendly, high contrast, large text switches available. Note: appearance is in site header dialog, NOT in Settings page

Preconditions: Authenticated, content items exist. ANTHROPIC_API_KEY set.

#StepExpected OutcomePass/Fail Criteria
10.1Navigate to /digestDigest page loadsPeriod selector and generate button visible
10.2Select period (e.g., “Last 7 days”)Period selection updatesDropdown reflects choice
10.3Click “Generate Digest”AI digest generation beginsLoading spinner shown
10.4Wait for digest to completeDigest content displayedSummary, key themes, item references visible
10.5Check digest historyPrevious digests listedTimestamps and periods shown

Error states:

  • Generate with no recent content: Appropriate message
  • API error: Error toast shown

Preconditions: Authenticated with editor role.

#StepExpected OutcomePass/Fail Criteria
11.1Navigate to /workspacesWorkspaces page loadsWorkspace list or empty state
11.2Create a new workspaceClick create, enter name and descriptionWorkspace created, appears in list
11.3View workspace detailClick workspace cardWorkspace detail with assigned items
11.4Add items to workspaceAssign content items to workspaceItems appear in workspace view

Preconditions: Authenticated, Q&A pairs exist in database. Spec: qa-library.spec.ts

#StepExpected OutcomePass/Fail Criteria
12.1Navigate to /libraryQ&A Library page loadsList of Q&A pairs visible with filter controls
12.2Apply domain filterList filters to selected domainItem count decreases, all visible items match
12.3Search within Q&A libraryResults filtered by search textMatching Q&A pairs shown
12.4Click a Q&A pairDetail view or inline expansionQuestion and answer content visible
12.5Copy a Q&A pair to a bidSelect bid target, confirm copySuccess confirmation, pair linked to bid

Note: The Q&A Library uses @tanstack/react-virtual (window virtualiser). With 173+ production Q&A pairs, items may be off-screen and require scrolling to access.


Preconditions: Authenticated, content items exist across multiple taxonomy domains. Spec: coverage-page.spec.ts

#StepExpected OutcomePass/Fail Criteria
13.1Navigate to /coverageCoverage page loadsDomain coverage overview visible
13.2Review domain coverageEach domain shows item counts and freshness distributionData matches DB reality
13.3Identify gapsDomains with low or no coverage highlightedGap indicators visible

Flow 14: Appearance and Accessibility Settings

Section titled “Flow 14: Appearance and Accessibility Settings”

Preconditions: Authenticated.

#StepExpected OutcomePass/Fail Criteria
14.1Click gear icon in site headerAppearance settings dialog opensTheme and accessibility options visible
14.2Toggle dark/light/system modeTheme changes instantlyPage re-renders with correct theme
14.3Enable dyslexia-friendly fontFont changes to Atkinson Hyperlegible or similarText re-renders
14.4Enable high contrast modeContrast increases across all elementsVisual change noticeable
14.5Enable large textText size increasesLayout adjusts to accommodate
14.6Close and reopen dialogSettings persistPreviously selected options still active

Preconditions: Authenticated with editor role, layer vocabulary configured. Spec: layer-suggestion.spec.ts

#StepExpected OutcomePass/Fail Criteria
15.1Navigate to /item/newCreate content form loadsForm fields visible including domain, content type
15.2Create a new content itemAfter saving, LayerSuggestionBanner appearsBanner shows as role="region" with aria-label “Layer suggestion”
15.3Accept suggested layerLayer assigned to itemBanner dismissed
15.4Navigate to /browse, check layer filterLayer filter available in filter panelFilter shows layer options from layer_vocabulary
15.5Apply layer filterBrowse results filtered by layerLayer badges visible on content cards

Preconditions: Authenticated, content items with entity mentions exist. Spec: entity-filters.spec.ts

#StepExpected OutcomePass/Fail Criteria
16.1Navigate to /browse, open filter panelFilter panel (Sheet dialog) opensEntity Type and Entities sections visible (collapsed by default)
16.2Expand Entity Type sectionEntity type buttons with counts shownButtons have aria-pressed state
16.3Select an entity typeBrowse results filteredFilter badge appears, item count changes
16.4Clear entity type filterResults restoredFilter badge removed
16.5Navigate to /item/{id} for item with entitiesEntity badges displayedBadge colours match entity type tokens

Preconditions: Authenticated, entity_mentions with certification metadata exist. Specs: wave1-cert-renew.spec.ts, wave1-dashboard-expiry.spec.ts

#StepExpected OutcomePass/Fail Criteria
17.1Navigate to / (dashboard)Compliance Status section rendersCertification and framework summary cards visible
17.2Verify expiry badges on certificationsExpiry status shown (valid/expiring_soon/expired)Badge colours use freshness semantic tokens
17.3Click “Renew” on expiring certificationNavigates to item detail with renewal_entity query parameterItem detail page loads
17.4Verify Expiring Content sectionItems expiring within 30 days listed with urgencyUrgency colour coding visible

Preconditions: Authenticated with editor role, guides configured. Specs: wave1-guide-sections.spec.ts, wave1-item-detail-dates.spec.ts

#StepExpected OutcomePass/Fail Criteria
18.1Navigate to /item/new, create contentGuideSectionBanner may appear after creationBanner shows as role="region" with matched guide sections
18.2Verify guide section linksSection links point to /guide/{slug}#{sectionId}Match strength badges visible
18.3Navigate to item with expiry_dateExpiryDateDisplay shows in DD/MM/YYYY formatUrgency badge uses freshness tokens
18.4Verify temporal references sectionCollapsible section with extracted datesUses aria-expanded and aria-controls

#CheckPass/Fail Criteria
A.1Keyboard navigationAll interactive elements reachable via Tab
A.2Focus indicatorsVisible focus ring on all focusable elements
A.3Screen reader landmarksSemantic HTML (headings, nav, main, sections)
A.4Colour contrastText meets WCAG 2.1 AA (4.5:1 ratio)
A.5No colour-alone meaningAll status indicators have text or icon backup
A.6Skip linkSkip to main content link available at page top
#CheckPass/Fail Criteria
R.1Mobile viewport (375px / Pixel 5)All pages usable, no horizontal scroll. Hamburger menu for navigation
R.2Tablet viewport (768px)Layout adapts, grids collapse appropriately. Settings sidebar becomes Sheet drawer
R.3Desktop viewport (1440px)Full layout, max-width containers centred
#CheckPass/Fail Criteria
E.1Network disconnectToast errors, no crashes
E.2Invalid route404 page displayed
E.3Unauthorised accessRedirect to login or appropriate error
E.4API errorsUser-friendly error messages, no raw stack traces

PageCovered By
/ (home)Flow 1, Flow 17, Flow 18
/loginFlow 0
/browseFlow 2, Flow 16
/searchFlow 2
/item/[id]Flow 3, Flow 17, Flow 18
/item/newFlow 15, Flow 18
/bidFlow 4
/bid/[id]Flow 4, 5, 6
/bid/[id]/sessionFlow 5
/bid/[id]/templatesFlow 7
/reviewFlow 8
/settingsFlow 9
/digestFlow 10
/workspacesFlow 11
/libraryFlow 12
/coverageFlow 13
/auth/callbackFlow 0 (implicit)
/oauth/consentFlow 0 (implicit, MCP OAuth)
Site header (appearance)Flow 14

Terminal window
# Install Playwright browsers (first time only)
bunx playwright install chromium
# Run all E2E specs (starts dev server automatically)
bunx playwright test
# Run a specific spec
bunx playwright test e2e/tests/browse-search.spec.ts
# Run Wave 1 specs only
bunx playwright test --grep @wave1
# Run with UI mode for debugging
bunx playwright test --ui
# View test report
bunx playwright show-report

Important: E2E tests need dangerouslyDisableSandbox: true in Claude Code due to port 3000 binding. The NEXT_PUBLIC_E2E=true environment variable is set automatically by playwright.config.ts to disable CopilotKit during tests.


Generated: Session 46, 5 March 2026. Updated: Session 69b, 9 March 2026. Updated: 23/03/2026 (S108).