1+ /*global globalThis*/
2+
3+ const queue = [ ] ;
4+ let stack = [ ] ;
5+ let index = 0 ;
6+ // let currentName;
7+ // let prefix = '';
8+
9+ async function process ( ) {
10+ const id = index ++ ;
11+ if ( id === queue . length ) {
12+ queue . length = index = 0 ;
13+ return ;
14+ }
15+ const [ op , name , fn , extra ] = queue [ id ] ;
16+ queue [ id ] = undefined ;
17+ await processors [ op ] ( name , fn , extra ) ;
18+ await process ( ) ;
19+ }
20+
21+ const processors = {
22+ async describe ( name , fn , path ) {
23+ // stack.push(Array.from({ length: stack.length + 1 }).join(' ') + name);
24+ stack . push ( name ) ;
25+ // log('INFO', Array.from(path).fill(' ').join('') + name);
26+ log ( 'INFO' , name ) ;
27+ await fn ( ) ;
28+ stack . pop ( ) ;
29+ } ,
30+ async test ( name , fn , path ) {
31+ let stackBefore = stack ;
32+ stack = path . concat ( name ) ;
33+ logBuffer = [ ] ;
34+ await new Promise ( resolve => {
35+ let calls = 0 ;
36+ const done = ( ) => {
37+ if ( calls ++ ) throw Error ( `Callback called multiple times\n\t${ name } ` ) ;
38+ log ( 'INFO' , `✅ ${ name } ` ) ;
39+ resolve ( ) ;
40+ } ;
41+ Promise . resolve ( done )
42+ . then ( fn )
43+ . then ( ( ) => calls || done ( ) )
44+ . catch ( err => {
45+ // setTimeout(process);
46+ // throw new Error(`\t${err.stack || err.message}`);
47+ log ( 'ERROR' , `🚨 ${ name } ` ) ;
48+ log ( 'ERROR' , '\t' + String ( err . stack || err . message || err ) ) ;
49+ // setTimeout(process);
50+ resolve ( ) ;
51+ } ) ;
52+ } ) ;
53+ for ( let i = 0 ; i < logBuffer . length ; i ++ ) log ( ...logBuffer [ i ] ) ;
54+ logBuffer = undefined ;
55+ stack = stackBefore ;
56+ // process();
57+ }
58+ } ;
59+
60+
61+ let logBuffer ;
62+
63+ function wrap ( obj , method ) {
64+ obj [ method ] = function ( ) {
65+ let out = ' ' ;
66+ for ( let i = 0 ; i < arguments . length ; i ++ ) {
67+ let val = arguments [ i ] ;
68+ if ( typeof val === 'object' && val ) {
69+ val = JSON . stringify ( val ) ;
70+ }
71+ if ( out ) out += ' ' ;
72+ out += val ;
73+ }
74+ if ( method !== 'error' ) out = `\u001b[37m${ out } \u001b[0m` ;
75+ if ( logBuffer ) {
76+ logBuffer . push ( [ method . toUpperCase ( ) , out ] ) ;
77+ }
78+ else {
79+ log ( method . toUpperCase ( ) , out ) ;
80+ }
81+ } ;
82+ }
83+ wrap ( console , 'log' ) ;
84+ wrap ( console , 'info' ) ;
85+ wrap ( console , 'warn' ) ;
86+ wrap ( console , 'error' ) ;
87+
88+ function log ( type , msg ) {
89+ if ( type === 'ERROR' ) {
90+ msg = `\u001b[31m${ msg } \u001b[39m` ;
91+ }
92+ if ( type === 'SUCCESS' ) {
93+ msg = `\u001b[32m${ msg } \u001b[39m` ;
94+ }
95+ print ( Array . from ( { length : stack . length } ) . fill ( ' ' ) . join ( '' ) + msg ) ;
96+ }
97+
98+ function push ( op , name , fn , extra ) {
99+ if ( queue . push ( [ op , name , fn , extra ] ) === 1 ) {
100+ setTimeout ( process ) ;
101+ }
102+ }
103+
104+ globalThis . describe = ( name , fn ) => {
105+ push ( 'describe' , name , fn , stack . slice ( ) ) ;
106+ } ;
107+
108+ globalThis . test = ( name , fn ) => {
109+ push ( 'test' , name , fn , stack . slice ( ) ) ;
110+ } ;
111+
112+ globalThis . expect = ( subject ) => new Expect ( subject ) ;
113+
114+ const SUBJECT = Symbol . for ( 'subject' ) ;
115+ const NEGATED = Symbol . for ( 'negated' ) ;
116+ class Expect {
117+ constructor ( subject ) {
118+ this [ SUBJECT ] = subject ;
119+ }
120+ get not ( ) {
121+ this [ NEGATED ] = true ;
122+ return this ;
123+ }
124+ toBeGreaterThan ( value ) {
125+ const subject = this [ SUBJECT ] ;
126+ const negated = this [ NEGATED ] ;
127+
128+ const isOver = subject > value ;
129+ let msg = `Expected ${ subject } ${ negated ?' not' :'' } to be greater than ${ value } ` ;
130+ if ( logBuffer ) {
131+ for ( let i = logBuffer . length ; i -- > - 1 ; ) {
132+ if ( i < 0 || logBuffer [ i ] [ 2 ] === 1 ) {
133+ logBuffer . splice ( i + 1 , 0 , [ isOver !== negated ? 'SUCCESS' : 'ERROR' , ' ' + msg , 1 ] ) ;
134+ break ;
135+ }
136+ }
137+ }
138+ else {
139+ log ( isOver !== negated ? 'SUCCESS' : 'ERROR' , ' ' + msg ) ;
140+ }
141+ }
142+ }
0 commit comments