video-shuoshan/web/test/e2e/bug2-rename.spec.ts
seaislee1209 dafdc8983f fix: v0.18.3 版权报错友好提示 + 图片删除即梦式连续重命名
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>
2026-04-17 18:03:36 +08:00

134 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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']);
});
});