UNPKG

@moyal/js-test

Version:

A lightweight, dependency-free JavaScript testing utility. This project is framework-agnostic and usable in both browser and Node.js environments.

7 lines (6 loc) 13.7 kB
/*! * @moyal/js-test v2.1.7 * (c) 2000–present Ilan Moyal * Released under the MIT License */ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).MoyalTest={})}(this,(function(e){"use strict";let t,r,s;class n{static#e=null;static __setup(e,n,i){t=e,r=n,s=i}static getDefaultLogger(){if(null===this.#e)try{"undefined"!=typeof window&&void 0!==window.document||"function"==typeof importScripts&&"undefined"!=typeof self?this.#e=new r:"undefined"!=typeof process&&process.versions?.node?this.#e=new s:this.#e=new t}catch{this.#e=new t}return this.#e}static isLogger(e){return e instanceof n&&Object.getPrototypeOf(e.constructor)===n}#t=new Set(["black","red","green","yellow","blue","magenta","cyan","white","gray","lightred","lightgreen","lightyellow","lightblue","lightmagenta","lightcyan","lightgray"]);isSupportedColor(e){return this.#t.has(e)}normalizeColor(e){return"string"==typeof e?e.toLowerCase():""}log(e,t,...r){}info(e,t,...r){}warn(e,t,...r){}error(e,t,...r){}group(e,t){}groupCollapsed(e,t){}groupEnd(){}}class i{static#r;static{this.#r="undefined"!=typeof performance&&"function"==typeof performance.now?()=>performance.now():()=>Date.now()}static now(){return this.#r()}static isString(e){return"string"==typeof e||"[object String]"===Object.prototype.toString.call(e)}static isIterable(e){return i.isFunctionOrGeneratorFunction(e?.[Symbol.iterator])}static isFunction(e){let t=typeof e;return("object"===t||"function"===t)&&"[object Function]"===Object.prototype.toString.call(e)}static isFunctionOrGeneratorFunction(e){const t=typeof e;if("function"!==t&&"object"!==t)return!1;const r=Object.prototype.toString.call(e);return"[object Function]"===r||"[object GeneratorFunction]"===r}}class o{static*#s(e,t){for(;;)yield e.replace("{0}",t++)}#n=null;#i=null;#o=null;constructor(e,t){if(null!=t&&(!Number.isInteger(t)||t<1))throw new Error("startValue must be a positive integer");this.#n=e??"{0}",this.#i=t??1}reset(){this.#o=o.#s(this.#n,this.#i)}next(){return null==this.#o&&this.reset(),this.#o.next().value}close(){this.#o?.return&&this.#o.return(),this.#o=null}*[Symbol.iterator](){let e=o.#s(this.#n,this.#i);for(let t of e)yield t}}class l extends o{constructor(e=1,t="{0}. "){if(t??="{0}. ",!i.isString(t)||t.indexOf("{0}")<0)throw new Error("Automatic numbering format must include {0}");super(t,e??1)}next(e){return super.next()+(e??"")}}class u{#l="";#u=[];#i=1;constructor(e){this.#i=e??1,this.reset()}reset(){this.#l="",this.#u.length=0,this.#u.push(new l(this.#i,null))}get level(){return this.#u.length}next(e){return this.#l=this.#u[this.#u.length-1].next(),this.#l+(e??"")}nest(e){let t=this.#l.trim();return t+="{0}. ",this.#u.push(new l(e??1,t)),this}unnest(){return this.#u.length>1&&this.#u.pop(),this}}class a{_result=null;_additionalData=null;constructor(e,t){this._result=e,this._additionalData=t}}class c{#a=null;#c=!0;#h=null;#d=null;#g=null;#_=[];#p=0;static#f=null;static __setup(e){this.#f=e}constructor(e,t,r,s){if(!i.isString(e))throw new Error("testName must be string");if(null!=t&&!i.isString(t))throw new Error("successMessage must be string, null or undefined");if(null!=r&&!i.isString(r))throw new Error("failureMessage must be string, null or undefined");this.#a=e,this.#h=t??"success",this.#d=r??"failure",this.#g=s}get name(){return this.#a}get successMessage(){return this.#h}get failureMessage(){return this.#d}get elapsed(){return this.#p}set elapsed(e){this.#p=e}get succeeded(){return this.#c}set succeeded(e){this.#c=!0===e}get failed(){return!0!==this.succeeded}get errors(){return this.#_}get errorCount(){return this.errors.length}get additionalData(){return this.#g}set additionalData(e){this.#g=e}get logger(){return c.#f.logger}run(e,t){return this.runImpl(),(!0===e||!1!==e&&!this.succeeded)&&this.write(t),this.succeeded}runImpl(){throw new Error("Method 'runImpl()' must be implemented by subclass")}_push_error(e){this.#_.push(e)}write(e){null!=e&&e instanceof u||(e=null);const t=this.name?.trim()||"(unnamed test)";let r=`${e?.next()??""}${t}: ${this.succeeded?this.successMessage:this.failureMessage} (${this.elapsed} ms`,s=this.succeeded?"green":"red";if(0===this.errorCount)r+=")";else{let e=(this.succeeded?"":"un")+"expected "+(this.errorCount>1?"errors":"error");r+=`, ${this.errorCount} ${e})`}if(0!=this.errorCount||null!=this.additionalData){if(this.logger.groupCollapsed(r,s),this.errorCount>0){null!=this.additionalData&&this.logger.groupCollapsed("errors");for(let e of this.errors)this.succeeded?this.logger.error(e,"black"):this.logger.error(e);null!=this.additionalData&&this.logger.groupEnd()}null!=this.additionalData&&(this.errorCount>0&&this.logger.groupCollapsed("additional data"),this.logger.log(JSON.stringify(this.additionalData)),this.errorCount>0&&this.logger.groupEnd()),this.logger.groupEnd()}else this.logger.log(r,s)}}class h extends c{#f=null;#w=null;constructor(e,t,r,s,n,i){super(e,r,s,n),this.#f=t,this.#w=i??globalThis}runImpl(){if(!0===this.#f)this.succeeded=!0;else if(i.isFunction(this.#f)){let e;const t=i.now();try{let t=this.#f.call(this.#w);t instanceof a?(this.additionalData=t._additionalData,e=!0===t._result):e=t}catch(t){this._push_error(t),e=!1}const r=i.now();this.elapsed=r-t,this.succeeded=e}else this.succeeded=!1;return this.succeeded}}class d extends h{#m=null;#w=null;#x=!0;constructor(e,t,r,s,n){if(super(e,r,(t=!0===t)?"An error was thrown (as expected)!":"An error was NOT thrown (as expected).",t?"Expected an error, but none was thrown or it did not satisfy the predicate.":"An error was not thrown (unexpectedly).",n),!i.isFunction(r))throw new Error("fn parameter must be a function");if(t&&null!=s&&!i.isFunction(s))throw new Error("checkErrorFn parameter must be a function, null or undefined");this.#x=t,this.#w=n,this.#m=s}runImpl(){super.runImpl();super.succeeded||1!==this.errors.length?this.succeeded=!this.#x:this.succeeded=this.#x&&(null==this.#m||!0===this.#m.call(this.#w,this.errors[0]))}}class g extends h{constructor(e,t,r,s,n){let o,l=null;i.isFunction(t)||i.isFunction(r)||i.isFunction(s)?o=()=>{let e=i.isFunction(t)?t.call(n??globalThis):t,o=i.isFunction(r)?r.call(n??globalThis):r;return new a(i.isFunction(s)?s.call(n??globalThis,e,o):e===o,{expected:e,actual:o})}:(o=t===r,l={expected:t,actual:r}),super(e,o,"Expected and actual values matched","Expected and actual values did not match",l,n)}}class _ extends h{constructor(e,t,r,s,n){let o,l=null;i.isFunction(t)||i.isFunction(r)||i.isFunction(s)?o=()=>{let e=i.isFunction(t)?t.call(n??globalThis):t,o=i.isFunction(r)?r.call(n??globalThis):r;return new a(i.isFunction(s)?!s.call(n??globalThis,e,o):e!==o,{not_expected:e,actual:o})}:(o=t!==r,l={not_expected:t,actual:r}),super(e,o,"Actual value did not match the disallowed value (as expected!)","Actual value matched the disallowed value (not as expected!)",l,n)}}class p extends _{constructor(e,t,r){super(e,void 0,t,null,r)}}class f extends g{constructor(e,t,r){super(e,!1,t,null,r)}}class w extends _{constructor(e,t,r){super(e,null,t,null,r)}}class m extends g{constructor(e,t,r){super(e,null,t,null,r)}}class x extends g{constructor(e,t,r){super(e,!0,t,null,r)}}class C extends g{constructor(e,t,r){super(e,void 0,t,null,r)}}class F extends d{constructor(e,t,r){super(e,!1,t,null,r)}}class b extends c{#x=null;#C=null;#F=null;#b=!0;#w=null;constructor(e,t,r,s,n){super(e,"Actual sequence equals to the expected sequence","Actual sequence does not equal to the expected sequence)",null,n),this.additionalData={},this.#x=t,this.#C=r,this.#F=s,this.#w=n,i.isIterable(t)||(this.additionalData.expected="ERROR: 'expected' argument is not iterable!",this.#b=!1),i.isIterable(r)||(this.additionalData.actual="ERROR: 'actual' argument is not iterable!",this.#b=!1)}runImpl(){if(this.#b){const t=i.now();let r,s=this.additionalData.expected=Array.from(this.#x),n=this.additionalData.actual=Array.from(this.#C);if(s.length===n.length){let t=[];for(var e=0;e<s.length;e++){!0!==(null!=this.#F?this.#F.call(this.#w??void 0,s[e],n[e]):s[e]===n[e])&&t.push(e)}t.length>0&&(this.additionalData["Mismatch at indices"]="Different element indices are: {"+t.join(", ")+"}"),r=0===t.length}else this.additionalData["Mismatch at indices"]="expected.length !== actual.length",r=!1;const o=i.now();this.elapsed=o-t,this.succeeded=r}else this.succeeded=!1}}class y extends d{constructor(e,t,r,s){super(e,!0,t,r,s)}}class E extends c{#y=[];#E=0;#v=0;#D=0;#$=0;#A=null;#T=null;constructor(e,...t){super(e),this.add(...t)}clear(){this.#y.length=0,this.#E=0,this.#v=0,this.#D=0,this.#$=0}get errorCount(){return this.#D}run(e,t){return this.#T=e,super.run(e,t)}runImpl(){this.#E=0,this.#D=0,this.#$=0;const e=i.now();for(let e of this.#y)e.runImpl(),e instanceof E?(this.#v+=e.totalFailureCount,this.#$+=e.unexpectedErrorCount):(this.#E+=e.succeeded?0:1,this.#$+=e.succeeded?0:e.errorCount,this.#v+=e.succeeded?0:1),this.#D+=e.errorCount;const t=i.now();return this.elapsed=t-e,0===this.#E}write(e,t){null!=e&&e instanceof u||(e=null);const r=null==t?this.#T:t;let s,n=`${e?.next()??""}${this.name}: (${this.elapsed}ms, `;if(this.succeeded?(s="green",n+="all passed"):(s="red",n+=`${0==this.#E?"no":this.#E.toString()} direct failure${1===this.#E?"":"s"}, ${this.#v} total failure${1===this.#v?"":"s"}`),this.#$>0&&(n+=`, ${this.#$} unexpected error${this.#$>1?"s":""}`),n+=")",this.succeeded?this.logger.groupCollapsed(n,s):this.logger.group(n,s),this.#y?.length>0){e?.nest();for(let t of this.#y)(!0===r||null==r&&!t.succeeded)&&t.write(e,this.#T);e?.unnest()}this.logger.groupEnd()}get unexpectedErrorCount(){return this.#$}get directFailureCount(){return this.#E}get totalFailureCount(){return this.#v}get succeeded(){return 0===this.#v}add(...e){this.#y.push(...e);for(let t of e)t instanceof E&&(t.#A=this)}groupStart(e){let t=new E(e);return this.add(t),t}groupClose(){return this.#A??this}areEqual(e,t,r,s,n){return this.add(new g(e,t,r,s,n)),this}areNotEqual(e,t,r,s,n){return this.add(new _(e,t,r,s,n)),this}isTrue(e,t,r=null){return this.add(new x(e,t,r)),this}isFalse(e,t,r){return this.add(new f(e,t,r)),this}isNull(e,t,r){return this.add(new m(e,t,r)),this}isNotNull(e,t,r=null){return this.add(new w(e,t,r)),this}isDefined(e,t,r=null){return this.add(new p(e,t,r)),this}isUndefined(e,t,r=null){return this.add(new C(e,t,r)),this}throws(e,t,r,s=null){return this.add(new y(e,t,r,s)),this}noThrows(e,t,r=null){return this.add(new F(e,t,r)),this}sequencesAreEqual(e,t,r,s){return this.add(new b(e,t,r,s)),this}}class v extends n{#S=0;#I="";#L(){this.#S++,this.#I=" ".repeat(this.#S)}#M(){this.#S--,this.#S<0&&(this.#S=0),this.#I=" ".repeat(this.#S)}prefixMessage(e){return this.#I+e}colorfy(e,t,r){return e}log(e,t,...r){return e??="",console.log(this.colorfy(this.prefixMessage(e),t,"white"),...r),this}info(e,t,...r){return e??="",console.info(this.colorfy(this.prefixMessage(e),t,"cyan"),...r),this}warn(e,t,...r){return e??="",console.warn(this.colorfy(this.prefixMessage(e),t,"yellow"),...r),this}error(e,t,...r){return e??="",console.error(this.colorfy(this.prefixMessage(e),t,"red"),...r),this}#N(e,t){e??="",console.log(this.colorfy(this.prefixMessage(`▼ ${e}`),t,"gray")),this.#L()}group(e,t){return this.#N(e,t),this}groupCollapsed(e,t){return this.#N(e,t),this}groupEnd(){return this.#M(),this}}class D extends n{#q(e){return e=this.normalizeColor(e),this.isSupportedColor(e)?e:void 0}log(e,t,...r){return e??="",console.log(`%c${e}`,`color:${this.#q(t)??"inherit"}`,...r),this}info(e,t,...r){return e??="",console.info(`%c${e}`,`color:${this.#q(t)??"blue"}`,...r),this}warn(e,t,...r){return e??="",console.warn(`%c${e}`,`color:${this.#q(t)??"orange"}`,...r),this}error(e,t,...r){return e??="",console.error(`%c${e}`,`color:${this.#q(t)??"red"}`,...r),this}group(e,t){return console.group(`%c${e}`,`color:${this.#q(t)??"inherit"}`),this}groupCollapsed(e,t){return console.groupCollapsed(`%c${e}`,`color:${this.#q(t)??"inherit"}`),this}groupEnd(){return console.groupEnd(),this}}class $ extends v{#j(e,t){return({black:"",red:"",green:"",yellow:"",blue:"",magenta:"",cyan:"",white:"",gray:"",lightred:"",lightgreen:"",lightyellow:"",lightblue:"",lightmagenta:"",lightcyan:"",lightgray:""}[e=this.normalizeColor(e)]??"")+t+""}colorfy(e,t,r){return this.#j(t?.toLowerCase()??r,e)}}n.__setup(v,D,$);class A{static version="2.1.7"}class T{static#z=null;static get Version(){return A.version}static get logger(){return null==this.#z&&(this.#z=n.getDefaultLogger()),this.#z}static set logger(e){null==e?this.#z=n.getDefaultLogger():n.isLogger(e)&&(this.#z=e)}static areEqual(e,t,r,s,n){return new g(e,t,r,s).run(n)}static areNotEqual(e,t,r,s,n){return new _(e,t,r,s).run(n)}static isTrue(e,t,r){return new x(e,t).run(r)}static isFalse(e,t,r){return new f(e,t).run(r)}static isNull(e,t,r){return new m(e,t).run(r)}static isNotNull(e,t,r){return new w(e,t).run(r)}static isDefined(e,t,r){return new p(e,t).run(r)}static isUndefined(e,t,r){return new C(e,t).run(r)}static throws(e,t,r,s,n){return new y(e,t,r,s).run(n)}static noThrows(e,t,r,s){return new F(e,t,r).run(s)}static sequencesAreEqual(e,t,r,s,n){return new b(e,t,r,s).run(n)}}c.__setup(T),e.AreEqual=g,e.AreNotEqual=_,e.Assert=h,e.AutoNumbering=l,e.BrowserLogger=D,e.IsDefined=p,e.IsFalse=f,e.IsNotNull=w,e.IsNull=m,e.IsTrue=x,e.IsUndefined=C,e.LoggerBase=n,e.MultiLevelAutoNumbering=u,e.NoThrows=F,e.NodeLogger=$,e.SequencesAreEqual=b,e.SequentialText=o,e.SimpleLogger=v,e.Test=T,e.TestBase=c,e.TestGroup=E,e.Throws=y,e.ThrowsBase=d}));