geo/frontend/e2e/tests/knowledge-interaction.spec.ts

582 lines
18 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.

import { test, expect } from "../fixtures";
test.describe("知识库 - 创建知识库交互测试", () => {
test.beforeEach(async ({ authenticatedPage }) => {
await authenticatedPage.goto("/dashboard/knowledge");
await authenticatedPage.waitForLoadState("networkidle");
});
test("点击创建知识库按钮打开对话框", async ({ authenticatedPage }) => {
const createBtn = authenticatedPage.getByRole("button", { name: /创建知识库/ }).first();
await expect(createBtn).toBeVisible({ timeout: 15000 });
await createBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 验证对话框标题
await expect(dialog.getByRole("heading", { name: "创建知识库" })).toBeVisible();
});
test("创建知识库对话框包含名称和描述输入框", async ({ authenticatedPage }) => {
const createBtn = authenticatedPage.getByRole("button", { name: /创建知识库/ }).first();
await expect(createBtn).toBeVisible({ timeout: 15000 });
await createBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 验证名称输入框
const nameInput = dialog.locator("#kb-name");
const hasNameInput = await nameInput.isVisible({ timeout: 5000 }).catch(() => false);
expect(hasNameInput).toBeTruthy();
// 验证描述输入框
const descTextarea = dialog.locator("#kb-desc");
const hasDesc = await descTextarea.isVisible({ timeout: 3000 }).catch(() => false);
expect(hasDesc).toBeTruthy();
});
test("填写知识库名称后创建按钮可点击", async ({ authenticatedPage }) => {
const createBtn = authenticatedPage.getByRole("button", { name: /创建知识库/ }).first();
await expect(createBtn).toBeVisible({ timeout: 15000 });
await createBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 初始状态下创建按钮应禁用
const submitBtn = dialog.getByRole("button", { name: "创建" });
const isDisabled = await submitBtn.isDisabled().catch(() => true);
expect(isDisabled).toBeTruthy();
// 填写名称
const nameInput = dialog.locator("#kb-name");
await nameInput.fill("E2E测试知识库");
// 创建按钮应变为可点击
await expect(submitBtn).toBeEnabled();
});
test("填写完整信息后点击创建提交", async ({ authenticatedPage }) => {
const createBtn = authenticatedPage.getByRole("button", { name: /创建知识库/ }).first();
await expect(createBtn).toBeVisible({ timeout: 15000 });
await createBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 填写名称
const nameInput = dialog.locator("#kb-name");
await nameInput.fill("E2E测试知识库");
// 填写描述
const descTextarea = dialog.locator("#kb-desc");
await descTextarea.fill("E2E自动化测试创建的知识库");
// 点击创建
const submitBtn = dialog.getByRole("button", { name: "创建" });
await submitBtn.click();
// 等待创建完成(对话框关闭或显示加载状态)
await authenticatedPage.waitForTimeout(3000);
});
test("点击取消按钮关闭创建对话框", async ({ authenticatedPage }) => {
const createBtn = authenticatedPage.getByRole("button", { name: /创建知识库/ }).first();
await expect(createBtn).toBeVisible({ timeout: 15000 });
await createBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 点击取消
const cancelBtn = dialog.getByRole("button", { name: "取消" });
await cancelBtn.click();
// 验证对话框关闭
await expect(dialog).not.toBeVisible({ timeout: 5000 });
});
});
test.describe("知识库 - 文档列表交互测试", () => {
test.beforeEach(async ({ authenticatedPage }) => {
await authenticatedPage.goto("/dashboard/knowledge");
await authenticatedPage.waitForLoadState("networkidle");
});
test("切换企业知识库和行业知识库Tab", async ({ authenticatedPage }) => {
const enterpriseTab = authenticatedPage.getByRole("tab", { name: /企业知识库/ });
const industryTab = authenticatedPage.getByRole("tab", { name: /行业知识库/ });
const hasEnterprise = await enterpriseTab.isVisible({ timeout: 15000 }).catch(() => false);
const hasIndustry = await industryTab.isVisible({ timeout: 3000 }).catch(() => false);
if (!hasEnterprise && !hasIndustry) {
test.skip();
return;
}
// 切换到行业知识库
if (hasIndustry) {
await industryTab.click();
await authenticatedPage.waitForTimeout(1000);
}
// 切换回企业知识库
if (hasEnterprise) {
await enterpriseTab.click();
await authenticatedPage.waitForTimeout(1000);
}
});
test("搜索知识库功能", async ({ authenticatedPage }) => {
// 查找搜索输入框
const searchInput = authenticatedPage.locator('input[placeholder*="搜索知识库"]');
const hasSearch = await searchInput.isVisible({ timeout: 15000 }).catch(() => false);
if (!hasSearch) {
test.skip();
return;
}
// 输入搜索关键词
await searchInput.fill("测试搜索");
// 验证搜索已触发前端过滤无需等待API
await authenticatedPage.waitForTimeout(500);
// 清空搜索
await searchInput.clear();
await authenticatedPage.waitForTimeout(500);
});
test("展开知识库卡片查看文档列表", async ({ authenticatedPage }) => {
// 等待知识库列表加载
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
// 查找知识库卡片
const kbCards = authenticatedPage.locator("div.grid.grid-cols-1 > div.space-y-3 > div.cursor-pointer, div.grid.gap-4 > div.space-y-3 > div.cursor-pointer");
const cardCount = await kbCards.count();
if (cardCount === 0) {
// 尝试更通用的选择器
const allCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const allCount = await allCards.count();
if (allCount === 0) {
test.skip();
return;
}
// 点击第一张卡片展开
await allCards.first().click();
} else {
// 点击第一张卡片展开
await kbCards.first().click();
}
// 等待文档列表加载
await authenticatedPage.waitForTimeout(2000);
// 验证文档列表标题可见
const docListTitle = authenticatedPage.getByText("文档列表");
const hasDocList = await docListTitle.isVisible({ timeout: 10000 }).catch(() => false);
if (!hasDocList) {
test.skip();
return;
}
await expect(docListTitle).toBeVisible();
});
test("文档列表显示上传文档按钮", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
// 展开第一个知识库
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
await kbCards.first().click();
await authenticatedPage.waitForTimeout(2000);
// 验证上传文档按钮
const uploadBtn = authenticatedPage.getByRole("button", { name: /上传文档/ });
const hasUpload = await uploadBtn.isVisible({ timeout: 10000 }).catch(() => false);
if (!hasUpload) {
test.skip();
return;
}
await expect(uploadBtn).toBeVisible();
});
});
test.describe("知识库 - 上传文档交互测试", () => {
test.beforeEach(async ({ authenticatedPage }) => {
await authenticatedPage.goto("/dashboard/knowledge");
await authenticatedPage.waitForLoadState("networkidle");
});
test("点击上传文档按钮打开上传对话框", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
// 展开第一个知识库
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
await kbCards.first().click();
await authenticatedPage.waitForTimeout(2000);
// 点击上传文档按钮
const uploadBtn = authenticatedPage.getByRole("button", { name: /上传文档/ });
const hasUpload = await uploadBtn.isVisible({ timeout: 10000 }).catch(() => false);
if (!hasUpload) {
test.skip();
return;
}
await uploadBtn.click();
// 验证上传对话框
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 验证对话框标题
await expect(dialog.getByRole("heading", { name: "上传文档" })).toBeVisible();
});
test("上传文档对话框包含标题、来源类型和内容输入", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
await kbCards.first().click();
await authenticatedPage.waitForTimeout(2000);
const uploadBtn = authenticatedPage.getByRole("button", { name: /上传文档/ });
const hasUpload = await uploadBtn.isVisible({ timeout: 10000 }).catch(() => false);
if (!hasUpload) {
test.skip();
return;
}
await uploadBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 验证标题输入框
const titleInput = dialog.locator("#doc-title");
const hasTitle = await titleInput.isVisible({ timeout: 5000 }).catch(() => false);
expect(hasTitle).toBeTruthy();
// 验证来源类型选择器
const sourceTypeLabel = dialog.getByText("来源类型");
const hasSourceType = await sourceTypeLabel.isVisible({ timeout: 3000 }).catch(() => false);
expect(hasSourceType).toBeTruthy();
});
test("切换来源类型为URL后显示URL输入框", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
await kbCards.first().click();
await authenticatedPage.waitForTimeout(2000);
const uploadBtn = authenticatedPage.getByRole("button", { name: /上传文档/ });
const hasUpload = await uploadBtn.isVisible({ timeout: 10000 }).catch(() => false);
if (!hasUpload) {
test.skip();
return;
}
await uploadBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 点击来源类型下拉框
const sourceTypeTrigger = dialog.locator("button").filter({ hasText: /文本|URL|Markdown/ }).first();
const hasTrigger = await sourceTypeTrigger.isVisible({ timeout: 5000 }).catch(() => false);
if (!hasTrigger) {
test.skip();
return;
}
await sourceTypeTrigger.click();
// 选择URL选项
const urlOption = authenticatedPage.getByRole("option", { name: "URL" })
.or(authenticatedPage.locator("[data-radix-collection-item]").filter({ hasText: "URL" }));
const hasUrlOption = await urlOption.first().isVisible({ timeout: 5000 }).catch(() => false);
if (!hasUrlOption) {
test.skip();
return;
}
await urlOption.first().click();
// 验证URL输入框出现
const urlInput = dialog.locator("#doc-url");
const hasUrlInput = await urlInput.isVisible({ timeout: 5000 }).catch(() => false);
expect(hasUrlInput).toBeTruthy();
});
test("填写文档信息后上传按钮可点击", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
await kbCards.first().click();
await authenticatedPage.waitForTimeout(2000);
const uploadBtn = authenticatedPage.getByRole("button", { name: /上传文档/ });
const hasUpload = await uploadBtn.isVisible({ timeout: 10000 }).catch(() => false);
if (!hasUpload) {
test.skip();
return;
}
await uploadBtn.click();
const dialog = authenticatedPage.getByRole("dialog");
await expect(dialog).toBeVisible({ timeout: 10000 });
// 填写标题
const titleInput = dialog.locator("#doc-title");
await titleInput.fill("E2E测试文档");
// 填写内容(默认是文本类型)
const contentTextarea = dialog.locator("#doc-content");
const hasContent = await contentTextarea.isVisible({ timeout: 3000 }).catch(() => false);
if (hasContent) {
await contentTextarea.fill("这是E2E自动化测试上传的文档内容");
}
// 验证上传按钮可点击
const submitBtn = dialog.getByRole("button", { name: "上传" });
await expect(submitBtn).toBeEnabled();
});
});
test.describe("知识库 - 删除文档交互测试", () => {
test.beforeEach(async ({ authenticatedPage }) => {
await authenticatedPage.goto("/dashboard/knowledge");
await authenticatedPage.waitForLoadState("networkidle");
});
test("展开知识库后文档列表中每行显示删除按钮", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
// 展开第一个知识库
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
await kbCards.first().click();
await authenticatedPage.waitForTimeout(2000);
// 查找文档表格
const docTable = authenticatedPage.locator("table");
const hasTable = await docTable.isVisible({ timeout: 10000 }).catch(() => false);
if (!hasTable) {
// 可能没有文档
const noDocs = authenticatedPage.getByText("暂无文档");
const hasNoDocs = await noDocs.isVisible({ timeout: 5000 }).catch(() => false);
if (hasNoDocs) {
test.skip();
return;
}
test.skip();
return;
}
// 验证操作列存在
const actionHeader = authenticatedPage.getByText("操作");
const hasActionHeader = await actionHeader.isVisible({ timeout: 5000 }).catch(() => false);
expect(hasActionHeader).toBeTruthy();
});
test("点击文档删除按钮移除文档", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
// 展开第一个知识库
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
await kbCards.first().click();
await authenticatedPage.waitForTimeout(2000);
// 查找文档表格行
const docRows = authenticatedPage.locator("table tbody tr");
const rowCount = await docRows.count();
if (rowCount === 0) {
test.skip();
return;
}
// 查找第一行的删除按钮
const firstRowDeleteBtn = docRows.first().locator("button").filter({
has: authenticatedPage.locator("svg.lucide-trash-2"),
});
const hasDeleteBtn = await firstRowDeleteBtn.isVisible({ timeout: 5000 }).catch(() => false);
if (!hasDeleteBtn) {
test.skip();
return;
}
// 点击删除
await firstRowDeleteBtn.click();
// 等待删除完成
await authenticatedPage.waitForTimeout(2000);
});
test("知识库卡片显示删除按钮", async ({ authenticatedPage }) => {
await authenticatedPage.waitForTimeout(2000);
const emptyState = authenticatedPage.getByText("还没有知识库");
const hasEmpty = await emptyState.isVisible({ timeout: 5000 }).catch(() => false);
if (hasEmpty) {
test.skip();
return;
}
// 查找知识库卡片中的删除按钮
const kbCards = authenticatedPage.locator("div.cursor-pointer.rounded-xl");
const cardCount = await kbCards.count();
if (cardCount === 0) {
test.skip();
return;
}
// 在第一张卡片中查找删除按钮
const deleteBtn = kbCards.first().locator("button").filter({
has: authenticatedPage.locator("svg.lucide-trash-2"),
});
const hasDeleteBtn = await deleteBtn.isVisible({ timeout: 5000 }).catch(() => false);
if (!hasDeleteBtn) {
test.skip();
return;
}
await expect(deleteBtn).toBeVisible();
});
});