go
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
// 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';
|
||||
@@ -30,7 +30,7 @@ describe('FlyerCorrectionTool', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Mock global fetch for fetching the image blob
|
||||
// Mock global fetch for fetching the image blob inside the component
|
||||
global.fetch = vi.fn(() =>
|
||||
Promise.resolve(new Response(new Blob(['dummy-image-content'], { type: 'image/jpeg' })))
|
||||
) as Mocked<typeof fetch>;
|
||||
@@ -42,6 +42,8 @@ describe('FlyerCorrectionTool', () => {
|
||||
clearRect: vi.fn(),
|
||||
strokeRect: vi.fn(),
|
||||
setLineDash: vi.fn(),
|
||||
strokeStyle: '',
|
||||
lineWidth: 0,
|
||||
} as unknown as CanvasRenderingContext2D;
|
||||
}
|
||||
return null;
|
||||
@@ -63,10 +65,8 @@ describe('FlyerCorrectionTool', () => {
|
||||
|
||||
it('should call onClose when the close button is clicked', () => {
|
||||
render(<FlyerCorrectionTool {...defaultProps} />);
|
||||
// The close button is an icon-only button inside the dialog header.
|
||||
// We find the dialog, then query within it for the button to be more specific.
|
||||
const dialog = screen.getByRole('dialog');
|
||||
fireEvent.click(dialog.querySelector('button')!); // Assumes the first button in the dialog is the close button.
|
||||
// Use the specific aria-label defined in the component
|
||||
fireEvent.click(screen.getByRole('button', { name: /close correction tool/i }));
|
||||
expect(defaultProps.onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -92,14 +92,18 @@ describe('FlyerCorrectionTool', () => {
|
||||
it('should call rescanImageArea with correct parameters and show success', async () => {
|
||||
mockedAiApiClient.rescanImageArea.mockResolvedValue(new Response(JSON.stringify({ text: 'Super Store' })));
|
||||
render(<FlyerCorrectionTool {...defaultProps} />);
|
||||
|
||||
// Wait for the image fetch to complete to ensure 'imageFile' state is populated
|
||||
await waitFor(() => expect(global.fetch).toHaveBeenCalledWith(defaultProps.imageUrl));
|
||||
|
||||
const canvas = screen.getByRole('dialog').querySelector('canvas')!;
|
||||
const image = screen.getByAltText('Flyer for correction');
|
||||
|
||||
// Mock image dimensions for coordinate scaling
|
||||
Object.defineProperty(image, 'naturalWidth', { value: 1000 });
|
||||
Object.defineProperty(image, 'naturalHeight', { value: 800 });
|
||||
Object.defineProperty(image, 'clientWidth', { value: 500 });
|
||||
Object.defineProperty(image, 'clientHeight', { value: 400 });
|
||||
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
|
||||
fireEvent.mouseDown(canvas, { clientX: 10, clientY: 10 });
|
||||
@@ -117,7 +121,8 @@ describe('FlyerCorrectionTool', () => {
|
||||
// Check that coordinates were scaled correctly (e.g., 500 -> 1000 is a 2x scale)
|
||||
expect(mockedAiApiClient.rescanImageArea).toHaveBeenCalledWith(
|
||||
expect.any(File),
|
||||
{ x: 20, y: 20, width: 100, height: 40 }, // 10*2, 10*2, (60-10)*2, (30-10)*2
|
||||
// 10*2=20, 10*2=20, (60-10)*2=100, (30-10)*2=40
|
||||
{ x: 20, y: 20, width: 100, height: 40 },
|
||||
'store_name'
|
||||
);
|
||||
});
|
||||
@@ -132,6 +137,10 @@ describe('FlyerCorrectionTool', () => {
|
||||
it('should show an error notification if rescan fails', async () => {
|
||||
mockedAiApiClient.rescanImageArea.mockRejectedValue(new Error('AI failed'));
|
||||
render(<FlyerCorrectionTool {...defaultProps} />);
|
||||
|
||||
// Wait for image fetch
|
||||
await waitFor(() => expect(global.fetch).toHaveBeenCalled());
|
||||
|
||||
const canvas = screen.getByRole('dialog').querySelector('canvas')!;
|
||||
|
||||
// Draw a selection to enable the button
|
||||
@@ -146,10 +155,19 @@ describe('FlyerCorrectionTool', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should show an error if trying to extract without a selection', () => {
|
||||
it('should show an error if trying to extract without a selection', async () => {
|
||||
render(<FlyerCorrectionTool {...defaultProps} />);
|
||||
// Buttons are disabled, but we can simulate a click for robustness
|
||||
fireEvent.click(screen.getByRole('button', { name: /extract store name/i }));
|
||||
|
||||
// Wait for image fetch to ensure we aren't failing on the missing file check
|
||||
await waitFor(() => expect(global.fetch).toHaveBeenCalled());
|
||||
|
||||
// Buttons are disabled by default, but we force a click to test the handler's validation logic
|
||||
// We need to find the button even if disabled
|
||||
const button = screen.getByRole('button', { name: /extract store name/i });
|
||||
|
||||
// React testing library fires events even on disabled elements, mimicking some DOM behaviors or direct invocation
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(mockedNotifyError).toHaveBeenCalledWith('Please select an area on the image first.');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user