This commit is contained in:
@@ -3,7 +3,7 @@ import { expect, test, type Page } from "@playwright/test";
|
||||
const responses: Record<string, unknown> = {
|
||||
"system/status": {
|
||||
initialized: true,
|
||||
appServer: true,
|
||||
cpa: true,
|
||||
version: "0.3.0-beta.1",
|
||||
},
|
||||
"auth/me": { username: "admin" },
|
||||
@@ -20,6 +20,7 @@ const responses: Record<string, unknown> = {
|
||||
{
|
||||
id: 1,
|
||||
displayName: "默认账号",
|
||||
authIndex: "index-default",
|
||||
email: "test@example.com",
|
||||
planType: "plus",
|
||||
expectedKind: "personal",
|
||||
@@ -56,7 +57,7 @@ async function openSettings(page: Page, version = "0.3.0-beta.1") {
|
||||
await new Promise((resolve) => setTimeout(resolve, 40));
|
||||
if (key === "system/status") {
|
||||
await route.fulfill({
|
||||
json: { initialized: true, appServer: true, version },
|
||||
json: { initialized: true, cpa: true, version },
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -159,7 +160,7 @@ test("shows every account as a collapsible summary on the overview", async ({
|
||||
const key = new URL(request.url()).pathname.replace("/api/v1/", "");
|
||||
if (key === "system/status")
|
||||
return route.fulfill({
|
||||
json: { initialized: true, appServer: true, version: "test" },
|
||||
json: { initialized: true, cpa: true, version: "test" },
|
||||
});
|
||||
if (key === "auth/me")
|
||||
return route.fulfill({ json: { username: "admin" } });
|
||||
@@ -247,7 +248,7 @@ test("shows a read-only overview before login", async ({ page }) => {
|
||||
const key = new URL(route.request().url()).pathname.replace("/api/v1/", "");
|
||||
if (key === "system/status")
|
||||
return route.fulfill({
|
||||
json: { initialized: true, appServer: true, version: "test" },
|
||||
json: { initialized: true, cpa: true, version: "test" },
|
||||
});
|
||||
if (key === "auth/me")
|
||||
return route.fulfill({ status: 401, json: { error: "未登录" } });
|
||||
@@ -354,7 +355,7 @@ test("keeps the authenticated brand on one line with a release version", async (
|
||||
test("shows the build version before setup", async ({ page }) => {
|
||||
await page.route("**/api/v1/system/status", (route) =>
|
||||
route.fulfill({
|
||||
json: { initialized: false, appServer: false, version: "test" },
|
||||
json: { initialized: false, cpa: false, version: "test" },
|
||||
}),
|
||||
);
|
||||
await page.goto("/");
|
||||
@@ -370,7 +371,7 @@ test("shows the build version before setup", async ({ page }) => {
|
||||
test("shows the build version on login", async ({ page }) => {
|
||||
await page.route("**/api/v1/system/status", (route) =>
|
||||
route.fulfill({
|
||||
json: { initialized: true, appServer: false, version: "test" },
|
||||
json: { initialized: true, cpa: false, version: "test" },
|
||||
}),
|
||||
);
|
||||
await page.route("**/api/v1/auth/me", (route) =>
|
||||
@@ -633,56 +634,50 @@ test("programmatic tab changes do not clamp an existing scroll position", async
|
||||
.toEqual(before.content);
|
||||
});
|
||||
|
||||
test("deleting a newly added account clears its device authorization", async ({
|
||||
test("deleting a newly added account keeps the CPA credential external", async ({
|
||||
page,
|
||||
}) => {
|
||||
let accounts: Array<(typeof responses.accounts)[number]> = [];
|
||||
let createdAuthIndex = "";
|
||||
await page.route("**/api/v1/**", async (route) => {
|
||||
const request = route.request();
|
||||
const key = new URL(request.url()).pathname.replace("/api/v1/", "");
|
||||
if (key === "accounts" && request.method() === "GET")
|
||||
return route.fulfill({ json: accounts });
|
||||
if (key === "accounts" && request.method() === "POST") {
|
||||
const body = request.postDataJSON() as { authIndex: string };
|
||||
createdAuthIndex = body.authIndex;
|
||||
const account = {
|
||||
...responses.accounts[0],
|
||||
id: 2,
|
||||
displayName: "账号 1",
|
||||
email: "",
|
||||
connected: false,
|
||||
validationStatus: "pending" as const,
|
||||
displayName: "CPA 账号",
|
||||
authIndex: body.authIndex,
|
||||
};
|
||||
accounts = [account];
|
||||
return route.fulfill({ json: account });
|
||||
}
|
||||
if (key === "accounts/2/login/device")
|
||||
return route.fulfill({
|
||||
json: {
|
||||
verificationUrl: "https://auth.openai.com/codex/device",
|
||||
userCode: "PLTJ-7M6I6",
|
||||
},
|
||||
});
|
||||
if (key === "accounts/2" && request.method() === "DELETE") {
|
||||
accounts = [];
|
||||
return route.fulfill({ json: { ok: true } });
|
||||
}
|
||||
return route.fulfill({ json: responses[key] ?? {} });
|
||||
});
|
||||
page.on("dialog", (dialog) => dialog.accept());
|
||||
page.on("dialog", (dialog) => {
|
||||
expect(dialog.message()).toContain("不会删除 CLIProxyAPI 中的凭据");
|
||||
void dialog.accept();
|
||||
});
|
||||
await page.goto("/settings");
|
||||
await page.getByRole("tab", { name: "Codex" }).click();
|
||||
await page.getByLabel("CPA authIndex", { exact: true }).fill("index-new");
|
||||
await page.getByRole("button", { name: "添加账号" }).click();
|
||||
await expect(page.getByText("PLTJ-7M6I6")).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole("link", { name: "https://auth.openai.com/codex/device" }),
|
||||
).toBeVisible();
|
||||
await expect.poll(() => createdAuthIndex).toBe("index-new");
|
||||
await expect(page.getByLabel("“CPA 账号”的 CPA authIndex")).toHaveValue(
|
||||
"index-new",
|
||||
);
|
||||
|
||||
await page.getByRole("button", { name: "删除“账号 1”" }).click();
|
||||
await expect(page.getByText("PLTJ-7M6I6")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "删除“CPA 账号”" }).click();
|
||||
await expect(
|
||||
page.getByRole("link", { name: "https://auth.openai.com/codex/device" }),
|
||||
).toHaveCount(0);
|
||||
await expect(
|
||||
page.getByText("尚未添加 Codex 账号", { exact: false }),
|
||||
page.getByText("尚未绑定 CPA Codex 账号", { exact: false }),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -690,7 +685,7 @@ test("sets public visibility when adding and editing an account", async ({
|
||||
page,
|
||||
}) => {
|
||||
let accounts: Array<(typeof responses.accounts)[number]> = [];
|
||||
let createdBody: { publicVisible?: boolean } | undefined;
|
||||
let createdBody: { authIndex?: string; publicVisible?: boolean } | undefined;
|
||||
let updatedBody: { publicVisible?: boolean } | undefined;
|
||||
await page.route("**/api/v1/**", async (route) => {
|
||||
const request = route.request();
|
||||
@@ -698,11 +693,15 @@ test("sets public visibility when adding and editing an account", async ({
|
||||
if (key === "accounts" && request.method() === "GET")
|
||||
return route.fulfill({ json: accounts });
|
||||
if (key === "accounts" && request.method() === "POST") {
|
||||
createdBody = request.postDataJSON() as { publicVisible?: boolean };
|
||||
createdBody = request.postDataJSON() as {
|
||||
authIndex?: string;
|
||||
publicVisible?: boolean;
|
||||
};
|
||||
const account = {
|
||||
...responses.accounts[0],
|
||||
id: 2,
|
||||
displayName: "账号 1",
|
||||
authIndex: createdBody.authIndex ?? "",
|
||||
email: "",
|
||||
connected: false,
|
||||
validationStatus: "pending" as const,
|
||||
@@ -711,13 +710,6 @@ test("sets public visibility when adding and editing an account", async ({
|
||||
accounts = [account];
|
||||
return route.fulfill({ json: account });
|
||||
}
|
||||
if (key === "accounts/2/login/device")
|
||||
return route.fulfill({
|
||||
json: {
|
||||
verificationUrl: "https://auth.openai.com/codex/device",
|
||||
userCode: "PLTJ-7M6I6",
|
||||
},
|
||||
});
|
||||
if (key === "accounts/2" && request.method() === "PUT") {
|
||||
updatedBody = request.postDataJSON() as { publicVisible?: boolean };
|
||||
accounts = [
|
||||
@@ -738,8 +730,10 @@ test("sets public visibility when adding and editing an account", async ({
|
||||
);
|
||||
await expect(addVisibility).not.toBeChecked();
|
||||
await addVisibility.check();
|
||||
await page.getByLabel("CPA authIndex", { exact: true }).fill("index-public");
|
||||
await page.getByRole("button", { name: "添加账号" }).click();
|
||||
await expect.poll(() => createdBody?.publicVisible).toBe(true);
|
||||
expect(createdBody?.authIndex).toBe("index-public");
|
||||
|
||||
const accountCard = page.locator(".account-card");
|
||||
const accountVisibility = accountCard.locator('input[type="checkbox"]');
|
||||
@@ -751,6 +745,35 @@ test("sets public visibility when adding and editing an account", async ({
|
||||
await expect(accountVisibility).not.toBeChecked();
|
||||
});
|
||||
|
||||
test("changing authIndex confirms local history deletion", async ({ page }) => {
|
||||
let account = { ...responses.accounts[0] };
|
||||
let updatedBody: { authIndex?: string } | undefined;
|
||||
await page.route("**/api/v1/**", async (route) => {
|
||||
const request = route.request();
|
||||
const key = new URL(request.url()).pathname.replace("/api/v1/", "");
|
||||
if (key === "accounts" && request.method() === "GET")
|
||||
return route.fulfill({ json: [account] });
|
||||
if (key === "accounts/1" && request.method() === "PUT") {
|
||||
updatedBody = request.postDataJSON() as { authIndex?: string };
|
||||
account = { ...account, authIndex: updatedBody.authIndex ?? "" };
|
||||
return route.fulfill({ json: { ok: true } });
|
||||
}
|
||||
return route.fulfill({ json: responses[key] ?? {} });
|
||||
});
|
||||
page.on("dialog", (dialog) => {
|
||||
expect(dialog.message()).toContain("会清除该本地账号已有的 Token 历史");
|
||||
void dialog.accept();
|
||||
});
|
||||
|
||||
await page.goto("/settings");
|
||||
await page.getByRole("tab", { name: "Codex" }).click();
|
||||
const input = page.getByLabel("“默认账号”的 CPA authIndex");
|
||||
await input.fill("index-rebound");
|
||||
await input.blur();
|
||||
await expect.poll(() => updatedBody?.authIndex).toBe("index-rebound");
|
||||
await expect(input).toHaveValue("index-rebound");
|
||||
});
|
||||
|
||||
test("Codex account cards fit within the viewport", async ({ page }) => {
|
||||
await openSettings(page);
|
||||
await page.getByRole("tab", { name: "Codex" }).click();
|
||||
|
||||
Reference in New Issue
Block a user