Also fixes the `completeProfile` form action: SvelteKit only supports form actions in `+page.server.ts`, not `+layout.server.ts`. Moved the action to a dedicated `/(app)/onboarding/+page.server.ts` and updated the dialog form's `action` attribute to the absolute path `/app/onboarding?/completeProfile`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
import { test, expect } from './helpers/fixtures';
|
|
import { mock } from './helpers/mock';
|
|
|
|
const UUID_USERNAME = '550e8400-e29b-41d4-a716-446655440000';
|
|
|
|
const emptyEventList = {
|
|
status: 200,
|
|
body: { status: 200, data: { items: [] } }
|
|
};
|
|
|
|
test('dialog appears for UUID username and is not dismissable', async ({ page, loggedInUser }) => {
|
|
void loggedInUser;
|
|
// Override user/info AFTER fixture runs (last writer wins)
|
|
await mock.override('GET', '/user/info', {
|
|
status: 200,
|
|
body: { status: 200, data: { ...loggedInUser, username: UUID_USERNAME } }
|
|
});
|
|
await mock.override('GET', '/event/list', emptyEventList);
|
|
|
|
await page.goto('/app/');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Dialog is visible
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
await expect(page.getByText('完善个人资料')).toBeVisible();
|
|
|
|
// Pressing Escape does not close it (non-dismissable)
|
|
await page.keyboard.press('Escape');
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
});
|
|
|
|
test('successful submit closes the dialog', async ({ page, loggedInUser }) => {
|
|
void loggedInUser;
|
|
await mock.override('GET', '/user/info', {
|
|
status: 200,
|
|
body: { status: 200, data: { ...loggedInUser, username: UUID_USERNAME } }
|
|
});
|
|
await mock.override('GET', '/event/list', emptyEventList);
|
|
|
|
await page.goto('/app/');
|
|
await page.waitForLoadState('networkidle');
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
|
|
// Register success responses before submitting
|
|
await mock.override('PATCH', '/user/update', { status: 200, body: { status: 200 } });
|
|
await mock.override('GET', '/user/info', {
|
|
status: 200,
|
|
body: { status: 200, data: { ...loggedInUser, username: 'alice_real', nickname: 'Alice Real' } }
|
|
});
|
|
|
|
const dialog = page.getByRole('dialog');
|
|
await dialog.locator('input[name="username"]').fill('alice_real');
|
|
await dialog.locator('input[name="nickname"]').fill('Alice Real');
|
|
await page.getByRole('button', { name: /保存并继续/i }).click();
|
|
|
|
await expect(page.getByRole('dialog')).not.toBeVisible();
|
|
|
|
// Verify PATCH body
|
|
const patches = await mock.requests({ method: 'PATCH', path: '/user/update' });
|
|
expect(patches).toHaveLength(1);
|
|
expect(patches[0].body).toMatchObject({ username: 'alice_real', nickname: 'Alice Real' });
|
|
});
|
|
|
|
test('backend error shows alert and keeps dialog open', async ({ page, loggedInUser }) => {
|
|
void loggedInUser;
|
|
await mock.override('GET', '/user/info', {
|
|
status: 200,
|
|
body: { status: 200, data: { ...loggedInUser, username: UUID_USERNAME } }
|
|
});
|
|
await mock.override('GET', '/event/list', emptyEventList);
|
|
|
|
await page.goto('/app/');
|
|
await page.waitForLoadState('networkidle');
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
|
|
await mock.override('PATCH', '/user/update', {
|
|
status: 409,
|
|
body: { status: 409, msg: '用户名已被使用' }
|
|
});
|
|
|
|
const dialog = page.getByRole('dialog');
|
|
await dialog.locator('input[name="username"]').fill('taken_name');
|
|
await dialog.locator('input[name="nickname"]').fill('Alice');
|
|
await page.getByRole('button', { name: /保存并继续/i }).click();
|
|
|
|
// Error alert is shown
|
|
await expect(page.getByText('用户名已被使用')).toBeVisible();
|
|
// Dialog remains open
|
|
await expect(page.getByRole('dialog')).toBeVisible();
|
|
});
|