soulsync/webui/src/platform/shell/bridge.test.ts
Antti Kettunen 30c687ae7b
refactor(webui): cancel similar-artists in route
- expose a shell-bridge cancel primitive for similar-artists loading
- stop stale similar-artists streams from the artist-detail route lifecycle
- keep the legacy loader abort-only and make abort logs page-agnostic
- update bridge and route tests for the new cleanup path
2026-05-19 09:28:05 +03:00

102 lines
3.3 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { ShellProfileContext } from './bridge';
import { SHELL_PROFILE_CONTEXT_CHANGED_EVENT, bindWindowWebRouter, waitForShellContext } from './bridge';
describe('waitForShellContext', () => {
beforeEach(() => {
window.SoulSyncWebShellBridge = undefined;
});
it('resolves immediately when the shell already has a profile', async () => {
window.SoulSyncWebShellBridge = {
getProfileHomePage: vi.fn(() => 'discover'),
isPageAllowed: vi.fn(() => true),
activateLegacyPath: vi.fn(),
getCurrentProfileContext: vi.fn(() => ({ profileId: 2, isAdmin: true })),
resolveLegacyPath: vi.fn(() => 'issues'),
setActivePageChrome: vi.fn(),
cancelSimilarArtistsLoad: vi.fn(),
showReactHost: vi.fn(),
} as NonNullable<typeof window.SoulSyncWebShellBridge>;
await expect(waitForShellContext()).resolves.toEqual({
bridge: window.SoulSyncWebShellBridge,
profile: {
profileId: 2,
isAdmin: true,
},
});
});
it('waits for the legacy shell to publish profile context', async () => {
const getCurrentProfileContext = vi.fn<() => ShellProfileContext | null>(() => null);
window.SoulSyncWebShellBridge = {
getProfileHomePage: vi.fn(() => 'discover'),
isPageAllowed: vi.fn(() => true),
activateLegacyPath: vi.fn(),
getCurrentProfileContext,
resolveLegacyPath: vi.fn(() => 'issues'),
setActivePageChrome: vi.fn(),
cancelSimilarArtistsLoad: vi.fn(),
showReactHost: vi.fn(),
} as NonNullable<typeof window.SoulSyncWebShellBridge>;
const contextPromise = waitForShellContext();
getCurrentProfileContext.mockReturnValue({ profileId: 5, isAdmin: false });
window.dispatchEvent(new CustomEvent(SHELL_PROFILE_CONTEXT_CHANGED_EVENT));
await expect(contextPromise).resolves.toEqual({
bridge: window.SoulSyncWebShellBridge,
profile: {
profileId: 5,
isAdmin: false,
},
});
});
});
describe('bindWindowWebRouter', () => {
it('navigates artist detail pages with source-aware URLs', async () => {
const navigate = vi.fn().mockResolvedValue(undefined);
bindWindowWebRouter({ navigate } as never);
await window.SoulSyncWebRouter?.navigateToPage('artist-detail', {
artistId: '2YZyLoL8N0Wb9xBt1NhZWg',
artistSource: 'spotify',
});
expect(navigate).toHaveBeenCalledWith({
href: '/artist-detail/spotify/2YZyLoL8N0Wb9xBt1NhZWg',
replace: false,
});
});
it('falls back artist detail URLs to library source when none is supplied', async () => {
const navigate = vi.fn().mockResolvedValue(undefined);
bindWindowWebRouter({ navigate } as never);
await window.SoulSyncWebRouter?.navigateToPage('artist-detail', {
artistId: '42',
replace: true,
});
expect(navigate).toHaveBeenCalledWith({
href: '/artist-detail/library/42',
replace: true,
});
});
it('refuses artist detail navigation without an artist id', async () => {
const navigate = vi.fn().mockResolvedValue(undefined);
bindWindowWebRouter({ navigate } as never);
await expect(window.SoulSyncWebRouter?.navigateToPage('artist-detail', {} as never)).resolves.toBe(false);
expect(navigate).not.toHaveBeenCalled();
});
});