UNPKG

web-snaps

Version:

Browser automation with automatic snapshotting.

107 lines (106 loc) 4.68 kB
import { check, checkWrap } from '@augment-vir/assert'; import { ensureErrorAndPrependMessage, log as logImport, wrapInTry, } from '@augment-vir/common'; import { getNowInIsoString, getNowInUtcTimezone } from 'date-vir'; import { JSDOM } from 'jsdom'; import { getAllPageHtml } from '../web-snap/get-html.js'; import { saveWebSnap } from '../web-snap/save-web-snap.js'; /** * Run a single {@link WebFlow}. A browser must already be loaded beforehand. * * @category Internal */ export async function runWebFlow({ browserParams, webFlow, options = {}, }) { const log = logImport.if(!options.silent); /* node:coverage ignore next 1: not testing the user provided page */ const page = options.existingPage || (await browserParams.browserContext.newPage()); const createdPage = !options.existingPage; try { try { const webFlowStartedAt = getNowInUtcTimezone(); await page.goto(webFlow.startUrl); log.faint(`${webFlow.flowKey}: start`); let wasSnapshotBlocked = false; const params = { ...browserParams, originalUrl: webFlow.startUrl, page, webFlowStartedAt, webFlowKey: webFlow.flowKey, silent: !!options.silent, blockSnapshot(shouldBlockSnapshot) { wasSnapshotBlocked = shouldBlockSnapshot; }, }; const phaseOutputs = []; const webSnapInProgress = { webFlow: { flowKey: webFlow.flowKey, startUrl: webFlow.startUrl, phaseNames: webFlow.phaseNames, }, generatedAt: getNowInIsoString(), phaseSnaps: [], }; try { for (const [index, phase,] of webFlow.phases.entries()) { try { const phaseParams = { ...params, phaseStartedAt: getNowInUtcTimezone(), }; log.faint(`${webFlow.flowKey}: phase ${index}: ${phase.name}`); const phaseResult = await wrapInTry(() => phase.run(phaseParams)); const error = checkWrap.instanceOf(phaseResult, Error); const { disableSnapshot, output } = checkWrap.notInstanceOf(phaseResult, Error) || { disableSnapshot: false, output: undefined, }; phaseOutputs.push(output); if (!wasSnapshotBlocked && !options.disableSnapshots && !phase.disableSnapshot && !disableSnapshot) { const rawHtml = await getAllPageHtml(page, browserParams.storeKey); const finalHtml = phase.sanitizeSnapshot ? await phase.sanitizeSnapshot({ ...phaseParams, get dom() { return new JSDOM(rawHtml); }, domString: rawHtml, }) : rawHtml; webSnapInProgress.phaseSnaps.push({ pageHtml: check.isString(finalHtml) ? finalHtml : finalHtml.serialize(), phaseName: phase.name, url: page.url(), }); } if (error) { throw error; } } catch (error) { throw ensureErrorAndPrependMessage(error, `Phase '${phase.name}' in WebFlow '${webFlow.flowKey}' failed:`); } } } finally { if (webSnapInProgress.phaseSnaps.length && options.webSnapDirPath) { await saveWebSnap(webFlow, webSnapInProgress, !!options.silent); } } return phaseOutputs; } catch (error) { throw ensureErrorAndPrependMessage(error, `WebFlow '${webFlow.flowKey}' failed:`); } } finally { if (createdPage) { await page.close(); } } }