Files
ai-learning-platform/frontend/e2e/functional-pages.spec.ts
T
yuzhiran-dev 538de50bb1 注册支持用户名/手机号/邮箱 + 镜像站部署脚本 + AI 助手 Tool Calling 重构
- Prisma User 模型新增 username 字段(唯一索引)
- 注册先查重复再创建,返回友好中文提示(非 500)
- 登录支持用户名/手机号/邮箱三种方式
- 前端注册表单增加用户名输入框,预校验 2-20 位格式
- 新增 scripts/deploy.sh:一键构建并部署主站+镜像站+重启后端+重载 Nginx
- 镜像站 www.yuzhiran.com.cn Nginx 配置与主站同步
- AI 助手架构升级:用户端/管理后台均采用完整 Tool Calling 架构
- 新增 UserAiAssistantService(18 工具)+ AiAssistantController
- admin 助手新增 search + mark-all-notifications-read 工具
- 修复注册 500 错误:catch Prisma P2002 → BadRequestException
- Baidu Analytics Script 注入 root layout
2026-06-01 23:14:42 +08:00

120 lines
3.7 KiB
TypeScript
Executable File

import { test, expect } from '@playwright/test';
test.describe('功能页面', () => {
test.describe('沙盒 (/sandbox)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/sandbox');
});
test('页面渲染正常', async ({ page }) => {
await expect(page.locator('h1')).toBeVisible();
});
test('模型选择器存在', async ({ page }) => {
const select = page.locator('select');
const count = await select.count();
expect(count).toBeGreaterThanOrEqual(1);
});
test('消息输入框存在', async ({ page }) => {
await expect(page.locator('textarea, input[type="text"]').first()).toBeVisible();
});
test('发送按钮存在', async ({ page }) => {
await expect(page.getByText('发送').first()).toBeVisible();
});
test('初始欢迎消息展示', async ({ page }) => {
await expect(page.getByText(/你好!我是宇之然 AI 助手/)).toBeVisible();
});
test('对比实验室链接存在', async ({ page }) => {
const compareLink = page.getByText('对比实验室').or(page.getByText('模型对比'));
const count = await page.getByText('对比实验室').count();
if (count > 0) {
const link = page.getByText('对比实验室').first();
await expect(link).toBeVisible();
const href = await link.getAttribute('href');
if (href) {
await expect(link).toHaveAttribute('href', /\/sandbox\/compare|\/compare/);
}
}
});
});
test.describe('对比实验室 (/sandbox/compare)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/sandbox/compare');
});
test('页面渲染正常', async ({ page }) => {
await expect(page.locator('h1')).toBeVisible();
});
});
test.describe('提示词工坊 (/prompts/workshop)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/prompts/workshop');
});
test('页面渲染正常', async ({ page }) => {
await expect(page.locator('h1')).toBeVisible();
});
});
test.describe('搜索 (/search)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/search');
});
test('搜索输入框存在', async ({ page }) => {
await expect(page.locator('input[type="text"], input[name="q"]').first()).toBeVisible();
});
test('搜索按钮存在', async ({ page }) => {
await expect(page.getByText('搜索').first()).toBeVisible();
});
});
test.describe('发现页及子页', () => {
test('/discover 渲染', async ({ page }) => {
await page.goto('/discover');
await expect(page.locator('h1')).toBeVisible();
const dailyLink = page.getByText('每日精选').first();
if (await dailyLink.isVisible()) {
await expect(dailyLink).toHaveAttribute('href', '/discover/daily');
}
});
test('/discover/daily 渲染', async ({ page }) => {
await page.goto('/discover/daily');
await expect(page.locator('h1')).toBeVisible();
});
test('/discover/hot 渲染', async ({ page }) => {
await page.goto('/discover/hot');
await expect(page.locator('h1')).toBeVisible();
});
test('/discover/tools 渲染', async ({ page }) => {
await page.goto('/discover/tools');
await expect(page.locator('h1')).toBeVisible();
});
});
test.describe('认证页 (/auth)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/auth');
});
test('登录表单可见', async ({ page }) => {
await expect(page.getByText('登录').first()).toBeVisible();
});
test('注册表单可切换', async ({ page }) => {
await page.goto('/auth?tab=register');
await expect(page.getByText('注册').first()).toBeVisible();
});
});
});