import React from 'react'; import '@testing-library/jest-dom'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { ConfirmProvider } from './confirm'; import { PromptProvider } from './prompt'; import { ToastProvider } from './toast'; import { I18nProvider } from './i18n/I18nProvider'; import JobDetailsDialog from './components/JobDetailsDialog'; import { api } from './api'; jest.setTimeout(15000); jest.mock('./api', () => ({ api: { get: jest.fn(), post: jest.fn(() => Promise.resolve({ data: {} })), put: jest.fn(() => Promise.resolve({ data: {} })), patch: jest.fn(() => Promise.resolve({ data: {} })), delete: jest.fn(() => Promise.resolve({ data: {} })), interceptors: { request: { use: jest.fn() }, response: { use: jest.fn() } }, }, getApiErrorMessage: jest.fn(() => 'error'), })); const mockedApi = api as jest.Mocked; function renderDialog() { return render( {}} /> , ); } beforeEach(() => { mockedApi.get.mockImplementation((url: string) => { if (url === '/jobapplications/42') { return Promise.resolve({ data: { id: 42, jobTitle: 'Backend Developer', status: 'Applied', dateApplied: new Date().toISOString(), daysSince: 3, company: { name: 'Acme' } } } as any); } if (url === '/jobapplications/42/status-suggestion') { return Promise.resolve({ data: { hasSuggestion: true, suggestedStatus: 'Interview', currentStatus: 'Applied', signal: 'schedule an interview', confidence: 'medium' } } as any); } if (url === '/auth/me') return Promise.resolve({ data: { roles: [] } } as any); if (url === '/jobapplications/42/history') return Promise.resolve({ data: [] } as any); if (url === '/attachments/42') return Promise.resolve({ data: [] } as any); return Promise.resolve({ data: {} } as any); }); }); afterEach(() => { jest.clearAllMocks(); }); test('status suggestion banner appears and applies via PATCH', async () => { renderDialog(); expect(await screen.findByText(/looks like a move to interview/i)).toBeInTheDocument(); fireEvent.click(await screen.findByRole('button', { name: /move to interview/i })); await waitFor(() => { expect(mockedApi.patch).toHaveBeenCalledWith('/jobapplications/42/status', { status: 'Interview' }); }); }); test('no banner when there is no suggestion', async () => { mockedApi.get.mockImplementation((url: string) => { if (url === '/jobapplications/42') { return Promise.resolve({ data: { id: 42, jobTitle: 'Backend Developer', status: 'Applied', dateApplied: new Date().toISOString(), daysSince: 3, company: { name: 'Acme' } } } as any); } if (url === '/jobapplications/42/status-suggestion') { return Promise.resolve({ data: { hasSuggestion: false } } as any); } if (url === '/auth/me') return Promise.resolve({ data: { roles: [] } } as any); if (url === '/jobapplications/42/history') return Promise.resolve({ data: [] } as any); if (url === '/attachments/42') return Promise.resolve({ data: [] } as any); return Promise.resolve({ data: {} } as any); }); renderDialog(); expect(await screen.findByText(/backend developer/i)).toBeInTheDocument(); expect(screen.queryByText(/looks like a move to/i)).not.toBeInTheDocument(); });