Files
gaokao-volunteer-system/apps/web/e2e/form-submit-validation.spec.ts

62 lines
2.4 KiB
TypeScript
Raw Normal View History

/**
* V10 · Sprint 4 · T-B-23.3 · e2e: form submit + validation (FormCard 3-step)
*
* FormCard ChatMessage
* chat send SubmitButton
*/
import { test, expect } from '@playwright/test';
test.describe('Form Submit + Validation (V10 Sprint 4 · T-B-23.3)', () => {
test.beforeEach(async ({ page }) => {
// 让 chat 流式接口返回空,避免影响
await page.route('**/api/**', async (route) => {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
});
});
test('SubmitButton guards send button during streaming', async ({ page }) => {
// 拦截 form submit 路径,模拟慢响应验证 spinner
await page.route('**/api/chat/stream', async (route) => {
await new Promise((r) => setTimeout(r, 1500));
await route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
});
await page.goto('/');
const input = page.getByRole('textbox', { name: '输入你的问题' });
await input.fill('测试提交');
// 使用 keyboard Enter 触发提交(更接近 keyboard interaction绕过 mobile nav 的 pointer intercept
await input.press('Enter');
// 发送按钮应立即切换到 disabledaria-label 会变 "请先输入内容"
await expect(page.getByRole('button', { name: '请先输入内容' })).toBeDisabled({ timeout: 2000 });
});
test('SubmitButton does not double-fire when clicked twice rapidly', async ({ page }) => {
let callCount = 0;
await page.route('**/api/chat/stream', async (route) => {
callCount += 1;
await new Promise((r) => setTimeout(r, 800));
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"content":""}' });
});
await page.goto('/');
const input = page.getByRole('textbox', { name: '输入你的问题' });
await input.fill('连续点击');
// 第一次按 Enter 触发提交
await input.press('Enter');
// 此时按钮应 disabledaria-label='请先输入内容'
await expect(page.getByRole('button', { name: '请先输入内容' })).toBeDisabled({ timeout: 2000 });
// 试图再次按 Enter在已 disabled 状态下不应触发新请求)
await page.waitForTimeout(200);
await input.press('Enter').catch(() => {});
await page.waitForTimeout(1500);
expect(callCount).toBe(1);
});
});