import { strict as assert } from 'node:assert'; import { rmSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; import { execa } from 'execa'; import { ensureDirectoryExistence, fileContentOfPath, safeCopyFile, tplReplacer, } from './building-utils'; const demoData = ['demo', 'demo-mobile', 'zero-execution']; const outputExtensionUnpackedBaseDir = join(__dirname, '../unpacked-extension'); const multiEntrySegment = fileContentOfPath('./fixture/multi-entries.html'); const reportTpl = fileContentOfPath('../html/report.html'); const reportCSS = fileContentOfPath('../dist/report.css'); const reportJS = fileContentOfPath('../dist/report.js'); const playgroundCSS = fileContentOfPath( '../unpacked-extension/lib/playground-entry.css', ); const playgroundTpl = fileContentOfPath('../html/playground.html'); const extensionSidepanelTpl = fileContentOfPath( '../html/extension-sidepanel.html', ); const outputReportHTML = join(__dirname, '../dist/report/index.html'); const outputMultiEntriesHTML = join(__dirname, '../dist/report/multi.html'); const outputEmptyDumpHTML = join(__dirname, '../dist/report/empty-error.html'); const outputExtensionZipDir = join(__dirname, '../dist/extension/'); const outputExtensionPageDir = join(outputExtensionUnpackedBaseDir, 'pages'); const outputExtensionPlayground = join( outputExtensionPageDir, 'playground.html', ); const outputExtensionSidepanel = join(outputExtensionPageDir, 'sidepanel.html'); const replaceStringWithFirstAppearance = ( str: string, target: string, replacement: string, ) => { const index = str.indexOf(target); return str.slice(0, index) + replacement + str.slice(index + target.length); }; /* report utils */ function emptyDumpReportHTML() { let html = replaceStringWithFirstAppearance( reportTpl, '{{css}}', `\n`, ); html = replaceStringWithFirstAppearance( html, '{{js}}', ``, ); return html; } const tplRetrieverFn = `window.get_midscene_report_tpl = () => { const tpl = document.getElementById('midscene_report_tpl').innerText; if (!tpl) { return ''; } const tplDecoded = decodeURIComponent(tpl); return tplDecoded; };`; function putReportTplIntoHTML(html: string, outsourceMode = false) { assert(html.indexOf('') !== -1, 'HTML must contain '); if (outsourceMode) { const tplWrapper = ``; // in Chrome extension return html.replace( '', `${tplWrapper}\n`, ); } return html; // return html.replace( // '', // `${tplWrapper}\n`, // ); } function reportHTMLWithDump( dumpJsonString?: string, rawDumpString?: string, filePath?: string, ) { let dumpContent = rawDumpString; if (!dumpContent && dumpJsonString) { dumpContent = ``; } const emptyDumpHTML = emptyDumpReportHTML(); assert( emptyDumpHTML.length < (process.env.CI ? 10 * 1000 * 1000 : 20 * 1000 * 1000), `emptyDumpHTML is too large, length: ${emptyDumpHTML.length}`, ); const reportHTML = replaceStringWithFirstAppearance( emptyDumpHTML, '{{dump}}', dumpContent || '{{dump}}', ); const html = putReportTplIntoHTML(reportHTML); if (filePath) { writeFileSync(filePath, html); console.log(`HTML file generated successfully: ${filePath}`); } return html; } /* build task: extension */ function buildExtension() { // clear everything in the extension page dir rmSync(outputExtensionPageDir, { recursive: true, force: true }); ensureDirectoryExistence(outputExtensionSidepanel); // write the set-report-tpl.js into the extension writeFileSync( join(__dirname, '../unpacked-extension/lib/set-report-tpl.js'), tplRetrieverFn, ); // playground.html const resultWithOutsource = tplReplacer(playgroundTpl, { css: `\n`, js: ``, bootstrap: '', // the entry iife will mount by itself }); writeFileSync( outputExtensionPlayground, putReportTplIntoHTML(resultWithOutsource, true), ); console.log(`HTML file generated successfully: ${outputExtensionPlayground}`); // sidepanel.html writeFileSync( outputExtensionSidepanel, putReportTplIntoHTML(extensionSidepanelTpl, true), ); console.log(`HTML file generated successfully: ${outputExtensionSidepanel}`); // put the htmlElement.js into the extension safeCopyFile( join(__dirname, '../../web-integration/dist/script/htmlElement.js'), join(__dirname, '../unpacked-extension/lib/htmlElement.js'), ); } async function zipDir(src: string, dest: string) { // console.log('cwd', dirname(src)); await execa('zip', ['-r', dest, '.'], { cwd: src, }); } async function packExtension() { const manifest = fileContentOfPath('../unpacked-extension/manifest.json'); const version = JSON.parse(manifest).version; const zipName = `midscene-extension-v${version}.zip`; const distFile = join(outputExtensionZipDir, zipName); ensureDirectoryExistence(distFile); // zip the extension await zipDir(outputExtensionUnpackedBaseDir, distFile); } /* build task: report and demo pages*/ function buildReport() { const reportHTMLContent = reportHTMLWithDump(); assert(reportHTMLContent.length >= 1000); ensureDirectoryExistence(outputReportHTML); writeFileSync(outputReportHTML, reportHTMLContent); console.log( `HTML file generated successfully: ${outputReportHTML}, size: ${reportHTMLContent.length}`, ); // demo pages for (const demo of demoData) { reportHTMLWithDump( fileContentOfPath(`./fixture/${demo}.json`), undefined, join(__dirname, `../dist/report/${demo}.html`), ); } // multi entries reportHTMLWithDump(undefined, multiEntrySegment, outputMultiEntriesHTML); // dump data with empty array reportHTMLWithDump( undefined, '', outputEmptyDumpHTML, ); // copy to @midscene/core safeCopyFile( outputReportHTML, join(__dirname, '../../midscene/report/index.html'), ); } buildReport(); buildExtension(); packExtension();