Repository navigation
Fix what end-to-end testing turned up - #38
Merged
Merged
Conversation
Found by running the app rather than by any test. The board sized its columns from a width obtained with measureInWindow, which is asynchronous and never resolves on web -- and react-navigation lays a tab screen out while it is still detached, so the one onLayout that does fire reports zero. A zero width made every column, and so every card, zero pixels wide: the whole board was in the DOM and none of it was visible. Width now comes from the window less the nav rail, which is always known, and a real measurement refines it if one arrives. Verified live at all three size classes: 320px columns on a 390 phone (neighbours peeking), exactly two 306px columns beside the rail at 700, exactly four 292px at 1280. Also from running it: SecureStore has no web implementation, so signing in on the web target threw and the token was never stored. It falls back to localStorage there -- the same store the web app keeps its own token in. The web build is for development and review against a real instance, which is precisely what it could not do. The teams query fired before anyone had signed in, because TeamProvider mounts outside the auth guard. It is gated on a session now, and the team list is treated as untrusted on the way out of a week-long persisted cache: a poisoned entry degraded to a crash at boot above the error boundary. react-native-web does not map accessibilityState.checked onto aria-checked, so a task list on the web build announced checkboxes with no state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The three appearance options carried no accessible label. Every other control in the app has one, and without it a screen reader announces three unnamed buttons -- and nothing automated can drive them either, which is how this was found. Also sets aria-selected, since react-native-web does not map accessibilityState.selected onto it, the same gap the task checkboxes had. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A status created through the web UI stores its colour as `var(--color-status-progress)` rather than a hex value -- the production instance has one, "In QA". A browser resolves that against the stylesheet; React Native hands it to the native layer, which cannot, so the dot renders as nothing. Seeded statuses carry hex and hid this. `resolveColor` maps the variable back onto the active theme's tokens, which also makes these dots follow light and dark rather than freezing at whatever the web's light palette happened to be. Anything already paintable passes through untouched, and an unrecognised value falls back to a visible grey instead of disappearing. Routed through a `Dot` primitive so every status and label dot resolves the same way, along with `Avatar` and `Chip`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The existing tests cover the conflict rule in isolation, which leaves the part that actually carries the feature untested: that React Query pauses these mutations when the network goes away and replays them when it returns. Three round trips against a running instance -- a move, a comment and an issue creation -- asserting the request is genuinely withheld while offline rather than merely failing, and that a move somebody else has overtaken is refused instead of applied on top of their work. The client is mounted, because an unmounted one never subscribes to `onlineManager` and so never resumes anything; and mutation `gcTime` is zero, because a settled mutation otherwise sits behind a five-minute collection timer that keeps the runner alive after the last assertion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Running them all against one instance surfaced two things that look like product failures and are not. They pick their fixture team by position, and `GET /teams` promises no order. The team-administration and onboarding suites create teams the API offers no way to delete, so an instance these have run against accumulates empty teams for good -- twenty of them on the local stack by now. `teams[0]` eventually lands on one, and the board suite fails with an empty page. `seededTeam()` asks for the seeded key instead, falling back to any team that actually has issues. They also cannot run in parallel. Several register accounts, registration is throttled per IP and charged even on success, and concurrent suites exhaust the budget at once. The 429 that comes back is an AxiosError whose circular req/res pair crashes the jest worker trying to serialize it, so it surfaces as `Test suite failed to run` with no mention of throttling -- which is what made this worth a note in the README rather than a shrug. `npm run test:live` runs them in band. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Running the app end to end against the local demo stack and then against production. Five commits: three bugs the testing found, and two pieces of test work that finding them required.
The bugs
A board whose columns rendered two pixels wide. Every column collapsed to 2px and every card to 0px.
measureInWindownever resolves on web, and tab screens lay out while still detached, so the measured width was never anything. The window width minus the rail is the source now, with the measurement used only once it means something.Status colours the web stores as CSS variables. This is the one only production could have shown. A status created through the web UI stores its colour as
var(--color-status-progress)— production has one, "In QA" on team BE. Seeded statuses carry hex, which is why every local instance looked fine. A browser resolves that against the stylesheet; React Native hands it to the native layer, which cannot, so the dot renders as nothing at all.resolveColormaps the variable back onto the active theme's tokens, which has the side benefit of making those dots follow light and dark instead of freezing at whatever the web's light palette happened to be. Anything already paintable passes through untouched, and an unrecognised value falls back to a visible grey rather than disappearing. Every status and label dot goes through oneDotprimitive now.Theme options that could not be announced or operated. The System/Light/Dark controls had no accessible name, and react-native-web does not map
accessibilityStateontoaria-*.The test work
The offline queue's pause and replay, against a real server. The conflict rule was unit-tested; the part actually carrying the feature was not — that React Query withholds these mutations when the network goes away and replays them when it returns. Four round trips now assert that, including a move somebody else overtook being refused rather than applied on top of their work.
Live suites that tripped over each other. Two things that look like product failures and are not:
GET /teamspromises no order. The team-administration and onboarding suites create teams the API offers no way to delete, so an instance these have run against accumulates empty teams permanently — twenty on the local stack by now.teams[0]eventually lands on one and the board suite fails on an empty page.AxiosErrorwhose circularreq/respair crashes the jest worker trying to serialize it, so it surfaces asTest suite failed to runwith no mention of throttling.npm run test:liveruns them in band.Checks
41 suites / 261 testspass with every live suite enabled against both the local stack and production, typecheck clean, 0 lint errors. CI runs without credentials, so the live suites skip there as before: 169 pass, 92 skip.Production was left as it was found — read-only apart from one scratch issue created and deleted in the same run, verified by a residue check.
Not covered
Nothing ran on a real device. Everything went through react-native-web, so SecureStore proper, NetInfo, the splash hold and board drag-and-drop are unverified on hardware. Production could only be driven through the client modules rather than the rendered UI, because its CORS allows only
https://softtrack.quantadev.io.🤖 Generated with Claude Code