Spaces:
Sleeping
Sleeping
| // Copyright (c) 2025-2026, RTE (https://www.rte-france.com) | |
| // SPDX-License-Identifier: MPL-2.0 | |
| import { describe, it, expect } from 'vitest'; | |
| import { extractApiError, apiErrorMessage, hasErrorCode } from './apiError'; | |
| describe('extractApiError', () => { | |
| it('reads the unified {detail, code} envelope from an axios error', () => { | |
| const err = { response: { status: 400, data: { detail: 'boom', code: 'BAD_REQUEST' } } }; | |
| expect(extractApiError(err)).toEqual({ message: 'boom', code: 'BAD_REQUEST', status: 400 }); | |
| }); | |
| it('surfaces the ACTION_RESULT_UNAVAILABLE discriminator', () => { | |
| const err = { | |
| response: { status: 400, data: { detail: 'no obs', code: 'ACTION_RESULT_UNAVAILABLE' } }, | |
| }; | |
| expect(hasErrorCode(err, 'ACTION_RESULT_UNAVAILABLE')).toBe(true); | |
| expect(hasErrorCode(err, 'BAD_REQUEST')).toBe(false); | |
| }); | |
| it('flattens a FastAPI 422 detail array into a message', () => { | |
| const err = { | |
| response: { | |
| status: 422, | |
| data: { | |
| code: 'VALIDATION', | |
| detail: [ | |
| { loc: ['body', 'x'], msg: 'field required', type: 'missing' }, | |
| { loc: ['body', 'y'], msg: 'must be int', type: 'int_type' }, | |
| ], | |
| }, | |
| }, | |
| }; | |
| const out = extractApiError(err); | |
| expect(out.code).toBe('VALIDATION'); | |
| expect(out.message).toBe('field required; must be int'); | |
| }); | |
| it('falls back to the axios error message when the body has no detail', () => { | |
| const err = { message: 'Network Error', response: { status: 500, data: {} } }; | |
| expect(apiErrorMessage(err, 'fallback')).toBe('Network Error'); | |
| }); | |
| it('uses the provided fallback when nothing is extractable', () => { | |
| expect(apiErrorMessage({}, 'nothing here')).toBe('nothing here'); | |
| }); | |
| it('handles a plain Error', () => { | |
| expect(apiErrorMessage(new Error('plain'))).toBe('plain'); | |
| }); | |
| it('surfaces the 409 STUDY_BUSY envelope with its status', () => { | |
| const err = { | |
| response: { | |
| status: 409, | |
| data: { | |
| detail: 'Another study operation is already in progress.', | |
| code: 'STUDY_BUSY', | |
| }, | |
| }, | |
| }; | |
| const out = extractApiError(err); | |
| expect(out.status).toBe(409); | |
| expect(out.code).toBe('STUDY_BUSY'); | |
| expect(hasErrorCode(err, 'STUDY_BUSY')).toBe(true); | |
| }); | |
| it('returns no code when the body omits one (pre-envelope backend)', () => { | |
| const err = { response: { status: 400, data: { detail: 'legacy only' } } }; | |
| const out = extractApiError(err); | |
| expect(out.message).toBe('legacy only'); | |
| expect(out.code).toBeUndefined(); | |
| }); | |
| }); | |