@fatso83/mini-mocha
Advanced tools
Comparing version 2.2.0 to 2.2.1
141
index.js
@@ -1,94 +0,51 @@ | ||
const { assertFunction, assertTitle } = require("./lib/util"); | ||
const { Processor, TASK_TYPE, TASK_ADDED_EVENT_NAME } = require("./lib/processor"); | ||
const { META_DATA } = require("./lib/executor"); | ||
const { assertNumber } = require("./lib/util"); | ||
const { Processor } = require("./lib/processor"); | ||
const { DefaultReporter, RunKitReporter } = require("./lib/reporters"); | ||
const functions = require("./lib/functions"); | ||
/** | ||
* Purpose of using the "caller" is to | ||
* keep the each "it"s and "eachHooks" inside the function. | ||
* I set the metaData attribute in the caller function. | ||
* (check the "describe" function) | ||
* | ||
* TODO: | ||
* Since "caller" attribute is none standard approach, | ||
* Lets try to replace this with better approach | ||
*/ | ||
function after(fn) { | ||
assertFunction(fn); | ||
after.caller[META_DATA].afterHook = fn; | ||
} | ||
function afterEach(fn) { | ||
assertFunction(fn); | ||
afterEach.caller[META_DATA].afterEachHookCollection.push(fn); | ||
} | ||
function before(fn) { | ||
assertFunction(fn); | ||
before.caller[META_DATA].beforeHook = fn; | ||
} | ||
function beforeEach(fn) { | ||
assertFunction(fn); | ||
beforeEach.caller[META_DATA].beforeEachHookCollection.push(fn); | ||
} | ||
function describe(title, fn) { | ||
assertTitle(title); | ||
assertFunction(fn); | ||
fn[META_DATA] = { | ||
title, | ||
afterHook: null, | ||
afterEachHookCollection: [], | ||
beforeHook: null, | ||
beforeEachHookCollection: [], | ||
fns: [], | ||
itCollection: [] | ||
}; | ||
if (describe.caller && describe.caller[META_DATA]) { | ||
describe.caller[META_DATA].fns.push(fn); | ||
} else { | ||
this.processor.queue.push({ | ||
type: TASK_TYPE.describe, | ||
fn | ||
}); | ||
this.processor.emit(TASK_ADDED_EVENT_NAME); | ||
const testingHookInterfaces = { | ||
bdd: { | ||
pre: "before", | ||
preEach: "beforeEach", | ||
post: "after", | ||
postEach: "afterEach" | ||
}, | ||
tdd: { | ||
pre: "setup", | ||
preEach: "suiteSetup", | ||
pre: "teardown", | ||
preEach: "suiteTeardown" | ||
} | ||
} | ||
}; | ||
function it(title, fn) { | ||
assertTitle(title); | ||
assertFunction(fn); | ||
// BDD | ||
const { post: after, postEach: afterEach, pre: before, preEach: beforeEach } = functions; | ||
// TDD | ||
const { post: teardown, postEach: suiteTeardown, pre: setup, preEach: suiteSetup } = functions; | ||
const caller = it.caller ? it.caller[META_DATA] : undefined; | ||
if (!caller) { | ||
this.processor.queue.push({ | ||
type: TASK_TYPE.it, | ||
title, | ||
fn | ||
}); | ||
module.exports = { | ||
install: function install(isRunKit = false, timeOut = 500) { | ||
if (timeOut !== undefined) { | ||
assertNumber(timeOut); | ||
} | ||
this.processor.emit(TASK_ADDED_EVENT_NAME); | ||
} else { | ||
caller.itCollection.push({ | ||
title, | ||
fn | ||
}); | ||
} | ||
} | ||
module.exports = { | ||
install: function install(isRunKit = false) { | ||
const reporter = isRunKit ? RunKitReporter : DefaultReporter; | ||
const processor = Processor.getProcessor(reporter); | ||
global.describe = describe.bind({ | ||
processor | ||
}); | ||
global.it = it.bind({ | ||
processor | ||
}); | ||
const params = { | ||
processor, | ||
timeOut | ||
}; | ||
// BDD | ||
const bddParams = { | ||
testingHookInterfaces: testingHookInterfaces.bdd, | ||
...params | ||
}; | ||
const describe = functions.testBlock.bind(bddParams); | ||
const it = functions.testCase.bind(bddParams); | ||
global.context = describe; | ||
global.describe = describe; | ||
global.it = it; | ||
global.specify = it; | ||
global.after = after; | ||
@@ -98,3 +55,17 @@ global.afterEach = afterEach; | ||
global.beforeEach = beforeEach; | ||
// TDD | ||
const tddParams = { | ||
testingHookInterfaces: testingHookInterfaces.tdd, | ||
...params | ||
}; | ||
const suite = functions.testBlock.bind(tddParams); | ||
const test = functions.testCase.bind(tddParams); | ||
global.suite = suite; | ||
global.test = test; | ||
global.teardown = teardown; | ||
global.suiteTeardown = suiteTeardown; | ||
global.setup = setup; | ||
global.suiteSetup = suiteSetup; | ||
} | ||
}; |
@@ -5,11 +5,16 @@ const { isAsync, isCallbackFunction, getPromisify, getErrorMessage } = require("./util"); | ||
class Executor { | ||
constructor(reporter) { | ||
passes = 0; | ||
failures = 0; | ||
constructor(reporter, timeOut, testingHookInterfaces) { | ||
this.reporter = reporter; | ||
this.timeOut = timeOut; | ||
this.testingHookInterfaces = testingHookInterfaces; | ||
} | ||
static getExecutor(reporter) { | ||
return new Executor(reporter); | ||
static getExecutor(reporter, timeOut, testingHookInterfaces) { | ||
return new Executor(reporter, timeOut, testingHookInterfaces); | ||
} | ||
async describe(fn) { | ||
async testBlock(fn) { | ||
await this.run(fn); | ||
@@ -22,39 +27,41 @@ | ||
// Before | ||
if (metaDataSection.beforeHook) { | ||
await this.hook("before", metaDataSection.beforeHook); | ||
if (metaDataSection.preHook) { | ||
await this.hook(this.testingHookInterfaces.pre, metaDataSection.preHook); | ||
} | ||
// It blocks | ||
for (const singleIt of metaDataSection.itCollection) { | ||
for (const singleTestCase of metaDataSection.testCaseCollection) { | ||
// BeforeEach | ||
for (const be of metaDataSection.beforeEachHookCollection) { | ||
await this.hook("beforeEach", be); | ||
for (const be of metaDataSection.preEachHookCollection) { | ||
await this.hook(this.testingHookInterfaces.preEach, be); | ||
} | ||
// It | ||
await this.it(singleIt.title, singleIt.fn); | ||
await this.testCase(singleTestCase.title, singleTestCase.fn); | ||
// AfterEach | ||
for (const ae of metaDataSection.afterEachHookCollection) { | ||
await this.hook("afterEach", ae); | ||
for (const ae of metaDataSection.postEachHookCollection) { | ||
await this.hook(this.testingHookInterfaces.postEach, ae); | ||
} | ||
} | ||
// describe | ||
// testBlock | ||
if (metaDataSection.fns.length) { | ||
for (const otherDescribe of metaDataSection.fns) { | ||
await this.describe(otherDescribe); | ||
await this.testBlock(otherDescribe); | ||
} | ||
} | ||
if (metaDataSection.afterHook) { | ||
await this.hook("after", metaDataSection.afterHook); | ||
if (metaDataSection.postHook) { | ||
await this.hook(this.testingHookInterfaces.post, metaDataSection.postHook); | ||
} | ||
} | ||
async it(title, fn) { | ||
async testCase(title, fn) { | ||
try { | ||
await this.run(fn); | ||
this.passes++; | ||
this.reporter.log(title); | ||
} catch (err) { | ||
this.failures++; | ||
this.reporter.log(title, getErrorMessage(err)); | ||
@@ -65,2 +72,15 @@ } | ||
async run(fn) { | ||
return Promise.race([this.runFn(fn), this.timeOutTrigger(this.timeOut)]); | ||
} | ||
timeOutTrigger(value) { | ||
return new Promise((resolve, reject) => { | ||
setTimeout(() => reject(new Error(`Error: Timeout of ${value}ms exceeded`)), value); | ||
}); | ||
} | ||
// issue #22: lack of `this` | ||
// TODO: to enable use of of Mocha API utils such as `this.timeout()`, etc. | ||
// we would need to create a new context for `fn` here, a la fn.call(Object.create(null)) | ||
async runFn(fn) { | ||
if (isCallbackFunction(fn)) { | ||
@@ -67,0 +87,0 @@ await getPromisify(fn)(); |
@@ -0,1 +1,2 @@ | ||
const debug = require("debug")("processor"); | ||
const { EventEmitter } = require("events"); | ||
@@ -7,7 +8,10 @@ | ||
const TASK_TYPE = { | ||
describe: "describe", | ||
it: "it" | ||
testBlock: "testBlock", | ||
testCase: "testCase" | ||
}; | ||
class Processor extends EventEmitter { | ||
totalFailures = 0; | ||
totalPasses = 0; | ||
constructor(reporterClass) { | ||
@@ -29,20 +33,35 @@ super(); | ||
if (this.queue.length) { | ||
debug(`Processing queue (${this.queue.length} elements remaining)`); | ||
if (!this.isProcessing) { | ||
this.isProcessing = true; | ||
this.task(); | ||
this.pickNextTaskForProcessing(); | ||
} | ||
} else { | ||
debug("No more tasks in processor queue"); | ||
debug(`${this.totalFailures} failures out of ${this.totalFailures + this.totalPasses} testcases`); | ||
// needs to be checked at this point, not at start, as test scripts can alter the value after startup | ||
const testMode = !!process.env["MINI_MOCHA_IGNORE_FAILURE"]; | ||
if (!testMode && this.totalFailures > 0) { | ||
debug("Exiting with non-zero value. Not test mode"); | ||
process.exit(1); | ||
} | ||
} | ||
} | ||
async task() { | ||
async pickNextTaskForProcessing() { | ||
const task = this.queue.shift(); | ||
const { fn, type, title } = task; | ||
const { fn, type, title, timeOut, testingHookInterfaces } = task; | ||
const reporter = this.reporterClass.getReporter(); | ||
const executor = Executor.getExecutor(reporter); | ||
const executor = Executor.getExecutor(reporter, timeOut, testingHookInterfaces); | ||
try { | ||
type === TASK_TYPE.it ? await executor.it(title, fn) : await executor.describe(fn); | ||
type === TASK_TYPE.testCase ? await executor.testCase(title, fn) : await executor.testBlock(fn); | ||
this.totalPasses += executor.passes; | ||
this.totalFailures += executor.failures; | ||
this.isProcessing = false; | ||
reporter.flush(); | ||
// restarts the loop (tail recursion) | ||
this.process(); | ||
@@ -49,0 +68,0 @@ } catch (error) { |
@@ -16,2 +16,7 @@ const assert = require("assert"); | ||
function assertNumber(number) { | ||
assert(typeof number === "number", "given value is not a number"); | ||
assert(number >= 0, "given value is not a positive number"); | ||
} | ||
function isCallbackFunction(fn) { | ||
@@ -39,3 +44,4 @@ return fn && fn.length === 1; | ||
getPromisify, | ||
getErrorMessage | ||
getErrorMessage, | ||
assertNumber | ||
}; |
{ | ||
"name": "@fatso83/mini-mocha", | ||
"version": "2.2.0", | ||
"version": "2.2.1", | ||
"description": "A minimal emulation of Mocha", | ||
@@ -16,3 +16,4 @@ "main": "index.js", | ||
"test:tarball": "./scripts/test-tarball.sh", | ||
"update-snapshots": "rimraf test/snapshot/* && npm t", | ||
"test:exit-status": "./integration-test/test.sh", | ||
"update-snapshots": "rimraf test/snapshot/tdd/* && rimraf test/snapshot/bdd/* && npm t", | ||
"clean": "rimraf package *.tgz" | ||
@@ -35,3 +36,4 @@ }, | ||
"dependencies": { | ||
"@runkit/value-viewer": "1.0.0" | ||
"@runkit/value-viewer": "1.0.0", | ||
"debug": "^4.3.3" | ||
}, | ||
@@ -38,0 +40,0 @@ "devDependencies": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
15932
10
396
0
2
1
+ Addeddebug@^4.3.3
+ Addeddebug@4.4.0(transitive)
+ Addedms@2.1.3(transitive)