splitting unit + integration testing apart attempt #1
All checks were successful
Deploy to Web Server flyer-crawler.projectium.com / deploy (push) Successful in 3m44s

This commit is contained in:
2025-12-01 14:39:17 -08:00
parent 7a6fe5fe75
commit f91c575142
4 changed files with 45 additions and 11 deletions

View File

@@ -27,7 +27,7 @@ describe('AnalysisPanel', () => {
mockedAiApiClient.getQuickInsights.mockReset();
mockedAiApiClient.getDeepDiveAnalysis.mockReset();
mockedAiApiClient.searchWeb.mockReset();
mockedAiApiClient.planTripWithMaps.mockReset(); // Corrected function name
mockedAiApiClient.planTripWithMaps.mockReset();
mockedAiApiClient.generateImageFromText.mockReset();
// Mock Geolocation API
@@ -66,7 +66,6 @@ describe('AnalysisPanel', () => {
it('should switch tabs and update the generate button text', () => {
render(<AnalysisPanel flyerItems={mockFlyerItems} store={mockStore} />);
// The tab elements now correctly have the role 'tab', not 'button'.
fireEvent.click(screen.getByRole('tab', { name: /deep dive/i }));
expect(screen.getByRole('button', { name: /generate deep dive/i })).toBeInTheDocument();
});
@@ -152,7 +151,7 @@ describe('AnalysisPanel', () => {
// It does not display a specific error message in the UI in this case.
// The test should verify that no result is displayed and no API call is made.
await waitFor(() => {
expect(mockedAiApiClient.planTripWithMaps).not.toHaveBeenCalled(); // Corrected function name
expect(mockedAiApiClient.planTripWithMaps).not.toHaveBeenCalled();
expect(screen.queryByText(/Please allow location access/i)).not.toBeInTheDocument();
});
});

View File

@@ -1,5 +1,11 @@
// src/services/logger.test.ts
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
// FIX: Explicitly unmock the logger module for this test file.
// This ensures we import the REAL implementation (which calls console.log),
// rather than the global mock defined in setup/unit-setup.ts (which does nothing).
vi.unmock('./logger');
import { logger } from './logger';
describe('Isomorphic Logger', () => {
@@ -31,8 +37,10 @@ describe('Isomorphic Logger', () => {
expect(spies.log).toHaveBeenCalledTimes(1);
// Use stringMatching for the dynamic parts (timestamp, PID)
// Note: In JSDOM/Vitest, process.pid usually exists. If it falls back to 'BROWSER', this regex might need adjustment,
// but the primary failure was 0 calls.
expect(spies.log).toHaveBeenCalledWith(
expect.stringMatching(/\[.+\] \[PID:\d+\] \[INFO\] This is an isomorphic info message/),
expect.stringMatching(/\[.+\] \[.+\] \[INFO\] This is an isomorphic info message/),
data
);
});
@@ -43,7 +51,7 @@ describe('Isomorphic Logger', () => {
expect(spies.warn).toHaveBeenCalledTimes(1);
expect(spies.warn).toHaveBeenCalledWith(
expect.stringMatching(/\[.+\] \[PID:\d+\] \[WARN\] This is an isomorphic warning/)
expect.stringMatching(/\[.+\] \[.+\] \[WARN\] This is an isomorphic warning/)
);
});
@@ -53,7 +61,10 @@ describe('Isomorphic Logger', () => {
logger.error(message, error);
expect(spies.error).toHaveBeenCalledTimes(1);
expect(spies.error).toHaveBeenCalledWith(expect.stringMatching(/\[.+\] \[PID:\d+\] \[ERROR\] An isomorphic error occurred/), error);
expect(spies.error).toHaveBeenCalledWith(
expect.stringMatching(/\[.+\] \[.+\] \[ERROR\] An isomorphic error occurred/),
error
);
});
it('logger.debug should format the message correctly with timestamp, PID, and [DEBUG] prefix', () => {
@@ -61,6 +72,9 @@ describe('Isomorphic Logger', () => {
logger.debug(message, { key: 'value' });
expect(spies.debug).toHaveBeenCalledTimes(1);
expect(spies.debug).toHaveBeenCalledWith(expect.stringMatching(/\[.+\] \[PID:\d+\] \[DEBUG\] Debugging isomorphic data/), { key: 'value' });
expect(spies.debug).toHaveBeenCalledWith(
expect.stringMatching(/\[.+\] \[.+\] \[DEBUG\] Debugging isomorphic data/),
{ key: 'value' }
);
});
});

View File

@@ -78,11 +78,14 @@ const { mockPoolInstance } = vi.hoisted(() => {
return { mockPoolInstance: instance };
});
// Expose the mock instance globally so it can be imported by tests if needed,
// though typically they should import from 'pg' directly.
export { mockPoolInstance };
/**
* Mocks the `pg` module globally.
* We define the MockPool function INSIDE the factory to ensure it remains a standard function.
*/
// 2. Mock 'pg' using the hoisted variables
vi.mock('pg', () => {
console.log('[DEBUG] unit-setup.ts: vi.mock("pg") factory executing');
@@ -115,9 +118,12 @@ vi.mock('@google/generative-ai', () => {
}),
};
return {
GoogleGenerativeAI: vi.fn(() => ({
getGenerativeModel: () => mockGenerativeModel,
})),
// FIX: Use a standard function so it can be called with 'new'
GoogleGenerativeAI: vi.fn(function() {
return {
getGenerativeModel: () => mockGenerativeModel,
};
}),
HarmCategory: {},
HarmBlockThreshold: {},
};
@@ -175,6 +181,21 @@ vi.mock('../../services/apiClient', () => ({
checkPm2Status: vi.fn(),
}));
// FIX: Mock the aiApiClient module as well, which is used by AnalysisPanel
vi.mock('../../services/aiApiClient', () => ({
isImageAFlyer: vi.fn(),
extractAddressFromImage: vi.fn(),
extractCoreDataFromImage: vi.fn(),
extractLogoFromImage: vi.fn(),
getQuickInsights: vi.fn(),
getDeepDiveAnalysis: vi.fn(),
searchWeb: vi.fn(),
planTripWithMaps: vi.fn(),
generateImageFromText: vi.fn(),
generateSpeechFromText: vi.fn(),
startVoiceSession: vi.fn(),
}));
/**
* Mocks the logger.
*/