Merge branch 'fix/pre-existing-test-failures'
Triage and fix of 12 pre-existing test failures on main (flagged by the #10 DM origin failover merge, commitff39ab0). Two root causes: 1. Node 20+'s built-in localStorage/sessionStorage stub shadows jsdom's working implementation because vitest's populateGlobal doesn't overwrite globals outside its known allow-list. Any zustand persist store threw "storage.setItem is not a function". Polyfilled with an in-memory Storage in src/test/setup.ts. Resolves 11 of 12 failures (10 keybindStore + 1 FriendsPage toast). 2. FriendsPage "Message button" DM test carried a stale two-arg assertion that predated the 2026-04-01 federation refactor (commit7f3ca4e) which dropped the second argument from addDmChannel. Dropped the trailing '' so the assertion matches current behavior. Hand-backs (not touched on this branch): - InviteModal.test.tsx and JoinSpace.test.tsx still fail to LOAD (not in the 12 tests but flagged by #10's merge note). After stubbing AudioManager a second blocker surfaces: TDZ error on _getApiForOrigin in spaceStore.ts:961, caused by a circular-import init order between spaceStore and instanceStore (via socialStore → useWebSocket → voiceStore). Federation-adjacent — filed as backlog item for a structural fix. Server: 90/90 unchanged. Web: 121/121 pass (was 109/121), 2 suite loads still failing (tracked).
This commit is contained in:
@@ -322,7 +322,7 @@ describe('FriendsPage', () => {
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockAddDmChannel).toHaveBeenCalledWith(expect.objectContaining({ id: 'dm-channel-99' }), '');
|
||||
expect(mockAddDmChannel).toHaveBeenCalledWith(expect.objectContaining({ id: 'dm-channel-99' }));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
|
||||
// Node 20+ ships a built-in `localStorage`/`sessionStorage` stub on globalThis
|
||||
// that has no methods unless `--localstorage-file=PATH` is provided. Vitest's
|
||||
// jsdom env only overwrites globals it knows about, and neither storage is in
|
||||
// that list — so Node's broken stub shadows jsdom's working implementation,
|
||||
// breaking anything that persists via zustand's `persist` middleware.
|
||||
// Replace both with an in-memory Storage-compatible polyfill.
|
||||
class InMemoryStorage implements Storage {
|
||||
private store = new Map<string, string>();
|
||||
get length(): number {
|
||||
return this.store.size;
|
||||
}
|
||||
clear(): void {
|
||||
this.store.clear();
|
||||
}
|
||||
getItem(key: string): string | null {
|
||||
return this.store.has(key) ? this.store.get(key)! : null;
|
||||
}
|
||||
key(index: number): string | null {
|
||||
return Array.from(this.store.keys())[index] ?? null;
|
||||
}
|
||||
removeItem(key: string): void {
|
||||
this.store.delete(key);
|
||||
}
|
||||
setItem(key: string, value: string): void {
|
||||
this.store.set(key, String(value));
|
||||
}
|
||||
}
|
||||
for (const name of ['localStorage', 'sessionStorage'] as const) {
|
||||
Object.defineProperty(globalThis, name, {
|
||||
value: new InMemoryStorage(),
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Polyfill ClipboardItem for jsdom (not included in jsdom)
|
||||
if (typeof ClipboardItem === 'undefined') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
||||
Reference in New Issue
Block a user