test: 加测试服 E2E — 1080P 分辨率支持线上验证 (8/8 通过)
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m29s

针对 airflow-studio.test.airlabs.art 使用团管账号 tudou 真实验证:
- Sidebar「今日剩余次数」文案 + 无钻石图标
- Toolbar 默认 720P
- AirDrama 可切 1080P
- 1080P 下 Fast Dropdown 置灰(UI 不可达 Fast+1080P)
- Fast 下 1080P Dropdown 置灰(反向)
- ProfilePage 预警文案无「今日额度」老称谓
- API 拒绝 Fast+1080P 组合(400 invalid_resolution)
- API 拒绝 adaptive ratio(400)

已跑通,附带 resolution-1080p.spec.ts (本地版,admin 账号,5/5 通过)
和 backend tests (23 unit + 5 integration 全过)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209 2026-04-17 19:14:28 +08:00
parent 6b22e1fa3f
commit 27bfa689ce

View File

@ -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);
});
});