/** Real xterm clicks resolve the complete filename or report its lookup error from either wrapped row. */ import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; import { chromium, type Browser } from 'playwright'; const publicDir = resolve(import.meta.dirname, '../src/web/public'); const basePath = '/mnt/user/Scratch/Kobo/Set-KoboCovers/Kobo eReader.conf'; describe('wrapped configuration file links (Chromium)', () => { let browser: Browser; beforeAll(async () => { browser = await chromium.launch({ headless: true }); }); afterAll(async () => { await browser.close(); }); it.each([ { wrap: 'soft', originalExists: false, extension: 'conf', registrationStatus: 200, prefix: '' }, { wrap: 'hard', originalExists: false, extension: 'conf', registrationStatus: 200, prefix: '' }, { wrap: 'hard', originalExists: true, extension: 'conf', registrationStatus: 200, prefix: '' }, { wrap: 'hard', originalExists: true, extension: 'svg', registrationStatus: 400, prefix: '' }, { wrap: 'hard', originalExists: true, extension: 'markdown', registrationStatus: 400, prefix: '' }, { wrap: 'hard', originalExists: false, extension: 'svg', registrationStatus: 400, prefix: '' }, { wrap: 'hard', originalExists: false, extension: 'conf', registrationStatus: 404, prefix: '' }, { wrap: 'hard', originalExists: false, extension: 'markdown', registrationStatus: 200, prefix: 'Path: ' }, ])( 'handles .$extension links on both rows: $wrap, original exists: $originalExists, prefix: $prefix', async ({ wrap, originalExists, extension, registrationStatus, prefix }) => { const path = basePath.replace('.conf', `.${extension}`); const original = path.replace('Kobo eReader', 'KoboeReader'); const expected = wrap === 'hard' && (originalExists || registrationStatus === 404) ? original : path; const lookupFails = registrationStatus === 400 && !originalExists; const lookups: string[] = []; const page = await browser.newPage({ viewport: { width: 1920, height: 600 } }); try { await page.route('http://fixture.test/', (route) => route.fulfill({ contentType: 'text/html', body: '
', }) ); await page.route('http://fixture.test/api/sessions/fixture/attachments', async (route) => { const body = route.request().postDataJSON(); expect(body.notify).toBe(false); lookups.push(body.path); const exists = body.path === path || (originalExists && body.path === original); const status = exists ? registrationStatus : 404; await route.fulfill({ status, json: status === 200 ? { success: true, data: { attachmentId: 'att-fixture' } } : { success: false, error: status === 400 ? 'Unsupported attachment type' : 'File not found' }, }); }); await page.goto('http://fixture.test/'); await page.addStyleTag({ path: resolve(publicDir, '../../../node_modules/@xterm/xterm/css/xterm.css') }); await page.addScriptTag({ path: resolve(publicDir, '../../../node_modules/@xterm/xterm/lib/xterm.js') }); await page.addScriptTag({ content: 'window.CodemanApp = class CodemanApp {};' }); for (const file of ['constants.js', 'terminal-ui.js', 'panels-ui.js']) { await page.addScriptTag({ content: readFileSync(resolve(publicDir, file), 'utf8') }); } await page.evaluate( async ({ path, wrap, workingDir, prefix }) => { const w = window as any; const boundary = path.lastIndexOf(' '); const first = `Found it: prepared a corrected configuration (${prefix}${path.slice(0, boundary)}`; const terminal = new w.Terminal({ cols: first.length + (wrap === 'soft' ? 1 : 20), rows: 6 }); terminal.open(document.getElementById('terminal')); w.opened = []; w.app = Object.assign(new w.CodemanApp(), { terminal, activeSessionId: 'fixture', sessions: new Map([['fixture', { workingDir }]]), openFilePreview: (file: string) => w.opened.push(file), openLogViewerWindow: (file: string) => w.opened.push(`log:${file}`), openFolderGrid: (file: string) => w.opened.push(`folder:${file}`), showToast: (message: string) => w.opened.push(`error:${message}`), }); w.app.registerFilePathLinkProvider(); const text = `${first}${wrap === 'soft' ? ' ' : '\r\n '}${path.slice(boundary + 1)}).`; await new Promise