Files
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 lines
5.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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/);
});
});