@tristan2828/ui-foundation 4.18.1 → 4.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -511,6 +511,29 @@ is a filled-in example while the Widgets demo is still here).
|
|
|
511
511
|
`onError` — and stub it through the override, never `page.route`,
|
|
512
512
|
which cannot see requests the MSW service worker makes
|
|
513
513
|
(`e2e/msw-contract.spec.ts` has an example).
|
|
514
|
+
**Forcing a mutation's success forces its refetch too.** A mutation
|
|
515
|
+
invalidates its queries when it answers, and the refetch reads the
|
|
516
|
+
mock store, which the override never changed, so the screen goes back
|
|
517
|
+
to the old record and the test fails on a value it just saw. Answer
|
|
518
|
+
the follow-up GET with the record the mutation answered:
|
|
519
|
+
|
|
520
|
+
```ts
|
|
521
|
+
// The record as the server would save it: what the PATCH answers.
|
|
522
|
+
const saved = { ...WIRELESS_MOUSE, status: 'archived' }
|
|
523
|
+
await waitForMswReady(page)
|
|
524
|
+
await page.evaluate((saved) => {
|
|
525
|
+
const { worker, http, HttpResponse } = window.__msw
|
|
526
|
+
worker.use(
|
|
527
|
+
http.patch('*/api/widgets/1', () => HttpResponse.json(saved)),
|
|
528
|
+
// The invalidation refetch: without this it shows the old status.
|
|
529
|
+
http.get('*/api/widgets/1', () => HttpResponse.json(saved)),
|
|
530
|
+
)
|
|
531
|
+
}, saved)
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
Answer the list's GET the same way if the screen shows the list. Only
|
|
535
|
+
a forced error needs no GET: a refused mutation changes nothing to
|
|
536
|
+
read back.
|
|
514
537
|
9. **Register the nav entry and route names** in `e2e/shell.spec.ts`'s
|
|
515
538
|
`NAV_ENTRIES` so the shell smoke test covers the new screen, add
|
|
516
539
|
`/<entity>/new` to `e2e/a11y.spec.ts`'s `formRoutes`, and add the view
|
|
@@ -153,3 +153,40 @@ test('running, paused and done', async ({ page }) => {
|
|
|
153
153
|
before the page loads:
|
|
154
154
|
`page.addInitScript(() => localStorage.setItem('my-app:routine:muted', 'true'))`.
|
|
155
155
|
- **Reduced motion:** `await page.emulateMedia({ reducedMotion: 'reduce' })`.
|
|
156
|
+
|
|
157
|
+
**An open-ended count-up: pause the fake clock.** After
|
|
158
|
+
`clock.install()` the fake clock still moves in real time between
|
|
159
|
+
steps, so every reading picks up however long the machine took since the
|
|
160
|
+
last `fastForward`. A count-up with no end (a stopwatch, a hold that
|
|
161
|
+
ends on a tap) has nothing to stop at, so under load its readings are
|
|
162
|
+
off by a second or more. Pause the clock once the session opens and
|
|
163
|
+
move it only with `fastForward`:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
test('the hold counts up until the tap', async ({ page }) => {
|
|
167
|
+
await page.clock.install()
|
|
168
|
+
await page.goto('/routine')
|
|
169
|
+
await page.getByRole('button', { name: 'Start' }).click()
|
|
170
|
+
// Slightly ahead, never Date.now() itself: the page's clock has already
|
|
171
|
+
// moved past the test's, and pauseAt() refuses an earlier time with
|
|
172
|
+
// "Cannot fast-forward to the past".
|
|
173
|
+
await page.clock.pauseAt(Date.now() + 50)
|
|
174
|
+
|
|
175
|
+
await page.clock.fastForward('00:42')
|
|
176
|
+
await expect(page.getByRole('timer', { name: 'Held for' })).toHaveText('0:42')
|
|
177
|
+
|
|
178
|
+
// A paused clock stops axe and the dialog's close animation: resume first.
|
|
179
|
+
await page.clock.resume()
|
|
180
|
+
await expectNoAxeViolations(page) // @tristan2828/ui-foundation/testing
|
|
181
|
+
await page.getByRole('button', { name: 'Close' }).click()
|
|
182
|
+
await expect(page.getByRole('dialog')).toBeHidden()
|
|
183
|
+
})
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
- **`pauseAt(Date.now() + 50)`, not `pauseAt(Date.now())`.** The page's
|
|
187
|
+
fake time is already a little ahead of the test's `Date.now()`, and
|
|
188
|
+
`pauseAt` fast-forwards to the time it's given, so a time already
|
|
189
|
+
passed fails with "Cannot fast-forward to the past".
|
|
190
|
+
- **`clock.resume()` before axe or closing the view.** With the clock
|
|
191
|
+
paused, axe's scan never finishes and the dialog's close animation
|
|
192
|
+
never ends, so the test times out with nothing pointing at the clock.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tristan2828/ui-foundation",
|
|
3
|
-
"version": "4.18.
|
|
3
|
+
"version": "4.18.3",
|
|
4
4
|
"description": "Shared UI foundation for contract-first, database-backed React apps: shadcn primitives, DataTable/EntityForm composites, auth, the gateway error seam, design tokens, lint rules and the AI playbook.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"sonner": "^2.0.8",
|
|
94
94
|
"tailwindcss": "^4.3.3",
|
|
95
95
|
"typescript-eslint": "^8.70.0",
|
|
96
|
-
"vite": "^8.3.
|
|
96
|
+
"vite": "^8.3.4",
|
|
97
97
|
"zod": "^4.6.5"
|
|
98
98
|
},
|
|
99
99
|
"peerDependenciesMeta": {
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
"tailwindcss": "^4.3.3",
|
|
184
184
|
"typescript": "~6.0.3",
|
|
185
185
|
"typescript-eslint": "^8.70.0",
|
|
186
|
-
"vite": "^8.3.
|
|
186
|
+
"vite": "^8.3.4",
|
|
187
187
|
"vitest": "^5.0.1",
|
|
188
188
|
"zod": "^4.6.5"
|
|
189
189
|
},
|