fix(auth): различать устаревшего бота и ненастроенного на экране логина

This commit is contained in:
kewldan
2026-07-23 04:09:06 +03:00
parent f04675b249
commit b3b07c322d
9 changed files with 87 additions and 7 deletions

View File

@@ -0,0 +1,59 @@
import { AxiosError, AxiosHeaders } from 'axios';
import { describe, expect, it } from 'vitest';
import { getApiErrorMessage, isEndpointMissingError } from './api-error';
function axiosErrorWithStatus(status: number, detail?: unknown): AxiosError {
const headers = new AxiosHeaders();
const config = { headers };
return new AxiosError(
'Request failed',
'ERR_BAD_REQUEST',
config,
{},
{
status,
statusText: '',
headers,
config,
data: detail === undefined ? {} : { detail },
},
);
}
describe('isEndpointMissingError', () => {
it('returns true for an axios 404', () => {
expect(isEndpointMissingError(axiosErrorWithStatus(404))).toBe(true);
});
it('returns false for other axios statuses', () => {
expect(isEndpointMissingError(axiosErrorWithStatus(403))).toBe(false);
expect(isEndpointMissingError(axiosErrorWithStatus(500))).toBe(false);
});
it('returns false for non-axios errors', () => {
expect(isEndpointMissingError(new Error('boom'))).toBe(false);
expect(isEndpointMissingError(undefined)).toBe(false);
expect(isEndpointMissingError(null)).toBe(false);
});
});
describe('getApiErrorMessage', () => {
it('returns string detail from an axios error', () => {
expect(getApiErrorMessage(axiosErrorWithStatus(400, 'Code must not be empty'), 'fb')).toBe(
'Code must not be empty',
);
});
it('joins pydantic validation errors', () => {
const err = axiosErrorWithStatus(422, [
{ loc: ['body', 'name'], msg: 'field required' },
{ loc: ['body', 'days'], msg: 'must be positive' },
]);
expect(getApiErrorMessage(err, 'fb')).toBe('name: field required; days: must be positive');
});
it('falls back for non-axios errors and missing detail', () => {
expect(getApiErrorMessage(new Error('boom'), 'fb')).toBe('fb');
expect(getApiErrorMessage(axiosErrorWithStatus(500), 'fb')).toBe('fb');
});
});

View File

@@ -1,5 +1,15 @@
import axios from 'axios';
/**
* True when the backend answered 404 on the route itself — for cabinet
* endpoints that means the bot build is too old to have them (e.g. the
* deep-link auth routes exist only since bot v3.33.0), as opposed to a
* missing entity inside a handler.
*/
export function isEndpointMissingError(err: unknown): boolean {
return axios.isAxiosError(err) && err.response?.status === 404;
}
export function getApiErrorMessage(err: unknown, fallback: string): string {
if (axios.isAxiosError(err)) {
const detail = err.response?.data?.detail;