项目文件夹

文件
wehub-resource-sync f1ba9c6c36
/ test (push) Failing after 1s
/ build-and-push-to-ghcr (push) Has been skipped
chore: import upstream snapshot with attribution
2026-07-13 12:23:39 +08:00

128 行
5.6 KiB
TypeScript

/**
* E2E tests for selector-based crawler options:
* targetSelector – return only the matched element's content
* removeSelector – strip matching elements before formatting
*/
import { describe, it } from 'node:test';
import assert from 'node:assert';
import { crawl, crawlWithHeaders } from '../helpers/client';
describe('targetSelector', () => {
it('returns only the targeted element content', async () => {
const res = await crawl({ targetSelector: '#main-content', respondWith: 'markdown' });
assert.strictEqual(res.status, 200);
const content: string = res.body.data.content;
assert.match(content, /Web Crawling Guide|Section One/i);
});
it('excludes elements outside the target', async () => {
const res = await crawl({ targetSelector: '#main-content', respondWith: 'markdown' });
const content: string = res.body.data.content;
assert.doesNotMatch(content, /Related articles sidebar/i);
assert.doesNotMatch(content, /Copyright 2024/i);
});
it('sidebar unique link is absent when targeting main-content', async () => {
const content: string = (await crawl({ targetSelector: '#main-content', respondWith: 'markdown' })).body.data.content;
// This href only exists in <aside class="sidebar">
assert.doesNotMatch(content, /example\.com\/related/);
});
it('footer privacy link is absent when targeting main-content', async () => {
const content: string = (await crawl({ targetSelector: '#main-content', respondWith: 'markdown' })).body.data.content;
// This link only exists in <footer>
assert.doesNotMatch(content, /\/privacy/);
});
it('narrows to a specific section', async () => {
const res = await crawl({ targetSelector: '.sidebar', respondWith: 'markdown' });
assert.strictEqual(res.status, 200);
const content: string = res.body.data.content;
assert.match(content, /sidebar|Related articles/i);
assert.doesNotMatch(content, /Section One: Basics/);
});
});
describe('removeSelector', () => {
it('strips matching elements from output', async () => {
const res = await crawl({ removeSelector: '.ads', respondWith: 'markdown' });
assert.strictEqual(res.status, 200);
const content: string = res.body.data.content;
assert.doesNotMatch(content, /Buy our product/i);
});
it('removes all text content inside the removed element', async () => {
const content: string = (await crawl({ removeSelector: '.ads', respondWith: 'markdown' })).body.data.content;
// The only text inside .ads is "Buy our product!" — verify complete removal
assert.doesNotMatch(content, /Buy our product!/i);
});
it('keeps the rest of the page intact', async () => {
const res = await crawl({ removeSelector: '.ads', respondWith: 'markdown' });
const content: string = res.body.data.content;
assert.match(content, /Web Crawling Guide|Section One/i);
});
it('can remove multiple selectors', async () => {
const res = await crawl({ removeSelector: ['.ads', '.sidebar', '#site-nav'], respondWith: 'markdown' });
assert.strictEqual(res.status, 200);
const content: string = res.body.data.content;
assert.doesNotMatch(content, /Buy our product/i);
assert.doesNotMatch(content, /Related articles sidebar/i);
assert.match(content, /Web Crawling Guide/i);
});
it('removing nav, sidebar, footer, and ads leaves article body intact', async () => {
const content: string = (await crawl({
removeSelector: ['#site-nav', '.sidebar', 'footer', '.ads'],
respondWith: 'markdown',
})).body.data.content;
// Removed content should be absent
assert.doesNotMatch(content, /Related articles sidebar content/i);
assert.doesNotMatch(content, /Copyright 2024/);
assert.doesNotMatch(content, /Buy our product/i);
// Main article body should survive
assert.match(content, /Web Crawling Guide/);
assert.match(content, /The web is a graph, not a tree/);
assert.match(content, /fetching pages/i);
});
});
describe('removeSelector via X-Remove-Selector header', () => {
it('strips element specified in header', async () => {
const res = await crawlWithHeaders(
{ 'X-Remove-Selector': '.ads, footer' },
{ respondWith: 'markdown' },
);
assert.strictEqual(res.status, 200);
assert.doesNotMatch(res.body.data.content, /Buy our product/i);
assert.doesNotMatch(res.body.data.content, /Copyright 2024/i);
});
});
describe('targetSelector via X-Target-Selector header', () => {
it('narrows output to the header-specified selector', async () => {
const res = await crawlWithHeaders(
{ 'X-Target-Selector': '#main-content' },
{ respondWith: 'markdown' },
);
assert.strictEqual(res.status, 200);
assert.doesNotMatch(res.body.data.content, /Related articles sidebar/i);
assert.match(res.body.data.content, /Section One|Section Two/i);
});
});
describe('combined targetSelector + removeSelector', () => {
it('first targets then removes within the target', async () => {
const res = await crawl({
targetSelector: '#main-content',
removeSelector: 'h2',
respondWith: 'markdown',
});
assert.strictEqual(res.status, 200);
const content: string = res.body.data.content;
assert.match(content, /web crawling|fetching pages/i);
assert.doesNotMatch(content, /Section One|Section Two/);
});
});