fix(i18n): restore safe processing label fallbacks for runtime keys
This commit is contained in:
@@ -20,6 +20,32 @@ beforeEach(() => {
|
||||
});
|
||||
afterEach(() => jest.useRealTimers());
|
||||
|
||||
test.each([
|
||||
['en', 'constructor', 'Other operation', 'Unknown', 'Unregistered worker', 'Not recorded'],
|
||||
['en', 'toString', 'Other operation', 'Unknown', 'Unregistered worker', 'Not recorded'],
|
||||
['en', '__proto__', 'Other operation', 'Unknown', 'Unregistered worker', 'Not recorded'],
|
||||
['nb', 'constructor', 'Annen oppgave', 'Ukjent', 'Uregistrert bakgrunnsprosess', 'Ikke registrert'],
|
||||
['nb', 'toString', 'Annen oppgave', 'Ukjent', 'Uregistrert bakgrunnsprosess', 'Ikke registrert'],
|
||||
['nb', '__proto__', 'Annen oppgave', 'Ukjent', 'Uregistrert bakgrunnsprosess', 'Ikke registrert'],
|
||||
])('uses safe %s fallbacks for inherited processing key %s', async (language, key, other, unknown, unregistered, notRecorded) => {
|
||||
localStorage.setItem('uiLanguage', language);
|
||||
const unknownItem = { ...item, taskType: key, status: key, stage: key };
|
||||
get.mockImplementation((url: string) => Promise.resolve({ data: url.includes('/events')
|
||||
? { items: [{ id: '1', kind: key, status: key, stage: key, attempt: 1, failureCode: null, atUtc: item.createdAtUtc }], hasMore: false, retentionDays: 30 }
|
||||
: url.includes(item.id) ? unknownItem
|
||||
: { ...listing, items: [unknownItem], counts: { [key]: 1 }, workers: [{ ...listing.workers[0], name: key }] } }));
|
||||
open();
|
||||
const details = await screen.findByText(other, { selector: 'button' });
|
||||
expect(screen.getByText(`${unknown}: 1`)).toBeVisible();
|
||||
const workerLabel = screen.getByText(new RegExp(`^${unregistered}:`));
|
||||
fireEvent.click(workerLabel.closest('details')!.querySelector('summary')!);
|
||||
expect(workerLabel).toBeVisible();
|
||||
fireEvent.click(details);
|
||||
const events = await screen.findByRole('list');
|
||||
expect(events).toHaveTextContent(`${unknown} · ${unknown}`);
|
||||
expect(events).toHaveTextContent(notRecorded);
|
||||
});
|
||||
|
||||
test('shows safe job metadata and real events with a copyable correlation ID', async () => {
|
||||
open();
|
||||
expect(await screen.findByText('Synthetic owner')).toBeVisible();
|
||||
|
||||
@@ -19,11 +19,11 @@ type Item = {
|
||||
type Listing = { items: Item[]; total: number; counts: Record<string, number>; workers: { name: string; flagEnabled: boolean; individualOperationsRecorded: boolean }[] };
|
||||
type Event = { id: string; atUtc: string; kind: string; status: string; stage: string | null; attempt: number; failureCode: string | null };
|
||||
type Events = { items: Event[]; hasMore: boolean; retentionDays: number };
|
||||
const statuses: Record<string, TranslationKey> = { queued: 'operationsStatusQueued', running: 'operationsStatusRunning', waiting_for_retry: 'operationsStatusWaitingForRetry', waiting_for_external_fallback: 'operationsStatusWaitingForFallback', succeeded: 'operationsStatusSucceeded', failed: 'operationsStatusFailed', cancelled: 'operationsStatusCancelled' };
|
||||
const tasks: Record<string, TranslationKey> = { 'cv.process': 'operationsTaskCv', 'strategy.snapshot': 'operationsTaskStrategy' };
|
||||
const stages: Record<string, TranslationKey> = { cv_validating_file: 'cvImportStageValidating', cv_extracting: 'cvImportStageExtracting', cv_identifying_sections: 'cvImportStageSections', cv_analysing: 'cvImportStageAnalysing', cv_validating_details: 'cvImportStageDetails', cv_preparing_review: 'cvImportStagePreparing', cv_review_ready: 'cvImportStageReady' };
|
||||
const kinds: Record<string, TranslationKey> = { Created: 'processingEventCreated', Claimed: 'processingEventClaimed', StageChanged: 'processingEventStageChanged', Completed: 'processingEventCompleted', RetryScheduled: 'processingEventRetryScheduled', Failed: 'processingEventFailed', CancellationRequested: 'processingEventCancellationRequested', Cancelled: 'processingEventCancelled', Retried: 'processingEventRetried', LeaseRecovered: 'processingEventLeaseRecovered', Expired: 'processingEventExpired' };
|
||||
const workers: Record<string, TranslationKey> = { AiOperations: 'processingWorkerAi', CvDocumentImports: 'processingWorkerDocument', JobEnrichment: 'processingWorkerEnrichment', Rules: 'processingWorkerRules', FollowUpReminders: 'processingWorkerReminders', DailyExport: 'processingWorkerExport', SavedJobSearchAlerts: 'processingWorkerSearch' };
|
||||
const statuses: Record<string, TranslationKey> = Object.assign(Object.create(null), { queued: 'operationsStatusQueued', running: 'operationsStatusRunning', waiting_for_retry: 'operationsStatusWaitingForRetry', waiting_for_external_fallback: 'operationsStatusWaitingForFallback', succeeded: 'operationsStatusSucceeded', failed: 'operationsStatusFailed', cancelled: 'operationsStatusCancelled' });
|
||||
const tasks: Record<string, TranslationKey> = Object.assign(Object.create(null), { 'cv.process': 'operationsTaskCv', 'strategy.snapshot': 'operationsTaskStrategy' });
|
||||
const stages: Record<string, TranslationKey> = Object.assign(Object.create(null), { cv_validating_file: 'cvImportStageValidating', cv_extracting: 'cvImportStageExtracting', cv_identifying_sections: 'cvImportStageSections', cv_analysing: 'cvImportStageAnalysing', cv_validating_details: 'cvImportStageDetails', cv_preparing_review: 'cvImportStagePreparing', cv_review_ready: 'cvImportStageReady' });
|
||||
const kinds: Record<string, TranslationKey> = Object.assign(Object.create(null), { Created: 'processingEventCreated', Claimed: 'processingEventClaimed', StageChanged: 'processingEventStageChanged', Completed: 'processingEventCompleted', RetryScheduled: 'processingEventRetryScheduled', Failed: 'processingEventFailed', CancellationRequested: 'processingEventCancellationRequested', Cancelled: 'processingEventCancelled', Retried: 'processingEventRetried', LeaseRecovered: 'processingEventLeaseRecovered', Expired: 'processingEventExpired' });
|
||||
const workers: Record<string, TranslationKey> = Object.assign(Object.create(null), { AiOperations: 'processingWorkerAi', CvDocumentImports: 'processingWorkerDocument', JobEnrichment: 'processingWorkerEnrichment', Rules: 'processingWorkerRules', FollowUpReminders: 'processingWorkerReminders', DailyExport: 'processingWorkerExport', SavedJobSearchAlerts: 'processingWorkerSearch' });
|
||||
const failureCodes = ['timeout', 'lease_expired', 'deadline_exceeded', 'entitlement_changed', 'document_unavailable', 'sidecar_unavailable', 'upstream_unavailable', 'invalid_response', 'circuit_open', 'rate_limited', 'permission_denied', 'cancelled', 'upload_rejected', 'parser_failed', 'malformed_output', 'provider_unavailable', 'processing_failed'];
|
||||
|
||||
export default function AdminProcessingPage() {
|
||||
|
||||
Reference in New Issue
Block a user