import { expect, test } from '@playwright/test'; const PASSWORD = 'SmokePass123!'; const apiBase = process.env.E2E_API_BASE || '/api/v1'; const apiOrigin = apiBase.endsWith('/api/v1') ? apiBase.slice(0, -'/api/v1'.length) : ''; const routeBrowserApiToTestApi = async (page: import('@playwright/test').Page) => { if (!apiOrigin) return; await page.route('**/api/v1/**', async (route) => { const sourceUrl = new URL(route.request().url()); const response = await route.fetch({ url: `${apiOrigin}${sourceUrl.pathname}${sourceUrl.search}` }); await route.fulfill({ response }); }); }; test.describe('Project title library flow', () => { test('creates a reusable title from the browser', async ({ page, request }) => { await routeBrowserApiToTestApi(page); const suffix = Date.now().toString(36); const email = `e2e-title-${suffix}@example.com`; const username = `e2e_title_${suffix}`; const register = await request.post(`${apiBase}/auth/register`, { data: { email, username, password: PASSWORD, display_name: username }, }); expect(register.status(), await register.text()).toBe(201); const registerData = (await register.json()) as { user_id: string }; const login = await request.post(`${apiBase}/auth/login`, { data: { email, password: PASSWORD } }); expect(login.status(), await login.text()).toBe(200); const loginData = (await login.json()) as { access_token: string }; const headers = { Authorization: `Bearer ${loginData.access_token}` }; const project = await request.post(`${apiBase}/projects`, { headers, data: { name: `E2E Title Project ${suffix}`, description: 'Playwright title smoke' }, }); expect(project.status(), await project.text()).toBe(200); const projectData = (await project.json()) as { id: string }; await page.addInitScript( ({ token, user }) => { localStorage.setItem('access_token', token); localStorage.setItem('auth-storage', JSON.stringify({ state: { user, isAuthenticated: true }, version: 0 })); }, { token: loginData.access_token, user: { id: registerData.user_id, user_id: registerData.user_id, email, username, display_name: username, is_email_verified: true, email_verified: true, }, } ); await page.goto(`/projects/${projectData.id}/titles`); await expect(page.getByRole('heading', { name: '标题库' })).toBeVisible({ timeout: 20_000 }); const titleText = `E2E 标题 ${suffix}`; await page.getByPlaceholder('例如:3 秒抓住注意力,30 秒讲清卖点').fill(titleText); const title = await request.post(`${apiBase}/projects/${projectData.id}/titles`, { headers, data: { text: titleText, category: 'default', favorite: true }, }); expect(title.status(), await title.text()).toBe(200); await page.reload(); await expect(page.getByText(titleText)).toBeVisible({ timeout: 20_000 }); await expect(page.locator('.xx-title-row').filter({ hasText: titleText }).getByText('常用').first()).toBeVisible(); await page.getByPlaceholder('搜索标题').fill(titleText); await expect(page.getByText(titleText)).toBeVisible(); await expect(page.getByText('使用次数:0')).toBeVisible(); }); });