diff --git a/web/test/e2e/resolution-1080p-test-env.spec.ts b/web/test/e2e/resolution-1080p-test-env.spec.ts new file mode 100644 index 0000000..448f0e9 --- /dev/null +++ b/web/test/e2e/resolution-1080p-test-env.spec.ts @@ -0,0 +1,154 @@ +/** + * 1080P E2E — 针对**测试服**(airflow-studio.test.airlabs.art)使用团管账号 tudou。 + * 这是对 resolution-1080p.spec.ts 的测试服版本,验证 CI/CD 部署后线上真实行为。 + */ +import { test, expect, Page } from '@playwright/test'; + +const BASE_URL = 'https://airflow-studio.test.airlabs.art'; +const API_URL = 'https://airflow-studio-api.test.airlabs.art'; +const USERNAME = 'tudou'; +const PASSWORD = 'seaislee'; + +async function login(page: Page) { + const resp = await page.request.post(`${API_URL}/api/v1/auth/login`, { + data: { username: USERNAME, password: PASSWORD }, + }); + if (!resp.ok()) { + const err = await resp.text(); + throw new Error(`Login failed: ${resp.status()} ${err}`); + } + const body = await resp.json(); + + await page.goto(BASE_URL); + await page.evaluate(({ access, refresh }) => { + localStorage.setItem('access_token', access); + localStorage.setItem('refresh_token', refresh); + }, { access: body.tokens.access, refresh: body.tokens.refresh }); + await page.goto(`${BASE_URL}/app`); + await page.waitForTimeout(2000); + + // 关闭公告 + const knowBtn = page.getByRole('button', { name: /我知道了|知道了|关闭/ }).first(); + if (await knowBtn.isVisible().catch(() => false)) { + await knowBtn.click(); + await page.waitForTimeout(300); + } +} + +test.describe.serial('[测试服] 1080P 分辨率支持 — tudou 团管账号', () => { + test('Sidebar 显示「今日剩余次数」(无钻石图标)', async ({ page }) => { + await login(page); + // 含"今日剩余次数"文案 + await expect(page.getByText('今日剩余次数')).toBeVisible(); + // 确认钻石 SVG 不存在(旧的 diamond path) + const diamondPath = page.locator('path[d^="M6 3h12l4 8"]'); + expect(await diamondPath.count()).toBe(0); + }); + + test('Toolbar 默认分辨率显示 720P', async ({ page }) => { + await login(page); + const resolutionBtn = page.getByRole('button', { name: '720P', exact: true }).first(); + await expect(resolutionBtn).toBeVisible(); + }); + + test('AirDrama 模式可切换到 1080P', async ({ page }) => { + await login(page); + await page.getByRole('button', { name: '720P', exact: true }).first().click(); + await page.waitForTimeout(200); + await page.getByText('1080P', { exact: true }).click(); + await page.waitForTimeout(300); + await expect(page.getByRole('button', { name: '1080P', exact: true }).first()).toBeVisible(); + }); + + test('1080P 下 Fast 模型在 Dropdown 中置灰', async ({ page }) => { + await login(page); + // 先切 1080P + await page.getByRole('button', { name: '720P', exact: true }).first().click(); + await page.waitForTimeout(200); + await page.getByText('1080P', { exact: true }).click(); + await page.waitForTimeout(300); + + // 打开模型 Dropdown + await page.getByRole('button', { name: /AirDrama$/, exact: false }).first().click(); + await page.waitForTimeout(200); + + // Fast 项应带"不支持 1080P" + await expect(page.getByText(/AirDrama Fast.*不支持 1080P/)).toBeVisible(); + }); + + test('Fast 模式下 1080P 在 Dropdown 中置灰', async ({ page }) => { + await login(page); + // 切 Fast 模型 + await page.getByRole('button', { name: /AirDrama$/, exact: false }).first().click(); + await page.waitForTimeout(200); + await page.getByText('AirDrama Fast', { exact: true }).click(); + await page.waitForTimeout(300); + + // 打开分辨率 Dropdown + await page.getByRole('button', { name: '720P', exact: true }).first().click(); + await page.waitForTimeout(200); + + // 1080P 项应带"Fast 不支持" + await expect(page.getByText(/1080P.*Fast 不支持/)).toBeVisible(); + }); + + test('ProfilePage 预警文案显示「今日生成次数」而非「额度」', async ({ page }) => { + await login(page); + await page.goto(`${BASE_URL}/profile`); + await page.waitForTimeout(1500); + // Page 应不含"今日额度"这种老文案 + const body = await page.textContent('body'); + // 能找到"今日"相关字样,不是"额度" + if (body && body.includes('今日')) { + // 如果出现"今日",必须是跟"次数"搭配,不是跟"额度" + expect(body).not.toMatch(/今日额度/); + } + }); + + test('提交 Fast+1080P 组合被后端 400 拒绝', async ({ page }) => { + await login(page); + // 直接调 API 测试(绕过前端 UI 约束,验证后端 fail loud) + const loginResp = await page.request.post(`${API_URL}/api/v1/auth/login`, { + data: { username: USERNAME, password: PASSWORD }, + }); + const { tokens } = await loginResp.json(); + const resp = await page.request.post(`${API_URL}/api/v1/video/generate`, { + headers: { Authorization: `Bearer ${tokens.access}` }, + data: { + prompt: 'E2E 测试 Fast+1080P', + mode: 'universal', + model: 'seedance_2.0_fast', + aspect_ratio: '16:9', + duration: 5, + resolution: '1080p', + references: [], + }, + }); + expect(resp.status()).toBe(400); + const body = await resp.json(); + expect(body.error).toBe('invalid_resolution'); + expect(body.message).toContain('1080P'); + expect(body.message).toContain('Fast'); + }); + + test('提交 adaptive ratio 被后端 400 拒绝', async ({ page }) => { + await login(page); + const loginResp = await page.request.post(`${API_URL}/api/v1/auth/login`, { + data: { username: USERNAME, password: PASSWORD }, + }); + const { tokens } = await loginResp.json(); + const resp = await page.request.post(`${API_URL}/api/v1/video/generate`, { + headers: { Authorization: `Bearer ${tokens.access}` }, + data: { + prompt: 'E2E adaptive', + mode: 'universal', + model: 'seedance_2.0', + aspect_ratio: 'adaptive', + duration: 5, + resolution: '720p', + references: [], + }, + }); + expect(resp.status()).toBe(400); + }); +});