{"version":3,"file":"mod.mjs","sources":["../src/mod.ts","../src/channel/dom.ts","../../lib/src/state.ts"],"sourcesContent":["import {RunEvent} from '../../lib/src/events';\nimport {create} from './channel/dom'; // TODO allow any implementation given by s\n\nconst path = decodeURIComponent(\n\tdocument.location.pathname.split('/').pop() ?? '',\n);\n// TODO receive this to long-polling or websocket and drop one-way DOM channel\n// implementation\nconst title = decodeURIComponent(document.location.hash.slice(1));\n\nexport type Test = () => Promise<void>;\n\nconst _tests = new Map<string, Test>();\n\nconst channel = create();\n\nconst init = async () => {\n\treturn channel.emit('init');\n};\n\nconst emit = async (event: RunEvent) => {\n\treturn channel.emit('event', event);\n};\n\nconst flush = async () => {\n\treturn channel.emit('flush');\n};\n\nconst run = async (title: string) => {\n\tconsole.error(`Running test ${title}`);\n\tconst testFn = _tests.get(title);\n\tif (testFn === undefined) {\n\t\tthrow new Error(`could not find title ${title}`);\n\t} else {\n\t\tawait emit({type: 'test-queue', path, title});\n\t\tawait flush();\n\t\tawait testFn().then(\n\t\t\tasync () => {\n\t\t\t\tawait emit({type: 'test-pass', path, title});\n\t\t\t\treturn flush();\n\t\t\t},\n\t\t\tasync (error: Error) => {\n\t\t\t\tconst {message, stack} = error;\n\t\t\t\tconsole.error(`Test ${title} failed with error`, {error});\n\t\t\t\tawait emit({type: 'test-fail', path, title, error: {message, stack}});\n\t\t\t\treturn flush();\n\t\t\t},\n\t\t);\n\t}\n};\n\nconst autorun = async () => {\n\tawait init();\n\tawait flush();\n\tfor (const title of _tests.keys()) {\n\t\t// TODO declare tests as we read them\n\t\t// eslint-disable-next-line no-await-in-loop\n\t\tawait emit({type: 'test-declare', path, title});\n\t}\n\n\tawait emit({type: 'parsed', path});\n\tawait flush();\n\tif (title !== '') {\n\t\trun(title).catch(async (error: Error) => {\n\t\t\tconst {message, stack} = error;\n\t\t\tawait emit({type: 'error', path, error: {message, stack}});\n\t\t\tawait flush();\n\t\t\tconsole.error(error);\n\t\t});\n\t}\n};\n\nlet to: any;\n\nconst setupAutorun = () => {\n\tto = setTimeout(autorun, 0);\n};\n\nconst cancelAutorun = () => {\n\tclearTimeout(to);\n};\n\nsetupAutorun();\n\nconst test = (title: string, testFn: Test) => {\n\tif (_tests.has(title)) {\n\t\tcancelAutorun();\n\t\tconst error = new Error(`duplicate title ${title}`);\n\t\tconst {message, stack} = error;\n\t\temit({type: 'error', path, error: {message, stack}})\n\t\t\t.then(flush)\n\t\t\t.catch((error: Error) => {\n\t\t\t\tconsole.error('uncaught error', error);\n\t\t\t});\n\t\treturn;\n\t}\n\n\t_tests.set(title, testFn);\n};\n\nexport default test;\n","import Emittery from 'emittery';\nimport {RunEvent, RunEventWithDateTime} from '../../../lib/src/events';\nimport {State, create as createState} from '../../../lib/src/state';\n\nexport const create = (): Emittery => {\n\tconst emitter = new Emittery();\n\n\tconst state = createState();\n\tlet events: RunEventWithDateTime[] = [];\n\n\tconst render = async () => {\n\t\treturn state.emit('dump', (state: State) => {\n\t\t\tconst done = state.pass + state.fail;\n\t\t\tconst _state = document.querySelector('#state');\n\t\t\tif (_state === null) {\n\t\t\t\tthrow new Error('could not find #state element');\n\t\t\t}\n\n\t\t\t_state.textContent = JSON.stringify(\n\t\t\t\t{\n\t\t\t\t\tdeclared: state.declared,\n\t\t\t\t\tqueued: state.queued,\n\t\t\t\t\tdone,\n\t\t\t\t\tpass: state.pass,\n\t\t\t\t\tfail: state.fail,\n\t\t\t\t\terror: state.error,\n\t\t\t\t\thistory: state.history,\n\t\t\t\t},\n\t\t\t\tundefined,\n\t\t\t\t2,\n\t\t\t);\n\t\t\tconst _events = document.querySelector('#events');\n\t\t\tif (_events === null) {\n\t\t\t\tthrow new Error('could not find #events element');\n\t\t\t}\n\n\t\t\t_events.textContent = JSON.stringify(events, undefined, 2);\n\t\t});\n\t};\n\n\temitter.on('init', async () => {\n\t\tevents = [];\n\t\treturn state.emit('init');\n\t});\n\n\temitter.on('flush', render);\n\n\temitter.on('event', async (event: RunEvent) => {\n\t\tevents.push({...event, datetime: new Date()});\n\t\treturn state.emit('event', event);\n\t});\n\n\treturn emitter;\n};\n","import Emittery from 'emittery';\n\nimport {RunEvent, ErrorDescription, TestHistory} from './events';\n\nexport type State = {\n\tparsed: boolean;\n\tdeclared: number;\n\tqueued: number;\n\tpass: number;\n\tfail: number;\n\terror: ErrorDescription | undefined;\n\thistory: Record<string, TestHistory>;\n};\n\nconst initHistory = () => {\n\treturn {\n\t\tqueued: false,\n\t\tdone: false,\n\t\tpass: false,\n\t\tfail: false,\n\t\trunning: false,\n\t\terrors: [],\n\t};\n};\n\nconst init = (): State => {\n\treturn {\n\t\tparsed: false,\n\t\tdeclared: 0,\n\t\tqueued: 0,\n\t\tpass: 0,\n\t\tfail: 0,\n\t\terror: undefined,\n\t\thistory: {},\n\t};\n};\n\nexport const create = (): Emittery => {\n\tconst emitter = new Emittery();\n\n\tlet state = init();\n\n\temitter.on('init', () => {\n\t\tstate = init();\n\t});\n\n\temitter.on('event', (event: RunEvent) => {\n\t\t// eslint-disable-next-line default-case\n\t\tswitch (event.type) {\n\t\t\tcase 'error':\n\t\t\t\tstate.error = event.error;\n\t\t\t\tbreak;\n\t\t\tcase 'test-declare':\n\t\t\t\t++state.declared;\n\t\t\t\tstate.history[event.title] = initHistory();\n\t\t\t\tbreak;\n\t\t\tcase 'test-queue':\n\t\t\t\tstate.history[event.title].queued = true;\n\t\t\t\t++state.queued;\n\t\t\t\tbreak;\n\t\t\tcase 'test-start':\n\t\t\t\tstate.history[event.title].queued = false;\n\t\t\t\tstate.history[event.title].running = true;\n\t\t\t\tbreak;\n\t\t\tcase 'test-pass':\n\t\t\t\tstate.history[event.title].running = false;\n\t\t\t\tstate.history[event.title].pass = true;\n\t\t\t\tstate.history[event.title].done = true;\n\t\t\t\t++state.pass;\n\t\t\t\tbreak;\n\t\t\tcase 'test-fail':\n\t\t\t\tstate.history[event.title].running = false;\n\t\t\t\tstate.history[event.title].fail = true;\n\t\t\t\tstate.history[event.title].done = true;\n\t\t\t\tstate.history[event.title].errors.push(event.error);\n\t\t\t\t++state.fail;\n\t\t\t\tbreak;\n\t\t\tcase 'parsed':\n\t\t\t\tstate.parsed = true;\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\temitter.on('dump', (cb: (state: State) => void) => {\n\t\tcb(state);\n\t});\n\n\treturn emitter;\n};\n"],"names":["decodeURIComponent","document","location","pathname","split","pop","_document$location$pa","title","hash","slice","_tests","Map","channel","emitter","Emittery","state","parsed","declared","queued","pass","fail","error","undefined","history","on","event","type","done","running","errors","push","cb","createState","events","async","emit","_state","querySelector","Error","textContent","JSON","stringify","_events","_extends","datetime","Date","create","to","setTimeout","init","flush","keys","path","console","testFn","get","then","message","stack","run","catch","test","has","clearTimeout","set"],"mappings":"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"}