Update spacetime-client bindings and frontend
Large update across server and web clients: regenerated/added many spacetime-client module bindings and input types (including new delete/work_delete input types and numerous procedure/reducer files), updates to server-rs API modules (bark_battle, jump_hop, wooden_fish, auth, module-runtime and shared contracts), and fixes in module-runtime behavior and domain logic. Frontend changes include new/updated components and tests (creative audio helpers, bark-battle/jump-hop/wooden-fish clients and views, unified generation pages, RPG entry views, and runtime shells), plus CSS and service updates. Documentation and operational notes updated (.hermes pitfalls and multiple PRD/docs) to cover daily-task refresh, banner asset fallback, recommend-key bug, and other platform behaviors. Tests and verification steps added/updated alongside these changes.
This commit is contained in:
@@ -17,10 +17,12 @@ const baseUser: AuthUser = {
|
||||
displayName: '138****8000',
|
||||
avatarUrl: null,
|
||||
publicUserCode: 'user-tester',
|
||||
phoneNumber: '13800138000',
|
||||
phoneNumberMasked: '138****8000',
|
||||
loginMethod: 'phone',
|
||||
bindingStatus: 'active',
|
||||
wechatBound: true,
|
||||
wechatAccount: 'wx-openid-bind-001',
|
||||
};
|
||||
|
||||
function renderAccountModal(overrides?: {
|
||||
@@ -112,6 +114,10 @@ test('settings header uses a generic title instead of the phone number', () => {
|
||||
expect(screen.queryByText('当前主题')).toBeNull();
|
||||
expect(screen.queryByRole('button', { name: '退出登录' })).toBeNull();
|
||||
expect(screen.queryByRole('button', { name: '退出全部设备' })).toBeNull();
|
||||
expect(screen.getByRole('button', { name: /主题设置/u })).toBeTruthy();
|
||||
expect(screen.getByRole('button', { name: /账号与安全/u })).toBeTruthy();
|
||||
expect(screen.queryByRole('button', { name: /主题外观/u })).toBeNull();
|
||||
expect(screen.queryByRole('button', { name: /账号信息/u })).toBeNull();
|
||||
});
|
||||
|
||||
test('direct account entry does not render the settings shell as another dialog', () => {
|
||||
@@ -129,12 +135,52 @@ test('direct account entry does not render the settings shell as another dialog'
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('account panel uses compact binding cards and keeps logout actions at the bottom', () => {
|
||||
renderAccountModal({ entryMode: 'account' });
|
||||
|
||||
const accountDialog = screen.getByRole('dialog', { name: '账号信息' });
|
||||
expect(within(accountDialog).getByText('账号信息')).toBeTruthy();
|
||||
expect(within(accountDialog).queryByText('身份信息')).toBeNull();
|
||||
expect(
|
||||
within(accountDialog).queryByText(
|
||||
'统一查看身份、安全状态、登录设备与最近操作。',
|
||||
),
|
||||
).toBeNull();
|
||||
expect(within(accountDialog).queryByText('登录方式')).toBeNull();
|
||||
expect(within(accountDialog).getByText('绑定手机号')).toBeTruthy();
|
||||
expect(within(accountDialog).getByText('13800138000')).toBeTruthy();
|
||||
expect(within(accountDialog).queryByText('138****8000')).toBeNull();
|
||||
expect(within(accountDialog).getByText('绑定微信')).toBeTruthy();
|
||||
expect(within(accountDialog).getByText('wx-openid-bind-001')).toBeTruthy();
|
||||
|
||||
const compactCards = accountDialog.querySelectorAll(
|
||||
'[data-account-binding-card]',
|
||||
);
|
||||
expect(compactCards).toHaveLength(2);
|
||||
expect(
|
||||
within(compactCards[0] as HTMLElement).getByRole('button', {
|
||||
name: '更换手机号',
|
||||
}),
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
within(compactCards[1] as HTMLElement).getByRole('button', {
|
||||
name: '更换微信号',
|
||||
}),
|
||||
).toBeTruthy();
|
||||
|
||||
const accountContent =
|
||||
accountDialog.querySelector('[data-account-content]') ?? accountDialog;
|
||||
expect(
|
||||
accountContent.lastElementChild?.getAttribute('data-account-actions'),
|
||||
).toBe('true');
|
||||
});
|
||||
|
||||
test('account actions open in independent panels instead of inline expansion', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderAccountModal();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /账号信息/ }));
|
||||
await user.click(screen.getByRole('button', { name: /账号与安全/ }));
|
||||
|
||||
const accountDialog = screen.getByRole('dialog', { name: '账号信息' });
|
||||
expect(accountDialog).toBeTruthy();
|
||||
@@ -162,7 +208,7 @@ test('nested settings panels keep back navigation without an extra close action'
|
||||
|
||||
renderAccountModal();
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /账号信息/ }));
|
||||
await user.click(screen.getByRole('button', { name: /账号与安全/ }));
|
||||
|
||||
const accountDialog = screen.getByRole('dialog', { name: '账号信息' });
|
||||
const accountHeader = accountDialog.firstElementChild as HTMLElement | null;
|
||||
@@ -201,7 +247,7 @@ test('settings overlays move focus away from inert triggers and restore it on ba
|
||||
|
||||
renderAccountModal();
|
||||
|
||||
const accountTrigger = screen.getByRole('button', { name: /账号信息/ });
|
||||
const accountTrigger = screen.getByRole('button', { name: /账号与安全/ });
|
||||
expect(document.activeElement).not.toBe(accountTrigger);
|
||||
|
||||
await user.click(accountTrigger);
|
||||
@@ -283,7 +329,7 @@ test('account panel includes merged security devices and audit sections', async
|
||||
],
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /账号信息/ }));
|
||||
await user.click(screen.getByRole('button', { name: /账号与安全/ }));
|
||||
|
||||
const accountDialog = screen.getByRole('dialog', { name: '账号信息' });
|
||||
expect(within(accountDialog).getByText('安全状态')).toBeTruthy();
|
||||
@@ -324,7 +370,7 @@ test('current merged session group hides kick action and shows count', async ()
|
||||
],
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /账号信息/ }));
|
||||
await user.click(screen.getByRole('button', { name: /账号与安全/ }));
|
||||
|
||||
const accountDialog = screen.getByRole('dialog', { name: '账号信息' });
|
||||
expect(within(accountDialog).getByText('2 个会话')).toBeTruthy();
|
||||
@@ -348,7 +394,7 @@ test('remote merged session group can be revoked with loading state', async () =
|
||||
revokingSessionIds: ['usess_remote'],
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /账号信息/ }));
|
||||
await user.click(screen.getByRole('button', { name: /账号与安全/ }));
|
||||
|
||||
const accountDialog = screen.getByRole('dialog', { name: '账号信息' });
|
||||
const revokeButton = within(accountDialog).getByRole('button', {
|
||||
@@ -373,7 +419,7 @@ test('remote session revoke passes the grouped session payload', async () => {
|
||||
onRevokeSession,
|
||||
});
|
||||
|
||||
await user.click(screen.getByRole('button', { name: /账号信息/ }));
|
||||
await user.click(screen.getByRole('button', { name: /账号与安全/ }));
|
||||
await user.click(
|
||||
within(screen.getByRole('dialog', { name: '账号信息' })).getByRole(
|
||||
'button',
|
||||
|
||||
Reference in New Issue
Block a user