134 lines
4.0 KiB
TypeScript
134 lines
4.0 KiB
TypeScript
import type { Mock } from 'jest-mock';
|
|
|
|
// ---- Mocks you can tweak per test ----
|
|
const createResponseMock = jest.fn();
|
|
const getLatestResponseTimeMock = jest.fn();
|
|
const getLatestUniqueAnalysResponsesMock = jest.fn();
|
|
const parsePersonalCodeMock = jest.fn(() => ({ gender: { value: 'male' } }));
|
|
|
|
// Mock OpenAI SDK
|
|
jest.mock('openai', () => {
|
|
return {
|
|
__esModule: true,
|
|
default: class OpenAI {
|
|
responses = { create: createResponseMock };
|
|
},
|
|
};
|
|
});
|
|
|
|
// Mock next/cache (global cache map so it persists between calls)
|
|
const globalCache = new Map<string, unknown>();
|
|
jest.mock('next/cache', () => {
|
|
return {
|
|
__esModule: true,
|
|
unstable_cache:
|
|
(fn: (...args: any[]) => Promise<any>, keyParts: any[], _opts?: any) =>
|
|
async (...args: any[]) => {
|
|
const key = JSON.stringify(keyParts);
|
|
if (globalCache.has(key)) return globalCache.get(key);
|
|
const val = await fn(...args);
|
|
globalCache.set(key, val);
|
|
return val;
|
|
},
|
|
};
|
|
});
|
|
|
|
// Mock your analysis helpers + personal code parser
|
|
jest.mock('../src/analysis-utils', () => ({
|
|
__esModule: true,
|
|
getLatestUniqueAnalysResponses: getLatestUniqueAnalysResponsesMock,
|
|
getLatestResponseTime: getLatestResponseTimeMock,
|
|
}));
|
|
jest.mock('../src/personal-code', () => ({
|
|
__esModule: true,
|
|
PersonalCode: { parsePersonalCode: parsePersonalCodeMock },
|
|
}));
|
|
|
|
describe('loadRecommendations', () => {
|
|
beforeEach(() => {
|
|
createResponseMock.mockReset();
|
|
getLatestResponseTimeMock.mockReset();
|
|
getLatestUniqueAnalysResponsesMock.mockReset();
|
|
globalCache.clear();
|
|
});
|
|
|
|
it('should call OpenAI once when latest date stays the same (cache hit on 2nd call)', async () => {
|
|
const date1 = new Date('2025-09-16T12:00:00Z');
|
|
getLatestResponseTimeMock.mockReturnValue(date1);
|
|
getLatestUniqueAnalysResponsesMock.mockImplementation((arr: any[]) => arr);
|
|
|
|
createResponseMock.mockResolvedValue({
|
|
output_text: JSON.stringify({ recommended: ['A', 'B'] }),
|
|
});
|
|
|
|
const { loadRecommendations } = await import('./load-recommendations');
|
|
|
|
const analysisResponses = [
|
|
{ name: 'x', value: 1, responseTime: date1 },
|
|
] as any[];
|
|
const analyses = [{ title: 't', description: 'd' }] as any[];
|
|
const account = { id: 'u1', personal_code: '12345678901' } as any;
|
|
|
|
// Act: 1st call (MISS)
|
|
const out1 = await loadRecommendations(
|
|
analysisResponses,
|
|
analyses,
|
|
account,
|
|
);
|
|
|
|
// Act: 2nd call with same date (HIT)
|
|
const out2 = await loadRecommendations(
|
|
analysisResponses,
|
|
analyses,
|
|
account,
|
|
);
|
|
|
|
// Assert: only one API call, result reused
|
|
expect(createResponseMock).toHaveBeenCalledTimes(1);
|
|
expect(out1).toEqual(['A', 'B']);
|
|
expect(out2).toEqual(['A', 'B']);
|
|
});
|
|
|
|
it('should call OpenAI again when latest date changes (new cache key)', async () => {
|
|
const date1 = new Date('2025-09-16T12:00:00Z');
|
|
const date2 = new Date('2025-09-17T00:00:00Z');
|
|
|
|
getLatestResponseTimeMock.mockReturnValueOnce(date1);
|
|
getLatestResponseTimeMock.mockReturnValueOnce(date2);
|
|
|
|
getLatestUniqueAnalysResponsesMock.mockImplementation((arr: any[]) => arr);
|
|
|
|
createResponseMock
|
|
.mockResolvedValueOnce({
|
|
output_text: JSON.stringify({ recommended: ['A', 'B'] }),
|
|
})
|
|
.mockResolvedValueOnce({
|
|
output_text: JSON.stringify({ recommended: ['C'] }),
|
|
});
|
|
|
|
const { loadRecommendations } = await import('./load-recommendations');
|
|
|
|
const analysisResponses = [
|
|
{ name: 'x', value: 1, responseTime: date1 },
|
|
] as any[];
|
|
const analyses = [{ title: 't', description: 'd' }] as any[];
|
|
const account = { id: 'u1', personal_code: '12345678901' } as any;
|
|
|
|
const out1 = await loadRecommendations(
|
|
analysisResponses,
|
|
analyses,
|
|
account,
|
|
);
|
|
|
|
const out2 = await loadRecommendations(
|
|
analysisResponses,
|
|
analyses,
|
|
account,
|
|
);
|
|
|
|
expect(createResponseMock).toHaveBeenCalledTimes(2);
|
|
expect(out1).toEqual(['A', 'B']);
|
|
expect(out2).toEqual(['C']);
|
|
});
|
|
});
|