Skip to content

Commit 87f6b00

Browse files
committed
✅ 新增 v1.4 关键改动的 E2E 覆盖
为 v1.4.0-beta.3 → beta.4 的核心改动补充 Playwright E2E(复用现有两阶段 userScripts fixture,并新增本地 mock server + host-resolver 域名映射,全程不依赖外网): - resource-update: @require/@resource 注入与读取、24h TTL 同 URL 去重、拉取失败优雅降级、多 require 并发全部加载 (#1193) - gm-xhr-site-access: 跨域 @connect 放行、x-sc-request-marker 经 DNR 剥离、非 @connect 域名拒绝 (#1477, mv3_utils) - background-script: @background 脚本经 Chrome offscreen 执行,具备 DOM 环境,并通过脚本内 GM 值读写闭环 + mock server probe 做稳定断言 (#1457) - user-config-yaml: 含 __proto__ 的恶意 @userconfig 被拒、原型链未污染 (#1494) - backup-zip: 备份导出/导入 zip 往返(JSZipp generateAsync/loadAsync)(#1479) - e2e waits: 移除固定 sleep/忙等,改为条件等待;并升级 workflow action runtime 版本 - server-fixtures: 共享 fixture + mock server
1 parent 313e464 commit 87f6b00

21 files changed

Lines changed: 1133 additions & 121 deletions

.github/workflows/build.yaml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ jobs:
1818
runs-on: ubuntu-latest
1919
name: Build
2020
steps:
21-
- uses: actions/checkout@v4
22-
- uses: pnpm/action-setup@v4
21+
- uses: actions/checkout@v5
22+
- uses: pnpm/action-setup@v5
2323

2424
- name: Use Node.js
25-
uses: actions/setup-node@v4
25+
uses: actions/setup-node@v5
2626
with:
2727
node-version: 22
2828
cache: 'pnpm'
@@ -38,17 +38,16 @@ jobs:
3838
pnpm run pack
3939
4040
- name: Archive production artifacts
41-
uses: actions/upload-artifact@v4
41+
uses: actions/upload-artifact@v6
4242
with:
4343
name: production-artifacts
4444
path: |
4545
dist/*.crx
4646
dist/*.zip
4747
4848
- name: Archive extension
49-
uses: actions/upload-artifact@v4
49+
uses: actions/upload-artifact@v6
5050
with:
5151
name: scriptcat-chrome-extension
5252
path: |
5353
dist/ext/*
54-

.github/workflows/packageRelease.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ jobs:
1111
runs-on: ubuntu-latest
1212

1313
steps:
14-
- uses: actions/checkout@v4
15-
- uses: pnpm/action-setup@v4
14+
- uses: actions/checkout@v5
15+
- uses: pnpm/action-setup@v5
1616

1717
- name: Use Node.js
18-
uses: actions/setup-node@v4
18+
uses: actions/setup-node@v5
1919
with:
2020
node-version: 22
2121
cache: 'pnpm'

.github/workflows/test.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ jobs:
1414
runs-on: ubuntu-latest
1515
name: Run tests
1616
steps:
17-
- uses: actions/checkout@v4
18-
- uses: pnpm/action-setup@v4
17+
- uses: actions/checkout@v5
18+
- uses: pnpm/action-setup@v5
1919

2020
- name: Use Node.js
21-
uses: actions/setup-node@v4
21+
uses: actions/setup-node@v5
2222
with:
2323
node-version: 22
2424
cache: 'pnpm'
@@ -30,7 +30,7 @@ jobs:
3030
run: pnpm i --frozen-lockfile
3131

3232
- name: Cache ESLint cache
33-
uses: actions/cache@v4
33+
uses: actions/cache@v5
3434
with:
3535
path: .eslintcache
3636
key: eslint-${{ hashFiles('pnpm-lock.yaml', '.eslintrc*') }}
@@ -54,11 +54,11 @@ jobs:
5454
runs-on: ubuntu-latest
5555
name: Run E2E tests
5656
steps:
57-
- uses: actions/checkout@v4
58-
- uses: pnpm/action-setup@v4
57+
- uses: actions/checkout@v5
58+
- uses: pnpm/action-setup@v5
5959

6060
- name: Use Node.js
61-
uses: actions/setup-node@v4
61+
uses: actions/setup-node@v5
6262
with:
6363
node-version: 22
6464
cache: 'pnpm'
@@ -71,7 +71,7 @@ jobs:
7171

7272
- name: Cache Playwright browsers
7373
id: playwright-cache
74-
uses: actions/cache@v4
74+
uses: actions/cache@v5
7575
with:
7676
path: ~/.cache/ms-playwright
7777
key: playwright-${{ hashFiles('pnpm-lock.yaml') }}
@@ -90,7 +90,7 @@ jobs:
9090

9191
- name: Upload test artifacts
9292
if: failure()
93-
uses: actions/upload-artifact@v4
93+
uses: actions/upload-artifact@v6
9494
with:
9595
name: e2e-test-results
9696
path: |

e2e/agent-chat.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { openAgentChatPage } from "./utils";
44
test.describe("Agent Chat", () => {
55
test("should show new chat button and model selector", async ({ context, extensionId }) => {
66
const page = await openAgentChatPage(context, extensionId);
7-
await page.waitForTimeout(2000);
87

98
// 新建会话按钮应可见
109
const newChatBtn = page.locator("button", { hasText: /new|/i }).first();

e2e/agent-navigation.spec.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,40 @@ import { openAgentChatPage, openAgentProviderPage, openOptionsPage } from "./uti
44
test.describe("Agent Navigation", () => {
55
test("should navigate to agent chat page via sidebar", async ({ context, extensionId }) => {
66
const page = await openOptionsPage(context, extensionId);
7-
await page.waitForTimeout(1000);
87

98
// Agent SubMenu title 的 onClick 直接导航到 /agent/chat
109
// Sider.tsx 中 SubMenu title 的 span onClick 设置 hash
1110
const agentMenuTitle = page.locator(".arco-menu-inline-header span", { hasText: /agent/i }).first();
11+
await expect(agentMenuTitle).toBeVisible({ timeout: 10_000 });
1212
await agentMenuTitle.click();
13-
await page.waitForTimeout(1000);
1413

1514
// 验证 URL hash 包含 /agent
16-
expect(page.url()).toContain("#/agent");
15+
await expect(page).toHaveURL(/#\/agent/);
1716
await page.close();
1817
});
1918

2019
test("should navigate to agent sub-pages via sidebar", async ({ context, extensionId }) => {
2120
const page = await openOptionsPage(context, extensionId);
22-
await page.waitForTimeout(1000);
2321

2422
// 先展开 Agent 子菜单
2523
const agentMenuHeader = page.locator(".arco-menu-inline-header").filter({ hasText: /agent/i }).first();
24+
await expect(agentMenuHeader).toBeVisible({ timeout: 10_000 });
2625
await agentMenuHeader.click();
27-
await page.waitForTimeout(500);
2826

2927
// 展开后点击 Provider 子菜单项(使用 key 属性匹配)
3028
const providerItem = page
3129
.locator('[class*="arco-menu-item"]')
3230
.filter({ hasText: /model service|provider|/i })
3331
.first();
32+
await expect(providerItem).toBeVisible({ timeout: 10_000 });
3433
await providerItem.click();
35-
await page.waitForTimeout(1000);
3634

37-
expect(page.url()).toContain("#/agent/provider");
35+
await expect(page).toHaveURL(/#\/agent\/provider/);
3836
await page.close();
3937
});
4038

4139
test("should load agent chat page directly", async ({ context, extensionId }) => {
4240
const page = await openAgentChatPage(context, extensionId);
43-
await page.waitForTimeout(2000);
4441

4542
// 聊天页面应包含新建会话按钮
4643
const newChatBtn = page.locator("button", { hasText: /new|/i }).first();
@@ -50,7 +47,6 @@ test.describe("Agent Navigation", () => {
5047

5148
test("should load agent provider page directly", async ({ context, extensionId }) => {
5249
const page = await openAgentProviderPage(context, extensionId);
53-
await page.waitForTimeout(2000);
5450

5551
// Provider 页面应包含添加模型按钮
5652
const addBtn = page.locator("button", { hasText: /add|/i }).first();
@@ -60,7 +56,6 @@ test.describe("Agent Navigation", () => {
6056

6157
test("should show empty state on provider page when no models configured", async ({ context, extensionId }) => {
6258
const page = await openAgentProviderPage(context, extensionId);
63-
await page.waitForTimeout(2000);
6459

6560
// 没有配置模型时应显示空状态
6661
const emptyState = page.locator(".arco-empty");

e2e/agent-provider.spec.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@ import { openAgentProviderPage } from "./utils";
44
test.describe("Agent Provider Management", () => {
55
test("should show empty state when no models configured", async ({ context, extensionId }) => {
66
const page = await openAgentProviderPage(context, extensionId);
7-
await page.waitForTimeout(2000);
87

98
await expect(page.locator(".arco-empty")).toBeVisible({ timeout: 10000 });
109
await page.close();
1110
});
1211

1312
test("should open add model dialog with correct form fields", async ({ context, extensionId }) => {
1413
const page = await openAgentProviderPage(context, extensionId);
15-
await page.waitForTimeout(2000);
1614

1715
// 点击添加按钮
1816
const addBtn = page.locator("button.arco-btn-primary").first();
17+
await expect(addBtn).toBeVisible({ timeout: 10_000 });
1918
await addBtn.evaluate((element) => (element as HTMLElement).click());
2019

2120
// 验证弹窗出现
@@ -50,21 +49,18 @@ test.describe("Agent Provider Management", () => {
5049
.locator("button", { hasText: /cancel|/i })
5150
.first()
5251
.evaluate((element) => (element as HTMLElement).click());
53-
await page.waitForTimeout(500);
5452
await expect(modal).not.toBeVisible();
5553

5654
await page.close();
5755
});
5856

5957
test("should switch provider between OpenAI and Anthropic", async ({ context, extensionId }) => {
6058
const page = await openAgentProviderPage(context, extensionId);
61-
await page.waitForTimeout(2000);
6259

6360
// 打开添加弹窗
64-
await page
65-
.locator("button.arco-btn-primary")
66-
.first()
67-
.evaluate((element) => (element as HTMLElement).click());
61+
const addBtn = page.locator("button.arco-btn-primary").first();
62+
await expect(addBtn).toBeVisible({ timeout: 10_000 });
63+
await addBtn.evaluate((element) => (element as HTMLElement).click());
6864
const modal = page.locator(".arco-modal");
6965
await expect(modal).toBeVisible({ timeout: 5000 });
7066

@@ -75,9 +71,9 @@ test.describe("Agent Provider Management", () => {
7571
// 切换到 Anthropic
7672
const providerSelect = modal.locator(".arco-select").first();
7773
await providerSelect.evaluate((element) => (element as HTMLElement).click());
78-
await page.waitForTimeout(300);
79-
await page.locator(".arco-select-option", { hasText: "Anthropic" }).click();
80-
await page.waitForTimeout(500);
74+
const anthropicOption = page.locator(".arco-select-option", { hasText: "Anthropic" });
75+
await expect(anthropicOption).toBeVisible({ timeout: 10_000 });
76+
await anthropicOption.click();
8177

8278
// placeholder 应变为 anthropic.com
8379
const anthropicInput = modal.locator('input[placeholder*="anthropic"]');

0 commit comments

Comments
 (0)