perfect-postcode/frontend/src/lib/auth-errors.test.ts
2026-07-12 15:10:26 +01:00

46 lines
1.8 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import type { TFunction } from 'i18next';
import { resolveAuthError } from './auth-errors';
// Echo the key so we can assert which generic fallback path ran.
const t = ((key: string) => key) as unknown as TFunction;
// All copy resolves through t(); the mock echoes the key, so we assert on keys.
describe('resolveAuthError', () => {
it('maps 429 to a rate-limit message on every flow', () => {
const r = resolveAuthError({ status: 429 }, 'login', t);
expect(r.message).toBe('auth.errorRateLimited');
expect(r.action).toBeNull();
});
it('maps a duplicate-email signup to "email taken" with a log-in affordance', () => {
const err = { status: 400, response: { data: { email: { code: 'validation_not_unique' } } } };
const r = resolveAuthError(err, 'register', t);
expect(r.message).toBe('auth.errorEmailTaken');
expect(r.action).toBe('switchToLogin');
});
it('maps a 400 login failure to invalid credentials (not a raw PB string)', () => {
const r = resolveAuthError({ status: 400 }, 'login', t);
expect(r.message).toBe('auth.errorInvalidCredentials');
expect(r.message).not.toMatch(/Failed to authenticate/);
});
it('maps a weak-password signup', () => {
const err = {
status: 400,
response: { data: { password: { code: 'validation_length_out_of_range' } } },
};
const r = resolveAuthError(err, 'register', t);
expect(r.message).toBe('auth.errorPasswordWeak');
});
it('falls back to the existing generic key for unknown login errors', () => {
expect(resolveAuthError({ status: 500 }, 'login', t).message).toBe('auth.loginFailed');
});
it('treats a missing status as a network error', () => {
const r = resolveAuthError(new Error('boom'), 'login', t);
expect(r.message).toBe('auth.errorNetwork');
});
});