Download tests/test_reader_architecture.js from VoiceOfML/Search: direct link, hf CLI and curl.
- Browser
- Download file 20.3 kB
-
https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/tests/test_reader_architecture.js
- Command line
-
hf download hf://spaces/VoiceOfML/Search/tests/test_reader_architecture.js
-
curl -L -o test_reader_architecture.js https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/tests/test_reader_architecture.js
20.3 kB
| const fs = require('fs') | |
| const path = require('path') | |
| const assert = require('assert') | |
| const { assertCode, codePattern, readReaderSource } = require('./reader_source_contract') | |
| const root = path.resolve(__dirname, '..') | |
| const readerEntry = fs.readFileSync(path.join(root, 'static/reader.js'), 'utf8') | |
| const reader = readReaderSource(root) | |
| assert.doesNotMatch(readerEntry, /^\s*(?:async\s+)?function\s+/m) | |
| assertCode(readerEntry, 'from "./reader/reader-components.mjs"') | |
| const searchController = fs.readFileSync(path.join(root, 'static/reader/search/reader-search-controller.mjs'), 'utf8') | |
| assertCode(reader, 'import { createReaderSearchController } from "./reader/search/reader-search-controller.mjs"') | |
| assertCode(reader, 'trackReaderResource(fullSearchController.dispose)') | |
| assertCode(reader, 'backend: { mode: () => capability.mode, search: searchReaderText') | |
| assert.doesNotMatch(reader, /dataset\.panelView\s*=\s*"full-search"/) | |
| assert.doesNotMatch(searchController, /new Worker|\bfetch\(|import\(/) | |
| const domSearch = fs.readFileSync(path.join(root, 'static/reader/search/reader-dom-search.mjs'), 'utf8') | |
| assertCode(reader, 'import { createReaderDomSearch, fullSearchEscape, fullSearchSnippet, fullSearchPageOffset } from "./reader/search/reader-dom-search.mjs"') | |
| assertCode(reader, 'trackReaderResource(domSearch.dispose)') | |
| assertCode(reader, 'getTocEntries: () => navigationState.tocEntries') | |
| assertCode(reader, 'domSearch.pruneMarks()') | |
| assert.doesNotMatch(reader, /function (?:fullSearchDomMatches|createDomSearchSnapshot|createFullSearchDomLocator|fullSearchTextNodes|highlightTextParts)\(/) | |
| assert.doesNotMatch(domSearch, /new Worker|\bfetch\(|import\(|readerRuntime|navigationState|fullSearchSession|fullSearchStatus/) | |
| assertCode(domSearch, 'const stopGeneration = runtime.events.on("generation"') | |
| assertCode(domSearch, 'function dispose() { stopGeneration()') | |
| assertCode(domSearch, 'publishPage(page(0), page, true)') | |
| const imageLoader = fs.readFileSync(path.join(root, 'static/reader/formats/reader-image-loader.mjs'), 'utf8') | |
| assertCode(reader, 'import { createReaderImageLoader } from "./reader/formats/reader-image-loader.mjs"') | |
| assertCode(reader, 'trackResource: trackReaderResource') | |
| assertCode(reader, 'await imageLoader.load(image, target, renderController.signal)') | |
| assert.doesNotMatch(reader, /function (?:waitReaderImage|loadReaderImage)\(/) | |
| assert.doesNotMatch(imageLoader, /readerRuntime|readerContentUrl|pdfPageManifest|documentState|new Image|import\(/) | |
| const css = fs.readFileSync(path.join(root, 'static/reader.css'), 'utf8') | |
| const view = fs.readFileSync(path.join(root, 'static/foliate-reader/view.js'), 'utf8') | |
| for (const marker of ["import('./epub.js')", "import('./mobi.js')", "import('./fb2.js')", "import('./pdf.js')", "isFBZ(file)", "isFB2(file)"]) assert.ok(view.includes(marker), marker) | |
| for (const file of ['epub.js', 'mobi.js', 'fb2.js', 'pdf.js', 'view.js', 'progress.js', 'ui/tree.js']) assert.ok(fs.existsSync(path.join(root, 'static/foliate-reader', file)), file) | |
| assert.match(fs.readFileSync(path.join(root, 'static/foliate-reader/mobi.js'), 'utf8'), /createDocument/) | |
| assert.match(fs.readFileSync(path.join(root, 'static/foliate-reader/fb2.js'), 'utf8'), /resolveHref/) | |
| assert.match(fs.readFileSync(path.join(root, 'static/foliate-reader/epub.js'), 'utf8'), /String\(href \?\? ''\)/) | |
| assert.match(fs.readFileSync(path.join(root, 'static/foliate-reader/epub.js'), 'utf8'), /item\.mediaType === MIME\.XHTML/) | |
| const foliateReader = fs.readFileSync(path.join(root, 'static/foliate-reader/reader.js'), 'utf8') | |
| for (const message of ['voice-foliate-goto-cfi', 'voice-foliate-search', 'voice-foliate-seek', 'voice-foliate-prev', 'voice-foliate-next']) assert.ok(foliateReader.includes(message), message) | |
| assert.strictEqual((reader.match(/async function renderFoliate\(/g) || []).length, 1) | |
| assert.strictEqual(reader.includes('renderFoliateClean'), false) | |
| assert.strictEqual(reader.includes('renderFoliateLegacy'), false) | |
| assert.strictEqual(reader.includes('foliate-continuous'), true) | |
| assert.strictEqual(reader.includes('document.querySelector("#toc-list").addEventListener'), false) | |
| assert.strictEqual(reader.includes('activateFoliateTocEntryLatest'), false) | |
| assert.strictEqual(reader.includes('setupFoliateToc'), false) | |
| assert.strictEqual(reader.includes('foliateVisibleSections'), false) | |
| assert.strictEqual(reader.includes('foliateVisibleNodes'), false) | |
| assert.strictEqual(reader.includes('directFoliateMoving'), false) | |
| assert.strictEqual(reader.includes('directFoliateContainer'), false) | |
| assert.strictEqual(reader.includes('setInterval(() => { loadNextFoliateSection(); }, 100)'), false) | |
| assert.strictEqual(reader.includes('setInterval(() => { const tab = document.querySelector("#toc-tab")'), false) | |
| assert.strictEqual(reader.includes('setInterval('), false) | |
| assert.match(reader, /function scheduleFoliateScrollSync\(\)/) | |
| assert.match(reader, /foliateSectionObserver\?\.disconnect\(\)/) | |
| assert.strictEqual((reader.match(/function disposeReader\(\)/g) || []).length, 1) | |
| assert.strictEqual((reader.match(/function setReaderPhase\(/g) || []).length, 1) | |
| assert.strictEqual((reader.match(/function classifyReaderError\(/g) || []).length, 1) | |
| assert.match(reader, /const readerLifecycle = readerRuntime\.state\.lifecycle/) | |
| assert.doesNotMatch(reader, /(?:^|\n)\s*let readerStage\b/) | |
| assert.match(reader, /readerRuntime\.setStage\(stage\)/) | |
| assert.match(reader, /\$\{readerLifecycle\.stage\}/) | |
| assertCode(reader, 'function scheduleSave() { if (readerLifecycle.disposed || readerAbortController.signal.aborted) return;') | |
| assertCode(reader, 'readerLifecycle.disposed || !documentState.restorationReady') | |
| assert.strictEqual((reader.match(/if \(!setReaderPhase\("ready"\)\) return/g) || []).length, 2) | |
| assert.match(reader, /addEventListener\("pagehide"/) | |
| assert.match(reader, /event\.persisted/) | |
| assert.match(reader, /!event\.persisted/) | |
| assert.doesNotMatch(reader, /id=["']ocr["']/i) | |
| assert.match(reader, /validatePdfPageManifest/) | |
| assert.match(reader, /const PDF_PREFETCH_MARGIN = 2400/) | |
| assert.match(reader, /const visibleObserver = new IntersectionObserver/) | |
| assert.match(reader, /promotePdfRenderWaiter\(shell\)/) | |
| assert.match(reader, /function pdfPagePriority\(shell\)/) | |
| assert.match(reader, /priority >= 3 \? "high" : priority >= 1 \? "auto" : "low"/) | |
| assert.match(reader, /const waiter = \{\s*shell,\s*priority,/) | |
| assert.match(reader, /waiter\.shell \? pdfPagePriority\(waiter\.shell\) : waiter\.priority/) | |
| assert.match(reader, /function cancelSpeculativePdfRenders\(protectedShell\)/) | |
| assert.match(reader, /isPdfPageVisible\(shell\)/) | |
| assert.match(reader, /shell\._renderCancel\?\.\(\)/) | |
| assert.match(reader, /const PDF_MANIFEST_PREFETCH_LIMIT = 12/) | |
| assert.match(reader, /const PDF_MANIFEST_PREFETCH_CONCURRENCY = 3/) | |
| assert.match(reader, /function takePdfManifestPrefetch\(target\)/) | |
| assert.match(reader, /function schedulePdfManifestPrefetch\(page\)/) | |
| assert.match(reader, /image\.fetchPriority = "low"/) | |
| assert.match(reader, /pdfManifestPrefetchActive\.add\(record\)/) | |
| assert.match(reader, /queuePdfManifestPrefetch\(\)/) | |
| const pdfPageRender = reader.match(/function renderPdfManifestShell\(shell, force = false, priority = false\) \{[\s\S]*?\n\}\s+function renderPdfShell/)[0] | |
| assert.match(pdfPageRender, /(?:const|let) target = pdfPageManifest\.pageUrl\(entry\.page\)/) | |
| assert.doesNotMatch(pdfPageRender, /entry\.j|entry\.w|\.jxl/) | |
| assert.match(reader, /chapterManifestObserver\?\.disconnect\(\)/) | |
| assert.match(reader, /content\.dataset\.errorCode = code/) | |
| assert.match(reader, /reader-request-manager\.js/) | |
| assert.match(reader, /VoiceOfMLReaderRequests\.createReaderRequestManager\(\)/) | |
| assert.match(reader, /readerRuntime\.track\(readerRequestManager\)/) | |
| assert.doesNotMatch(reader, /legacyReaderTitle/) | |
| for (const generation of ['navigation', 'search', 'bookmarks', 'pdf']) assert.match(reader, new RegExp(`nextReaderGeneration\\("${generation}"\\)`)) | |
| for (const timer of ['saveTimer', 'themeAnimationTimer', 'panelAnimationTimer']) assert.match(reader, new RegExp(`clearTimeout\\(${timer}\\)`)) | |
| assertCode(reader, 'for (const frame of [markerFrame, foliateScrollFrame, foliateWindowFrame, epubSeekFrame]) if (frame) cancelAnimationFrame(frame)') | |
| assert.match(reader, /trackReaderResource\(destroy\)/) | |
| assert.match(reader, /task\.destroy\(\)/) | |
| assert.match(reader, /mediaElement\.pause\(\)/) | |
| assert.match(reader, /mediaElement\.removeAttribute\("src"\)/) | |
| assert.strictEqual(reader.includes('activeReaderControllers'), false) | |
| assert.strictEqual(reader.includes('readerRequests'), false) | |
| assert.match(reader, /function syncTocTab\(\)/) | |
| assert.match(reader, /function applyReaderMetadata\(data\)/) | |
| assert.strictEqual((reader.match(/function applyReaderMetadata\(data\)/g) || []).length, 1) | |
| const viewportDeclaration = codePattern('const viewport = document.querySelector("#viewport")').exec(reader) | |
| const metadataApplication = codePattern('applyReaderMetadata(resolvedReaderData)').exec(reader) | |
| assert.ok(viewportDeclaration && metadataApplication && viewportDeclaration.index < metadataApplication.index) | |
| assertCode(reader, 'formatAdapters.active.open()') | |
| assertCode(reader, 'await formatAdapters.active.render(prepared)') | |
| assertCode(reader, 'await applyInitialRestoration(restored, generation)') | |
| assertCode(reader, 'await restoreInitialPosition(entry, generation)') | |
| assertCode(reader, 'await formatAdapters.active.restore(entry, generation)') | |
| assert.match(reader, /const restorationPromise = loadReaderRestoration\(\)/) | |
| assert.match(reader, /await formatAdapters\.active\.render\(prepared\)[\s\S]*?const restored = await awaitReader\(restorationPromise\)/) | |
| assert.doesNotMatch(reader, /Promise\.all\(\[loadReaderRestoration\(\)/) | |
| assert.strictEqual((reader.match(/function loadPdfDocument\(/g) || []).length, 1) | |
| for (const renderer of ['renderImageDocument', 'renderMedia']) assert.strictEqual((reader.match(new RegExp(`function ${renderer}\\s*\\(`,'g')) || []).length, 1) | |
| for (const renderer of ['renderTextDocument', 'renderMarkdownDocument']) assert.strictEqual((reader.match(new RegExp(`function ${renderer}\\(`,'g')) || []).length, 1) | |
| for (const loader of ['loadTextDocument', 'loadMarkdownDocument', 'loadHtmlDocument']) assert.strictEqual((reader.match(new RegExp(`function ${loader}\\(`,'g')) || []).length, 1) | |
| for (const loader of ['loadMediaDocument', 'loadImageDocument', 'loadChapterManifestDocument']) assert.strictEqual((reader.match(new RegExp(`function ${loader}\\(`,'g')) || []).length, 1) | |
| assert.doesNotMatch(reader, /loadFoliateDocument/) | |
| assert.match(reader, /reader-chapter-repository\.js/) | |
| assert.match(reader, /reader-scroll-anchor\.js/) | |
| assert.match(reader, /reader-section-virtualizer\.js/) | |
| assert.match(reader, /VoiceOfMLReaderChapters\.createChapterRepository\(/) | |
| assert.match(reader, /VoiceOfMLReaderScroll\.createScrollAnchorManager\(/) | |
| assert.match(reader, /VoiceOfMLReaderVirtual\.createSectionVirtualizer\(/) | |
| assert.match(reader, /foliateChapterRepository\?\.dispose\(\)/) | |
| assertCode(reader, 'readerRuntime.track(VoiceOfMLReaderScroll') | |
| assert.match(reader, /foliateSectionVirtualizer\?\.dispose\(\)/) | |
| assert.match(reader, /function foliateSectionRoot\(article\)/) | |
| assertCode(reader, 'article.attachShadow({ mode: "open" })') | |
| assert.match(reader, /event\.composedPath\(\)/) | |
| assert.match(reader, /foliateSectionRoot\(node\)/) | |
| assert.match(reader, /foliateScrollAnchors\.observe\(article\)/) | |
| assert.ok((reader.match(/foliateScrollAnchors\.invalidate\(\)/g) || []).length >= 3) | |
| const renderFoliateSource = reader.match(/async\s+function\s+renderFoliate\s*\([\s\S]*?status\.textContent\s*=\s*"EPUB";/)[0] | |
| assert.strictEqual(renderFoliateSource.includes('loaded = new Set'), false) | |
| assert.strictEqual(renderFoliateSource.includes('pending = new Map'), false) | |
| assert.match(reader, /stream\.insertBefore\(article, next \|\| null\)/) | |
| assert.match(reader, /foliateSectionLoader\s*=\s*(?:\(index\)|index)\s*=>/) | |
| assert.doesNotMatch(reader, /^let navigationGeneration\b/m) | |
| assert.doesNotMatch(reader, /syncReaderState/) | |
| assert.doesNotMatch(reader, /^(?:let|var|const)\s+title\b/m) | |
| for (const mirror of ['zoom', 'currentPage', 'pageCount', 'restoredEntry', 'restorationReady', 'tocEntries', 'currentChapterIndex', 'fullSearchResults', 'fullSearchIndex', 'fullSearchGeneration', 'showingAllBookmarks', 'editingBookmark', 'pdfRenderGeneration']) assert.doesNotMatch(reader, new RegExp(`(?:let|var|const)\\s+${mirror}\\b`), mirror) | |
| assert.doesNotMatch(reader, /readerRuntime\.updateFormat\(/) | |
| for (const domain of ['document', 'navigation', 'search', 'panel']) assert.match(reader, new RegExp(`readerRuntime\\.state\\.${domain}`)) | |
| assert.match(reader, /readerRuntime\.currentGeneration\("pdf"\)/) | |
| assertCode(reader, 'nextGeneration: () => nextReaderGeneration("search")') | |
| assertCode(searchController, 'const generation = nextGeneration()') | |
| assert.match(reader, /isReaderGenerationCurrent\("navigation", generation\)/) | |
| assert.match(reader, /registerReaderFormatAdapters\(\)/) | |
| assert.match(reader, /function disposeFormatResources\(mode\)/) | |
| assertCode(reader, 'link.target = "_blank"; link.rel = "noopener noreferrer"') | |
| assert.doesNotMatch(reader, /function (?:navigateFormat|searchFormat)\(/) | |
| assert.match(reader, /async function restoreFormat\(mode, entry, generation/) | |
| assert.match(reader, /formatAdapters\.activate\(capability\.mode\)/) | |
| assert.match(reader, /readerRuntime\.events\.on\("phase"/) | |
| assert.strictEqual((reader.match(/function navigateTocEntry\(/g) || []).length, 1) | |
| assert.match(reader, /await navigateTocEntry\(index\)/) | |
| assert.strictEqual((reader.match(/function navigateFoliateSearchResult\(/g) || []).length, 1) | |
| assert.strictEqual((reader.match(/function\s+fullSearchFoliateMatches\s*\(/g) || []).length, 1) | |
| assertCode(reader, 'publishSearchResults(generation, await fullSearchFoliateMatches(query, generation))') | |
| assert.match(reader, /function captureFoliateBookmarkPosition\(\)/) | |
| assert.match(reader, /function restoreFoliateBookmarkPosition\(entry, generation/) | |
| assert.match(reader, /foliatePosition = captureFoliateBookmarkPosition\(\)/) | |
| assert.match(reader, /new IntersectionObserver/) | |
| assert.doesNotMatch(reader, /article\.innerHTML = styles \+/) | |
| assert.match(reader, /target = await epubRendition\?\.book\?\.resolveHref/) | |
| assert.match(reader, /applyReaderMetadata\(resolvedReaderData\)/) | |
| assert.match(css, /\.foliate-continuous\s+a\s*\{\s*color:\s*#8ab4e8\s*!important;\s*\}/) | |
| assert.match(css, /min-height:\s*0\s*!important;\s*height:\s*auto\s*!important;/) | |
| assert.strictEqual(view.includes('.find(x => x.index = resolved.index)'), false) | |
| assert.strictEqual(view.includes('.find(x => x.index === resolved.index)'), true) | |
| const vm = require('vm') | |
| const priorityFunctions = reader.match(/function pdfPagePriority\(shell\) \{[\s\S]*?\n\}\s+function normalizePdfPriority\(priority\) \{[\s\S]*?\n\}/) | |
| assert.ok(priorityFunctions, 'PDF page priority functions') | |
| const priorityContext = { viewport: { getBoundingClientRect: () => ({ top: 0, bottom: 100 }) }, PDF_PREFETCH_MARGIN: 2400 } | |
| vm.runInNewContext(priorityFunctions[0], priorityContext) | |
| for (const [top, bottom, expected] of [[10, 90, 3], [70, 160, 2], [110, 190, 1], [2600, 2800, 0]]) | |
| assert.strictEqual(priorityContext.pdfPagePriority({ getBoundingClientRect: () => ({ top, bottom }) }), expected) | |
| assert.strictEqual(priorityContext.normalizePdfPriority(true), 3) | |
| const sandbox = { self: {} }; sandbox.self = sandbox; | |
| const frontMatterSource = fs.readFileSync(path.join(root, 'static/reader/formats/reader-html-format.mjs'), 'utf8') | |
| const frontMatterStart = frontMatterSource.indexOf('export function stripMarkdownFrontMatter') | |
| const frontMatterEnd = frontMatterSource.indexOf('\n}\n', frontMatterStart) | |
| assert.ok(frontMatterStart >= 0 && frontMatterEnd > frontMatterStart, 'Markdown front matter helper') | |
| const frontMatterContext = {} | |
| vm.runInNewContext( | |
| frontMatterSource.slice(frontMatterStart, frontMatterEnd + 3).replace(/^export /, '') + | |
| ';this.stripMarkdownFrontMatter = stripMarkdownFrontMatter;', | |
| frontMatterContext | |
| ) | |
| const stripFrontMatter = frontMatterContext.stripMarkdownFrontMatter | |
| for (const [input, expected] of [ | |
| ['---\ntitle: "标题"\nauthor: "作者"\nsection: "分类"\ndate: "日期"\nsource: "https://example.invalid"\nsource_path: "chinese/a.htm"\n---\n# 正文\n', '# 正文\n'], | |
| ['\uFEFF---\r\ntitle: "T"\r\n---\r\n正文', '正文'], | |
| ['---\ntitle: "T"\n---', ''], | |
| ['---\n\n---\n# Body', '---\n\n---\n# Body'], | |
| ['# Body\n---\n', '# Body\n---\n'], | |
| ['---\ntitle: "T"\n', '---\ntitle: "T"\n'], | |
| ]) assert.strictEqual(stripFrontMatter(input), expected) | |
| assert.match(reader, /marked\.parse\(stripMarkdownFrontMatter\(text\)\)/) | |
| function loadExports(file, name) { vm.runInNewContext(fs.readFileSync(path.join(root, 'static', file), 'utf8'), sandbox); return sandbox[name]; } | |
| const contractFeatures = loadExports('reader/core/reader-contract.js', 'VoiceOfMLReader').features | |
| const runtimeMatrix = loadExports('reader/core/reader-runtime.js', 'VoiceOfMLReaderRuntime').FEATURE_MATRIX | |
| assert.strictEqual(runtimeMatrix, contractFeatures) | |
| for (const mode of Object.keys(contractFeatures)) assert.strictEqual(JSON.stringify(runtimeMatrix[mode]), JSON.stringify(contractFeatures[mode]), mode) | |
| assert.strictEqual(JSON.stringify(runtimeMatrix.unsupported), JSON.stringify({ toc: false, search: false, zoom: false, bookmarks: false, pagination: false, media: false })) | |
| // Evaluate the owning registry with identifiable loaders/renderers, so comments or | |
| // dead dispatch functions cannot satisfy the format wiring contract. | |
| const registry = reader.match(/function\s+registerReaderFormatAdapters\s*\(\)\s*\{[\s\S]*?\n\}/) | |
| assert.ok(registry, 'format adapter registry') | |
| const expected = { | |
| pdf: ['loadPdfDocument', 'renderPdf'], image: ['loadImageDocument', 'renderImageDocument'], | |
| text: ['loadTextDocument', 'renderTextDocument'], markdown: ['loadMarkdownDocument', 'renderMarkdownDocument'], | |
| html: ['loadHtmlDocument', 'renderHtml'], 'epub-chapters': ['loadChapterManifestDocument', 'renderChapterManifest'], | |
| foliate: ['loadMediaDocument', 'renderFoliate'], | |
| swf: ['loadSwfDocument', 'renderSwf'], | |
| } | |
| const registered = new Map(), calls = [] | |
| const registryContext = { formatAdapters: { register: (mode, adapter) => registered.set(mode, adapter) } } | |
| for (const name of [...new Set(Object.values(expected).flat()), 'preloadPdfFirstPage', 'fetchReaderResponse', 'renderPdfPages', 'renderImagePages', 'renderMedia', 'restoreFormat', 'disposeFormatResources']) registryContext[name] = (...args) => calls.push([name, ...args]) | |
| vm.runInNewContext(registry[0] + '; registerReaderFormatAdapters();', registryContext) | |
| assert.deepStrictEqual([...registered.keys()].sort(), [...Object.keys(expected), 'pdf-pages', 'image-pages', 'audio', 'video'].sort()) | |
| for (const [mode, [open, render]] of Object.entries(expected)) { | |
| assert.strictEqual(registered.get(mode).open, registryContext[open], mode + ' loader') | |
| assert.strictEqual(registered.get(mode).render, registryContext[render], mode + ' renderer') | |
| } | |
| registered.get('pdf-pages').open() | |
| assert.deepStrictEqual(calls.splice(0), [['fetchReaderResponse']]) | |
| assert.match(reader, /const initialPage = initialReaderPage\(totalPages\);[\s\S]*?await preloadPdfFirstPage\(totalPages\)/) | |
| assert.strictEqual(registered.get('pdf-pages').render, registryContext.renderPdfPages) | |
| registered.get('image-pages').open() | |
| assert.deepStrictEqual(calls.splice(0), [['fetchReaderResponse']]) | |
| assert.strictEqual(registered.get('image-pages').render, registryContext.renderImagePages) | |
| for (const mode of ['audio', 'video']) { | |
| assert.strictEqual(registered.get(mode).open, registryContext.loadMediaDocument) | |
| registered.get(mode).render() | |
| assert.deepStrictEqual(calls.splice(0), [['renderMedia', mode]]) | |
| } | |
| for (const [mode, adapter] of registered) { | |
| const entry = { page: 2 } | |
| adapter.restore(entry, 17) | |
| adapter.dispose() | |
| assert.deepStrictEqual(calls.splice(0), [['restoreFormat', mode, entry, 17], ['disposeFormatResources', mode]]) | |
| } | |
| const html = fs.readFileSync(path.join(root, 'static/reader.html'), 'utf8') | |
| const securityScript = html.indexOf('src="/static/reader/core/reader-security.js"') | |
| assert.ok(securityScript >= 0 && securityScript < html.indexOf('src="/static/reader/core/reader-contract.js"')) | |
| assert.match(reader, /readerRuntime\.track\(window\.__VOICE_PDF_PRELOAD__\)/) | |
| console.log('reader architecture contracts passed') | |