UNPKG

zoroaster

Version:

The 2020 Most Modern Testing Framework For Node.JS With Test Contexts (Reusable BeforeEach / AfterEach Via Separate Files); Masks (Inputs/Outputs In Non-Js Files) And Fork Testing; Interactive Snapshots.

1,139 lines (1,135 loc) 32.7 kB
#!/usr/bin/env node const path = require('path'); const os = require('os'); const fs = require('fs'); const stream = require('stream'); const util = require('util'); const assert = require('assert'); const readline = require('readline'); const w = os.EOL, aa = os.homedir; const ba = /\s+at.*(?:\(|\s)(.*)\)?/, ca = /^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:IGNORED_MODULES)\/.*)?\w+)\.js:\d+:\d+)|native)/, x = a => { const {pretty:b = !1, ignoredModules:c = ["pirates", "@artdeco/pirates"]} = {}, d = c.join("|"), e = new RegExp(ca.source.replace("IGNORED_MODULES", d)); return a.replace(/\\/g, "/").split("\n").filter(f => { f = f.match(ba); if (null === f || !f[1]) { return !0; } f = f[1]; return f.includes(".app/Contents/Resources/electron.asar") || f.includes(".app/Contents/Resources/default_app.asar") ? !1 : !e.test(f); }).filter(f => f.trim()).map(f => { if (b) { const g = aa().replace(/\\/g, "/"); return f.replace(/\s+at.*(?:\(|\s)(.*)\)?/, (h, k) => h.replace(k, k.replace(g, "~"))); } return f; }).join("\n"); }; const da = (a, b, c, d = !1, e = !1) => { const f = c ? new RegExp(`^-(${c}|-${b})$`) : new RegExp(`^--${b}$`); b = a.findIndex(g => f.test(g)); if (-1 == b) { return {argv:a}; } if (d) { return {value:!0, index:b, length:1}; } d = a[b + 1]; if (!d || "string" == typeof d && d.startsWith("--")) { return {argv:a}; } e && (d = parseInt(d, 10)); return {value:d, index:b, length:2}; }, ea = a => { const b = []; for (let c = 0; c < a.length; c++) { const d = a[c]; if (d.startsWith("-")) { break; } b.push(d); } return b; }, fa = () => { var a = y; return Object.keys(a).reduce((b, c) => { const d = a[c]; if ("string" == typeof d) { return b[`-${d}`] = "", b; } c = d.command ? c : `--${c}`; d.short && (c = `${c}, -${d.short}`); let e = d.description; d.default && (e = `${e}\nDefault: ${d.default}.`); b[c] = e; return b; }, {}); }; const y = {tests:{description:"The location of the test suite directory or file.", command:!0, multiple:!0}, alamode:{description:"Enable import/export transpilation with \u00c0LaMode.", boolean:!0, short:"a"}, watch:{description:"Start the runner in _watch_ mode (rerun on changes).", boolean:!0, short:"w"}, timeout:{description:"Timeout for tests in ms.", number:!0, default:"2000", short:"t"}, snapshot:{description:"The location of the snapshot dir.", default:"test/snapshot", short:"s"}, snapshotRoot:{description:"The list of folders that will be roots in the snapshot dir.", default:"test/spec,test/mask", short:"r"}, interactive:{description:"Run in interactive mode, allowing to update snapshots\nand mask results when they don't match currently expected.", boolean:!0, short:"i"}, environment:{description:"\u00c0LaMode environment for applying settings via `.alamoderc.json`.\nEquivalent to setting `ALAMODE_ENV` env variable.", short:"e"}, babel:{description:"Require `@babel/register` (needs to be installed).", boolean:!0, short:"b"}, version:{description:"Show the current version.", boolean:!0, short:"v"}, help:{description:"Display help information.", boolean:!0, short:"h"}}, z = function(a = {}, b = process.argv) { let [, , ...c] = b; const d = ea(c); c = c.slice(d.length); a = Object.entries(a).reduce((g, [h, k]) => { g[h] = "string" == typeof k ? {short:k} : k; return g; }, {}); const e = []; a = Object.entries(a).reduce((g, [h, k]) => { let l; try { const m = k.short, n = k.boolean, p = k.number, q = k.command, t = k.multiple; if (q && t && d.length) { l = d; } else { if (q && d.length) { l = d[0]; } else { const r = da(c, h, m, n, p); ({value:l} = r); const u = r.index, v = r.length; void 0 !== u && v && e.push({index:u, length:v}); } } } catch (m) { return g; } return void 0 === l ? g : {...g, [h]:l}; }, {}); let f = c; e.forEach(({index:g, length:h}) => { Array.from({length:h}).forEach((k, l) => { f[g + l] = null; }); }); f = f.filter(g => null !== g); Object.assign(a, {C:f}); return a; }(y), ha = z.tests, ia = z.alamode, ja = z.watch, ka = z.timeout || 2000, la = z.snapshot || "test/snapshot", ma = z.snapshotRoot || "test/spec,test/mask", na = z.interactive, A = z.environment, oa = z.babel, pa = z.version, qa = z.help, ra = z.C; const B = path.dirname, C = path.join, D = path.relative, E = path.resolve; const sa = fs.createReadStream, ta = fs.createWriteStream, F = fs.lstat, ua = fs.mkdir, G = fs.readdir, va = fs.rmdir, wa = fs.unlink, xa = fs.unwatchFile, ya = fs.watchFile; var za = stream; const H = stream.Transform, Aa = stream.Writable; const I = (a, b = 0, c = !1) => { if (0 === b && !c) { return a; } a = a.split("\n", c ? b + 1 : void 0); return c ? a[a.length - 1] : a.slice(b).join("\n"); }, Ba = (a, b = !1) => I(a, 2 + (b ? 1 : 0)), Ca = a => { ({callee:{caller:a}} = a); return a; }; function Da(a, b, c = !1) { return function(d) { var e = Ca(arguments), {stack:f} = Error(); const g = I(f, 2, !0), h = (f = d instanceof Error) ? d.message : d; e = [`Error: ${h}`, ...null !== e && a === e || c ? [b] : [g, b]].join("\n"); e = x(e); return Object.assign(f ? d : Error(), {message:h, stack:e}); }; } ;function J(a) { var {stack:b} = Error(); const c = Ca(arguments); b = Ba(b, a); return Da(c, b, a); } ;const Ea = (a, b) => { b.once("error", c => { a.emit("error", c); }); return b; }; class K extends Aa { constructor(a) { const {binary:b = !1, rs:c = null, ...d} = a || {}, {G:e = J(!0), proxyError:f} = a || {}, g = (h, k) => e(k); super(d); this.a = []; this.F = new Promise((h, k) => { this.on("finish", () => { let l; b ? l = Buffer.concat(this.a) : l = this.a.join(""); h(l); this.a = []; }); this.once("error", l => { if (-1 == l.stack.indexOf("\n")) { g`${l}`; } else { const m = x(l.stack); l.stack = m; f && g`${l}`; } k(l); }); c && Ea(this, c).pipe(this); }); } _write(a, b, c) { this.a.push(a); c(); } get j() { return this.F; } } const Fa = async a => { ({j:a} = new K({rs:a, G:J(!0)})); return await a; }; /* diff package https://github.com/kpdecker/jsdiff BSD License Copyright (c) 2009-2015, Kevin Decker <kpdecker@gmail.com> */ function Ga(a, b, c) { let d = a[a.length - 1]; d && d.g === b && d.l === c ? a[a.length - 1] = {count:d.count + 1, g:b, l:c} : a.push({count:1, g:b, l:c}); } function Ha(a, b, c, d, e) { let f = c.length, g = d.length, h = b.f; e = h - e; let k = 0; for (; h + 1 < f && e + 1 < g && a.equals(c[h + 1], d[e + 1]);) { h++, e++, k++; } k && b.h.push({count:k}); b.f = h; return e; } function Ia(a) { let b = []; for (let c = 0; c < a.length; c++) { a[c] && b.push(a[c]); } return b; } function Ja(a, b) { var c = new Ka; a = Ia(a.split("")); b = Ia(b.split("")); let d = b.length, e = a.length, f = 1, g = d + e, h = [{f:-1, h:[]}]; var k = Ha(c, h[0], b, a, 0); if (h[0].f + 1 >= d && k + 1 >= e) { return [{value:c.join(b), count:b.length}]; } for (; f <= g;) { a: { for (k = -1 * f; k <= f; k += 2) { var l = void 0; l = h[k - 1]; let n = h[k + 1]; var m = (n ? n.f : 0) - k; l && (h[k - 1] = void 0); let p = l && l.f + 1 < d; m = n && 0 <= m && m < e; if (p || m) { !p || m && l.f < n.f ? (l = {f:n.f, h:n.h.slice(0)}, Ga(l.h, void 0, !0)) : (l.f++, Ga(l.h, !0, void 0)); m = Ha(c, l, b, a, k); if (l.f + 1 >= d && m + 1 >= e) { k = La(c, l.h, b, a); break a; } h[k] = l; } else { h[k] = void 0; } } f++; k = void 0; } if (k) { return k; } } } class Ka { equals(a, b) { return a === b; } join(a) { return a.join(""); } } function La(a, b, c, d) { let e = 0, f = b.length, g = 0, h = 0; for (; e < f; e++) { var k = b[e]; if (k.l) { k.value = a.join(d.slice(h, h + k.count)), h += k.count, e && b[e - 1].g && (k = b[e - 1], b[e - 1] = b[e], b[e] = k); } else { if (k.g) { k.value = a.join(c.slice(g, g + k.count)); } else { let l = c.slice(g, g + k.count); l = l.map(function(m, n) { n = d[h + n]; return n.length > m.length ? n : m; }); k.value = a.join(l); } g += k.count; k.g || (h += k.count); } } c = b[f - 1]; 1 < f && "string" === typeof c.value && (c.g || c.l) && a.equals("", c.value) && (b[f - 2].value += c.value, b.pop()); return b; } ;const Ma = {black:30, red:31, green:32, yellow:33, blue:34, magenta:35, cyan:36, white:37, grey:90}, Na = {black:40, red:41, green:42, yellow:43, blue:44, magenta:45, cyan:46, white:47}, L = {reset:0, bold:1, underline:4, slow_blink:5, L:6, reverse:7, conceal:8, crossed_out:9, primary_font:10}, M = a => { Array.isArray(a) && (a = a.join(";")); return `\x1b[${a}m`; }; function N(a, b) { b = [Ma[b], ...Object.keys({}).map(d => L[d.toLowerCase()])].filter(Boolean); if (!b.length) { return a; } b = M(b); const c = M(L.reset); return `${b}${a}${c}`; } function O(a, b) { b = [Na[b], ...Object.keys({}).map(d => L[d])].filter(Boolean); if (!b.length) { return a; } b = M(b); const c = M(L.reset); return `${b}${a}${c}`; } function Oa(a, b) { return Ja(a, b).map(({g:c, l:d, value:e}) => { let f; const g = e.split(" "); if (c || d) { f = g.map(h => h.replace(/(\r?\n)$/mg, "\u23ce$1").replace(/(\r+)([^\n]|$)/g, (k, l, m) => "<CR>".repeat(l.length) + m)); } c ? f = f.map(h => N(h, "green")).join(O(" ", "green")) : d ? f = f.map(h => N(h, "red")).join(O(" ", "red")) : f = N(e, "grey"); return f; }).join(""); } ;function P(a, b) { return a.replace(/^(?!\s*$)/mg, b); } function Pa({error:a, name:b}) { if (!a) { throw Error("cannot filter stack when a test does not have an error"); } var c = a.stack.split(/\n/); const d = new RegExp(`at( async)? (.+\\.)?${b}`); b = c.findIndex(e => d.test(e)) + 1; return (c = c.slice(0, b).join("\n")) ? c : x(a.stack); } const Qa = " " + N("\u2713", "green") + " ", Ra = " " + N("\u2717", "red") + " "; function Sa() { const a = []; return new H({objectMode:!0, transform({type:b, name:c, ...d}, e, f) { "test-suite-start" == b && "default" != c ? a.push(c) : "test-suite-end" == b && "default" != c && a.pop(); e = a.slice(); this.push({type:b, name:c, stack:e, ...d}); f(); }}); } function Ta() { return new H({objectMode:!0, transform({type:a, name:b, stack:c, result:d}, e, f) { "test-suite-start" == a && "default" != b ? (this.push(P(b, Array.from({length:2 * c.length}).join(" "))), this.push(w)) : "test-end" == a && (this.push(P(d, Array.from({length:2 * c.length}).join(" "))), this.push(w)); f(); }}); } function Ua() { return new H({objectMode:!0, transform({error:a, stack:b, name:c}, d, e) { if (!a) { return e(); } this.push("\u001b[31m"); this.push(b.join(" > ")); this.push(` > ${c}`); this.push("\u001b[0m"); this.push(w); this.push(P(Pa({error:a, name:c}), " ")); this.push(w); this.push(w); e(); }}); } ;async function Q(a, b, c) { const d = J(!0); if ("function" != typeof a) { throw Error("Function must be passed."); } if (!a.length) { throw Error(`Function${a.name ? ` ${a.name}` : ""} does not accept any arguments.`); } return await new Promise((e, f) => { const g = (k, l) => k ? (k = d(k), f(k)) : e(c || l); let h = [g]; Array.isArray(b) ? h = [...b, g] : 1 < Array.from(arguments).length && (h = [b, g]); a(...h); }); } ;function Va(a, b, c) { return setTimeout(() => { const d = Error(`${a ? a : "Promise"} has timed out after ${b}ms`); d.stack = `Error: ${d.message}`; c(d); }, b); } function Wa(a, b) { let c; const d = new Promise((e, f) => { c = Va(a, b, f); }); return {timeout:c, j:d}; } async function R(a, b, c) { if (!(a instanceof Promise)) { throw Error("Promise expected"); } if (!b) { throw Error("Timeout must be a number"); } if (0 > b) { throw Error("Timeout cannot be negative"); } const {j:d, timeout:e} = Wa(c, b); try { return await Promise.race([a, d]); } finally { clearTimeout(e); } } ;async function Xa(a = []) { a = (Array.isArray(a) ? a : [a]).map(Ya); return await Promise.all(a); } const Ya = async a => { if ("function" != (typeof a).toLowerCase()) { return a; } try { const b = {}; await a.call(b); return b; } catch (b) { if (!/^Class constructor/.test(b.message)) { throw b; } a = new a; a._init && await a._init(); return new Proxy(a, {get(c, d) { return "then" == d ? c : "function" == typeof c[d] ? c[d].bind(c) : c[d]; }}); } }, S = async a => { a = a.map(async b => { if ("function" == (typeof b._destroy).toLowerCase()) { return await b._destroy(); } }); return await Promise.all(a); }; const $a = async a => { const {context:b, timeout:c = null, fn:d, persistentContext:e, onCatchment:f} = a; a = new Date; let g = null, h = null, k = null, l = [], m, n; try { b && (m = b ? Xa(b) : Promise.resolve([]), m.then(() => { n = !0; }), l = await (c ? R(m, c, "Evaluate context") : m)); const p = e ? [...Array.isArray(e) ? e : [e], ...l] : l, q = d(...p); q instanceof Promise ? h = await (c ? R(q, c, "Test") : q) : h = q; } catch (p) { g = p; } if (h instanceof za) { try { const p = new K({rs:h}); f && f(p); h = await p.j; } catch (p) { g = p; } } try { const p = S(l); k = await (c ? R(p, c, "Destroy") : p); } catch (p) { g = p; } !n && m && Za(m); return {started:a, finished:new Date, error:g, result:h, destroyResult:k}; }, Za = async a => { a = await a; await S(a); }; const ab = async(a, b) => { const {onlyFocused:c = !1, runTest:d, runTestSuite:e} = b, f = !c; return await a.reduce(async(g, h) => { const k = h.name, l = h.isFocused; var m = h.hasFocused; const n = !!h.fn; if (f || l || m) { g = g instanceof Promise ? await g : g, n ? (m = await d(h), Object.assign(h, m), g[k] = h) : (h = await e(h, m), g[k] = h); } return g; }, {}); }; const bb = assert.equal; const cb = readline.createInterface; function db(a, b = {}) { const {timeout:c, password:d = !1, output:e = process.stdout, input:f = process.stdin, ...g} = b, h = cb({input:f, output:e, ...g}); if (d) { const k = h.output; h._writeToOutput = l => { if (["\r\n", "\n", "\r"].includes(l)) { return k.write(l); } l = l.split(a); "2" == l.length ? (k.write(a), k.write("*".repeat(l[1].length))) : k.write("*"); }; } b = new Promise(k => { h.question(a, k); }); b = c ? R(b, c, `reloquent: ${a}`) : b; h.promise = eb(b, h); return h; } const eb = async(a, b) => { try { return await a; } finally { b.close(); } }; async function fb(a, b) { if ("object" != typeof a) { throw Error("Please give an object with questions"); } return await Object.keys(a).reduce(async(c, d) => { c = await c; var e = a[d]; switch(typeof e) { case "object": e = {...e}; break; case "string": e = {text:e}; break; default: throw Error("A question must be a string or an object."); } e.text = `${e.text}${e.text.endsWith("?") ? "" : ":"} `; var f; if (e.defaultValue) { var g = e.defaultValue; } e.getDefault && (f = await e.getDefault()); let h = g || ""; g && f && g != f ? h = `\x1b[90m${g}\x1b[0m` : g && g == f && (h = ""); g = f || ""; ({promise:g} = db(`${e.text}${h ? `[${h}] ` : ""}${g ? `[${g}] ` : ""}`, {timeout:b, password:e.password, ...e})); f = await g || f || e.defaultValue; "function" == typeof e.validation && e.validation(f); "function" == typeof e.postProcess && (f = await e.postProcess(f)); return {...c, [d]:f}; }, {}); } ;async function T(a) { const {defaultYes:b = !0, timeout:c} = {}; a = "string" == typeof a ? {text:a} : a; const d = a.text, e = d.endsWith("?"); ({question:a} = await fb({question:{defaultValue:b ? "y" : "n", ...a, text:`${e ? d.replace(/\?$/, "") : d} (y/n)${e ? "?" : ""}`}}, c)); return "y" == a; } ;const gb = util.inspect; async function hb(a) { a = sa(a); return await Fa(a); } ;async function ib(a, b) { if (!a) { throw Error("No path is given."); } const c = J(!0), d = ta(a); await new Promise((e, f) => { d.on("error", g => { g = c(g); f(g); }).on("close", e).end(b); }); } ;async function jb(a) { const b = B(a); try { return await U(b), a; } catch (c) { if (/EEXIST/.test(c.message) && -1 != c.message.indexOf(b)) { return a; } throw c; } } async function U(a) { try { await Q(ua, a); } catch (b) { if ("ENOENT" == b.code) { const c = B(a); await U(c); await U(a); } else { if ("EEXIST" != b.code) { throw b; } } } } ;const kb = (a, b) => { a = " ".repeat(Math.max(a - b.length, 0)); return `${b}${a}`; }, lb = a => { a = a.split("\n"); const b = {}.width || a.reduce((c, {length:d}) => d > c ? d : c, 0); return a.map(kb.bind(null, b)).join("\n"); }; function mb(a) { const {padding:b = 1} = {}; var c = a.split("\n").reduce((f, {length:g}) => g > f ? g : f, 0) + 2 * b; const d = `\u250c${"\u2500".repeat(c)}\u2510`; c = `\u2514${"\u2500".repeat(c)}\u2518`; const e = " ".repeat(b); a = lb(a).split("\n").map(f => `\u2502${e}${f}${e}\u2502`).join("\n"); return `${d}\n${a}\n${c}`; } ;async function V(a, b, c) { a = E(a.a, b); await jb(a); /\.json$/.test(a) ? (c = JSON.stringify(c, null, 2), await ib(a, c)) : await ib(a, c); } async function nb(a, b, c, d) { if (!c) { throw Error("Give snapshot to save"); } if (await a.prompt(c, d)) { await V(a, b, c); } else { throw Error("Could not test missing snapshot"); } } async function ob(a, b, c, d, e = !1) { if (!c) { throw Error("Pass the actual value for snapshot."); } const f = J(!0), g = /\.json$/.test(b); let h; try { if (h = await a.read(b), g) { const {deepEqual:l} = require("@zoroaster/assert"); l(c, h); } else { bb(c, h); } } catch (l) { if ("ENOENT" == l.code) { await nb(a, b, c, d); } else { var k; g || (k = Oa(h, c)); if (e && (g ? console.log(l.message) : console.log(k), await T(`Update snapshot${d ? ` for ${d}` : ""}?`))) { await V(a, b, c); return; } if (!g) { throw !e && console.log(k), a = f("The string didn't match the snapshot."), a.erte = k, a; } throw f(l); } } } class pb { constructor() { this.a = "test/snapshot"; } async prompt(a, b) { if ("string" == typeof a) { let c = a.split(/\r?\n/).reduce((d, e) => { if (e.length > d) { return e.length; } }, 0); process.stdout.isTTY && process.stdout.columns - 4 >= c ? console.log(mb(a)) : console.log(a); } else { console.log(gb(a, {colors:!0})); } return await T(`Save snapshot${b ? ` for ${b}` : ""}?`); } async read(a) { a = E(this.a, a); return /\.json$/.test(a) ? (a = await hb(a), JSON.parse(a)) : await hb(a); } } ;const W = async a => { try { return await Q(F, a); } catch (b) { return null; } }; async function qb(a, b) { b = b.map(async c => { const d = C(a, c); return {lstat:await Q(F, d), path:d, relativePath:c}; }); return await Promise.all(b); } const rb = a => a.lstat.isDirectory(), sb = a => !a.lstat.isDirectory(); async function tb(a) { if (!a) { throw Error("Please specify a path to the directory"); } const {ignore:b = []} = {}; if (!(await Q(F, a)).isDirectory()) { var c = Error("Path is not a directory"); c.code = "ENOTDIR"; throw c; } c = await Q(G, a); var d = await qb(a, c); c = d.filter(rb); d = d.filter(sb).reduce((e, f) => { var g = f.lstat.isDirectory() ? "Directory" : f.lstat.isFile() ? "File" : f.lstat.isSymbolicLink() ? "SymbolicLink" : void 0; return {...e, [f.relativePath]:{type:g}}; }, {}); c = await c.reduce(async(e, {path:f, relativePath:g}) => { const h = D(a, f); if (b.includes(h)) { return e; } e = await e; f = await tb(f); return {...e, [g]:f}; }, {}); return {content:{...d, ...c}, type:"Directory"}; } ;const ub = async a => { await Q(wa, a); }, vb = async a => { const {content:b} = await tb(a); var c = Object.keys(b).filter(e => { ({type:e} = b[e]); if ("File" == e || "SymbolicLink" == e) { return !0; } }), d = Object.keys(b).filter(e => { ({type:e} = b[e]); if ("Directory" == e) { return !0; } }); c = c.map(e => C(a, e)); await Promise.all(c.map(ub)); d = d.map(e => C(a, e)); await Promise.all(d.map(vb)); await Q(va, a); }, wb = async a => { (await Q(F, a)).isDirectory() ? await vb(a) : await ub(a); }; const xb = a => a.replace(/^!/, ""), yb = async(a, b, c, d = "", e = [], f = !1, g = "txt") => { var h = b.replace(/^!/, ""); const k = h.replace(/ /g, "-"); b = "string" == typeof a; const l = `${k}.${b ? g : "json"}`; let m = C(...c.map(xb)); (c = e.find(n => { n = C(...n.split("/")); return m.startsWith(n); })) && (m = m.slice(c.length)); e = C(d, m); d = C(e, l); if (a) { if (c = new pb, c.a = e, g = C(e, `${k}.${b ? "json" : g}`), await W(g)) { h = `Snapshot of another type exists: ${N(g, "red")}`, f || X(h), console.log("%s.\nNew data:", h), console.log(b ? a : gb(a, {colors:!0})), await T(`Update snapshot ${N(g, "yellow")} to a new type?`) || X(h), await V(c, l, a), await wb(g); } else { try { await ob(c, l, a, N(h, "yellow"), f); } catch (n) { "The string didn't match the snapshot." == n.message && (n.message = `The string didn't match the snapshot ${N(d, "yellow")}`), X(n); } } } else { a = await W(d), a || (d = d.replace(/json$/, g), a = await W(d)), a && X(`Snapshot ${d} exists, but the test did not return anything.`); } }, X = a => { a = Error(a); a.stack = a.message; throw a; }; const Y = require("../"); async function zb(a, b, {name:c, context:d, fn:e, timeout:f, persistentContext:g}, h = {}, k = null) { a && a({name:c, type:"test-start"}); let l, m, n; d = Array.isArray(d) ? d : [d]; d.forEach(r => { r.prototype instanceof Y && (l = r.snapshotExtension, n = r.serialise); }); d = (e.name ? d.slice(0, e.length) : d).map(r => { try { return r === Y || r.prototype instanceof Y ? {["snapshotExtension"](u) { l = u; }, ["snapshotSource"](u, v) { m = u; v && (l = v); }} : r; } catch (u) { return r; } }); let p, q; const t = r => { if (p) { return p.emit("error", r); } k = r; }; if (!k) { process.once("uncaughtException", t); process.once("unhandledRejection", t); try { q = await $a({context:d, persistentContext:g, fn:e, timeout:f, onCatchment(v) { p = v; }}); let {result:r, error:u} = q; k || (k = u); if (!k) { try { void 0 !== r && n && (r = n(r)), await yb(r, m || c, b, h.m, h.o, h.i, l); } catch (v) { k = v; } } if (h.i && u && u.handleUpdate) { try { await u.handleUpdate() && (k = null); } catch (v) { k = v; } } } finally { process.removeListener("uncaughtException", t), process.removeListener("unhandledRejection", t); } } a && a({name:c, error:k, type:"test-end", result:Ab({error:k, name:c})}); return q; } function Ab({error:a, name:b}) { return null === a ? `${Qa} ${b}` : `${Ra} ${b}` + w + P(Pa({error:a, name:b}), " | "); } async function Bb(a, b, {name:c, tests:d, persistentContext:e}, f, g, h) { a && a({type:"test-suite-start", name:c}); let k, l; if (e && !h) { try { k = await Cb(e), Db(d, k); } catch (m) { m.message = `Persistent context failed to evaluate: ${m.message}`, m.stack = m.stack.split("\n", 2).join("\n"), h = m; } } try { const m = [...b, c.replace(/\.jsx?$/, "")]; l = await Eb(a, m, d, f, g, h); a && a({type:"test-suite-end", name:c}); } finally { if (k) { try { await Fb(k); } catch (m) { m.stack = m.stack.split("\n", 2).join("\n"), console.log(N(m.stack, "red")); } } } return l; } const Db = (a, b) => { a.forEach(c => { c.persistentContext = b; }); }, Gb = async a => { const b = Ya(a); return await R(b, a.u || 5000, `Evaluate persistent context ${a.name ? a.name : ""}`); }, Cb = async a => { a = Array.isArray(a) ? a : [a]; return await Promise.all(a.map(b => Gb(b))); }, Hb = async a => { const b = S([a]); return await R(b, a.u || 5000, `Destroy persistent context ${a.name ? a.name : ""}`); }, Fb = async a => await Promise.all(a.map(b => Hb(b))); async function Eb(a, b, c, d, e, f) { return await ab(c, {onlyFocused:d, runTest(g) { return zb(a, b, g, e, f); }, runTestSuite(g, h) { return Bb(a, b, g, d ? h : !1, e, f); }}); } ;class Ib { constructor(a, b, c = 2000, d = []) { this.timeout = c; this.name = a; this.fn = b; this.context = d; this.error = this.persistentContext = null; } get isFocused() { return this.name.startsWith("!"); } } ;function Jb({v:a}) { return a instanceof Z; } const Kb = a => a.some(b => b.startsWith("!") || b.startsWith("$")), Lb = a => a.reduce((b, c) => c instanceof Z ? [...b, c.name, ...c.I] : [...b, c.name], []); function Mb(a, b) { if (Array.isArray(b) || "function" == (typeof b).toLowerCase()) { return a.a = b, !0; } if ("object" == (typeof b).toLowerCase()) { return a.a = Object.freeze({...a.a || {}, ...b}), !0; } } class Z { constructor(a, b, c, d, e) { if (!a) { throw Error("Test suite name must be given."); } this.J = a; this.K = c; this.u = e || (Jb(this) ? this.v.timeout : void 0); this.a = this.A = void 0; !Mb(this, d) && Jb(this) && (this.a = c.context); if ("object" != typeof b) { throw Error("You must provide tests in an object."); } this.B = !1; this.s = []; this.w = []; { const {context:f, persistentContext:g, ...h} = b; void 0 !== f && Mb(this, f); void 0 !== g && (a = g, Array.isArray(a) ? this.A = a : "function" == (typeof a).toLowerCase() && (this.A = a)); this.s = Nb(h, this); this.w = Lb(this.s); this.B = Kb(this.w); } } get name() { return this.J; } get v() { return this.K; } get tests() { return this.s; } get context() { return this.a; } get timeout() { return this.u; } get hasFocused() { return this.B; } get I() { return this.w; } get isFocused() { return this.name.startsWith("!") || this.name.startsWith("$"); } dump() { const a = this.name + w + this.tests.map(b => b.dump()).join("\n"); return this.v ? P(a, " ") : a; } get persistentContext() { return this.A; } } const Ob = ({name:a}, {name:b}) => "default" == a ? -1 : "default" == b ? 1 : 0; function Pb(a) { const b = [], c = []; a.forEach(d => { d instanceof Ib ? c.push(d) : b.push(d); }); a = b.sort(Ob); return [...c, ...a]; } function Nb(a, b) { const c = Object.keys(a).map(d => { const e = a[d]; if (e instanceof Z) { return e; } switch(typeof e) { case "function": return new Ib(d, e, b.timeout, b.context); case "object": return new Z(d, e, b); } }).filter(d => d); return Pb(c); } ;function Qb() { Object.keys(require.cache).forEach(a => { D("", a).startsWith("node_modules") || a == require.resolve("../") || delete require.cache[a]; }); } const Sb = async(a, b) => { a = await a.reduce(async(c, d) => { c = await c; const e = await Rb(d); return e ? {...c, [d]:e} : c; }, {}); return new Z("Zoroaster Root Test Suite", a, null, void 0, b); }; async function Tb(a) { return (await Q(G, a)).reduce(async(b, c) => { b = await b; const d = C(a, c), e = await Q(F, d); let f; if (e.isFile()) { var g = E(d); g = require(g); f = c.replace(/\.jsx?$/, ""); } else { e.isDirectory() && (g = await Tb(d), f = c); } return b[f] ? (console.warn("Merging %s with %s in %s", f, c, a), b[f] = Ub(b[f], g), b) : {...b, [f]:g}; }, {}); } const Ub = (a, b) => { Object.keys(b).forEach(c => { if (a[c]) { throw Error(`Duplicate key ${c}`); } }); return {...a, ...b}; }; async function Rb(a) { try { const b = await Q(F, a); if (b.isFile()) { const c = E(a); return require(c); } if (b.isDirectory()) { return await Tb(a); } } catch (b) { throw a = N("Could not require ", "red") + O(N(a, "white"), "red"), b.message += `${w}${a}`, b; } } ;function Vb(a, b) { a.forEach(c => { ya(c, (...d) => { b(c, ...d); }); }); } function Wb(a) { a.forEach(b => { xa(b); }); } async function Xb({paths:a, watch:b, timeout:c, m:d, o:e, i:f}, {D:g = [], H:h} = {}) { Wb(g); h && process.removeListener("beforeExit", h); g = await Sb(a, c); const k = Sa(); h = Ua(); const l = Ta(); k.pipe(l).pipe(process.stdout); k.pipe(h); ({j:h} = new K({rs:h})); var m = 0, n = 0; await Eb(q => { "object" == typeof q && (k.write(q), "test-end" == q.type && (m++, q.error && n++)); }, [], g.tests, g.hasFocused, {m:d, o:e, i:f}); k.end(); g = await h; process.stdout.write(w); process.stdout.write(g); process.stdout.write(`\ud83e\udd85 Executed ${m} test${1 == m ? "" : "s"}`); n && process.stdout.write(`: ${n} error${1 < n ? "s" : ""}`); process.stdout.write(`.${w}`); const p = () => { process.exit(n); }; process.once("beforeExit", p); if (b) { const q = Object.keys(require.cache).filter(t => !t.startsWith(`${process.cwd()}/node_modules/`)); Vb(q, async(t, r) => { const u = a.filter(v => E(v) != t || r.mtime.getTime() ? !0 : (console.warn("Test suite file %s was deleted.", N(v, "yellow")), !1)); Qb(); await Xb({paths:u, watch:b, timeout:c, m:d, o:e, i:f}, {D:q, H:p}); }); } } ;function Yb(a = {usage:{}}) { const {usage:b = {}, description:c, line:d, example:e} = a; a = Object.keys(b); const f = Object.values(b), [g] = a.reduce(([l = 0, m = 0], n) => { const p = b[n].split("\n").reduce((q, t) => t.length > q ? t.length : q, 0); p > m && (m = p); n.length > l && (l = n.length); return [l, m]; }, []), h = (l, m) => { m = " ".repeat(m - l.length); return `${l}${m}`; }; a = a.reduce((l, m, n) => { n = f[n].split("\n"); m = h(m, g); const [p, ...q] = n; m = `${m}\t${p}`; const t = h("", g); n = q.map(r => `${t}\t${r}`); return [...l, m, ...n]; }, []).map(l => `\t${l}`); const k = [c, ` ${d || ""}`].filter(l => l ? l.trim() : l).join("\n\n"); a = `${k ? `${k}\n` : ""} ${a.join("\n")} `; return e ? `${a} Example: ${e} ` : a; } ;if (pa) { console.log(require("../../package.json").version), process.exit(); } else { if (qa) { var Zb; { const a = fa(); Zb = Yb({usage:a, description:"A context-testing framework with support for mask and fork-testing.\nAutomatically transpiles import/export and JSX with \u00c0LaMode.\nhttps://www.contexttesting.com", line:"zoroaster path [pathN] [-w] [-a [-e env]] [-sr] [-vh]", example:"zoroaster test/spec test/mask -a"}); } console.log(Zb); process.exit(); } } if (oa) { try { require("@babel/register"); } catch (a) { const b = E(process.cwd(), "node_modules/@babel/register"); require(b); } } ia && (A && (process.env.ALAMODE_ENV = A), require("alamode")()); (async() => { try { await Xb({paths:[...ha || [], ...ra], watch:ja, timeout:ka, m:la, o:ma.split(","), i:na}); } catch (a) { console.log(x(a.stack)), process.exit(1); } })();