@link-assistant/web-capture 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +12 -0
- package/package.json +1 -1
- package/tests/integration/wikipedia-download.test.js +142 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @link-assistant/web-capture
|
|
2
2
|
|
|
3
|
+
## 1.10.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 31b93a8: Add a live integration test that downloads the Wikipedia page
|
|
8
|
+
(https://en.wikipedia.org/wiki/Wikipedia) as both Markdown and an image (PNG
|
|
9
|
+
screenshot) using every supported browser engine — Puppeteer and Playwright
|
|
10
|
+
(issue #8). The suite is gated behind `WIKIPEDIA_INTEGRATION=true` so default
|
|
11
|
+
offline runs stay deterministic, and is wired into CI as a dedicated live step.
|
|
12
|
+
|
|
3
13
|
## 1.10.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -456,6 +456,18 @@ npm run test:e2e # Run end-to-end tests
|
|
|
456
456
|
npm run test:all # Run all tests including build
|
|
457
457
|
```
|
|
458
458
|
|
|
459
|
+
Some integration suites hit live servers and are skipped by default. Enable them
|
|
460
|
+
with environment variables:
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
# Download the Wikipedia page (markdown + image) in every supported engine
|
|
464
|
+
WIKIPEDIA_INTEGRATION=true npm test -- --testPathPattern="wikipedia-download"
|
|
465
|
+
|
|
466
|
+
# Habr articles and public Google Docs live suites
|
|
467
|
+
HABR_INTEGRATION=true npm test -- --testPathPattern="habr-article"
|
|
468
|
+
GDOCS_INTEGRATION=true npm test -- --testPathPattern="gdocs-public-doc"
|
|
469
|
+
```
|
|
470
|
+
|
|
459
471
|
## Built With
|
|
460
472
|
|
|
461
473
|
- Express.js for the web server
|
package/package.json
CHANGED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for downloading the Wikipedia page (issue #8).
|
|
3
|
+
*
|
|
4
|
+
* Verifies that web-capture can actually download the Wikipedia article about
|
|
5
|
+
* Wikipedia itself (https://en.wikipedia.org/wiki/Wikipedia) as both Markdown
|
|
6
|
+
* and an image (PNG screenshot) using every supported browser engine
|
|
7
|
+
* (Puppeteer and Playwright).
|
|
8
|
+
*
|
|
9
|
+
* These tests hit the live Wikipedia servers. Set WIKIPEDIA_INTEGRATION=true to
|
|
10
|
+
* run them. In CI they are enabled via the workflow environment variable. When
|
|
11
|
+
* the variable is unset the suite is skipped so default/offline runs stay
|
|
12
|
+
* deterministic.
|
|
13
|
+
*
|
|
14
|
+
* Navigation uses retry with exponential backoff to absorb transient network
|
|
15
|
+
* failures, mirroring the Habr integration suite.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { jest } from '@jest/globals';
|
|
19
|
+
import { createBrowser } from '../../src/browser.js';
|
|
20
|
+
import { convertHtmlToMarkdown } from '../../src/lib.js';
|
|
21
|
+
import { retry } from '../../src/retry.js';
|
|
22
|
+
|
|
23
|
+
const WIKIPEDIA_URL = 'https://en.wikipedia.org/wiki/Wikipedia';
|
|
24
|
+
|
|
25
|
+
// PNG magic number (89 50 4E 47 0D 0A 1A 0A).
|
|
26
|
+
const PNG_SIGNATURE = Buffer.from([
|
|
27
|
+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
const SKIP_LIVE =
|
|
31
|
+
!process.env.WIKIPEDIA_INTEGRATION ||
|
|
32
|
+
process.env.WIKIPEDIA_INTEGRATION === 'false';
|
|
33
|
+
const describeIfLive = SKIP_LIVE ? describe.skip : describe;
|
|
34
|
+
|
|
35
|
+
// These tests hit live servers and may take a while.
|
|
36
|
+
jest.setTimeout(120000);
|
|
37
|
+
|
|
38
|
+
// Navigate with retry + exponential backoff, then give the page a moment to
|
|
39
|
+
// settle so late-loading content and images are present before we capture.
|
|
40
|
+
async function navigateWithRetry(page, url) {
|
|
41
|
+
await retry(
|
|
42
|
+
async () => {
|
|
43
|
+
await page.goto(url, {
|
|
44
|
+
waitUntil: 'networkidle0',
|
|
45
|
+
timeout: 60000,
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
retries: 3,
|
|
50
|
+
baseDelay: 2000,
|
|
51
|
+
onRetry: (err, attempt, delay) => {
|
|
52
|
+
console.log(
|
|
53
|
+
`Navigation retry ${attempt} for ${url} after ${delay}ms: ${err.message}`
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Run the full matrix (Markdown + image) once per supported engine.
|
|
62
|
+
describe.each(['puppeteer', 'playwright'])(
|
|
63
|
+
'Wikipedia Page Download (%s engine)',
|
|
64
|
+
(engine) => {
|
|
65
|
+
describeIfLive(`${engine}`, () => {
|
|
66
|
+
let browser;
|
|
67
|
+
let page;
|
|
68
|
+
|
|
69
|
+
beforeAll(async () => {
|
|
70
|
+
browser = await createBrowser(engine);
|
|
71
|
+
page = await browser.newPage();
|
|
72
|
+
await page.setViewport({ width: 1280, height: 800 });
|
|
73
|
+
await navigateWithRetry(page, WIKIPEDIA_URL);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
afterAll(async () => {
|
|
77
|
+
if (browser) {
|
|
78
|
+
await browser.close();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('downloads the Wikipedia page as Markdown', async () => {
|
|
83
|
+
const html = await page.content();
|
|
84
|
+
expect(html).toMatch(/<html/i);
|
|
85
|
+
expect(html.length).toBeGreaterThan(1000);
|
|
86
|
+
|
|
87
|
+
const markdown = convertHtmlToMarkdown(html, WIKIPEDIA_URL);
|
|
88
|
+
|
|
89
|
+
// Markdown should carry the page's real content...
|
|
90
|
+
expect(markdown).toContain('Wikipedia');
|
|
91
|
+
expect(markdown.length).toBeGreaterThan(500);
|
|
92
|
+
// ...and should contain markdown structure (headings and/or links)...
|
|
93
|
+
expect(markdown).toMatch(/(^#{1,6}\s)|(\[.*?\]\(.*?\))/m);
|
|
94
|
+
// ...but no longer be raw HTML document scaffolding.
|
|
95
|
+
expect(markdown).not.toMatch(/<html/i);
|
|
96
|
+
expect(markdown).not.toMatch(/<head[\s>]/i);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('downloads the Wikipedia page as an image (PNG screenshot)', async () => {
|
|
100
|
+
const screenshot = await page.screenshot({ type: 'png' });
|
|
101
|
+
|
|
102
|
+
expect(screenshot).toBeInstanceOf(Buffer);
|
|
103
|
+
expect(screenshot.length).toBeGreaterThan(1000);
|
|
104
|
+
// Verify the PNG signature so we know it is a real image.
|
|
105
|
+
expect(screenshot.slice(0, 8)).toEqual(PNG_SIGNATURE);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
describeIfLive('Wikipedia Page Download (engine parity)', () => {
|
|
112
|
+
it('both engines download Markdown and an image for the Wikipedia page', async () => {
|
|
113
|
+
const engines = ['puppeteer', 'playwright'];
|
|
114
|
+
const results = [];
|
|
115
|
+
|
|
116
|
+
for (const engine of engines) {
|
|
117
|
+
const browser = await createBrowser(engine);
|
|
118
|
+
try {
|
|
119
|
+
const page = await browser.newPage();
|
|
120
|
+
await page.setViewport({ width: 1280, height: 800 });
|
|
121
|
+
await navigateWithRetry(page, WIKIPEDIA_URL);
|
|
122
|
+
|
|
123
|
+
const html = await page.content();
|
|
124
|
+
const markdown = convertHtmlToMarkdown(html, WIKIPEDIA_URL);
|
|
125
|
+
const screenshot = await page.screenshot({ type: 'png' });
|
|
126
|
+
|
|
127
|
+
results.push({ engine, markdown, screenshot });
|
|
128
|
+
} finally {
|
|
129
|
+
await browser.close();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const { markdown, screenshot } of results) {
|
|
134
|
+
// Markdown captured from both engines.
|
|
135
|
+
expect(markdown).toContain('Wikipedia');
|
|
136
|
+
expect(markdown.length).toBeGreaterThan(500);
|
|
137
|
+
// Image captured from both engines.
|
|
138
|
+
expect(screenshot.slice(0, 8)).toEqual(PNG_SIGNATURE);
|
|
139
|
+
expect(screenshot.length).toBeGreaterThan(1000);
|
|
140
|
+
}
|
|
141
|
+
}, 180000);
|
|
142
|
+
});
|