Files
xiaoxia-saas/apps/web/e2e/core-upload.spec.ts
T
灵应 8935196fcd
Deploy / Staging E2E Tests (push) Has been skipped
Deploy / Build Production Runtime Images (push) Has been skipped
Deploy / Deploy Production (push) Has been skipped
Deploy / Production Browser E2E (push) Has been skipped
Deploy / Deploy Staging (push) Failing after 138h4m33s
CI/CD Pipeline / Frontend Lint (push) Failing after 138h4m39s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 138h4m39s
style: 后端代码black格式化
2026-07-03 18:49:54 +08:00

179 lines
5.4 KiB
TypeScript
Executable File

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 });
});
};
type ProjectResponse = { id: string };
type LibraryResponse = { id: string };
test.describe("Core media upload flow", () => {
test("uploads a MOV asset from the browser and shows it as ready", async ({
page,
request,
}) => {
test.setTimeout(120_000);
await routeBrowserApiToTestApi(page);
const suffix = Date.now().toString(36);
const email = `e2e-mov-${suffix}@example.com`;
const username = `e2e_mov_${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 Project ${suffix}`,
description: "Playwright upload smoke",
},
});
expect(project.status(), await project.text()).toBe(200);
const projectData = (await project.json()) as ProjectResponse;
const library = await request.post(`${apiBase}/asset-libraries`, {
headers,
data: {
project_id: projectData.id,
name: `E2E Video Library ${suffix}`,
kind: "video",
},
});
expect(library.status(), await library.text()).toBe(200);
const libraryData = (await library.json()) as LibraryResponse;
await page.addInitScript(
({ token, user, projectId }) => {
localStorage.setItem("access_token", token);
localStorage.setItem(
"auth-storage",
JSON.stringify({
state: { user, isAuthenticated: true },
version: 0,
}),
);
},
{
token: loginData.access_token,
projectId: projectData.id,
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}/assets`);
await expect(page.getByText("点击或拖拽素材到这里上传")).toBeEnabled({
timeout: 20_000,
});
const upload = await request.post(`${apiBase}/upload`, {
headers,
multipart: {
project_id: projectData.id,
library_id: libraryData.id,
file: {
name: "e2e-sample.MOV",
mimeType: "video/quicktime",
buffer: Buffer.from("playwright mov upload smoke"),
},
},
});
expect(upload.status(), await upload.text()).toBe(200);
await expect(
page.getByText(/上传失败|素材列表加载失败|素材库加载失败/),
).toHaveCount(0, { timeout: 5_000 });
await expect
.poll(
async () => {
const assets = await request.get(`${apiBase}/assets`, {
headers,
params: { library_id: libraryData.id },
});
if (!assets.ok()) {
return `http_${assets.status()}`;
}
const data = (await assets.json()) as {
items: Array<{
name: string;
status: string;
file_type?: string;
mime_type?: string;
}>;
};
const asset = data.items.find(
(item) => item.name === "e2e-sample.MOV",
);
return asset
? `${asset.mime_type || asset.file_type || ""}:${asset.status}`
: "missing";
},
{ timeout: 30_000, intervals: [1_000, 2_000, 3_000] },
)
.toMatch(/^(video\/quicktime|video\/mp4|video)?:ready$/);
await page.reload();
await expect(page.getByText(/素材就绪度|Ready/)).toBeVisible({
timeout: 20_000,
});
await expect(
page.getByText(/预计成片|视频素材数量偏少|素材准备度良好/),
).toBeVisible({ timeout: 20_000 });
await expect(page.getByText("e2e-sample.MOV", { exact: true })).toBeVisible(
{ timeout: 20_000 },
);
await page
.locator(".xx-vertical-card")
.filter({ hasText: "e2e-sample.MOV" })
.getByRole("button", { name: /通\s*过/ })
.click();
await expect(page.getByText("复核状态已更新")).toBeVisible({
timeout: 10_000,
});
await expect(page.getByText(/已通过|approved/)).toBeVisible({
timeout: 20_000,
});
await expect(page.getByText(/素材加载失败|上传失败/)).toHaveCount(0);
});
});