import test from 'brittle' import { readFile } from 'node:fs/promises' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = dirname(fileURLToPath(import.meta.url)) async function load() { const parts = await Promise.all([ readFile(join(__dirname, '../lib/summon/summon-url.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-cookie.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-http.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-html.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-css.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-layout.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-form.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-dom.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-js.js'), 'utf8'), readFile(join(__dirname, '../lib/summon/summon-session.js'), 'utf8') ]) const hook = {} new Function( 'exports', parts.join('\n') + ` exports.bareSummonParseUrl = bareSummonParseUrl; exports.bareSummonResolveUrl = bareSummonResolveUrl; exports.bareSummonUrlOk = bareSummonUrlOk; exports.bareSummonCreateCookieJar = bareSummonCreateCookieJar; exports.bareSummonFetch = bareSummonFetch; exports.bareSummonParseHtml = bareSummonParseHtml; exports.bareSummonTextContent = bareSummonTextContent; exports.bareSummonParseStylesheet = bareSummonParseStylesheet; exports.bareSummonLayout = bareSummonLayout; exports.bareSummonReaderText = bareSummonReaderText; exports.bareSummonEncodeForm = bareSummonEncodeForm; exports.bareSummonCollectForm = bareSummonCollectForm; exports.bareSummonSubmitUrl = bareSummonSubmitUrl; exports.bareSummonCreateSession = bareSummonCreateSession; exports.bareSummonCurrent = bareSummonCurrent; exports.bareSummonAboutBody = bareSummonAboutBody; exports.bareSummonApplyDocument = bareSummonApplyDocument; exports.bareSummonNavigate = bareSummonNavigate; exports.bareSummonAddBookmark = bareSummonAddBookmark; exports.bareSummonNewTab = bareSummonNewTab; exports.bareSummonMatches = bareSummonMatches; exports.bareSummonQueryAll = bareSummonQueryAll; exports.bareSummonCreateDocumentApi = bareSummonCreateDocumentApi; exports.bareSummonRunDocumentJs = bareSummonRunDocumentJs; exports.bareSummonEnhanceDocument = bareSummonEnhanceDocument; exports.bareSummonScriptSource = bareSummonScriptSource; ` )(hook) return hook } test('summon URL parse / resolve / reject javascript', async (t) => { const h = await load() const about = h.bareSummonParseUrl('about:summon') t.ok(about) t.is(about.protocol, 'about:') t.is(about.pathname, 'summon') const https = h.bareSummonParseUrl('https://example.com/a') t.ok(h.bareSummonUrlOk(https)) const rel = h.bareSummonResolveUrl('/b', 'https://example.com/a') t.is(rel.href, 'https://example.com/b') t.is( h.bareSummonResolveUrl('javascript:alert(1)', 'https://example.com/'), null ) }) test('summon cookie jar first-party + path', async (t) => { const h = await load() const jar = h.bareSummonCreateCookieJar() t.ok( jar.put( 'sid=abc; Path=/app; Domain=example.com', 'https://example.com/app/page' ) ) t.is(jar.headerFor('https://example.com/app/x'), 'sid=abc') t.is(jar.headerFor('https://other.com/app/x'), '') t.absent( jar.put('evil=1; Domain=other.com', 'https://example.com/', { thirdParty: false }) ) }) test('summon HTML tokenizer + tree + script count', async (t) => { const h = await load() const doc = h.bareSummonParseHtml( '
Hello world

hidden
Alpha and ' + 'Beta' ) const sheets = [] function collect(n) { if (n && n.type === 'element' && n.name === 'style') { sheets.push(h.bareSummonParseStylesheet(h.bareSummonTextContent(n))) } const ch = (n && n.children) || [] for (const c of ch) collect(c) } collect(doc.head) const layout = h.bareSummonLayout(doc, { cols: 40, sheets }) t.is(layout.title, 'T') t.is(layout.links.length, 2) t.ok(layout.plain.join('\n').includes('[1]')) t.ok(layout.plain.join('\n').includes('Alpha')) t.absent(layout.plain.join('\n').includes('hidden')) }) test('summon form GET encode', async (t) => { const h = await load() const doc = h.bareSummonParseHtml( '' ) const form = doc.body.children.find((n) => n.name === 'form') const spec = h.bareSummonCollectForm(form) t.is(spec.method, 'GET') const sub = h.bareSummonSubmitUrl(spec, 'https://example.com/page') t.ok(sub.url.includes('https://example.com/s?')) t.ok(sub.url.includes('q=hi%20there')) }) test('summon about: pages + navigate without HTTP', async (t) => { const h = await load() const ctx = { env: { HOME: '/home/guest' }, vfs: {}, console: { log() {}, error() {} } } const session = h.bareSummonCreateSession(ctx, { url: 'about:summon' }) const tab = await h.bareSummonNavigate(session, 'about:summon') t.is(tab.status, 200) t.ok(tab.layout.plain.join('\n').toLowerCase().includes('summon')) h.bareSummonAddBookmark(session, 'https://example.com/', 'ex') const marks = await h.bareSummonNavigate(session, 'about:bookmarks') t.ok( (marks.layout.links || []).some((l) => String(l.href || '').includes('example.com') ) ) h.bareSummonNewTab(session, 'about:blank') t.is(session.tabs.length, 2) }) test('summon HTTP fetch follows redirect and stores cookie', async (t) => { const h = await load() const hops = [] const ctx = { httpFetch: async (url, opts) => { hops.push({ url, method: opts.method, cookie: (opts.headers || {}).cookie }) if (url === 'https://example.com/go') { return { status: 302, headers: { location: '/next', 'set-cookie': 'tok=1; Path=/' }, text: async () => '' } } return { status: 200, headers: { 'content-type': 'text/html' }, text: async () => 'ok
' } } } const jar = h.bareSummonCreateCookieJar() const res = await h.bareSummonFetch(ctx, 'https://example.com/go', { jar }) t.ok(res.ok) t.is(res.url, 'https://example.com/next') t.is(res.redirects, 1) t.ok(res.body.includes('ok')) t.is(jar.headerFor('https://example.com/next'), 'tok=1') t.is(hops.length, 2) }) test('summon keeps script source and matches descendant CSS', async (t) => { const h = await load() const doc = h.bareSummonParseHtml( 'hi
nobefore
' + '' + '' const tab = session.tabs[0] h.bareSummonApplyDocument(session, tab, html, 'about:blank') await h.bareSummonEnhanceDocument(session, tab, 'about:blank') t.is(tab.js.ran, 1) t.ok(tab.layout.plain.join('\n').includes('after')) t.absent(tab.layout.plain.join('\n').includes('before')) t.is(tab.doc.title, 'js-ok') })