feat: add Playwright-based fallback scraper
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gwc3aCiyQxmCWQke8RvEz
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { fetchAndExtractPriceViaBrowser } = require('../src/browserScraper');
|
||||
|
||||
test('fetchAndExtractPriceViaBrowser extracts a price from the rendered page', async () => {
|
||||
let closed = false;
|
||||
const html = '<html><head><meta property="og:price:amount" content="42.00" /></head><body></body></html>';
|
||||
const page = {
|
||||
goto: async () => {},
|
||||
content: async () => html,
|
||||
close: async () => { closed = true; },
|
||||
};
|
||||
const browser = { newPage: async () => page };
|
||||
const result = await fetchAndExtractPriceViaBrowser(browser, 'https://example.com');
|
||||
assert.deepEqual(result, { price: 42, method: 'meta', error: null });
|
||||
assert.equal(closed, true);
|
||||
});
|
||||
|
||||
test('fetchAndExtractPriceViaBrowser returns an error when navigation fails, and still closes the page', async () => {
|
||||
let closed = false;
|
||||
const page = {
|
||||
goto: async () => { throw new Error('Timeout 20000ms exceeded'); },
|
||||
content: async () => '',
|
||||
close: async () => { closed = true; },
|
||||
};
|
||||
const browser = { newPage: async () => page };
|
||||
const result = await fetchAndExtractPriceViaBrowser(browser, 'https://example.com');
|
||||
assert.equal(result.price, null);
|
||||
assert.equal(result.method, null);
|
||||
assert.ok(result.error instanceof Error);
|
||||
assert.equal(closed, true);
|
||||
});
|
||||
|
||||
test('fetchAndExtractPriceViaBrowser returns null price when nothing matches, and still closes the page', async () => {
|
||||
let closed = false;
|
||||
const page = {
|
||||
goto: async () => {},
|
||||
content: async () => '<html><body><p>Geen prijs</p></body></html>',
|
||||
close: async () => { closed = true; },
|
||||
};
|
||||
const browser = { newPage: async () => page };
|
||||
const result = await fetchAndExtractPriceViaBrowser(browser, 'https://example.com');
|
||||
assert.deepEqual(result, { price: null, method: null, error: null });
|
||||
assert.equal(closed, true);
|
||||
});
|
||||
|
||||
test('fetchAndExtractPriceViaBrowser closes the page even if reading its content throws', async () => {
|
||||
let closed = false;
|
||||
const page = {
|
||||
goto: async () => {},
|
||||
content: async () => { throw new Error('content failed'); },
|
||||
close: async () => { closed = true; },
|
||||
};
|
||||
const browser = { newPage: async () => page };
|
||||
const result = await fetchAndExtractPriceViaBrowser(browser, 'https://example.com');
|
||||
assert.ok(result.error instanceof Error);
|
||||
assert.equal(closed, true);
|
||||
});
|
||||
|
||||
test('fetchAndExtractPriceViaBrowser passes the timeout option through to page.goto', async () => {
|
||||
let receivedOptions;
|
||||
const page = {
|
||||
goto: async (url, options) => { receivedOptions = options; },
|
||||
content: async () => '<html><body></body></html>',
|
||||
close: async () => {},
|
||||
};
|
||||
const browser = { newPage: async () => page };
|
||||
await fetchAndExtractPriceViaBrowser(browser, 'https://example.com', { timeoutMs: 5000 });
|
||||
assert.equal(receivedOptions.timeout, 5000);
|
||||
});
|
||||
Reference in New Issue
Block a user