fix(app): harden account and workflow state
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
|
||||
import { api } from './api';
|
||||
import { AccountPlanProvider } from './accountPlan';
|
||||
import { ApplicationStatusSuggestion, ApplicationStrategySnapshot } from './components/ApplicationWorkflowAssist';
|
||||
import { I18nProvider } from './i18n/I18nProvider';
|
||||
import { ToastProvider } from './toast';
|
||||
|
||||
jest.mock('./api', () => ({
|
||||
api: { get: jest.fn(), post: jest.fn(), patch: jest.fn() },
|
||||
getApiErrorMessage: (_error: unknown, fallback?: string) => fallback || 'Request failed.',
|
||||
}));
|
||||
|
||||
const mockedApi = api as jest.Mocked<typeof api>;
|
||||
|
||||
beforeEach(() => jest.clearAllMocks());
|
||||
|
||||
test('recruiter status suggestions require an explicit apply action', async () => {
|
||||
const applied = jest.fn();
|
||||
mockedApi.get.mockResolvedValue({ data: { hasSuggestion: true, currentStatus: 'Applied', suggestedStatus: 'Interview' } } as any);
|
||||
mockedApi.patch.mockResolvedValue({ data: {} } as any);
|
||||
render(<ToastProvider><ApplicationStatusSuggestion jobId={42} onApplied={applied} /></ToastProvider>);
|
||||
|
||||
const button = await screen.findByRole('button', { name: 'Apply Interview' });
|
||||
expect(mockedApi.patch).not.toHaveBeenCalled();
|
||||
fireEvent.click(button);
|
||||
await waitFor(() => expect(mockedApi.patch).toHaveBeenCalledWith('/jobapplications/42/status', { status: 'Interview' }));
|
||||
expect(applied).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('strategy snapshot shows saved output and queues regeneration only on request', async () => {
|
||||
mockedApi.get.mockImplementation((url: string) => {
|
||||
if (url.endsWith('/focus-plan')) return Promise.resolve({ data: {
|
||||
strategicSummary: 'Lead with delivery evidence.',
|
||||
immediatePriorities: ['Tailor the summary'],
|
||||
proofPointsToLeadWith: ['Reduced lead time'],
|
||||
cvBulletIdeas: ['Quantify the migration'],
|
||||
coverLetterAngles: ['Public-service impact'],
|
||||
followUpApproach: ['Follow up after five days'],
|
||||
} } as any);
|
||||
return Promise.reject(new Error('no operation'));
|
||||
});
|
||||
mockedApi.post.mockResolvedValue({ data: {
|
||||
created: true,
|
||||
statusUrl: '/operations/op-1',
|
||||
operation: { id: 'op-1', taskType: 'focus-plan', status: 'queued', createdAtUtc: '', canCancel: true, canRetry: false },
|
||||
} } as any);
|
||||
|
||||
render(<I18nProvider><ToastProvider><AccountPlanProvider value={{ plan: 'pro', canUseAi: true, canUseProThemes: true }}><ApplicationStrategySnapshot jobId={42} /></AccountPlanProvider></ToastProvider></I18nProvider>);
|
||||
expect(await screen.findByText('Lead with delivery evidence.')).toBeInTheDocument();
|
||||
expect(mockedApi.post).not.toHaveBeenCalled();
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Regenerate' }));
|
||||
await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith('/jobapplications/42/focus-plan/operations', { attachmentIds: null }));
|
||||
expect(await screen.findByText('queued')).toBeInTheDocument();
|
||||
});
|
||||
Reference in New Issue
Block a user