one moar time - we can do it?
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 32m32s

This commit is contained in:
2025-12-17 04:49:01 -08:00
parent 1d18646818
commit d3ad50cde6
12 changed files with 482 additions and 235 deletions

View File

@@ -1,10 +1,10 @@
// src/components/FlyerCorrectionTool.test.tsx
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach, type Mocked } from 'vitest';
import { FlyerCorrectionTool } from './FlyerCorrectionTool';
import * as aiApiClient from '../services/aiApiClient';
import { notifySuccess } from '../services/notificationService';
import { notifyError, notifySuccess } from '../services/notificationService';
// Mock dependencies
vi.mock('../services/aiApiClient');
@@ -90,41 +90,60 @@ describe('FlyerCorrectionTool', () => {
});
it('should call rescanImageArea with correct parameters and show success', async () => {
// Mock the response with a slight delay. This ensures the "Processing..."
// state has time to render before the mock resolves, making the test more stable.
mockedAiApiClient.rescanImageArea.mockImplementation(async () => {
await new Promise(r => setTimeout(r, 50)); // 50ms delay
return new Response(JSON.stringify({ text: 'Super Store' }));
console.log('\n--- [TEST LOG] ---: Starting test: "should call rescanImageArea..."');
// 1. Create a controllable promise for the mock.
console.log('--- [TEST LOG] ---: 1. Setting up controllable promise for rescanImageArea.');
let resolveRescanPromise: (value: Response | PromiseLike<Response>) => void;
const rescanPromise = new Promise<Response>(resolve => {
resolveRescanPromise = resolve;
});
mockedAiApiClient.rescanImageArea.mockReturnValue(rescanPromise);
render(<FlyerCorrectionTool {...defaultProps} />);
// Wait for the image fetch to complete to ensure 'imageFile' state is populated
console.log('--- [TEST LOG] ---: Awaiting image fetch inside component...');
await waitFor(() => expect(global.fetch).toHaveBeenCalledWith(defaultProps.imageUrl));
console.log('--- [TEST LOG] ---: Image fetch complete.');
const canvas = screen.getByRole('dialog').querySelector('canvas')!;
const image = screen.getByAltText('Flyer for correction');
// Mock image dimensions for coordinate scaling
console.log('--- [TEST LOG] ---: Mocking image dimensions.');
Object.defineProperty(image, 'naturalWidth', { value: 1000, configurable: true });
Object.defineProperty(image, 'naturalHeight', { value: 800, configurable: true });
Object.defineProperty(image, 'clientWidth', { value: 500, configurable: true });
Object.defineProperty(image, 'clientHeight', { value: 400, configurable: true });
// Simulate drawing a rectangle
console.log('--- [TEST LOG] ---: Simulating user drawing a rectangle...');
fireEvent.mouseDown(canvas, { clientX: 10, clientY: 10 });
fireEvent.mouseMove(canvas, { clientX: 60, clientY: 30 });
fireEvent.mouseUp(canvas);
console.log('--- [TEST LOG] ---: Rectangle drawn.');
// Click the extract button
// 2. Click the extract button, which will trigger the pending promise.
console.log('--- [TEST LOG] ---: 2. Clicking "Extract Store Name" button.');
fireEvent.click(screen.getByRole('button', { name: /extract store name/i }));
// Check for loading state - this should now pass because of the delay
expect(await screen.findByText('Processing...')).toBeInTheDocument();
// 3. Assert the loading state.
try {
console.log('--- [TEST LOG] ---: 3. Awaiting "Processing..." loading state.');
expect(await screen.findByText('Processing...')).toBeInTheDocument();
console.log('--- [TEST LOG] ---: 3a. SUCCESS: Found "Processing..." text.');
} catch (error) {
console.error('--- [TEST LOG] ---: 3a. ERROR: Did not find "Processing..." text.');
screen.debug();
throw error;
}
// 4. Check that the API was called with correctly scaled coordinates.
console.log('--- [TEST LOG] ---: 4. Awaiting API call verification...');
await waitFor(() => {
console.log('--- [TEST LOG] ---: 4a. waitFor check: Checking rescanImageArea call...');
expect(mockedAiApiClient.rescanImageArea).toHaveBeenCalledTimes(1);
// Check that coordinates were scaled correctly (e.g., 500 -> 1000 is a 2x scale)
expect(mockedAiApiClient.rescanImageArea).toHaveBeenCalledWith(
expect.any(File),
// 10*2=20, 10*2=20, (60-10)*2=100, (30-10)*2=40
@@ -132,11 +151,24 @@ describe('FlyerCorrectionTool', () => {
'store_name'
);
});
console.log('--- [TEST LOG] ---: 4b. SUCCESS: API call verified.');
// 5. Resolve the promise.
console.log('--- [TEST LOG] ---: 5. Manually resolving the API promise inside act()...');
await act(async () => {
console.log('--- [TEST LOG] ---: 5a. Calling resolveRescanPromise...');
resolveRescanPromise(new Response(JSON.stringify({ text: 'Super Store' })));
});
console.log('--- [TEST LOG] ---: 5b. Promise resolved and act() block finished.');
// 6. Assert the final state after the promise has resolved.
console.log('--- [TEST LOG] ---: 6. Awaiting final state assertions...');
await waitFor(() => {
console.log('--- [TEST LOG] ---: 6a. waitFor check: Verifying notifications and callbacks...');
expect(mockedNotifySuccess).toHaveBeenCalledWith('Extracted: Super Store');
expect(defaultProps.onDataExtracted).toHaveBeenCalledWith('store_name', 'Super Store');
expect(defaultProps.onClose).toHaveBeenCalledTimes(1);
});
console.log('--- [TEST LOG] ---: 6b. SUCCESS: Final state verified.');
});
});