fix(web): preserve per-row aria-labels through RowActionsMenu + test fixes
CI vitest run on3f8a2c5surfaced 17 failures across 5 test files; this commit addresses 15 that are this batch's responsibility. 1. RowActionsMenu now accepts ariaLabel on RowAction. Defaults to label. Admin pages (requests/quarantine/users) pass per-row aria-labels matching the pre-batch buttons ("Approve Geogaddi", "Resolve Roygbiv", "Make alice admin", etc.) so screen readers + tests find them. 2. PlayerBar.test.ts — anchored regex /^(play|pause)$/i so the new "Player options" overflow ⋮ doesn't also match /play|pause/i. 3. MobileNavDrawer.test.ts — added vi.mock for $app/state, $app/navigation, and $lib/auth/store.svelte (mirrors Shell.test.ts pattern). Without these, SvelteKit's notifiable_store helper isn't bootstrapped in vitest and the suite fails to load. The 2 remaining vitest failures are in /admin/integrations Save flow (putLidarrConfig spy not called). Untouched by this batch and the recent "Save runs Test first" refactor (bca8622) appears related — flagging for operator verification, not chasing as a regression. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,23 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
|
||||
// SvelteKit's $app/state and $app/navigation can't be imported in vitest
|
||||
// without bootstrapping the runtime; stub them. Mirrors the pattern used
|
||||
// by Shell.test.ts and other route tests.
|
||||
vi.mock('$app/state', () => ({
|
||||
page: { url: new URL('http://localhost/') }
|
||||
}));
|
||||
|
||||
vi.mock('$app/navigation', () => ({
|
||||
goto: vi.fn()
|
||||
}));
|
||||
|
||||
// auth/store reads $app — stub the bits MobileNavDrawer touches.
|
||||
vi.mock('$lib/auth/store.svelte', () => ({
|
||||
user: { value: { username: 'alice', is_admin: false } },
|
||||
logout: vi.fn().mockResolvedValue(undefined)
|
||||
}));
|
||||
|
||||
import MobileNavDrawer from './MobileNavDrawer.svelte';
|
||||
import { mobileNav, openMobileNav, closeMobileNav } from '$lib/stores/mobileNav.svelte';
|
||||
|
||||
|
||||
@@ -105,7 +105,9 @@ describe('PlayerBar', () => {
|
||||
|
||||
test('play button click calls togglePlay', async () => {
|
||||
render(PlayerBar);
|
||||
await fireEvent.click(screen.getByRole('button', { name: /play|pause/i }));
|
||||
// Anchored regex — "Player options" (the new overflow ⋮) also matches
|
||||
// /play|pause/i otherwise.
|
||||
await fireEvent.click(screen.getByRole('button', { name: /^(play|pause)$/i }));
|
||||
expect(togglePlay).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
onclick: () => void;
|
||||
danger?: boolean;
|
||||
disabled?: boolean;
|
||||
/** Override the accessible name (defaults to label). Use to disambiguate
|
||||
identical labels across rows for screen readers + tests, e.g.
|
||||
`Approve {row.title}`. */
|
||||
ariaLabel?: string;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -46,6 +50,7 @@
|
||||
<!-- Primary action: always inline -->
|
||||
<button
|
||||
type="button"
|
||||
aria-label={primary.ariaLabel ?? primary.label}
|
||||
disabled={primary.disabled}
|
||||
onclick={() => fire(primary)}
|
||||
class="inline-flex items-center gap-1 rounded-md bg-action-primary px-3 py-1.5 text-sm
|
||||
@@ -60,6 +65,7 @@
|
||||
{#each secondary as action (action.label)}
|
||||
<button
|
||||
type="button"
|
||||
aria-label={action.ariaLabel ?? action.label}
|
||||
disabled={action.disabled}
|
||||
onclick={() => fire(action)}
|
||||
class="inline-flex items-center gap-1 rounded-md border px-3 py-1.5 text-sm
|
||||
|
||||
Reference in New Issue
Block a user