Skip to main content

Portal — system tests (POR-ST-*)

Human-driven protocol for @enode/portal in a desktop browser (plus one mobile-viewport spot check) against backdev. Environment, accounts, and run recording: system test plan. Requirements covered: portal.md + shared.md.

Keep DevTools open (Console + Network) — a case passes only with a correct UI and no console errors and 2xx (or documented 31x) responses. Case IDs are POR-ST-<section>.<case> and are stable — append, never renumber.

Preconditions for the whole run: Pro coach/admin account on backdev with ≥2 athletes, ≥1 template, scheduled + recurring workouts, completed sessions (run tracking protocol §7 first if history is empty); a One account; a restricted (athlete) account; the roster CSV fixture.

1. Auth & entry

#Use caseCoversStepsExpected resultResultNotes
1.1Pro sign-inSHR-AUTH-01, POR-AUTH-01Sign in with the Pro coach account at /Redirects to /dashboard; sidebar shows privilege-appropriate entries[automate]
1.2One sign-inPOR-AUTH-01Sign in with the One accountLogin succeeds; migration entry is prominent (One users come to migrate)
1.3Registration (Pro-only)SHR-AUTH-03, POR-AUTH-01Walk the registration flow; test one invalid inputPro registration completes; validation errors shown inline; no One registration offered
1.4Cold-start redirectSHR-AUTH-02With a stored token, open /Redirects straight to /dashboard[automate]
1.5Sign out & 401 bounceSHR-AUTH-05Sign out; then open /dashboard/users directlyBack at login; the deep link bounces to login while unauthenticated
1.6Device-limit dialogSHR-AUTH-06, POR-AUTH-02Exceed the account's device sessions, then sign in310 → device-limit dialog; freeing a slot lets login continue
1.7Invitation flowSHR-AUTH-07, POR-AUTH-02Sign in with a freshly invited user312 → invitation dialog; accepting continues into the dashboard
1.8Onboarding redirectSHR-AUTH-08, POR-AUTH-02Sign in with an account with incomplete onboarding311 → onboarding flow before the dashboard

2. Dashboard

#Use caseCoversStepsExpected resultResultNotes
2.1Range summariesPOR-DASH-01Open /dashboard; switch the time rangeAthletes / sessions / volume / sets cards update per range
2.2Trends vs prior periodPOR-DASH-01Read the trend indicatorsTrend deltas plausible vs the prior equal-length period (spot-check one against history)
2.3RankingsPOR-DASH-02Check top exercises + athlete activityRankings populated and consistent with recent sessions
2.4Sessions tablePOR-DASH-02Check the completed-sessions tableRecent sessions listed; opening one shows its details

3. Planner

Run the full Planner manual test protocol (§1–§11) as part of a release run — it covers POR-PLAN-01..03 in depth.

#Use caseCoversStepsExpected resultResultNotes
3.1Drag & drop reschedulePOR-PLAN-02Drag a workout chip to another day (month view)Chip moves; backend updated (2xx or 313 flow); persists on refreshnot in the planner protocol

4. Devices

#Use caseCoversStepsExpected resultResultNotes
4.1List & searchPOR-DEVICES-01Open /dashboard/devices; search for a known deviceDevice sessions listed; search narrows correctly
4.2Remove sessionPOR-DEVICES-01Remove a device session (e.g. the tracking test device)Removed from the list; that device is signed out / must re-auth

5. Users & roster

#Use caseCoversStepsExpected resultResultNotes
5.1Table search & role filterPOR-USERS-01Search a name; toggle admin/coach/athlete filtersRows filter correctly; counts match[automate]
5.2Create & edit userPOR-USERS-02Create an athlete with metadata; reopen and editCreated user appears; edits persist after reload
5.3Bulk add tagsPOR-USERS-03Select 2+ users → bulk add a tagTag applied to all selected; visible in the table/drawer
5.4Bulk deletePOR-USERS-03Select the test users → bulk deleteConfirmation required; users gone after confirm + reload
5.5Roster CSV uploadPOR-USERS-04, POR-NOTIF-02Upload the CSV fixture: dropzone → mapping → validation → review → uploadColumns auto-map; invalid rows flagged in review; upload runs async with live progress; users exist afterwards
5.6Units in user drawerSHR-UNITS-01, POR-USERS-02Toggle metric ↔ imperial; open a user's height/weightValues convert correctly both ways
5.7Per-user actionsPOR-USERS-05From a user row: export data; view upcoming workoutsExport starts (see §13); upcoming workouts listed

6. Exercises

#Use caseCoversStepsExpected resultResultNotes
6.1SearchPOR-EXER-01Search by name and by tagMatching exercises shown[automate]
6.2Filters & favouritesPOR-EXER-01Apply equipment + muscle-category filters; favourite an exerciseFilters combine correctly; favourite persists after reload
6.3Custom overridesPOR-EXER-02In the detail drawer, set a custom name/details; saveOverride shown in the catalogue; base catalogue data still visible in the drawer

7. Workout templates

#Use caseCoversStepsExpected resultResultNotes
7.1List, search, tag filterPOR-WKT-01Search templates; filter by tagCards filter correctly
7.2Create & editPOR-WKT-01Create a template with 2 exercises; reopen and editTemplate persists; edits visible in the tracking app's template picker too
7.3Bulk deletePOR-WKT-01Select test templates → deleteConfirmation; gone after reload

8. Tags

#Use caseCoversStepsExpected resultResultNotes
8.1List & access-level filterPOR-TAGS-01Filter by visibility chipsTags filter by access level
8.2Create & editPOR-TAGS-01Create a tag with color/details; edit itPersists; color renders in pills; relations section populates where linked
8.3Bulk deletePOR-TAGS-01Select test tags → deleteConfirmation; gone after reload; no orphaned pills on users/exercises

9. Insights (custom charts)

#Use caseCoversStepsExpected resultResultNotes
9.1Build a chartPOR-INS-01Builder drawer → pick a chart type, metric, athletes → saveChart renders with real data on the board
9.2Board layoutPOR-INS-01Drag a chart to a new positionLayout change persists after reload
9.3Per-user persistencePOR-INS-01Reload; sign out/inCharts and layout restored for the same user

10. Profiles (performance matrix)

#Use caseCoversStepsExpected resultResultNotes
10.1Matrix rendersPOR-PROF-01Open Profiles; pick axes with known dataAthlete × exercise matrix populates
10.2List/grid persistedPOR-PROF-01Switch list ↔ grid; reloadChosen view persists
10.3Pair detail & trendPOR-PROF-01Open a cell/pairPair detail with per-athlete trend renders

11. History & session details

#Use caseCoversStepsExpected resultResultNotes
11.1Search & filtersPOR-HIST-01Filter history by athlete/exerciseSessions filter correctly[automate]
11.2Pagination & windowPOR-HIST-01Page through resultsPagination works; results within the last-year default window
11.3Session drawerPOR-HIST-02Open a session (one recorded in the tracking run)Drawer opens with summary tab + technique board; set data matches what was tracked

12. Migration

#Use caseCoversStepsExpected resultResultNotes
12.1Entry pointsSHR-AUTH-04, POR-MIGR-01Open migration from the sidebar and from the auth-time entry (One account)Wizard opens from both
12.2Wizard flowPOR-MIGR-01Walk the wizard with a legacy test account (athletes/groups/history)Steps complete; migrated entities appear (users/tags/history)needs legacy test data
12.3Manual exercise mappingPOR-MIGR-02Reach the exercise-mapping stepNo auto-suggestions (by design); coach picks each mapping manually; picks are applied

13. Export

#Use caseCoversStepsExpected resultResultNotes
13.1Export flow + deep linkPOR-EXP-01Run an export from the route; then open an export deep-link URLExport produces a download; deep link seeds the flow's selections
13.2PDF exportPOR-EXP-01Export as PDFValid, readable PDF with the selected data

14. Notifications

#Use caseCoversStepsExpected resultResultNotes
14.1Live arrivalPOR-NOTIF-01Trigger a notification (e.g. finish a roster upload or export) while on another pageArrival peek shows; bell unread badge increments without reload
14.2Inbox operationsPOR-NOTIF-01In the inbox: switch filter segments, mark read, deleteAll three work; unread badge updates
14.3Deep-link expandPOR-NOTIF-01Open a notification deep link (expand param)Inbox opens with that notification expanded

15. Privileges & roles

#Use caseCoversStepsExpected resultResultNotes
15.1Gated navigationPOR-RBAC-01Sign in with the restricted (athlete) accountUsers/Insights/roster/migration/export entries hidden per missing privileges
15.2Direct-route blockPOR-RBAC-01As the restricted user, open /dashboard/users and /dashboard/data/insights directlyBlocked/redirected — no data renders
15.3Role modelPOR-RBAC-02As admin, inspect the Users role filters and an owner accountFilters show admin ("Facility")/coach/athlete; owner excluded from filters but visible with full access

16. Cross-cutting

#Use caseCoversStepsExpected resultResultNotes
16.1Offline surfaceSHR-ERR-01Toggle DevTools offline mode on the dashboardConnection-loss card/banner appears; recovery restores data without reload artifacts
16.2Error surfacesSHR-ERR-02, SHR-ERR-03Provoke a failing request (e.g. save while offline / force a 5xx via DevTools blocking)Toast/inline alert with backend message or fallback; Try again + Report offered on application errors; blocking dialog only for blocking class
16.3i18n scanSHR-I18N-01Scan all pages visited this runNo raw keys, undefined, or hardcoded dev strings
16.4Reference-data gatingSHR-ERR-04Load a data page with its reference call blocked (DevTools request blocking), then unblock + retryExplicit error/retry state (RequireData), never an empty-but-broken table; retry recovers
16.5Debug absent in prodOn a production build, open /dashboard/debugRenders nothing/404; no Debug nav entry
16.6Mobile viewport spot checkNarrow to <1024px; navigate 3 pages; open a drawerSidebar becomes slide-in overlay and auto-collapses on navigation; no horizontal scroll; drawers usable

17. Archived users

Precondition: one archived athlete with recorded history, and one scheduled on a future workout. Archive via a user's drawer (needs writeUserStatus).

#Use caseCoversStepsExpected resultResultNotes
17.1Hidden from every live surfaceSHR-ARCH-01Look for the archived athlete in: any athlete picker (planner, insights, export), the history search typeahead, and the Profiles athlete axisAbsent everywhere; only the Users page's Archived view lists them
17.2History archived compartmentSHR-ARCH-03, POR-HIST-05On History, find a page containing their sessions; toggle the Archived chipDefault view hides their sessions; the Archived view shows only theirs; "Showing X of Y on this page" reflects the splitarchived pages are often empty — page around
17.3Data stays exportableSHR-ARCH-03Users → Archived → select the athlete → ExportThe export flow opens seeded with them and produces their data (not an empty export)
17.4Saving doesn't drop themSHR-ARCH-04Planner: open a workout that has an archived participant, change only the name/time, save. Inspect the request bodyThe archived athlete's id is still in participants — they were not silently removed[automate]
17.5Explicit edit drops themSHR-ARCH-02Same workout: open the athlete picker and confirm without changing anything; saveThe archived athlete is now removed (an explicit edit, not a silent one)
17.6Names still resolveSHR-ARCH-03Open a saved insights chart whose config names the archived athleteThe facet shows their name, not a raw UUIDkey regression

Coverage table

RequirementCases
POR-AUTH-011.1, 1.2, 1.3
POR-AUTH-021.6, 1.7, 1.8
POR-DASH-012.1, 2.2
POR-DASH-022.3, 2.4
POR-PLAN-01Planner protocol §1–§5
POR-PLAN-02Planner protocol §6, §8, §9 + 3.1
POR-PLAN-03Planner protocol §7
POR-DEVICES-014.1, 4.2
POR-USERS-015.1
POR-USERS-025.2, 5.6
POR-USERS-035.3, 5.4
POR-USERS-045.5
POR-USERS-055.7
POR-EXER-016.1, 6.2
POR-EXER-026.3
POR-WKT-017.1, 7.2, 7.3
POR-TAGS-018.1, 8.2, 8.3
POR-INS-019.1, 9.2, 9.3
POR-INS-02— mocked; known behaviour
POR-PROF-0110.1, 10.2, 10.3
POR-HIST-0111.1, 11.2
POR-HIST-0211.3
POR-HIST-03— wip; known behaviour
POR-HIST-04— wip
POR-HIST-0517.2
SHR-ARCH-01..0417.1, 17.5, 17.2/17.3/17.6, 17.4
POR-MIGR-0112.1, 12.2
POR-MIGR-0212.3
POR-EXP-0113.1, 13.2
POR-NOTIF-0114.1, 14.2, 14.3
POR-NOTIF-025.5
POR-RBAC-0115.1, 15.2
POR-RBAC-0215.3
SHR-AUTH-01..081.1, 1.4, 1.3, 12.1, 1.5, 1.6, 1.7, 1.8
SHR-I18N-0116.3
SHR-UNITS-015.6
SHR-ERR-01..0416.1, 16.2, 16.2, 16.4

Known/expected behaviours (not defects)

  • Insights builder preview / empty state / walkthrough charts are synthetic (POR-INS-02) — educational visuals, not backend data.
  • Session-summary zone-distribution & muscle-map cards are WIP (POR-HIST-03): real V2 DTO data, marked WIP in code; zone card only on conventional-strength exercises. Oddities there are tracked as WIP, not run defects — but crashes still count.
  • History has no dedicated date-range picker yet (POR-HIST-04); default window is the last year.
  • The Workouts page carries an in-code "structural first pass" note; rough edges beyond the tested cases in §7 should be logged as notes, not blockers.
  • Roobert font 404s in dev are expected locally (see the planner protocol).