Skip to content

Commit 1b3f74c

Browse files
authored
test: focus adapter coverage on four priority sites (#339)
1 parent bdcffd1 commit 1b3f74c

8 files changed

Lines changed: 172 additions & 15 deletions

File tree

.github/workflows/ci.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,24 @@ jobs:
5454
run: npm ci
5555

5656
- name: Run unit tests (Node ${{ matrix.node-version }}, shard ${{ matrix.shard }}/2)
57-
run: npx vitest run src/ --reporter=verbose --shard=${{ matrix.shard }}/2
57+
run: npm test -- --reporter=verbose --shard=${{ matrix.shard }}/2
58+
59+
adapter-test:
60+
runs-on: ubuntu-latest
61+
needs: build
62+
steps:
63+
- uses: actions/checkout@v6
64+
65+
- uses: actions/setup-node@v6
66+
with:
67+
node-version: '22'
68+
cache: 'npm'
69+
70+
- name: Install dependencies
71+
run: npm ci
72+
73+
- name: Run focused adapter tests
74+
run: npm run test:adapter -- --reporter=verbose
5875

5976
# ── Smoke tests (scheduled / manual only) ──
6077
smoke-test:

CONTRIBUTING.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ npm run build
1717

1818
# 4. Run a few checks
1919
npx tsc --noEmit
20-
npx vitest run src/
20+
npm test
21+
npm run test:adapter
2122

2223
# 5. Link globally (optional, for testing `opencli` command)
2324
npm link
@@ -161,7 +162,8 @@ args: [
161162
See [TESTING.md](./TESTING.md) for the full guide and exact test locations.
162163

163164
```bash
164-
npx vitest run src/ # Unit tests
165+
npm test # Core unit tests (non-adapter)
166+
npm run test:adapter # Focused adapter tests: zhihu/twitter/reddit/bilibili
165167
npx vitest run tests/e2e/ # E2E tests
166168
npx vitest run # All tests
167169
```
@@ -194,7 +196,8 @@ Common scopes: site name (`twitter`, `reddit`) or module name (`browser`, `pipel
194196
3. Run the checks that apply:
195197
```bash
196198
npx tsc --noEmit # Type check
197-
npx vitest run src/ # Unit tests
199+
npm test # Core unit tests
200+
npm run test:adapter # Focused adapter tests (if you touched adapter logic)
198201
opencli validate # YAML validation (if applicable)
199202
```
200203
4. Commit using conventional commit format

docs/developer/contributing.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ npm run build
1717

1818
# 4. Run a few checks
1919
npx tsc --noEmit
20-
npx vitest run src/
20+
npm test
21+
npm run test:adapter
2122

2223
# 5. Link globally (optional, for testing `opencli` command)
2324
npm link
@@ -129,7 +130,8 @@ chore: bump vitest to v4
129130
3. Run the checks:
130131
```bash
131132
npx tsc --noEmit # Type check
132-
npx vitest run src/ # Unit tests
133+
npm test # Core unit tests
134+
npm run test:adapter # Focused adapter tests (if adapter logic changed)
133135
opencli validate # YAML validation (if applicable)
134136
```
135137
4. Commit using conventional commit format

docs/developer/testing.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,28 @@ tests/
3030
├── smoke/
3131
│ └── api-health.test.ts # 外部 API、adapter 定义、命令注册健康检查
3232
src/
33-
└── **/*.test.ts # 单元测试(当前 31 个文件)
33+
├── **/*.test.ts # 核心单元测试(默认 `unit` project)
34+
└── clis/{zhihu,twitter,reddit,bilibili}/**/*.test.ts # 聚焦 adapter tests
3435
```
3536

3637
|| 位置 | 当前文件数 | 运行方式 | 用途 |
3738
|---|---|---:|---|---|
38-
| 单元测试 | `src/**/*.test.ts` | 31 | `npx vitest run src/` | 内部模块、pipeline、adapter 工具函数 |
39+
| 单元测试 | `src/**/*.test.ts`(排除 `src/clis/**`| - | `npm test` | 内部模块、pipeline、runtime |
40+
| Adapter 测试 | `src/clis/{zhihu,twitter,reddit,bilibili}/**/*.test.ts` | - | `npm run test:adapter` | 保留 4 个重点站点的 adapter 覆盖 |
3941
| E2E 测试 | `tests/e2e/*.test.ts` | 5 | `npx vitest run tests/e2e/` | 真实 CLI 命令执行 |
4042
| 烟雾测试 | `tests/smoke/*.test.ts` | 1 | `npx vitest run tests/smoke/` | 外部 API 与注册完整性 |
4143

4244
---
4345

4446
## 当前覆盖范围
4547

46-
### 单元测试(31 个文件)
48+
### 单元测试与 Adapter 测试
4749

4850
| 领域 | 文件 |
4951
|---|---|
5052
| 核心运行时与输出 | `src/browser.test.ts`, `src/browser/dom-snapshot.test.ts`, `src/build-manifest.test.ts`, `src/capabilityRouting.test.ts`, `src/doctor.test.ts`, `src/engine.test.ts`, `src/interceptor.test.ts`, `src/output.test.ts`, `src/plugin.test.ts`, `src/registry.test.ts`, `src/snapshotFormatter.test.ts` |
5153
| pipeline 与下载 | `src/download/index.test.ts`, `src/pipeline/executor.test.ts`, `src/pipeline/template.test.ts`, `src/pipeline/transform.test.ts` |
52-
| 站点 / adapter 逻辑 | `src/clis/apple-podcasts/commands.test.ts`, `src/clis/apple-podcasts/utils.test.ts`, `src/clis/bloomberg/utils.test.ts`, `src/clis/chaoxing/utils.test.ts`, `src/clis/coupang/utils.test.ts`, `src/clis/google/utils.test.ts`, `src/clis/grok/ask.test.ts`, `src/clis/twitter/timeline.test.ts`, `src/clis/weread/utils.test.ts`, `src/clis/xiaohongshu/creator-note-detail.test.ts`, `src/clis/xiaohongshu/creator-notes-summary.test.ts`, `src/clis/xiaohongshu/creator-notes.test.ts`, `src/clis/xiaohongshu/user-helpers.test.ts`, `src/clis/xiaoyuzhou/utils.test.ts`, `src/clis/youtube/transcript-group.test.ts`, `src/clis/zhihu/download.test.ts` |
54+
| 聚焦 adapter 逻辑 | `src/clis/zhihu/download.test.ts`, `src/clis/twitter/timeline.test.ts`, `src/clis/reddit/read.test.ts`, `src/clis/bilibili/dynamic.test.ts` |
5355

5456
这些测试覆盖的重点包括:
5557

@@ -99,8 +101,11 @@ npm run build # 编译(E2E / smoke 测试需要 dist/main.js)
99101
### 运行命令
100102

101103
```bash
102-
# 全部单元测试
103-
npx vitest run src/
104+
# 默认核心单元测试(不含大多数 adapter tests)
105+
npm test
106+
107+
# 聚焦 adapter tests(只保留 4 个重点站点)
108+
npm run test:adapter
104109

105110
# 全部 E2E 测试(会真实调用外部 API / 浏览器)
106111
npx vitest run tests/e2e/
@@ -192,7 +197,8 @@ it('producthunt me fails gracefully without login', async () => {
192197
| Job | 触发条件 | 内容 |
193198
|---|---|---|
194199
| `build` | push/PR 到 `main`,`dev` | `tsc --noEmit` + `npm run build` |
195-
| `unit-test` | push/PR 到 `main`,`dev` | Node `20``22` 双版本运行 `src/` 单元测试,按 `2` shard 并行 |
200+
| `unit-test` | push/PR 到 `main`,`dev` | Node `20``22` 双版本运行核心 `unit` tests,按 `2` shard 并行 |
201+
| `adapter-test` | push/PR 到 `main`,`dev` | Node `22` 运行聚焦的 `zhihu/twitter/reddit/bilibili` adapter tests |
196202
| `smoke-test` | `schedule``workflow_dispatch` | 安装真实 Chrome,`xvfb-run` 执行 `tests/smoke/` |
197203

198204
### `e2e-headed.yml`
@@ -214,7 +220,7 @@ strategy:
214220
node-version: ['20', '22']
215221
shard: [1, 2]
216222
steps:
217-
- run: npx vitest run src/ --reporter=verbose --shard=${{ matrix.shard }}/2
223+
- run: npm test -- --reporter=verbose --shard=${{ matrix.shard }}/2
218224
```
219225
:::
220226

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"lint": "tsc --noEmit",
3131
"prepublishOnly": "npm run build",
3232
"test": "vitest run --project unit",
33+
"test:adapter": "vitest run --project adapter",
3334
"test:all": "vitest run",
3435
"test:e2e": "vitest run --project e2e",
3536
"docs:dev": "vitepress dev docs",

src/clis/bilibili/dynamic.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
3+
const { mockApiGet } = vi.hoisted(() => ({
4+
mockApiGet: vi.fn(),
5+
}));
6+
7+
vi.mock('./utils.js', () => ({
8+
apiGet: mockApiGet,
9+
}));
10+
11+
import { getRegistry } from '../../registry.js';
12+
import './dynamic.js';
13+
14+
describe('bilibili dynamic adapter', () => {
15+
const command = getRegistry().get('bilibili/dynamic');
16+
17+
beforeEach(() => {
18+
mockApiGet.mockReset();
19+
});
20+
21+
it('maps desc text rows from the dynamic feed payload', async () => {
22+
mockApiGet.mockResolvedValue({
23+
data: {
24+
items: [
25+
{
26+
id_str: '123',
27+
modules: {
28+
module_author: { name: 'Alice' },
29+
module_dynamic: { desc: { text: 'hello world' } },
30+
module_stat: { like: { count: 9 } },
31+
},
32+
},
33+
],
34+
},
35+
});
36+
37+
const result = await command!.func!({} as any, { limit: 5 });
38+
39+
expect(mockApiGet).toHaveBeenCalledWith({}, '/x/polymer/web-dynamic/v1/feed/all', { params: {}, signed: false });
40+
expect(result).toEqual([
41+
{
42+
id: '123',
43+
author: 'Alice',
44+
text: 'hello world',
45+
likes: 9,
46+
url: 'https://t.bilibili.com/123',
47+
},
48+
]);
49+
});
50+
51+
it('falls back to archive title when desc text is absent', async () => {
52+
mockApiGet.mockResolvedValue({
53+
data: {
54+
items: [
55+
{
56+
id_str: '456',
57+
modules: {
58+
module_author: { name: 'Bob' },
59+
module_dynamic: { major: { archive: { title: 'Video title' } } },
60+
module_stat: { like: { count: 3 } },
61+
},
62+
},
63+
],
64+
},
65+
});
66+
67+
const result = await command!.func!({} as any, { limit: 5 });
68+
69+
expect(result).toEqual([
70+
{
71+
id: '456',
72+
author: 'Bob',
73+
text: 'Video title',
74+
likes: 3,
75+
url: 'https://t.bilibili.com/456',
76+
},
77+
]);
78+
});
79+
});

src/clis/reddit/read.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { describe, expect, it, vi } from 'vitest';
2+
import { getRegistry } from '../../registry.js';
3+
import './read.js';
4+
5+
describe('reddit read adapter', () => {
6+
const command = getRegistry().get('reddit/read');
7+
8+
it('returns threaded rows from the browser-evaluated payload', async () => {
9+
const page = {
10+
goto: vi.fn().mockResolvedValue(undefined),
11+
evaluate: vi.fn().mockResolvedValue([
12+
{ type: 'POST', author: 'alice', score: 10, text: 'Title' },
13+
{ type: 'L0', author: 'bob', score: 5, text: 'Comment' },
14+
]),
15+
} as any;
16+
17+
const result = await command!.func!(page, { 'post-id': 'abc123', limit: 5 });
18+
19+
expect(page.goto).toHaveBeenCalledWith('https://www.reddit.com');
20+
expect(result).toEqual([
21+
{ type: 'POST', author: 'alice', score: 10, text: 'Title' },
22+
{ type: 'L0', author: 'bob', score: 5, text: 'Comment' },
23+
]);
24+
});
25+
26+
it('surfaces adapter-level API errors clearly', async () => {
27+
const page = {
28+
goto: vi.fn().mockResolvedValue(undefined),
29+
evaluate: vi.fn().mockResolvedValue({ error: 'Reddit API returned HTTP 403' }),
30+
} as any;
31+
32+
await expect(command!.func!(page, { 'post-id': 'abc123' })).rejects.toThrow('Reddit API returned HTTP 403');
33+
});
34+
});

vitest.config.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,34 @@ export default defineConfig({
77
test: {
88
name: 'unit',
99
include: ['src/**/*.test.ts'],
10+
exclude: ['src/clis/**/*.test.ts'],
1011
// Run unit tests before e2e tests to avoid project-level contention in CI.
1112
sequence: {
1213
groupOrder: 0,
1314
},
1415
},
1516
},
17+
{
18+
test: {
19+
name: 'adapter',
20+
include: [
21+
'src/clis/zhihu/**/*.test.ts',
22+
'src/clis/twitter/**/*.test.ts',
23+
'src/clis/reddit/**/*.test.ts',
24+
'src/clis/bilibili/**/*.test.ts',
25+
],
26+
sequence: {
27+
groupOrder: 1,
28+
},
29+
},
30+
},
1631
{
1732
test: {
1833
name: 'e2e',
1934
include: ['tests/**/*.test.ts'],
2035
maxWorkers: 2,
2136
sequence: {
22-
groupOrder: 1,
37+
groupOrder: 2,
2338
},
2439
},
2540
},

0 commit comments

Comments
 (0)