f435d48399
- auth_error.rs:枚举改为 newtype 变体,每个变体持有一个同名 `#[ts(export)]` 载荷结构体
- auth_session.rs:41 处构造点改为 `ClientAuthError::X(X { .. })` 并导入载荷类型
- 重新生成 services/generated:ClientAuthError.ts 变成 `{ type } & 具名类型`,新增 19 个载荷类型文件
- tests/clientAuthError.test.ts:新增编译期用例,switch (error.type) 分支里错误窄化成具名载荷类型
78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { isClientAuthError } from '../src/services/clientAuthError';
|
|
import type { AuthServiceUnavailable } from '../src/services/generated/AuthServiceUnavailable';
|
|
import type { ClientAuthError } from '../src/services/generated/ClientAuthError';
|
|
import type { PhoneNumberInvalid } from '../src/services/generated/PhoneNumberInvalid';
|
|
|
|
/**
|
|
* 编译期用例:每个变体在 `type` 上判别后都能落到一个**具名载荷类型**,
|
|
* 等价于 Java 的 `catch (PhoneNumberInvalid e)`;类型不匹配时 `tsc` 会直接报错。
|
|
*/
|
|
function handleByNamedType(error: ClientAuthError) {
|
|
switch (error.type) {
|
|
case 'phoneNumberInvalid': {
|
|
const payload: PhoneNumberInvalid = error;
|
|
return payload.message;
|
|
}
|
|
case 'authServiceUnavailable': {
|
|
const payload: AuthServiceUnavailable = error;
|
|
return `${payload.status}:${payload.message}`;
|
|
}
|
|
default:
|
|
return '';
|
|
}
|
|
}
|
|
|
|
describe('AGC 认证命令错误的形状读取', () => {
|
|
it('判别后按具名载荷类型分支处理', () => {
|
|
expect(
|
|
handleByNamedType({
|
|
type: 'phoneNumberInvalid',
|
|
message: '请输入正确的手机号',
|
|
}),
|
|
).toBe('请输入正确的手机号');
|
|
expect(
|
|
handleByNamedType({
|
|
type: 'authServiceUnavailable',
|
|
status: 503,
|
|
message: '登录服务暂时不可用',
|
|
}),
|
|
).toBe('503:登录服务暂时不可用');
|
|
});
|
|
|
|
it('只按形状读取 Rust 的结构化拒绝,裸字符串与 Error 都不算', () => {
|
|
expect(
|
|
isClientAuthError({
|
|
type: 'phoneOrPasswordMismatch',
|
|
message: '手机号或密码错误',
|
|
}),
|
|
).toEqual({ type: 'phoneOrPasswordMismatch', message: '手机号或密码错误' });
|
|
expect(isClientAuthError('手机号或密码错误')).toBeNull();
|
|
expect(isClientAuthError(new Error('手机号或密码错误'))).toBeNull();
|
|
expect(
|
|
isClientAuthError({ type: '', message: '手机号或密码错误' }),
|
|
).toBeNull();
|
|
expect(isClientAuthError({ type: 'phoneNumberInvalid' })).toBeNull();
|
|
expect(isClientAuthError(null)).toBeNull();
|
|
});
|
|
|
|
it('未知变体也算形状合法,由调用方按 default 交给错误池', () => {
|
|
expect(
|
|
isClientAuthError({ type: 'brandNewRejection', message: '新变体' }),
|
|
).toEqual({ type: 'brandNewRejection', message: '新变体' });
|
|
});
|
|
|
|
it('status 故意不校验:缺 status 但 message 可用的拒绝仍可读', () => {
|
|
expect(
|
|
isClientAuthError({
|
|
type: 'authServiceUnavailable',
|
|
message: '登录服务暂时不可用',
|
|
}),
|
|
).toEqual({
|
|
type: 'authServiceUnavailable',
|
|
message: '登录服务暂时不可用',
|
|
});
|
|
});
|
|
});
|