You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
9.5 KiB
270 lines
9.5 KiB
import { test, expect } from "@playwright/test";
|
|
import { E2E_ADMIN, FIXED_CAPTCHA } from "../fixtures/test-users";
|
|
|
|
async function loginViaUI(page: import("@playwright/test").Page) {
|
|
await page.goto("/auth/login");
|
|
await page.fill("#login-username", E2E_ADMIN.username);
|
|
await page.fill("#login-password", E2E_ADMIN.password);
|
|
await page.fill("#login-captcha", FIXED_CAPTCHA);
|
|
await page.click('button[type="submit"]');
|
|
await page.waitForURL("/", { timeout: 15000 });
|
|
}
|
|
|
|
async function createDocViaAPI(
|
|
request: import("@playwright/test").APIRequestContext,
|
|
body: Record<string, unknown>,
|
|
) {
|
|
const res = await request.post("/api/agent-documents", { data: body });
|
|
return res;
|
|
}
|
|
|
|
test.describe("Agent 文档", () => {
|
|
test("列表页可访问(空状态)", async ({ page, request }) => {
|
|
await loginViaUI(page);
|
|
await page.goto("/agent-documents");
|
|
await expect(page.locator(".agent-documents-page")).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test("通过 API 创建文档后列表显示", async ({ page, request }) => {
|
|
await loginViaUI(page);
|
|
|
|
const title = `E2E测试文档_${Date.now()}`;
|
|
const res = await createDocViaAPI(request, {
|
|
title,
|
|
content: "## 测试内容\n这是一个E2E测试创建的文档。",
|
|
type: "document",
|
|
tags: ["e2e", "test"],
|
|
});
|
|
expect(res.ok()).toBeTruthy();
|
|
const json = await res.json();
|
|
expect(json.code).toBe(0);
|
|
const docId = json.data.id;
|
|
|
|
await page.goto("/agent-documents");
|
|
await expect(page.locator(".document-card").first()).toBeVisible({ timeout: 10000 });
|
|
await expect(page.locator(".document-card").first()).toContainText(title);
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
});
|
|
|
|
test("详情页显示文档内容", async ({ page, request }) => {
|
|
await loginViaUI(page);
|
|
|
|
const title = `E2E详情测试_${Date.now()}`;
|
|
const content = "## 详情页测试\nMarkdown渲染验证。";
|
|
const res = await createDocViaAPI(request, {
|
|
title,
|
|
content,
|
|
type: "document",
|
|
tags: ["detail"],
|
|
});
|
|
const json = await res.json();
|
|
const docId = json.data.id;
|
|
|
|
await page.goto(`/agent-documents/${docId}`);
|
|
await expect(page.locator(".detail-title")).toContainText(title, { timeout: 10000 });
|
|
await expect(page.locator(".detail-content")).toBeVisible();
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
});
|
|
|
|
test("类型筛选工作正常", async ({ page, request }) => {
|
|
await loginViaUI(page);
|
|
|
|
const docRes = await createDocViaAPI(request, {
|
|
title: `E2E文档类型_${Date.now()}`,
|
|
content: "文档类型测试",
|
|
type: "document",
|
|
});
|
|
const memRes = await createDocViaAPI(request, {
|
|
title: `E2E记忆类型_${Date.now()}`,
|
|
content: "记忆类型测试",
|
|
type: "memory",
|
|
});
|
|
const docId = (await docRes.json()).data.id;
|
|
const memId = (await memRes.json()).data.id;
|
|
|
|
await page.goto("/agent-documents");
|
|
await page.click(".filter-tab", { text: "文档" });
|
|
await page.waitForTimeout(500);
|
|
const docCards = page.locator(".document-card");
|
|
const count1 = await docCards.count();
|
|
expect(count1).toBeGreaterThan(0);
|
|
for (let i = 0; i < count1; i++) {
|
|
await expect(docCards.nth(i).locator(".type-badge")).toHaveClass(/document/);
|
|
}
|
|
|
|
await page.click(".filter-tab", { text: "记忆" });
|
|
await page.waitForTimeout(500);
|
|
const memCards = page.locator(".document-card");
|
|
const count2 = await memCards.count();
|
|
expect(count2).toBeGreaterThan(0);
|
|
for (let i = 0; i < count2; i++) {
|
|
await expect(memCards.nth(i).locator(".type-badge")).toHaveClass(/memory/);
|
|
}
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
await request.delete(`/api/agent-documents/${memId}`);
|
|
});
|
|
|
|
test("关键词搜索工作正常", async ({ page, request }) => {
|
|
await loginViaUI(page);
|
|
|
|
const unique = `E2E搜索关键词_${Date.now()}`;
|
|
const res = await createDocViaAPI(request, {
|
|
title: unique,
|
|
content: "搜索测试内容",
|
|
type: "document",
|
|
});
|
|
const docId = (await res.json()).data.id;
|
|
|
|
await page.goto("/agent-documents");
|
|
await page.fill(".search-input", unique);
|
|
await page.waitForTimeout(600);
|
|
|
|
const cards = page.locator(".document-card");
|
|
await expect(cards.first()).toBeVisible({ timeout: 10000 });
|
|
const count = await cards.count();
|
|
expect(count).toBeGreaterThanOrEqual(1);
|
|
await expect(cards.first()).toContainText(unique);
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
});
|
|
|
|
test("详情页编辑文档", async ({ page, request }) => {
|
|
await loginViaUI(page);
|
|
|
|
const res = await createDocViaAPI(request, {
|
|
title: `E2E编辑前_${Date.now()}`,
|
|
content: "编辑前内容",
|
|
type: "document",
|
|
});
|
|
const docId = (await res.json()).data.id;
|
|
|
|
await page.goto(`/agent-documents/${docId}`);
|
|
await page.click("button.action-btn", { text: "编辑" });
|
|
await expect(page.locator(".form-dialog")).toBeVisible({ timeout: 5000 });
|
|
|
|
await page.fill(".form-input", `E2E编辑后_${Date.now()}`);
|
|
await page.click("button.btn-save");
|
|
|
|
await expect(page.locator(".Toastify__toast").first()).toBeVisible({ timeout: 10000 });
|
|
await page.waitForTimeout(500);
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
});
|
|
|
|
test("详情页删除文档", async ({ page, request }) => {
|
|
await loginViaUI(page);
|
|
|
|
const res = await createDocViaAPI(request, {
|
|
title: `E2E删除测试_${Date.now()}`,
|
|
content: "待删除",
|
|
type: "document",
|
|
});
|
|
const docId = (await res.json()).data.id;
|
|
|
|
await page.goto(`/agent-documents/${docId}`);
|
|
await page.click("button.action-btn.danger");
|
|
await expect(page.locator(".confirm-dialog")).toBeVisible({ timeout: 5000 });
|
|
await page.click(".confirm-dialog .btn-save.danger");
|
|
|
|
await expect(page).toHaveURL(/\/agent-documents$/, { timeout: 10000 });
|
|
});
|
|
|
|
test("未登录访问列表页重定向到登录", async ({ page }) => {
|
|
await page.goto("/agent-documents");
|
|
await expect(page).toHaveURL(/\/auth\/login/);
|
|
});
|
|
|
|
test("未登录 API 返回 401", async ({ request }) => {
|
|
const res = await request.get("/api/agent-documents");
|
|
expect(res.status()).toBe(401);
|
|
});
|
|
|
|
test("导航栏包含文档入口", async ({ page }) => {
|
|
await loginViaUI(page);
|
|
await page.goto("/");
|
|
const docLink = page.locator(".nav-links a", { hasText: "文档" });
|
|
await expect(docLink).toBeVisible({ timeout: 10000 });
|
|
});
|
|
|
|
test("带 agentSlug 创建的文档绑定到该 agent", async ({ page }) => {
|
|
await loginViaUI(page);
|
|
const request = page.request;
|
|
|
|
const title = `E2E绑定Agent_${Date.now()}`;
|
|
const res = await request.post("/api/agent-documents", {
|
|
data: { title, content: "绑定到 default agent", type: "document", agentSlug: "default" },
|
|
});
|
|
expect(res.ok()).toBeTruthy();
|
|
const json = await res.json();
|
|
expect(json.code).toBe(0);
|
|
const docId = json.data.id;
|
|
|
|
// 带 agentSlug 查询应能找到
|
|
const listRes = await request.get("/api/agent-documents?agentSlug=default");
|
|
const listJson = await listRes.json();
|
|
const found = listJson.data.items.some((i: { id: number }) => i.id === docId);
|
|
expect(found).toBeTruthy();
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
});
|
|
|
|
test("不带 agentSlug 创建的文档为全局共享", async ({ page }) => {
|
|
await loginViaUI(page);
|
|
const request = page.request;
|
|
|
|
const title = `E2E全局文档_${Date.now()}`;
|
|
const res = await request.post("/api/agent-documents", {
|
|
data: { title, content: "全局共享文档", type: "document" },
|
|
});
|
|
const json = await res.json();
|
|
const docId = json.data.id;
|
|
|
|
// 不带 agentSlug 查询(全部)应能找到
|
|
const listRes = await request.get("/api/agent-documents");
|
|
const listJson = await listRes.json();
|
|
const found = listJson.data.items.some((i: { id: number }) => i.id === docId);
|
|
expect(found).toBeTruthy();
|
|
|
|
// 带 agentSlug=default 查询也应能找到(全局共享对当前 agent 可见)
|
|
const agentListRes = await request.get("/api/agent-documents?agentSlug=default");
|
|
const agentListJson = await agentListRes.json();
|
|
const foundInAgent = agentListJson.data.items.some((i: { id: number }) => i.id === docId);
|
|
expect(foundInAgent).toBeTruthy();
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
});
|
|
|
|
test("PATCH 切换文档归属(全局 ↔ agent 专属)", async ({ page }) => {
|
|
await loginViaUI(page);
|
|
const request = page.request;
|
|
|
|
// 先创建全局文档
|
|
const createRes = await request.post("/api/agent-documents", {
|
|
data: { title: `E2E切换归属_${Date.now()}`, content: "待切换", type: "document" },
|
|
});
|
|
const docId = (await createRes.json()).data.id;
|
|
|
|
// PATCH 绑定到 default agent
|
|
const patchRes1 = await request.patch(`/api/agent-documents/${docId}`, {
|
|
data: { agentSlug: "default" },
|
|
});
|
|
expect(patchRes1.ok()).toBeTruthy();
|
|
|
|
// 验证:带 agentSlug=default 应能找到
|
|
const agentListRes = await request.get("/api/agent-documents?agentSlug=default");
|
|
const agentListJson = await agentListRes.json();
|
|
const foundInAgent = agentListJson.data.items.some((i: { id: number }) => i.id === docId);
|
|
expect(foundInAgent).toBeTruthy();
|
|
|
|
// PATCH 改回全局共享
|
|
const patchRes2 = await request.patch(`/api/agent-documents/${docId}`, {
|
|
data: { agentSlug: null },
|
|
});
|
|
expect(patchRes2.ok()).toBeTruthy();
|
|
|
|
await request.delete(`/api/agent-documents/${docId}`);
|
|
});
|
|
});
|
|
|