fix(web/m7-364): vitest failures — exact-match query, inert prop, -0, user guard
CI test-web was blocking on:
- QueueDrawer.test close-button query: getByLabelText(/close queue/i)
matched BOTH the backdrop button (aria-label="Close queue backdrop")
and the close button (aria-label="Close queue"). Switched to exact
string match.
- QueueDrawer.test inert assertion: Svelte 5 + jsdom uses property
binding for `inert`, not attribute, so hasAttribute('inert') returns
false. Check the DOM property (with attribute fallback for
robustness) instead.
- queue-row-math.ts -0 normalization: Math.round(-0.5) returns -0,
and Object.is(-0, 0) is false — vitest's .toBe(0) fails. Added
`|| 0` to normalize -0 to +0 at the function boundary so consumers
never see -0.
- player/store.svelte.ts user import guard: persistence $effect.root
reads `user.value?.id` at module-init, but in test files where
auth/store.svelte.ts is imported transitively (auth/store.test,
playlists/playlists.test), the player module loads via auth's
import chain before auth's `user` binding is assigned. `user?.value`
guards against that init-order race. The proper fix is to invert
the auth↔player import dep (filed as I2 follow-up under #375).
This commit is contained in:
@@ -63,7 +63,7 @@ describe('QueueDrawer', () => {
|
|||||||
|
|
||||||
it('clicking the close button calls closeQueueDrawer', async () => {
|
it('clicking the close button calls closeQueueDrawer', async () => {
|
||||||
render(QueueDrawer);
|
render(QueueDrawer);
|
||||||
const close = screen.getByLabelText(/close queue/i);
|
const close = screen.getByLabelText('Close queue');
|
||||||
await fireEvent.click(close);
|
await fireEvent.click(close);
|
||||||
expect(closeQueueDrawer).toHaveBeenCalled();
|
expect(closeQueueDrawer).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -84,12 +84,16 @@ describe('QueueDrawer', () => {
|
|||||||
expect(aside!.getAttribute('aria-hidden')).toBe('true');
|
expect(aside!.getAttribute('aria-hidden')).toBe('true');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('drawer has inert attribute when closed', () => {
|
it('drawer is inert when closed', () => {
|
||||||
openValue = false;
|
openValue = false;
|
||||||
queueValue = [t('a')];
|
queueValue = [t('a')];
|
||||||
render(QueueDrawer);
|
render(QueueDrawer);
|
||||||
const aside = document.querySelector('aside[aria-label="Playback queue"]');
|
const aside = document.querySelector('aside[aria-label="Playback queue"]');
|
||||||
expect(aside).not.toBeNull();
|
expect(aside).not.toBeNull();
|
||||||
expect(aside!.hasAttribute('inert')).toBe(true);
|
// Svelte 5 + jsdom uses property binding for `inert`, not attribute. Check both
|
||||||
|
// to be robust regardless of which jsdom version handles the mirror.
|
||||||
|
const inertProp = (aside as unknown as { inert?: boolean }).inert === true;
|
||||||
|
const inertAttr = aside!.hasAttribute('inert');
|
||||||
|
expect(inertProp || inertAttr).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,5 +4,7 @@
|
|||||||
// the user's drop intent maps to a clean queue index.
|
// the user's drop intent maps to a clean queue index.
|
||||||
export function offsetToDelta(offsetY: number, rowHeight: number): number {
|
export function offsetToDelta(offsetY: number, rowHeight: number): number {
|
||||||
if (rowHeight <= 0) return 0;
|
if (rowHeight <= 0) return 0;
|
||||||
return Math.round(offsetY / rowHeight);
|
// `|| 0` normalizes -0 to +0. Math.round(-0.5) === -0; downstream
|
||||||
|
// consumers (and Object.is in tests) treat -0 and +0 as distinct.
|
||||||
|
return Math.round(offsetY / rowHeight) || 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,7 +397,10 @@ $effect.root(() => {
|
|||||||
// queue/index changes drive it. The throttled-write effect below
|
// queue/index changes drive it. The throttled-write effect below
|
||||||
// covers position drift.
|
// covers position drift.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const userId = user.value?.id;
|
// `user?.value` (not `user.value`) guards against module-init order during
|
||||||
|
// tests: auth/store.svelte.ts imports from this file, so when this module
|
||||||
|
// loads via that chain, `user` may not yet be assigned. See I2 follow-up.
|
||||||
|
const userId = user?.value?.id;
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
// Reading these registers the reactive dependency; the values
|
// Reading these registers the reactive dependency; the values
|
||||||
// themselves are unused — writePersistedQueue re-reads live state.
|
// themselves are unused — writePersistedQueue re-reads live state.
|
||||||
@@ -413,7 +416,7 @@ $effect.root(() => {
|
|||||||
|
|
||||||
// Throttled write on position changes.
|
// Throttled write on position changes.
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const userId = user.value?.id;
|
const userId = user?.value?.id;
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
const _p = _position;
|
const _p = _position;
|
||||||
void _p;
|
void _p;
|
||||||
|
|||||||
Reference in New Issue
Block a user