UNPKG

manten

Version:

満点 - Lightweight testing library for Node.js

13 lines (11 loc) 13.5 kB
"use strict";var le=Object.defineProperty;var o=(e,t)=>le(e,"name",{value:t,configurable:!0});var fe=require("node:events"),B=require("node:util"),N=require("node:path"),I=require("node:fs"),j=require("node:os"),de=require("expect");let b=!0;const S=typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{};let T=0;if(S.process&&S.process.env&&S.process.stdout){const{FORCE_COLOR:e,NODE_DISABLE_COLORS:t,NO_COLOR:s,TERM:n,COLORTERM:r}=S.process.env;t||s||e==="0"?b=!1:e==="1"||e==="2"||e==="3"?b=!0:n==="dumb"?b=!1:"CI"in S.process.env&&["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI","GITHUB_ACTIONS","BUILDKITE","DRONE"].some(c=>c in S.process.env)?b=!0:b=process.stdout.isTTY,b&&(process.platform==="win32"||r&&(r==="truecolor"||r==="24bit")?T=3:n&&(n.endsWith("-256color")||n.endsWith("256"))?T=2:T=1)}let z={enabled:b,supportLevel:T};function $(e,t,s=1){const n=`\x1B[${e}m`,r=`\x1B[${t}m`,c=new RegExp(`\\x1b\\[${t}m`,"g");return u=>z.enabled&&z.supportLevel>=s?n+(""+u).replace(c,n)+r:""+u}o($,"kolorist");const g=$(2,22),P=$(31,39),J=$(32,39),V=$(33,39),Y=o(e=>Number.isFinite(e)?e:0,"toZeroIfInfinity");function he(e){return{days:Math.trunc(e/864e5),hours:Math.trunc(e/36e5%24),minutes:Math.trunc(e/6e4%60),seconds:Math.trunc(e/1e3%60),milliseconds:Math.trunc(e%1e3),microseconds:Math.trunc(Y(e*1e3)%1e3),nanoseconds:Math.trunc(Y(e*1e6)%1e3)}}o(he,"parseNumber");function me(e){return{days:e/86400000n,hours:e/3600000n%24n,minutes:e/60000n%60n,seconds:e/1000n%60n,milliseconds:e%1000n,microseconds:0n,nanoseconds:0n}}o(me,"parseBigint");function pe(e){switch(typeof e){case"number":{if(Number.isFinite(e))return he(e);break}case"bigint":return me(e)}throw new TypeError("Expected a finite number or bigint")}o(pe,"parseMilliseconds");const ge=o(e=>e===0||e===0n,"isZero"),ye=o((e,t)=>t===1||t===1n?e:`${e}s`,"pluralize"),be=1e-7,we=24n*60n*60n*1000n;function F(e,t){const s=typeof e=="bigint";if(!s&&!Number.isFinite(e))throw new TypeError("Expected a finite number or bigint");t={...t};const n=e<0?"-":"";e=e<0?-e:e,t.colonNotation&&(t.compact=!1,t.formatSubMilliseconds=!1,t.separateMilliseconds=!1,t.verbose=!1),t.compact&&(t.unitCount=1,t.secondsDecimalDigits=0,t.millisecondsDecimalDigits=0);let r=[];const c=o((f,d)=>{const p=Math.floor(f*10**d+be);return(Math.round(p)/10**d).toFixed(d)},"floorDecimals"),u=o((f,d,p,h)=>{if(!((r.length===0||!t.colonNotation)&&ge(f)&&!(t.colonNotation&&p==="m"))){if(h??=String(f),t.colonNotation){const w=h.includes(".")?h.split(".")[0].length:h.length,v=r.length>0?2:1;h="0".repeat(Math.max(0,v-w))+h}else h+=t.verbose?" "+ye(d,f):p;r.push(h)}},"add"),a=pe(e),i=BigInt(a.days);if(t.hideYearAndDays?u(BigInt(i)*24n+BigInt(a.hours),"hour","h"):(t.hideYear?u(i,"day","d"):(u(i/365n,"year","y"),u(i%365n,"day","d")),u(Number(a.hours),"hour","h")),u(Number(a.minutes),"minute","m"),!t.hideSeconds)if(t.separateMilliseconds||t.formatSubMilliseconds||!t.colonNotation&&e<1e3&&!t.subSecondsAsDecimals){const f=Number(a.seconds),d=Number(a.milliseconds),p=Number(a.microseconds),h=Number(a.nanoseconds);if(u(f,"second","s"),t.formatSubMilliseconds)u(d,"millisecond","ms"),u(p,"microsecond","\xB5s"),u(h,"nanosecond","ns");else{const w=d+p/1e3+h/1e6,v=typeof t.millisecondsDecimalDigits=="number"?t.millisecondsDecimalDigits:0,ue=w>=1?Math.round(w):Math.ceil(w),q=v?w.toFixed(v):ue;u(Number.parseFloat(q),"millisecond","ms",q)}}else{const f=(s?Number(e%we):e)/1e3%60,d=typeof t.secondsDecimalDigits=="number"?t.secondsDecimalDigits:1,p=c(f,d),h=t.keepDecimalsOnWholeSeconds?p:p.replace(/\.0+$/,"");u(Number.parseFloat(h),"second","s",h)}if(r.length===0)return n+"0"+(t.verbose?" milliseconds":"ms");const l=t.colonNotation?":":" ";return typeof t.unitCount=="number"&&(r=r.slice(0,Math.max(t.unitCount,1))),n+r.join(l)}o(F,"prettyMilliseconds");const y=` `,Se=" ",{log:A,error:k}=console,Te=J("\u2714"),ve=P("\u2716"),$e=V("\u2022"),ke=g("\u25CB"),R=o(()=>{const e=new Date,t=String(e.getHours()).padStart(2,"0"),s=String(e.getMinutes()).padStart(2,"0"),n=String(e.getSeconds()).padStart(2,"0");return g(`${t}:${s}:${n}`)},"formatTimestamp"),U=o(({startTime:e,timeout:t,endTime:s})=>{const n=(s||Date.now())-e;let r=F(n);return t&&(r+=` / ${F(t)}`),n<50?"":` ${g(`(${r})`)}`},"prettyDuration"),Ee=o(e=>e.replaceAll(/^/gm,Se),"indentMultiline"),M=o((e,t=!0)=>{const{title:s,attempt:n,retry:r}=e;let c=`${s+U(e)}`;return t&&r>1&&(c+=g(` (${n}/${r})`)),c},"getTestTitle"),O=o((e,t,s)=>{let n=`${R()} ${ve} ${M(e)}`;s&&(n+=` [${s}]`),k(n),k(`${Ee(B.inspect(t))} `)},"logTestFail"),Le=o(e=>{A(`${R()} ${Te} ${M(e)}`)},"logTestSuccess"),W=o(e=>{A(`${R()} ${ke} ${M(e,!1)}`)},"logTestSkip"),De=o(e=>{if(e.length===0)return;const t=[];let s=0,n=0,r=0,c,u;for(const i of e)i.startTime&&(!c||c>i.startTime)&&(c=i.startTime),i.endTime===void 0?t.push(i):((!u||u<i.endTime)&&(u=i.endTime),i.error?n+=1:i.skip?r+=1:s+=1);let a="";if(t.length>0){for(const i of t)a+=`${y}${$e} ${i.title+U(i)}`;a+=y}a+=`${y}${g(F((u??Date.now())-c))}`,a+=y+(s>0?J:g)(`${s.toLocaleString()} passed`),n>0&&(a+=y+P(`${n.toLocaleString()} failed`)),r>0&&(a+=y+g(`${r.toLocaleString()} skipped`)),t.length>0&&(a+=y+V(`${t.length.toLocaleString()} pending`)),a+=y,A(a)},"logReport"),Ne=o(()=>{let e,t;const s=new Promise((n,r)=>{e=n,t=r});return Object.assign(s,{resolve:e,reject:t})},"createDeferred"),Ie=o((e,t)=>{const s=Ne(),n=setTimeout(()=>{const r=new Error(`Timeout: ${e}ms`);t?.abort(r),s.reject(r)},e);return Object.assign(s,{timeoutId:n})},"setTimer"),G=o((e,t,s)=>{if(!e||!("then"in e)||t===void 0||t===0)return e;const n=Ie(t,s);return Promise.race([e,n]).finally(()=>{clearTimeout(n.timeoutId)})},"timeLimitFunction"),K=o(e=>{const t=[];return{addHook:o(r=>{t.push(r)},"addHook"),runHooks:o(async(...r)=>{for(const c of t)try{await c(...r)}catch(u){await e(u)}},"runHooks")}},"createHook"),Pe=o(async(e,t)=>{for(let s=1;s<=t;s+=1)try{await e(s);return}catch(n){if(s===t)throw n}},"retry"),Fe=o(e=>{const t=Object.keys(e).sort(),s={};for(const n of t)s[n]=e[n];return JSON.stringify(s,null,2)},"stableJsonStringify"),Ae=o(e=>{const t=[];return e.new>0&&t.push(`\u{1F4F8} ${e.new} new`),e.updated>0&&t.push(`\u270F\uFE0F ${e.updated} updated`),t.length>0?` Snapshots: ${t.join(", ")}`:""},"formatSnapshotSummary"),Re=o(e=>B.inspect(e,{depth:null,sorted:!0,breakLength:80,maxArrayLength:1/0,maxStringLength:1/0}),"serialize");let m;const E=new Set,L=new Set,C=new Map;let Z=!1,_=process.env.MANTEN_SNAPSHOT_PATH||".manten.snap";const Me=process.env.MANTEN_UPDATE_SNAPSHOTS==="1"||process.env.MANTEN_UPDATE_SNAPSHOTS==="true",Oe=o(()=>{if(m===void 0)try{const e=N.resolve(_),t=I.readFileSync(e,"utf8");m=JSON.parse(t)}catch{m={}}},"loadSnapshots"),_e=o((e,t)=>{m===void 0&&Oe();const s=C.get(e);if(s!==void 0&&s!==t)throw new Error(`Duplicate test title detected: "${e}". Test titles must be unique across all files when using global snapshots.`);C.set(e,t);let n=0;return{expectSnapshot:o((u,a)=>{let i;a?i=a:(n+=1,i=`${e} ${n}`);const l=Re(u);if(E.has(i)||L.has(i)){const d=m[i];if(l===d)return;throw new Error(`Duplicate snapshot key: "${i}". Test names must be unique across all test files.`)}if(!Object.hasOwn(m,i)){m[i]=l,E.add(i);return}const f=m[i];if(l!==f)if(Me)m[i]=l,L.add(i);else throw new Error(`Snapshot mismatch for "${i}" Expected: ${f} Received: ${l}`)},"expectSnapshot"),reset:o(()=>{n=0},"reset")}},"createSnapshotContext"),xe=o(()=>{if(E.size===0&&L.size===0||!m)return;const e=N.resolve(_),t=N.dirname(e);Z||(I.mkdirSync(t,{recursive:!0}),Z=!0);const s=Fe(m);I.writeFileSync(e,s,"utf8")},"saveSnapshots"),He=o(()=>({new:E.size,updated:L.size}),"getSnapshotSummary"),qe=o(e=>{if(e.snapshotPath!==void 0&&m!==void 0)throw new Error("configure() must be called before any snapshot tests are run. Snapshots have already been loaded from the default location. Please ensure configure() is called at the beginning of your test suite.");e.snapshotPath!==void 0&&(_=e.snapshotPath)},"configure");class Q extends Error{static{o(this,"SkipError")}constructor(t){super(t||"Test skipped"),this.name="SkipError"}}const X=o(e=>(e&&typeof e=="object"&&"matcherResult"in e&&e.constructor.name==="JestAssertionError"&&delete e.matcherResult,e),"patchJestAssertionError"),ee=o(async(e,t)=>{const{testFunction:s,timeout:n}=e,r=K(i=>{O(e,i,"onTestFail")}),c=o(async i=>{await r.runHooks(i)},"handleError"),u=K(async i=>{O(e,X(i),"onTestFinish")}),a=_e(e.title,e);try{await Pe(async i=>{e.attempt=i,e.startTime=Date.now(),i>1&&a.reset();const l=new AbortController;let f;t&&(f=o(()=>{l.signal.aborted||l.abort(t.abortController.signal.reason)},"handleParentAbort"),t.abortController.signal.addEventListener("abort",f),t.abortController.signal.aborted&&f());try{await G(s({signal:l.signal,onTestFail:r.addHook,onTestFinish:u.addHook,skip:o(d=>{throw new Q(d)},"skip"),expectSnapshot:a.expectSnapshot}),n,l),Le(e)}catch(d){if(d instanceof Q)e.skip=!0,W(e);else throw O(e,X(d)),await c(d),d}finally{t&&f&&t.abortController.signal.removeEventListener("abort",f),l.signal.aborted||l.abort(),await u.runHooks(),e.endTime=Date.now()}},e.retry)}catch(i){e.error=i,process.exitCode=1}},"runTest"),te=[];process.on("exit",()=>{try{xe()}catch(t){process.stderr.write(`Failed to save snapshots: ${t} `)}De(te);const e=He();if(e.new>0||e.updated>0){const t=Ae(e);process.stdout.write(`${t} `)}});const D=process.env.TESTONLY;D&&console.log(g(`Only running tests that match: ${JSON.stringify(D)} `));const se=o((e,t)=>((s,n,r)=>{if(e&&(s=`${e} ${s}`),t&&(t.testsStarted=!0),D&&!s.includes(D))return Promise.resolve();const c={title:s,testFunction:n,retry:1};if(r!==void 0&&(typeof r=="number"?c.timeout=r:(c.timeout=r?.timeout,r?.retry&&(c.retry=r?.retry))),te.push(c),t?.skipped){c.skip=!0,c.skipReason=t.skipReason;const u=Date.now();return c.startTime=u,c.endTime=u,W(c),Promise.resolve()}return(async()=>{const a=o(async()=>{if(t?.concurrencyLimiter){const i=await t.concurrencyLimiter.acquire();try{await ee(c,t)}finally{i()}}else await ee(c,t)},"executeTest")();t&&t.pendingTests.push(a),await a})()}),"createTest"),Be=o(async e=>{for(;e.length>0;){const t=e.splice(0);await Promise.all(t)}},"waitAllPromises"),je=o(e=>("default"in e&&(e=e.default),"default"in e&&(e=e.default),e),"unwrapModule"),x=o(e=>{let t=typeof e=="number"?e:ne(),s=0;const n=[];let r;return e==="auto"&&(r=setInterval(()=>{const i=ne();if(i!==t)for(t=i;n.length>0&&s<t;){const l=n.shift();l&&(s+=1,l())}},5e3),r.unref()),{acquire:o(()=>s<t?(s+=1,Promise.resolve(()=>{s-=1;const i=n.shift();i&&(s+=1,i())})):new Promise(i=>{n.push(()=>{i(()=>{s-=1;const l=n.shift();l&&(s+=1,l())})})}),"acquire"),setLimit:o(i=>{for(t=i;n.length>0&&s<t;){const l=n.shift();l&&(s+=1,l())}},"setLimit"),cleanup:o(()=>{r&&clearInterval(r)},"cleanup")}},"createSemaphore"),ne=o(()=>{const e=j.cpus().length,t=j.loadavg()[0];return Math.max(1,Math.min(Math.floor(e*(1-Math.min(t/e,.8))),e))},"calculateAutoLimit"),re=o((e,t)=>((s,n,r)=>(e&&(s=`${e} ${s}`),t&&(t.testsStarted=!0),(async()=>{const c=H(s,r?.parallel,r?.timeout);await o(async()=>{if(t?.concurrencyLimiter){const a=await t.concurrencyLimiter.acquire();try{await c.run(n,t)}finally{a()}}else await c.run(n,t)},"executeDescribe")()})())),"createDescribe"),oe=o((e,t)=>((s,...n)=>{t&&(t.testsStarted=!0);const r=o(()=>{const c=H(e);return c.run(async()=>je(await s).apply(c,n),t)},"executeTestSuite");return t?.concurrencyLimiter?t.concurrencyLimiter.acquire().then(c=>r().finally(c)):r()}),"createRunTestSuite"),ie=se(),ce=re(),ae=oe(),H=o((e,t,s)=>{let n;t!==void 0&&(t===!0?n=void 0:t===!1?n=x(1):typeof t=="number"?n=x(t):t==="auto"&&(n=x("auto")));const r=new AbortController;fe.setMaxListeners(0,r.signal);const c={pendingTests:[],callbacks:{onFinish:[]},concurrencyLimiter:n,abortController:r,timeout:s,skipped:!1,skipReason:void 0,testsStarted:!1,run:o(async(u,a)=>{a?.skipped&&(c.skipped=!0,c.skipReason=a.skipReason);let i;a&&(i=o(()=>{r.signal.aborted||r.abort(a.abortController.signal.reason)},"handleParentAbort"),a.abortController.signal.addEventListener("abort",i),a.abortController.signal.aborted&&i());try{const l=(async()=>{await u(c.api),await Be(c.pendingTests)})();a&&a.pendingTests.push(l),await G(l,s,r)}catch(l){k(l),process.exitCode=1}finally{a&&i&&a.abortController.signal.removeEventListener("abort",i),r.signal.aborted||r.abort(),n&&n.cleanup();for(const l of c.callbacks.onFinish)try{await l()}catch(f){k(f),process.exitCode=1}}},"run")};return c.api={signal:r.signal,test:e?se(`${e} \u203A`,c):ie,describe:e?re(`${e} \u203A`,c):ce,runTestSuite:e?oe(e,c):ae,onFinish:o(u=>{c.callbacks.onFinish.push(u)},"onFinish"),skip:o(u=>{if(c.testsStarted)throw new Error("skip() must be called before any tests or nested describes run. Move skip() to the beginning of the describe callback.");c.skipped=!0,c.skipReason=u},"skip")},c},"createContext"),ze=H(),Je=o((e,t,s)=>{const n=typeof e=="string"?e:void 0,r=typeof e=="string"?t:e,c=typeof e=="string"?s:void 0;return o(async function(...a){const i=this||ze;n?await i.api.describe(n,l=>r(l,...a),c):await r(i.api,...a)},"testSuiteWrapper")},"testSuite"),Ve=o(e=>{setTimeout(()=>{process.exitCode=1,console.error(P(`\u2716 Process timed out after ${e}ms`)),setImmediate(()=>process.exit(1))},e).unref()},"setProcessTimeout");Object.defineProperty(exports,"expect",{enumerable:!0,get:o(function(){return de.expect},"get")}),exports.configure=qe,exports.describe=ce,exports.runTestSuite=ae,exports.setProcessTimeout=Ve,exports.test=ie,exports.testSuite=Je;