Bug 1: 版权限制错误友好提示 - ERROR_MESSAGES 加 OutputVideoSensitiveContentDetected.PolicyViolation 映射 - 漫威等知名 IP 触发的版权拦截不再显示英文 raw error Bug 2: 图片删除后同类型引用连续重命名(即梦逻辑) - inputBar.ts::removeReference 重写:删除后同类型剩余引用按顺序 1/2/3 连续编号 - 用 DOMParser 同步更新 editorHtml 里对应 data-ref-id 的 @mention span textContent - 缩略图区和提示词栏同步刷新,避免"两个图片2"命名冲突 验证 - 11 个 Vitest 单元测试覆盖图片/视频/音频删除、空 editorHtml、无 @mention、 连续快速删除等边界场景 - 3 个 Playwright E2E 真实浏览器验证:上传 3 张图 → 删中间 → 再上传 → 编号不冲突 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
134 lines
5.0 KiB
TypeScript
134 lines
5.0 KiB
TypeScript
/**
|
||
* Bug 2 E2E 验证:图片删除后即梦式连续重命名
|
||
* 针对本地开发环境(localhost:5173 + 127.0.0.1:8000)
|
||
*/
|
||
import { test, expect, Page } from '@playwright/test';
|
||
|
||
const BASE_URL = 'http://localhost:5173';
|
||
const API_URL = 'http://127.0.0.1:8000';
|
||
const USERNAME = 'admin';
|
||
const PASSWORD = 'admin123';
|
||
|
||
const TEST_IMAGES_DIR = 'C:/Users/Air-work/AppData/Local/Temp/bug2test';
|
||
const IMG_RED = `${TEST_IMAGES_DIR}/test_red.png`;
|
||
const IMG_GREEN = `${TEST_IMAGES_DIR}/test_green.png`;
|
||
const IMG_BLUE = `${TEST_IMAGES_DIR}/test_blue.png`;
|
||
|
||
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 errText = await resp.text();
|
||
console.log('LOGIN FAILED:', resp.status(), errText);
|
||
}
|
||
expect(resp.ok()).toBeTruthy();
|
||
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(1500);
|
||
|
||
// 关闭初次登录可能出现的公告弹窗
|
||
const knowBtn = page.getByRole('button', { name: /我知道了|知道了|关闭/ }).first();
|
||
if (await knowBtn.isVisible().catch(() => false)) {
|
||
await knowBtn.click();
|
||
await page.waitForTimeout(300);
|
||
}
|
||
}
|
||
|
||
test.describe.serial('Bug 2: 图片删除后即梦式连续重命名', () => {
|
||
test('上传 3 张图 → 删除图片2 → 图片3 变为图片2', async ({ page }) => {
|
||
await login(page);
|
||
|
||
// 上传 3 张图
|
||
const fileInput = page.locator('input[type="file"]').first();
|
||
await fileInput.setInputFiles([IMG_RED, IMG_GREEN, IMG_BLUE]);
|
||
await page.waitForTimeout(2000); // 等图片校验和 ref 添加完成
|
||
|
||
// 展开缩略图堆栈(hover 触发)
|
||
const thumbRow = page.locator('[class*="thumbRow"]').first();
|
||
await thumbRow.hover();
|
||
await page.waitForTimeout(500);
|
||
|
||
// 验证上传后初始状态:图片1/图片2/图片3
|
||
const labelsInitial = await page.locator('[class*="thumbLabel"]').allTextContents();
|
||
console.log('初始标签:', labelsInitial);
|
||
expect(labelsInitial).toEqual(['图片1', '图片2', '图片3']);
|
||
|
||
// 点第 2 张图的删除按钮
|
||
const secondThumb = page.locator('[class*="thumbItem"]').nth(1);
|
||
await secondThumb.hover();
|
||
await secondThumb.locator('[class*="thumbClose"]').click({ force: true });
|
||
await page.waitForTimeout(500);
|
||
|
||
// 验证重命名后:图片1/图片2(原图片3)
|
||
await thumbRow.hover();
|
||
await page.waitForTimeout(300);
|
||
const labelsAfterDelete = await page.locator('[class*="thumbLabel"]').allTextContents();
|
||
console.log('删除图片2后:', labelsAfterDelete);
|
||
expect(labelsAfterDelete).toEqual(['图片1', '图片2']);
|
||
expect(labelsAfterDelete.length).toBe(2);
|
||
});
|
||
|
||
test('删除图片2 后再上传 1 张 → 新图是图片3(不和现有冲突)', async ({ page }) => {
|
||
await login(page);
|
||
|
||
// 上传 3 张
|
||
const fileInput = page.locator('input[type="file"]').first();
|
||
await fileInput.setInputFiles([IMG_RED, IMG_GREEN, IMG_BLUE]);
|
||
await page.waitForTimeout(2000);
|
||
|
||
const thumbRow = page.locator('[class*="thumbRow"]').first();
|
||
await thumbRow.hover();
|
||
await page.waitForTimeout(500);
|
||
|
||
// 删除第 2 张
|
||
const secondThumb = page.locator('[class*="thumbItem"]').nth(1);
|
||
await secondThumb.hover();
|
||
await secondThumb.locator('[class*="thumbClose"]').click({ force: true });
|
||
await page.waitForTimeout(500);
|
||
|
||
// 再上传 1 张
|
||
await fileInput.setInputFiles([IMG_RED]);
|
||
await page.waitForTimeout(2000);
|
||
|
||
// 验证:原图片1、原图片3(已改名图片2)、新图片3
|
||
await thumbRow.hover();
|
||
await page.waitForTimeout(300);
|
||
const finalLabels = await page.locator('[class*="thumbLabel"]').allTextContents();
|
||
console.log('删除后再上传:', finalLabels);
|
||
expect(finalLabels).toEqual(['图片1', '图片2', '图片3']);
|
||
// 无重复编号
|
||
expect(new Set(finalLabels).size).toBe(finalLabels.length);
|
||
});
|
||
|
||
test('删除第 1 张 → 剩余图片全部前移', async ({ page }) => {
|
||
await login(page);
|
||
|
||
const fileInput = page.locator('input[type="file"]').first();
|
||
await fileInput.setInputFiles([IMG_RED, IMG_GREEN, IMG_BLUE]);
|
||
await page.waitForTimeout(2000);
|
||
|
||
const thumbRow = page.locator('[class*="thumbRow"]').first();
|
||
await thumbRow.hover();
|
||
await page.waitForTimeout(500);
|
||
|
||
// 删除第 1 张
|
||
const firstThumb = page.locator('[class*="thumbItem"]').nth(0);
|
||
await firstThumb.hover();
|
||
await firstThumb.locator('[class*="thumbClose"]').click({ force: true });
|
||
await page.waitForTimeout(500);
|
||
|
||
await thumbRow.hover();
|
||
await page.waitForTimeout(300);
|
||
const labels = await page.locator('[class*="thumbLabel"]').allTextContents();
|
||
console.log('删除图片1后:', labels);
|
||
expect(labels).toEqual(['图片1', '图片2']);
|
||
});
|
||
});
|