Fixed error message logging, added detailed diagnostics.

This commit is contained in:
qwsdcvghyu89
2026-06-17 07:43:13 +10:00
parent fdd1d1131d
commit a5145c6902
3 changed files with 394 additions and 10 deletions
+148
View File
@@ -0,0 +1,148 @@
import { describe, test, expect } from 'bun:test';
import { analyzeTocPage } from '../src/services/analyzer.ts';
const SCOPE = '#list-chapter .chapter-archive-grid';
const PATTERN = 'https://novelbin\\.com/b/the-mech-touch/.*';
function makeHtml(opts: {
title?: string;
body?: string;
links?: string[];
extraHead?: string;
}) {
const links = (opts.links ?? [])
.map(href => `<a href="${href}">link</a>`)
.join('');
return `<html>
<head>
<title>${opts.title ?? 'Test Page'}</title>
${opts.extraHead ?? ''}
</head>
<body>${opts.body ?? ''}${links}</body>
</html>`;
}
describe('analyzer — Cloudflare detection', () => {
test('flags "Just a moment" title as Cloudflare', () => {
const html = makeHtml({ title: 'Just a moment...' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const cf = d.findings.find(f => f.check === 'Cloudflare challenge')!;
expect(cf.passed).toBe(false);
expect(d.likelyCause).toContain('Cloudflare');
});
test('flags #challenge-form element as Cloudflare', () => {
const html = makeHtml({ body: '<form id="challenge-form"></form>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const cf = d.findings.find(f => f.check === 'Cloudflare challenge')!;
expect(cf.passed).toBe(false);
});
test('does not flag a clean page as Cloudflare', () => {
const html = makeHtml({ title: 'The Mech Touch — Chapters', body: '<div id="list-chapter"><div class="chapter-archive-grid"></div></div>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const cf = d.findings.find(f => f.check === 'Cloudflare challenge')!;
expect(cf.passed).toBe(true);
});
});
describe('analyzer — security block detection', () => {
test('flags "you have been blocked" body text', () => {
const html = makeHtml({ body: '<p>You have been blocked from accessing this site.</p>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'Security / bot block')!;
expect(check.passed).toBe(false);
expect(d.likelyCause).toContain('Security block');
});
});
describe('analyzer — CAPTCHA detection', () => {
test('flags g-recaptcha div', () => {
const html = makeHtml({ body: '<div class="g-recaptcha" data-sitekey="abc"></div>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'CAPTCHA')!;
expect(check.passed).toBe(false);
});
});
describe('analyzer — login wall detection', () => {
test('flags password input', () => {
const html = makeHtml({ body: '<form><input type="password"/></form>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'Login wall')!;
expect(check.passed).toBe(false);
expect(d.likelyCause).toContain('Login');
});
});
describe('analyzer — scope selector breakdown', () => {
test('reports root missing when neither segment exists', () => {
const html = makeHtml({ body: '<div id="something-else"></div>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'TOC scope selector')!;
expect(check.passed).toBe(false);
expect(check.detail).toContain('#list-chapter');
expect(check.detail).toContain('not found anywhere');
expect(d.likelyCause).toContain('redesigned');
});
test('reports inner selector missing when root exists but child does not', () => {
const html = makeHtml({ body: '<div id="list-chapter"><ul><li>no grid here</li></ul></div>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'TOC scope selector')!;
expect(check.passed).toBe(false);
expect(check.detail).toContain('#list-chapter');
expect(check.detail).toContain('.chapter-archive-grid');
expect(d.likelyCause).toContain('Inner selector');
});
test('notes when inner selector exists elsewhere on the page (wrong hierarchy)', () => {
const html = makeHtml({
body: '<div id="list-chapter"></div><div class="chapter-archive-grid"></div>',
});
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'TOC scope selector')!;
expect(check.passed).toBe(false);
expect(check.detail).toContain('exists elsewhere');
});
test('passes when full scope matches', () => {
const html = makeHtml({
body: '<div id="list-chapter"><div class="chapter-archive-grid"></div></div>',
});
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'TOC scope selector')!;
expect(check.passed).toBe(true);
});
});
describe('analyzer — link pattern check', () => {
test('finds matching links outside the scope when scope is missing', () => {
const links = [
'https://novelbin.com/b/the-mech-touch/chapter-1',
'https://novelbin.com/b/the-mech-touch/chapter-2',
];
const html = makeHtml({ body: '<div id="other">' + links.map(l => `<a href="${l}">ch</a>`).join('') + '</div>' });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'Link pattern (anywhere)')!;
expect(check.passed).toBe(true);
expect(check.detail).toContain('2 link');
expect(d.likelyCause).toContain('scope selector');
});
test('reports no matching links and samples what is there', () => {
const html = makeHtml({ links: ['https://other.com/a', 'https://other.com/b'] });
const d = analyzeTocPage(html, SCOPE, PATTERN);
const check = d.findings.find(f => f.check === 'Link pattern (anywhere)')!;
expect(check.passed).toBe(false);
expect(check.detail).toContain('other.com');
});
});
describe('analyzer — actualUrl', () => {
test('includes the landed URL in the diagnosis', () => {
const html = makeHtml({});
const d = analyzeTocPage(html, SCOPE, PATTERN, 'https://novelbin.com/redirected');
expect(d.actualUrl).toBe('https://novelbin.com/redirected');
});
});