收口前端平台组件库能力

新增 PlatformUiKit 通用弹窗、按钮、状态、空态、媒体、表单和标签等公共组件
迁移结果页、创作工作台、认证入口、RPG 暗色面板和运行态弹窗的重复 UI chrome
补充组件测试、页面回归测试、技术文档和 Hermes 共享决策记录
This commit is contained in:
2026-06-10 10:24:18 +08:00
parent a4ee6ff698
commit 1ad25e30f8
226 changed files with 23364 additions and 7825 deletions

View File

@@ -54,12 +54,14 @@ vi.mock('../../services/authService', () => ({
getCurrentAuthUser: authMocks.getCurrentAuthUser,
getAuthSessions: authMocks.getAuthSessions,
getCaptchaChallengeFromError: vi.fn(() => null),
isWechatMiniProgramWebViewRuntime: authMocks.isWechatMiniProgramWebViewRuntime,
isWechatMiniProgramWebViewRuntime:
authMocks.isWechatMiniProgramWebViewRuntime,
liftAuthRiskBlock: vi.fn(),
loginWithPhoneCode: authMocks.loginWithPhoneCode,
logoutAllAuthSessions: authMocks.logoutAllAuthSessions,
logoutAuthUser: authMocks.logoutAuthUser,
requestWechatMiniProgramPhoneLogin: authMocks.requestWechatMiniProgramPhoneLogin,
requestWechatMiniProgramPhoneLogin:
authMocks.requestWechatMiniProgramPhoneLogin,
redeemRegistrationInviteCode: authMocks.redeemRegistrationInviteCode,
resetPassword: authMocks.resetPassword,
revokeAuthSessions: authMocks.revokeAuthSessions,
@@ -440,7 +442,9 @@ test('auth gate uses mini program auth bridge instead of opening login modal in
await user.click(await screen.findByRole('button', { name: '进入作品' }));
await waitFor(() => {
expect(authMocks.requestWechatMiniProgramPhoneLogin).toHaveBeenCalledTimes(1);
expect(authMocks.requestWechatMiniProgramPhoneLogin).toHaveBeenCalledTimes(
1,
);
});
expect(authMocks.startWechatLogin).not.toHaveBeenCalled();
expect(screen.queryByRole('dialog', { name: '账号入口' })).toBeNull();
@@ -476,9 +480,7 @@ test('login modal requires first-time legal consent before sms login', async ()
await user.click(
within(dialog).getByRole('button', { name: '《用户协议》' }),
);
expect(
await screen.findByRole('dialog', { name: '用户协议' }),
).toBeTruthy();
expect(await screen.findByRole('dialog', { name: '用户协议' })).toBeTruthy();
await user.click(screen.getByRole('button', { name: '我知道了' }));
expect(legalSwitch.getAttribute('aria-checked')).toBe('false');
@@ -849,6 +851,14 @@ test('auth gate separates sms and password login by tabs', async () => {
.getByRole('tab', { name: '短信登录' })
.getAttribute('aria-selected'),
).toBe('true');
expect(
within(dialog)
.getByRole('tab', { name: '短信登录' })
.className.includes('h-12'),
).toBe(true);
expect(
within(dialog).getByRole('tablist', { name: '登录方式' }).className,
).toContain('bg-transparent');
expect(within(dialog).queryByLabelText('密码')).toBeNull();
await user.click(within(dialog).getByRole('tab', { name: '密码登录' }));
@@ -903,7 +913,9 @@ test('auth gate revokes merged session group and refreshes sessions', async () =
const accountDialog = await screen.findByRole('dialog', {
name: '账号信息',
});
await user.click(within(accountDialog).getByRole('button', { name: '踢下线' }));
await user.click(
within(accountDialog).getByRole('button', { name: '踢下线' }),
);
await waitFor(() => {
expect(authMocks.revokeAuthSessions).toHaveBeenCalledWith([
@@ -945,7 +957,10 @@ test('auth gate clears account state after password change', async () => {
const passwordDialog = await screen.findByRole('dialog', {
name: '修改登录密码',
});
await user.type(within(passwordDialog).getByLabelText('当前密码'), 'oldpass1');
await user.type(
within(passwordDialog).getByLabelText('当前密码'),
'oldpass1',
);
await user.type(within(passwordDialog).getByLabelText('新密码'), 'newpass1');
await user.click(
within(passwordDialog).getByRole('button', { name: '确认修改密码' }),