import test from 'node:test'; import assert from 'node:assert/strict'; import { mapLoginResult, mapMeResult, mapUserAccount, mapUserAccountList } from './authUserMap'; import { AuthClient } from './auth'; const snakeAdminUser = { id: 1, username: 'admin', name: '系统管理员', status: 'active', must_change_password: false, role_id: 'role-admin', position: '系统管理员', employee_id: 'SYS-000', department: '系统运维部', created_at: '2026-09-13T00:00:00Z', updated_at: '2026-09-13T00:00:00Z', }; test('mapUserAccount: snake_case Go contract → camelCase', () => { const u = mapUserAccount(snakeAdminUser); assert.equal(u.roleId, 'role-admin'); assert.equal(u.employeeId, 'SYS-000'); assert.equal(u.mustChangePassword, false); assert.equal(u.createdAt, '2026-09-13T00:00:00Z'); assert.equal(u.updatedAt, '2026-09-13T00:00:00Z'); assert.equal(u.username, 'admin'); }); test('mapUserAccount: prefers snake_case when both present', () => { const u = mapUserAccount({ ...snakeAdminUser, roleId: 'role-guest', role_id: 'role-admin', employeeId: 'WRONG', employee_id: 'SYS-000', }); assert.equal(u.roleId, 'role-admin'); assert.equal(u.employeeId, 'SYS-000'); }); test('mapLoginResult/mapMeResult use top-level must_change_password as sole authority', () => { // Nested true must not revive when top-level is false (post password-change cache). const me = mapMeResult({ user: { ...snakeAdminUser, must_change_password: true }, must_change_password: false, env: 'dev', capabilities: [], }); assert.equal(me.mustChangePassword, false); assert.equal(me.user.mustChangePassword, false); const login = mapLoginResult({ token: 'tok-2', user: { ...snakeAdminUser, must_change_password: true }, must_change_password: false, env: 'dev', }); assert.equal(login.mustChangePassword, false); assert.equal(login.user.mustChangePassword, false); }); test('mapUserAccountList maps admin users list', () => { const list = mapUserAccountList([ snakeAdminUser, { id: 2, username: 'eng', name: '工程师', status: 'active', must_change_password: true, role_id: 'role-engineer', position: '助理工程师', employee_id: 'RD-010', department: '研发', created_at: '2026-09-13T01:00:00Z', updated_at: '2026-09-13T01:00:00Z', }, ]); assert.equal(list.length, 2); assert.equal(list[0].roleId, 'role-admin'); assert.equal(list[1].roleId, 'role-engineer'); assert.equal(list[1].mustChangePassword, true); assert.equal(list[1].employeeId, 'RD-010'); }); test('AuthClient.login + fetchMe map real snake_case wire payloads', async () => { const originalFetch = globalThis.fetch; const originalWindow = (globalThis as { window?: unknown }).window; const store: Record = {}; const localStorage = { getItem: (k: string) => store[k] ?? null, setItem: (k: string, v: string) => { store[k] = v; }, removeItem: (k: string) => { delete store[k]; }, }; const mockFetch = (async (input: RequestInfo | URL, init?: RequestInit) => { const url = String(input); if (url.includes('/api/v1/auth/login')) { return new Response( JSON.stringify({ token: 'wire-token', user: snakeAdminUser, must_change_password: false, env: 'dev', }), { status: 200, headers: { 'Content-Type': 'application/json' } }, ); } if (url.includes('/api/v1/auth/me')) { return new Response( JSON.stringify({ user: snakeAdminUser, must_change_password: false, env: 'dev', capabilities: ['admin:manage_users'], }), { status: 200, headers: { 'Content-Type': 'application/json' } }, ); } if (url.includes('/api/v1/admin/users') && (!init?.method || init.method === 'GET')) { return new Response(JSON.stringify({ users: [snakeAdminUser] }), { status: 200, headers: { 'Content-Type': 'application/json' }, }); } return new Response('not found', { status: 404 }); }) as typeof fetch; globalThis.fetch = mockFetch; (globalThis as { window: unknown }).window = { fetch: mockFetch, localStorage }; try { const client = new AuthClient(); const session = await client.login({ username: 'admin', password: 'x' }); assert.equal(session.user.roleId, 'role-admin'); assert.equal(session.user.employeeId, 'SYS-000'); assert.equal(session.mustChangePassword, false); assert.ok(session.capabilities?.includes('admin:manage_users')); const me = await client.fetchMe(); assert.equal(me.user.roleId, 'role-admin'); assert.equal(me.user.employeeId, 'SYS-000'); assert.equal(me.mustChangePassword, false); const users = await client.getAdminUsers(); assert.equal(users[0].roleId, 'role-admin'); assert.equal(users[0].employeeId, 'SYS-000'); } finally { globalThis.fetch = originalFetch; if (originalWindow === undefined) { delete (globalThis as { window?: unknown }).window; } else { (globalThis as { window: unknown }).window = originalWindow; } } });