come on ai get it right
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 3m50s
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 3m50s
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
// src/services/aiApiClient.test.ts
|
||||
import { describe, it, expect, vi, beforeEach, beforeAll, afterAll, afterEach } from 'vitest';
|
||||
import { setupServer } from 'msw/node';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
// CRITICAL FIX: Ensure the module under test is NOT mocked.
|
||||
// This prevents Vitest from automocking the module, ensuring we test the
|
||||
// real implementation of functions (e.g. ensuring startVoiceSession actually throws).
|
||||
vi.unmock('./aiApiClient');
|
||||
|
||||
import * as aiApiClient from './aiApiClient';
|
||||
import type { MasterGroceryItem } from '../types';
|
||||
|
||||
@@ -14,11 +21,11 @@ vi.mock('./logger', () => ({
|
||||
}));
|
||||
|
||||
// 2. Mock ./apiClient to simply pass calls through to the global fetch.
|
||||
// This is critical: it removes the complex authentication logic but keeps the
|
||||
// "transport" mechanism intact so MSW can intercept it.
|
||||
// This preserves the "transport" mechanism so MSW can intercept it via network layer.
|
||||
vi.mock('./apiClient', () => ({
|
||||
apiFetchWithAuth: (url: string, options: RequestInit) => {
|
||||
// Ensure relative URLs work in the Node test environment by prepending a dummy host
|
||||
// which matches the host handled by the MSW server below.
|
||||
const fullUrl = url.startsWith('/') ? `http://localhost${url}` : url;
|
||||
return fetch(fullUrl, options);
|
||||
},
|
||||
@@ -28,22 +35,25 @@ vi.mock('./apiClient', () => ({
|
||||
const requestSpy = vi.fn();
|
||||
|
||||
const server = setupServer(
|
||||
// We define a wildcard handler to capture all requests to the AI endpoints
|
||||
// Wildcard handler to capture all POST requests to the AI endpoints
|
||||
http.post('http://localhost/ai/:endpoint', async ({ request, params }) => {
|
||||
let body: any = {};
|
||||
const contentType = request.headers.get('content-type');
|
||||
|
||||
// Parse the body based on content type so we can inspect it in tests
|
||||
// Parse the body based on content type to verify payload
|
||||
if (contentType?.includes('application/json')) {
|
||||
body = await request.json();
|
||||
try {
|
||||
body = await request.json();
|
||||
} catch (e) { /* ignore parse error */ }
|
||||
} else if (contentType?.includes('multipart/form-data')) {
|
||||
// For FormData, we extract entries to verify fields exist
|
||||
const formData = await request.formData();
|
||||
body = Object.fromEntries(formData.entries());
|
||||
body._isFormData = true; // Flag for assertions
|
||||
try {
|
||||
const formData = await request.formData();
|
||||
body = Object.fromEntries(formData.entries());
|
||||
body._isFormData = true;
|
||||
} catch (e) { /* ignore parse error */ }
|
||||
}
|
||||
|
||||
// Capture the details for the test assertion
|
||||
// Capture details for assertions
|
||||
requestSpy({
|
||||
endpoint: params.endpoint,
|
||||
method: request.method,
|
||||
@@ -56,10 +66,13 @@ const server = setupServer(
|
||||
|
||||
describe('AI API Client (Network Mocking with MSW)', () => {
|
||||
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }));
|
||||
|
||||
afterEach(() => {
|
||||
server.resetHandlers();
|
||||
requestSpy.mockClear();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
afterAll(() => server.close());
|
||||
|
||||
describe('isImageAFlyer', () => {
|
||||
@@ -103,8 +116,7 @@ describe('AI API Client (Network Mocking with MSW)', () => {
|
||||
|
||||
expect(req.endpoint).toBe('process-flyer');
|
||||
expect(req.body._isFormData).toBe(true);
|
||||
// FormData.entries() in the mock might conflate multiple files with same key,
|
||||
// checking one exists is sufficient for this transport test.
|
||||
// FormData.entries() might conflate keys, but we check existence
|
||||
expect(req.body.flyerImages).toBeInstanceOf(File);
|
||||
expect(req.body.masterItems).toBe(JSON.stringify(masterItems));
|
||||
});
|
||||
@@ -177,7 +189,7 @@ describe('AI API Client (Network Mocking with MSW)', () => {
|
||||
|
||||
describe('startVoiceSession', () => {
|
||||
it('should throw an error as it is not implemented', () => {
|
||||
// This is a synchronous function that throws immediately, so MSW is not involved.
|
||||
// Because we unmocked the module, this real function will run and throw.
|
||||
expect(() => aiApiClient.startVoiceSession({ onmessage: vi.fn() } as any)).toThrow(
|
||||
'Voice session feature is not fully implemented and requires a backend WebSocket proxy.'
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user