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