UNPKG

jsdom-context-require

Version:

Allows you to require files in a jsdom window context.

135 lines (134 loc) 4.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createBrowser = void 0; const jsdom_1 = require("jsdom"); const context_require_1 = require("context-require"); const resolve_1 = require("./resolve"); /** * Creates a custom Module object which runs all required scripts * in a new jsdom instance. */ function createBrowser({ dir, html, extensions, beforeParse, ...jsdomOptions }) { const browser = new jsdom_1.JSDOM("", { runScripts: "dangerously", pretendToBeVisual: true, ...jsdomOptions, }); const { window } = browser; const resolveExtensions = extensions ? [ ...new Set([ ...Object.keys(extensions), ...Object.keys(require.extensions).reverse(), ]), ] : Object.keys(require.extensions).reverse(); // Pass through istanbul coverage. if ("__coverage__" in globalThis) { window.__coverage__ = globalThis.__coverage__; } // Expose some globals commonly shimmed by bundlers. window.global = window; window.Buffer = Buffer; window.process = { ...process, browser: true }; window.setImmediate || (window.setImmediate = (() => { const msg = `${Math.random()}`; let queue = []; let offset = 0; window.addEventListener("message", (ev) => { if (ev.data === msg) { const cbs = queue; offset += cbs.length; queue = []; for (const cb of cbs) { if (cb) { cb(); } } } }); window.clearImmediate = function clearImmediate(id) { const index = id - offset; if (index >= 0) { queue[index] = undefined; } }; return function setImmediate(cb, ...args) { const index = queue.push(args.length ? () => cb(...args) : cb) - 1; if (!index) { window.postMessage(msg, "*"); } return index + offset; }; })()); browser.require = (0, context_require_1.default)({ dir, context: browser, extensions, resolve(basedir, req, { filename }) { const resolved = (0, resolve_1.resolve)(req, basedir, resolveExtensions); if (resolved) return resolved; throw new Error(`Cannot find module '${req}' from '${filename}'`); }, }); browser.yield = () => new Promise((resolve) => window.setImmediate(resolve)); browser.act = async (fn) => { let errors; let errorStage = 0; window.addEventListener("error", handleError); window.addEventListener("unhandledrejection", handleError); try { const result = await fn?.(); await browser.yield(); return result; } catch (err) { trackError(err); } finally { window.removeEventListener("error", handleError); window.removeEventListener("unhandledrejection", handleError); switch (errorStage) { case 0: break; case 1: throw errors; default: throw new window.AggregateError(errors); } } function handleError(ev) { if (!ev.defaultPrevented) { let error = "error" in ev ? ev.error : ev.reason || ev; if ("detail" in error) error = error.detail; ev.preventDefault(); } } function trackError(err) { switch (errorStage) { case 0: errors = err; errorStage = 1; break; case 1: if (err !== errors) { errors = new Set([errors, err]); errorStage = 2; } break; default: errors.add(err); break; } } }; if (beforeParse) { beforeParse(window, browser); } window.document.open(); window.document.write(html || "<!DOCTYPE html><html><head></head><body></body></html>"); return browser; } exports.createBrowser = createBrowser;