chore: retire openhub and pi ts runtime
This commit is contained in:
@@ -97,8 +97,8 @@ async function main() {
|
||||
|
||||
const openHubLink = page.locator('a[href="/page-ai/openhub/admin"]');
|
||||
assert(
|
||||
await openHubLink.count() >= 1,
|
||||
"OpenHub Admin 独立入口必须保留",
|
||||
await openHubLink.count() === 0,
|
||||
"OpenHub Admin 独立入口必须从当前 AI 管理页移除",
|
||||
);
|
||||
|
||||
await page.getByRole("link", { name: "模型配置" }).click();
|
||||
@@ -122,27 +122,37 @@ async function main() {
|
||||
await page.getByRole("button", { name: "保存策略" }).click();
|
||||
await page.locator("[data-ai-admin-tools-save-status]").filter({ hasText: /已保存/ }).waitFor();
|
||||
|
||||
await page.getByRole("link", { name: "技能 / MCP" }).click();
|
||||
await page.getByRole("link", { name: "Skills" }).click();
|
||||
await page.locator("#ai-admin-skills.is-active").waitFor();
|
||||
await page.getByRole("button", { name: "+ 添加 Skill" }).click();
|
||||
const skillRow = page.locator(".mnote-ai-admin-skill-row").last();
|
||||
await skillRow.locator('[name="skillName"]').fill(skillName);
|
||||
await skillRow.locator('[name="skillDescription"]').fill("浏览器验收技能");
|
||||
await skillRow.locator('[name="skillEnabled"]').check();
|
||||
const skillsPanel = page.locator("#ai-admin-skills");
|
||||
await skillsPanel.getByRole("button", { name: "保存 Skills" }).click();
|
||||
await assertEventually(
|
||||
async () => (await skillsPanel.locator("[data-ai-admin-skills-save-status]").textContent()) || "",
|
||||
(text) => text.includes("已保存"),
|
||||
"Skills 配置保存状态未变为已保存",
|
||||
);
|
||||
|
||||
await page.getByRole("link", { name: "MCP" }).click();
|
||||
await page.locator("#ai-admin-mcp.is-active").waitFor();
|
||||
await page.getByRole("button", { name: "+ 添加 MCP" }).click();
|
||||
const mcpRow = page.locator("[data-mcp-idx]").last();
|
||||
await mcpRow.locator("summary").click();
|
||||
await mcpRow.locator('[name="mcpName"]').fill(mcpName);
|
||||
await mcpRow.locator('[name="mcpTransport"]').selectOption("stdio");
|
||||
await mcpRow.locator('[name="mcpCommand"]').fill("scripts/lightrag-native-mcp.sh");
|
||||
await mcpRow.locator('[name="mcpSecretRefs"]').fill("env://LIGHTRAG_API_KEY");
|
||||
await mcpRow.locator('[name="mcpEnabled"]').check();
|
||||
const skillsPanel = page.locator("#ai-admin-skills");
|
||||
await skillsPanel.getByRole("button", { name: "保存配置" }).click();
|
||||
const mcpPanel = page.locator("#ai-admin-mcp");
|
||||
await mcpPanel.getByRole("button", { name: "保存 MCP" }).click();
|
||||
await assertEventually(
|
||||
async () => (await skillsPanel.locator("[data-ai-admin-skills-save-status]").textContent()) || "",
|
||||
async () => (await mcpPanel.locator("[data-ai-admin-mcp-save-status]").textContent()) || "",
|
||||
(text) => text.includes("已保存"),
|
||||
"技能/MCP 配置保存状态未变为已保存",
|
||||
"MCP 配置保存状态未变为已保存",
|
||||
);
|
||||
await page.screenshot({
|
||||
path: path.join(OUTPUT_DIR, "skills-mcp.png"),
|
||||
@@ -155,19 +165,55 @@ async function main() {
|
||||
await targetUser.waitFor();
|
||||
await targetUser.click();
|
||||
await page.locator('[data-ai-admin-user-settings] h3', { hasText: "ai-user" }).waitFor();
|
||||
await page.locator('[data-user-model="omniroute/freefirst-fast"]').evaluate((input) => {
|
||||
input.checked = false;
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
const disabledModelId = await page.locator("[data-user-model]").evaluateAll((inputs) => {
|
||||
const checked = inputs
|
||||
.filter((input) => input.checked)
|
||||
.map((input) => input.getAttribute("data-user-model") || "")
|
||||
.filter(Boolean);
|
||||
return checked.length > 1 ? (checked.find((id) => id !== "omniroute/freefirst") || checked[1]) : "";
|
||||
});
|
||||
await page.locator('[data-action="save-user-settings"]').click();
|
||||
await page.locator("[data-ai-admin-user-save-status]").filter({ hasText: /已保存/ }).waitFor();
|
||||
if (disabledModelId) {
|
||||
await page.locator(`[data-user-model="${disabledModelId}"]`).evaluate((input) => {
|
||||
input.checked = false;
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
});
|
||||
const saveModelOverride = await Promise.all([
|
||||
page.waitForResponse((response) =>
|
||||
response.url().includes("/api/ai-admin/users/ai-user/settings") &&
|
||||
response.request().method() === "PUT"
|
||||
),
|
||||
page.locator('[data-action="save-user-settings"]').click(),
|
||||
]).then(([response]) => response);
|
||||
assert(
|
||||
saveModelOverride.ok(),
|
||||
`模型降权保存失败: ${saveModelOverride.status()} ${await saveModelOverride.text()}`,
|
||||
);
|
||||
}
|
||||
await page.locator('[data-user-tab="skills"]').click();
|
||||
await page.locator(`[data-user-skill="${skillName}"]`).evaluate((input) => {
|
||||
input.checked = false;
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
const disabledSkillId = await page.locator("[data-user-skill]").evaluateAll((inputs) => {
|
||||
const checked = inputs
|
||||
.filter((input) => input.checked)
|
||||
.map((input) => input.getAttribute("data-user-skill") || "")
|
||||
.filter(Boolean);
|
||||
return checked[0] || "";
|
||||
});
|
||||
await page.locator('[data-action="save-user-settings"]').click();
|
||||
await page.locator("[data-ai-admin-user-save-status]").filter({ hasText: /已保存/ }).waitFor();
|
||||
if (disabledSkillId) {
|
||||
await page.locator(`[data-user-skill="${disabledSkillId}"]`).evaluate((input) => {
|
||||
input.checked = false;
|
||||
input.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
});
|
||||
const saveSkillOverride = await Promise.all([
|
||||
page.waitForResponse((response) =>
|
||||
response.url().includes("/api/ai-admin/users/ai-user/settings") &&
|
||||
response.request().method() === "PUT"
|
||||
),
|
||||
page.locator('[data-action="save-user-settings"]').click(),
|
||||
]).then(([response]) => response);
|
||||
assert(
|
||||
saveSkillOverride.ok(),
|
||||
`Skill 降权保存失败: ${saveSkillOverride.status()} ${await saveSkillOverride.text()}`,
|
||||
);
|
||||
}
|
||||
await page.screenshot({
|
||||
path: path.join(OUTPUT_DIR, "users.png"),
|
||||
fullPage: false,
|
||||
@@ -178,17 +224,23 @@ async function main() {
|
||||
const drawer = document.querySelector("[data-ai-admin-user-drawer]");
|
||||
return !drawer || !drawer.classList.contains("is-open");
|
||||
});
|
||||
await page.getByRole("link", { name: "技能 / MCP" }).click();
|
||||
await page.getByRole("link", { name: "Skills" }).click();
|
||||
await page.reload({ waitUntil: "commit" });
|
||||
await page.locator("#ai-admin-skills.is-active").waitFor();
|
||||
assert.equal(
|
||||
await page.locator(`[name="skillName"][value="${skillName}"]`).count(),
|
||||
1,
|
||||
await assertEventually(
|
||||
async () => page.locator('[name="skillName"]').evaluateAll((inputs) =>
|
||||
inputs.map((input) => input.value || ""),
|
||||
),
|
||||
(values) => values.includes(skillName),
|
||||
"Skill 保存后刷新必须仍存在",
|
||||
);
|
||||
assert.equal(
|
||||
await page.locator(`[name="mcpName"][value="${mcpName}"]`).count(),
|
||||
1,
|
||||
await page.getByRole("link", { name: "MCP" }).click();
|
||||
await page.locator("#ai-admin-mcp.is-active").waitFor();
|
||||
await assertEventually(
|
||||
async () => page.locator('[name="mcpName"]').evaluateAll((inputs) =>
|
||||
inputs.map((input) => input.value || ""),
|
||||
),
|
||||
(values) => values.includes(mcpName),
|
||||
"MCP 保存后刷新必须仍存在",
|
||||
);
|
||||
|
||||
@@ -213,16 +265,20 @@ async function main() {
|
||||
const response = await fetch("/api/ai-admin/users/ai-user/settings", { credentials: "include" });
|
||||
return response.json();
|
||||
});
|
||||
assert.equal(
|
||||
(userSettings.allowedModels || []).some((model) => model.id === "omniroute/freefirst-fast"),
|
||||
false,
|
||||
"ai-user 刷新后不应包含被禁用模型",
|
||||
);
|
||||
assert.equal(
|
||||
(userSettings.skills || []).find((skill) => skill.id === skillName)?.enabled,
|
||||
false,
|
||||
"ai-user 刷新后应保留 Skill 禁用覆盖",
|
||||
);
|
||||
if (disabledModelId) {
|
||||
assert.equal(
|
||||
(userSettings.allowedModels || []).some((model) => model.id === disabledModelId),
|
||||
false,
|
||||
`ai-user 刷新后不应包含被禁用模型 ${disabledModelId}`,
|
||||
);
|
||||
}
|
||||
if (disabledSkillId) {
|
||||
assert.equal(
|
||||
(userSettings.skills || []).find((skill) => skill.id === disabledSkillId)?.enabled,
|
||||
false,
|
||||
`ai-user 刷新后应保留 Skill 禁用覆盖 ${disabledSkillId}`,
|
||||
);
|
||||
}
|
||||
|
||||
const userContext = await browser.newContext({ viewport: { width: 1280, height: 800 } });
|
||||
const userResponse = await userContext.request.post(`${BASE}/api/auth`, {
|
||||
@@ -244,16 +300,20 @@ async function main() {
|
||||
const userEffectiveResponse = await userContext.request.get(`${BASE}/api/ai-settings/effective`);
|
||||
assert(userEffectiveResponse.ok(), `ai-user effective 读取失败: ${userEffectiveResponse.status()}`);
|
||||
const userEffective = await userEffectiveResponse.json();
|
||||
assert.equal(
|
||||
(userEffective.models || []).some((model) => model.id === "omniroute/freefirst-fast"),
|
||||
false,
|
||||
"ai-user effective 不应包含被管理员取消的模型",
|
||||
);
|
||||
assert.equal(
|
||||
(userEffective.skills || []).some((skill) => skill.name === skillName),
|
||||
false,
|
||||
"ai-user effective 不应包含被禁用 Skill",
|
||||
);
|
||||
if (disabledModelId) {
|
||||
assert.equal(
|
||||
(userEffective.models || []).some((model) => model.id === disabledModelId),
|
||||
false,
|
||||
`ai-user effective 不应包含被管理员取消的模型 ${disabledModelId}`,
|
||||
);
|
||||
}
|
||||
if (disabledSkillId) {
|
||||
assert.equal(
|
||||
(userEffective.skills || []).some((skill) => skill.id === disabledSkillId || skill.name === disabledSkillId),
|
||||
false,
|
||||
`ai-user effective 不应包含被禁用 Skill ${disabledSkillId}`,
|
||||
);
|
||||
}
|
||||
await userContext.close();
|
||||
|
||||
console.log(JSON.stringify({
|
||||
|
||||
Reference in New Issue
Block a user