test(import): use MSW route handlers

- replace direct fetch stubs with shared MSW handlers
- keep fetch spying only for request assertions
- cover the shell prefetch with an issues counts handler
This commit is contained in:
Antti Kettunen 2026-05-18 21:30:35 +03:00
parent 7a0548ac94
commit e65ec37c9e
No known key found for this signature in database
GPG key ID: C6B2A3D250359BD7

View file

@ -3,6 +3,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { ShellBridge, ShellPageId } from '@/platform/shell/bridge';
import { HttpResponse, http, server } from '@/test/msw';
import { createAppQueryClient } from '@/app/query-client';
import { AppRouterProvider, createAppRouter } from '@/app/router';
@ -10,13 +11,6 @@ import { AppRouterProvider, createAppRouter } from '@/app/router';
import type { ImportStagingFile } from './-import.types';
import { resetImportWorkflowStore } from './-import.store';
function createResponse(body: unknown, status = 200) {
return new Response(JSON.stringify(body), {
status,
headers: { 'Content-Type': 'application/json' },
});
}
function createShellBridge(overrides: Partial<ShellBridge> = {}): ShellBridge {
return {
getCurrentProfileContext: vi.fn(() => ({ profileId: 2, isAdmin: true })),
@ -83,22 +77,18 @@ describe('import route', () => {
window.SoulSyncWebShellBridge = createShellBridge();
window.showToast = vi.fn();
window.showConfirmDialog = vi.fn(async () => true);
vi.spyOn(globalThis, 'fetch');
vi.stubGlobal(
'fetch',
vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input instanceof Request ? input.url : String(input);
if (url.includes('/api/import/staging/files')) {
return createResponse({
server.use(
http.get('/api/import/staging/files', () => {
return HttpResponse.json({
success: true,
staging_path: '/music/Staging',
files: stagingFilesPayload,
});
}
if (url.includes('/api/import/staging/groups')) {
return createResponse({
}),
http.get('/api/import/staging/groups', () => {
return HttpResponse.json({
success: true,
groups: [
{
@ -109,10 +99,9 @@ describe('import route', () => {
},
],
});
}
if (url.includes('/api/import/staging/suggestions')) {
return createResponse({
}),
http.get('/api/import/staging/suggestions', () => {
return HttpResponse.json({
success: true,
ready: true,
suggestions: [
@ -126,10 +115,9 @@ describe('import route', () => {
},
],
});
}
if (url.includes('/api/import/search/albums')) {
return createResponse({
}),
http.get('/api/import/search/albums', () => {
return HttpResponse.json({
success: true,
albums: [
{
@ -142,18 +130,11 @@ describe('import route', () => {
},
],
});
}
if (url.includes('/api/import/album/match')) {
const body =
input instanceof Request
? ((await input.clone().json()) as Record<string, unknown>)
: (JSON.parse(typeof init?.body === 'string' ? init.body : '{}') as Record<
string,
unknown
>);
}),
http.post('/api/import/album/match', async ({ request }) => {
const body = (await request.json()) as Record<string, unknown>;
albumMatchBodies.push(body);
return createResponse({
return HttpResponse.json({
success: true,
received: body,
album: {
@ -175,27 +156,24 @@ describe('import route', () => {
},
],
});
}
if (url.includes('/api/auto-import/status')) {
return createResponse({
}),
http.get('/api/auto-import/status', () => {
return HttpResponse.json({
success: true,
running: true,
current_status: 'idle',
active_imports: [],
});
}
if (url.includes('/api/auto-import/settings')) {
return createResponse({
}),
http.get('/api/auto-import/settings', () => {
return HttpResponse.json({
success: true,
scan_interval: 60,
confidence_threshold: 0.9,
});
}
if (url.includes('/api/auto-import/results')) {
return createResponse({
}),
http.get('/api/auto-import/results', () => {
return HttpResponse.json({
success: true,
results: [
{
@ -210,10 +188,19 @@ describe('import route', () => {
},
],
});
}
return createResponse({ success: true });
}) as unknown as typeof fetch,
}),
http.get('/api/issues/counts', () => {
return HttpResponse.json({
success: true,
counts: {
open: 0,
in_progress: 0,
resolved: 0,
dismissed: 0,
total: 0,
},
});
}),
);
});
@ -227,9 +214,7 @@ describe('import route', () => {
await waitFor(() =>
expect(getFetchUrls().some((url) => url.includes('/api/import/staging/groups'))).toBe(true),
);
expect(getFetchUrls().some((url) => url.includes('/api/import/staging/suggestions'))).toBe(
true,
);
expect(getFetchUrls().some((url) => url.includes('/api/import/staging/suggestions'))).toBe(true);
expect(window.SoulSyncWebShellBridge?.showReactHost).toHaveBeenCalledWith('import');
expect(window.SoulSyncWebShellBridge?.setActivePageChrome).toHaveBeenCalledWith('import');
});