import { describe, expect, it } from 'vitest'; import { classify } from '../src/core/openai'; const res = (status: number, text = '') => ({ status, text }); describe('classify: 2xx', () => { it('returns the text as is', () => { expect(classify(res(200, '{"text":"привет"}'))).toEqual({ ok: true, text: 'привет' }); }); it('returns whitespace-only text unchanged (queue decides "no speech")', () => { expect(classify(res(200, '{"text":" "}'))).toEqual({ ok: true, text: ' ' }); }); it.each(['oops', '{"foo":1}', '{"text":5}', 'null', '[]', '"str"'])( '200 with %s → permanent', (body) => { expect(classify(res(200, body))).toEqual({ ok: false, kind: 'permanent', message: `HTTP 200: ответ без поля text: ${body}`, }); }, ); it('cuts the body to 200 chars', () => { const body = `${'x'.repeat(1000)}`; expect(classify(res(200, body))).toEqual({ ok: false, kind: 'permanent', message: `HTTP 200: ответ без поля text: ${body.slice(0, 200)}`, }); }); it('empty 2xx body → permanent without snippet', () => { expect(classify(res(204, ''))).toEqual({ ok: false, kind: 'permanent', message: 'HTTP 204: ответ без поля text' }); }); }); describe('classify: errors', () => { it.each([301, 302, 399, 400, 401, 403, 404, 413, 415, 422, 499])('%i → permanent', (status) => { expect(classify(res(status, 'x'))).toEqual({ ok: false, kind: 'permanent', message: `HTTP ${status}: x` }); }); it.each([100, 101, 408, 429, 500, 502, 503, 599, 600])('%i → temporary', (status) => { expect(classify(res(status, 'x'))).toEqual({ ok: false, kind: 'temporary', message: `HTTP ${status}: x` }); }); it('takes error.message from an OpenAI-style body', () => { expect(classify(res(401, '{"error":{"message":"Invalid API key"}}'))).toEqual({ ok: false, kind: 'permanent', message: 'HTTP 401: Invalid API key', }); }); it.each(['{"error":{"message":""}}', '{"error":"bad"}', '{"error":null}'])( 'falls back to the body when error.message is unusable: %s', (body) => { expect(classify(res(400, body))).toEqual({ ok: false, kind: 'permanent', message: `HTTP 400: ${body}` }); }, ); it('cuts a plain body to 200 chars after trim', () => { expect(classify(res(500, ` ${'y'.repeat(1000)}`))).toEqual({ ok: false, kind: 'temporary', message: `HTTP 500: ${'y'.repeat(200)}`, }); }); it.each(['', ' \n '])('empty body %j → "HTTP "', (body) => { expect(classify(res(503, body))).toEqual({ ok: false, kind: 'temporary', message: 'HTTP 503' }); }); });