New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

micro-should

Package Overview
Dependencies
Maintainers
0
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

micro-should - npm Package Compare versions

Comparing version 0.5.0 to 0.5.1

8

index.d.ts

@@ -6,2 +6,3 @@ /*! micro-should - MIT License (c) 2019 Paul Miller (paulmillr.com) */

*/
/** A single test. */
export interface StackItem {

@@ -22,4 +23,5 @@ message: string;

PRINT_MULTILINE: boolean;
STOP_AT_ERROR: boolean;
MSHOULD_QUIET: boolean;
STOP_ON_ERROR: boolean;
QUIET: boolean;
FAST: number;
}

@@ -74,3 +76,3 @@ export interface DescribeFunction {

declare const it: TestFunction;
export { it, describe, beforeEach, afterEach, it as should };
export { afterEach, beforeEach, describe, it, it as should };
export default it;

@@ -9,13 +9,26 @@ /*! micro-should - MIT License (c) 2019 Paul Miller (paulmillr.com) */

let onlyStack;
let running = false;
let isRunning = false;
const isCli = 'process' in globalThis;
// Dumb bundlers parse code and assume we have hard dependency on "process". We don't.
// The trick (also import(mod) below) ensures parsers can't see it.
// @ts-ignore
const proc = isCli ? globalThis['process'] : undefined;
const opts = {
PRINT_TREE: true,
PRINT_MULTILINE: true,
STOP_AT_ERROR: true,
MSHOULD_QUIET: isCli && process.env.MSHOULD_QUIET,
STOP_ON_ERROR: true,
QUIET: isCli && ['1', 'true'].includes(proc.env.MSHOULD_QUIET),
FAST: parseFast(proc.env.MSHOULD_FAST),
};
function isQuiet() {
return opts.MSHOULD_QUIET;
function parseFast(str) {
if (!isCli)
return 0;
let val = str === 'true' ? 1 : Number.parseInt(str, 10);
if (!Number.isSafeInteger(val) || val < 1 || val > 256)
return 0;
return val;
}
function imp(moduleName) {
return import(moduleName);
}
// String formatting utils

@@ -48,3 +61,3 @@ const _c = String.fromCharCode(27); // x1b, control code for terminal colors

function log(...args) {
if (isQuiet())
if (opts.QUIET)
return logQuiet(false);

@@ -56,6 +69,6 @@ // @ts-ignore

if (fail) {
process.stderr.write(color('red', '!'));
proc.stderr.write(color('red', '!'));
}
else {
process.stdout.write('.');
proc.stdout.write('.');
}

@@ -66,3 +79,3 @@ }

// @ts-ignore
if (!isQuiet())
if (!opts.QUIET)
console.error(error); // loud = show error now. quiet = show in the end

@@ -78,6 +91,2 @@ }

}
function tdiff(start) {
const sec = Math.round((Date.now() - start) / 1000);
return sec < 60 ? `${sec} sec` : `${Math.floor(sec / 60)} min ${sec % 60} sec`;
}
async function runTest(info, printTree = false, multiLine = false, stopAtError = true) {

@@ -90,3 +99,3 @@ if (!printTree && multiLine)

let messages = [];
let onlyLogsToPrint = [];
let onlyStackToLog = [];
let beforeEachFns = [];

@@ -97,3 +106,3 @@ let afterEachFns = []; // will be reversed

if (printTree && info.only)
onlyLogsToPrint.push(`${parent.prefix}${parent.message}`);
onlyStackToLog.push(`${parent.prefix}${parent.message}`);
if (parent.beforeEach)

@@ -105,12 +114,11 @@ beforeEachFns.push(parent.beforeEach);

afterEachFns.reverse();
if (onlyLogsToPrint.length)
onlyLogsToPrint.forEach((l) => log(l));
const path = `${messages.join('/')}/`;
const full = path + title;
if (onlyStackToLog.length)
onlyStackToLog.forEach((l) => log(l));
const path = messages.slice().concat(title).join('/');
// Skip is always single-line
if (multiLine && !info.skip) {
log(printTree ? `${info.prefix}${title}: ☆` : `☆ ${full}:`);
if (multiLine && !info.skip && !opts.QUIET) {
log(printTree ? `${info.prefix}${title}: ☆` : `☆ ${path}:`);
}
else if (info.skip) {
log(printTree ? `${info.prefix}${title} (skip)` : `☆ ${full} (skip)`);
log(printTree ? `${info.prefix}${title} (skip)` : `☆ ${path} (skip)`);
return true;

@@ -123,14 +131,14 @@ }

// stopAtError = true | false
function logTaskDone(fail = false, suffix = '') {
function formatTaskDone(fail = false, suffix = '') {
const symbol = fail ? '☓' : '✓';
const clr = fail ? 'red' : 'green';
const title_ = suffix ? [title, suffix].join('/') : title;
const full_ = suffix ? [full, suffix].join('/') : full;
log(printTree
const full_ = suffix ? [path, suffix].join('/') : path;
return printTree
? `${info.childPrefix}` + color(clr, `${title_}: ${symbol}`)
: color(clr, `${symbol} ${full_}`));
: color(clr, `${symbol} ${full_}`);
}
// Emit
function logErrorStack(suffix) {
if (isQuiet()) {
if (opts.QUIET) {
// when quiet, either stop & log trace; or log !

@@ -140,3 +148,3 @@ if (stopAtError) {

console.error();
console.error(color('red', `☓ ${full}/${suffix}`));
console.error(formatTaskDone(true, suffix));
}

@@ -150,3 +158,3 @@ else {

// when loud, log (maybe formatted) tree structure
logTaskDone(true, suffix);
console.error(formatTaskDone(true, suffix));
}

@@ -165,3 +173,3 @@ }

else
addToErrorLog(`${full}/beforeEach`, cause);
addToErrorLog(`${path}/beforeEach`, cause);
return false;

@@ -181,3 +189,3 @@ }

else
addToErrorLog(`${full}`, cause);
addToErrorLog(`${path}`, cause);
return false;

@@ -196,7 +204,7 @@ }

else
addToErrorLog(`${full}/afterEach`, cause);
addToErrorLog(`${path}/afterEach`, cause);
return false;
}
}
logTaskDone();
log(formatTaskDone());
return true;

@@ -263,3 +271,3 @@ }

function begin(total, workers) {
const features = [isQuiet() ? '+quiet' : '', workers ? `+fast-x${workers}` : ''].filter((a) => a);
const features = [opts.QUIET ? '+quiet' : '', workers ? `+fast-x${workers}` : ''].filter((a) => a);
const modes = features.length ? `(${features.join(' ')}) ` : '';

@@ -271,23 +279,27 @@ // No need to log stats when tests fit on one screen

function finalize(total, startTime) {
isRunning = false;
console.log();
if (isQuiet())
if (opts.QUIET)
console.log();
const totalFailed = errorLog.length;
const sec = Math.round((Date.now() - startTime) / 1000);
const tdiff = sec < 2 ? '' : sec < 60 ? `in ${sec} sec` : `in ${Math.floor(sec / 60)} min ${sec % 60} sec`;
if (totalFailed) {
console.error();
console.error(`${color('red', totalFailed)} tests failed`);
if (isQuiet()) {
if (opts.QUIET) {
errorLog.forEach((err) => console.error(err));
}
if (errorLog.length > 0)
throw new Error(`${errorLog.length} of ${total} tests failed ${tdiff}`);
}
else {
console.log(`${color('green', total)} tests passed in ${tdiff(startTime)}`);
console.log(`${color('green', total)} tests passed ${tdiff}`);
}
return total;
}
async function runTests(forceSequential = false) {
if (running)
if (isRunning)
throw new Error('should.run() has already been called, wait for end');
if (!forceSequential && isCli && !!process?.env?.MSHOULD_FAST)
if (!forceSequential && opts.FAST)
return runTestsInParallel();
running = true;
isRunning = true;
const tasks = cloneAndReset();

@@ -302,7 +314,5 @@ const total = tasks.filter((i) => !!i.test).length;

continue;
await runTest(test, opts.PRINT_TREE, opts.PRINT_MULTILINE, opts.STOP_AT_ERROR);
await runTest(test, opts.PRINT_TREE, opts.PRINT_MULTILINE, opts.STOP_ON_ERROR);
}
finalize(total, startTime);
running = false;
return total;
return finalize(total, startTime);
}

@@ -313,4 +323,4 @@ async function runTestsWhen(importMetaUrl) {

// @ts-ignore
const url = await import('node:url');
return importMetaUrl === url.pathToFileURL(process.argv[1]).href ? runTests() : undefined;
const { pathToFileURL } = await imp('node:url');
return importMetaUrl === pathToFileURL(proc.argv[1]).href ? runTests() : undefined;
}

@@ -322,3 +332,3 @@ // Doesn't support tree and multiline

throw new Error('must run in cli');
if ('deno' in process.versions)
if ('deno' in proc.versions)
return runTests(true);

@@ -328,13 +338,11 @@ const tasks = cloneAndReset().filter((i) => !!i.test); // Filter describe elements

const startTime = Date.now();
const runTestPar = (info) => runTest(info, false, false, opts.STOP_AT_ERROR);
const runTestPar = (info) => runTest(info, false, false, opts.STOP_ON_ERROR);
let cluster, err;
let totalW = Number.parseInt(process.env.MSHOULD_FAST, 10);
if (totalW === 1)
totalW = 0;
let totalW = opts.FAST;
try {
// @ts-ignore
cluster = (await import('node:cluster')).default;
cluster = (await imp('node:cluster')).default;
// @ts-ignore
if (!totalW)
totalW = (await import('node:os')).cpus().length;
if (totalW === 1)
totalW = (await imp('node:os')).cpus().length;
}

@@ -344,7 +352,7 @@ catch (error) {

}
if (!cluster || !totalW)
if (!cluster || !parseFast(totalW))
throw new Error('parallel tests are not supported: ' + err);
// the code is ran in workers
if (!cluster.isPrimary) {
process.on('error', (err) => console.log('internal error:', 'child crashed?', err));
proc.on('error', (err) => console.log('internal error:', 'child crashed?', err));
let tasksDone = 0;

@@ -359,6 +367,6 @@ const id = cluster.worker.id;

}
process.send({ name: 'parallelTests', worker: strId, tasksDone, errorLog });
process.exit();
proc.send({ name: 'parallelTests', worker: strId, tasksDone, errorLog });
proc.exit();
}
// the code is ran in primary process
// the code is ran in primary proc
return await new Promise((resolve, reject) => {

@@ -389,11 +397,10 @@ begin(total, totalW);

msg.errorLog.forEach((item) => errorLog.push(item));
if (workersDone === totalW) {
if (tasksDone === total) {
finalize(total, startTime);
resolve(tasksDone);
}
else {
reject(new Error('internal error: not all tasks have been completed'));
}
}
if (workersDone !== totalW)
return;
if (tasksDone !== total)
return reject(new Error('internal error: not all tasks have been completed'));
// @ts-ignore
globalThis.setTimeout(() => {
resolve(finalize(total, startTime));
}, 0);
});

@@ -417,3 +424,3 @@ }

it.opts = opts;
export { it, describe, beforeEach, afterEach, it as should };
export { afterEach, beforeEach, describe, it, it as should };
export default it;

@@ -7,2 +7,3 @@ /*! micro-should - MIT License (c) 2019 Paul Miller (paulmillr.com) */

/** A single test. */
export interface StackItem {

@@ -24,4 +25,5 @@ message: string;

PRINT_MULTILINE: boolean;
STOP_AT_ERROR: boolean;
MSHOULD_QUIET: boolean;
STOP_ON_ERROR: boolean;
QUIET: boolean;
FAST: number;
}

@@ -67,3 +69,2 @@

declare const process: any;
declare const console: any;

@@ -74,14 +75,27 @@

let onlyStack: StackItem | undefined;
let running = false;
let isRunning = false;
const isCli = 'process' in globalThis;
// Dumb bundlers parse code and assume we have hard dependency on "process". We don't.
// The trick (also import(mod) below) ensures parsers can't see it.
// @ts-ignore
const proc: any = isCli ? globalThis['process'] : undefined;
const opts: Options = {
PRINT_TREE: true,
PRINT_MULTILINE: true,
STOP_AT_ERROR: true,
MSHOULD_QUIET: isCli && process.env.MSHOULD_QUIET,
STOP_ON_ERROR: true,
QUIET: isCli && ['1', 'true'].includes(proc.env.MSHOULD_QUIET),
FAST: parseFast(proc.env.MSHOULD_FAST),
};
function isQuiet() {
return opts.MSHOULD_QUIET;
function parseFast(str: string | number): number {
if (!isCli) return 0;
let val = str === 'true' ? 1 : Number.parseInt(str as string, 10);
if (!Number.isSafeInteger(val) || val < 1 || val > 256) return 0;
return val;
}
function imp(moduleName: string): any {
return import(moduleName);
}
// String formatting utils

@@ -116,3 +130,3 @@ const _c = String.fromCharCode(27); // x1b, control code for terminal colors

function log(...args: (string | undefined)[]) {
if (isQuiet()) return logQuiet(false);
if (opts.QUIET) return logQuiet(false);
// @ts-ignore

@@ -123,5 +137,5 @@ console.log(...args);

if (fail) {
process.stderr.write(color('red', '!'));
proc.stderr.write(color('red', '!'));
} else {
process.stdout.write('.');
proc.stdout.write('.');
}

@@ -132,3 +146,3 @@ }

// @ts-ignore
if (!isQuiet()) console.error(error); // loud = show error now. quiet = show in the end
if (!opts.QUIET) console.error(error); // loud = show error now. quiet = show in the end
}

@@ -144,7 +158,2 @@

function tdiff(start: number) {
const sec = Math.round((Date.now() - start) / 1000);
return sec < 60 ? `${sec} sec` : `${Math.floor(sec / 60)} min ${sec % 60} sec`;
}
async function runTest(

@@ -161,3 +170,3 @@ info: StackItem,

let messages: string[] = [];
let onlyLogsToPrint: string[] = [];
let onlyStackToLog: string[] = [];
let beforeEachFns: Function[] = [];

@@ -167,3 +176,3 @@ let afterEachFns: Function[] = []; // will be reversed

messages.push(parent.message);
if (printTree && info.only) onlyLogsToPrint.push(`${parent.prefix}${parent.message}`);
if (printTree && info.only) onlyStackToLog.push(`${parent.prefix}${parent.message}`);
if (parent.beforeEach) beforeEachFns.push(parent.beforeEach);

@@ -173,12 +182,11 @@ if (parent.afterEach) afterEachFns.push(parent.afterEach);

afterEachFns.reverse();
if (onlyLogsToPrint.length) onlyLogsToPrint.forEach((l) => log(l));
if (onlyStackToLog.length) onlyStackToLog.forEach((l) => log(l));
const path = `${messages.join('/')}/`;
const full = path + title;
const path = messages.slice().concat(title).join('/');
// Skip is always single-line
if (multiLine && !info.skip) {
log(printTree ? `${info.prefix}${title}: ☆` : `☆ ${full}:`);
if (multiLine && !info.skip && !opts.QUIET) {
log(printTree ? `${info.prefix}${title}: ☆` : `☆ ${path}:`);
} else if (info.skip) {
log(printTree ? `${info.prefix}${title} (skip)` : `☆ ${full} (skip)`);
log(printTree ? `${info.prefix}${title} (skip)` : `☆ ${path} (skip)`);
return true;

@@ -192,12 +200,10 @@ }

// stopAtError = true | false
function logTaskDone(fail = false, suffix = '') {
function formatTaskDone(fail = false, suffix = '') {
const symbol = fail ? '☓' : '✓';
const clr = fail ? 'red' : 'green';
const title_ = suffix ? [title, suffix].join('/') : title;
const full_ = suffix ? [full, suffix].join('/') : full;
log(
printTree
? `${info.childPrefix}` + color(clr, `${title_}: ${symbol}`)
: color(clr, `${symbol} ${full_}`)
);
const full_ = suffix ? [path, suffix].join('/') : path;
return printTree
? `${info.childPrefix}` + color(clr, `${title_}: ${symbol}`)
: color(clr, `${symbol} ${full_}`);
}

@@ -207,3 +213,3 @@

function logErrorStack(suffix: string) {
if (isQuiet()) {
if (opts.QUIET) {
// when quiet, either stop & log trace; or log !

@@ -213,3 +219,3 @@ if (stopAtError) {

console.error();
console.error(color('red', `☓ ${full}/${suffix}`));
console.error(formatTaskDone(true, suffix));
} else {

@@ -221,3 +227,3 @@ // log !, continue

// when loud, log (maybe formatted) tree structure
logTaskDone(true, suffix);
console.error(formatTaskDone(true, suffix));
}

@@ -234,3 +240,3 @@ }

if (stopAtError) throw cause;
else addToErrorLog(`${full}/beforeEach`, cause);
else addToErrorLog(`${path}/beforeEach`, cause);

@@ -249,3 +255,3 @@ return false;

if (stopAtError) throw cause;
else addToErrorLog(`${full}`, cause);
else addToErrorLog(`${path}`, cause);
return false;

@@ -262,7 +268,7 @@ }

if (stopAtError) throw cause;
else addToErrorLog(`${full}/afterEach`, cause);
else addToErrorLog(`${path}/afterEach`, cause);
return false;
}
}
logTaskDone();
log(formatTaskDone());
return true;

@@ -343,3 +349,5 @@ }

function begin(total: number, workers?: number | undefined) {
const features = [isQuiet() ? '+quiet' : '', workers ? `+fast-x${workers}` : ''].filter((a) => a);
const features = [opts.QUIET ? '+quiet' : '', workers ? `+fast-x${workers}` : ''].filter(
(a) => a
);
const modes = features.length ? `(${features.join(' ')}) ` : '';

@@ -351,20 +359,25 @@ // No need to log stats when tests fit on one screen

function finalize(total: number, startTime: number) {
isRunning = false;
console.log();
if (isQuiet()) console.log();
if (opts.QUIET) console.log();
const totalFailed = errorLog.length;
const sec = Math.round((Date.now() - startTime) / 1000);
const tdiff =
sec < 2 ? '' : sec < 60 ? `in ${sec} sec` : `in ${Math.floor(sec / 60)} min ${sec % 60} sec`;
if (totalFailed) {
console.error();
console.error(`${color('red', totalFailed)} tests failed`);
if (isQuiet()) {
if (opts.QUIET) {
errorLog.forEach((err) => console.error(err));
}
if (errorLog.length > 0)
throw new Error(`${errorLog.length} of ${total} tests failed ${tdiff}`);
} else {
console.log(`${color('green', total)} tests passed in ${tdiff(startTime)}`);
console.log(`${color('green', total)} tests passed ${tdiff}`);
}
return total;
}
async function runTests(forceSequential = false) {
if (running) throw new Error('should.run() has already been called, wait for end');
if (!forceSequential && isCli && !!process?.env?.MSHOULD_FAST) return runTestsInParallel();
running = true;
if (isRunning) throw new Error('should.run() has already been called, wait for end');
if (!forceSequential && opts.FAST) return runTestsInParallel();
isRunning = true;
const tasks = cloneAndReset();

@@ -377,7 +390,5 @@ const total = tasks.filter((i) => !!i.test).length;

if (!test.test) continue;
await runTest(test, opts.PRINT_TREE, opts.PRINT_MULTILINE, opts.STOP_AT_ERROR);
await runTest(test, opts.PRINT_TREE, opts.PRINT_MULTILINE, opts.STOP_ON_ERROR);
}
finalize(total, startTime);
running = false;
return total;
return finalize(total, startTime);
}

@@ -388,4 +399,4 @@

// @ts-ignore
const url = await import('node:url');
return importMetaUrl === url.pathToFileURL(process.argv[1]).href ? runTests() : undefined;
const { pathToFileURL } = await imp('node:url');
return importMetaUrl === pathToFileURL(proc.argv[1]).href ? runTests() : undefined;
}

@@ -397,24 +408,23 @@

if (!isCli) throw new Error('must run in cli');
if ('deno' in process.versions) return runTests(true);
if ('deno' in proc.versions) return runTests(true);
const tasks = cloneAndReset().filter((i) => !!i.test); // Filter describe elements
const total = tasks.length;
const startTime = Date.now();
const runTestPar = (info: StackItem) => runTest(info, false, false, opts.STOP_AT_ERROR);
const runTestPar = (info: StackItem) => runTest(info, false, false, opts.STOP_ON_ERROR);
let cluster: any, err: any;
let totalW = Number.parseInt(process.env.MSHOULD_FAST, 10);
if (totalW === 1) totalW = 0;
let totalW = opts.FAST;
try {
// @ts-ignore
cluster = (await import('node:cluster')).default;
cluster = (await imp('node:cluster')).default;
// @ts-ignore
if (!totalW) totalW = (await import('node:os')).cpus().length;
if (totalW === 1) totalW = (await imp('node:os')).cpus().length;
} catch (error) {
err = error;
}
if (!cluster || !totalW!) throw new Error('parallel tests are not supported: ' + err);
if (!cluster || !parseFast(totalW)) throw new Error('parallel tests are not supported: ' + err);
// the code is ran in workers
if (!cluster.isPrimary) {
process.on('error', (err: any) => console.log('internal error:', 'child crashed?', err));
proc.on('error', (err: any) => console.log('internal error:', 'child crashed?', err));
let tasksDone = 0;

@@ -428,7 +438,7 @@ const id = cluster.worker.id;

}
process.send({ name: 'parallelTests', worker: strId, tasksDone, errorLog });
process.exit();
proc.send({ name: 'parallelTests', worker: strId, tasksDone, errorLog });
proc.exit();
}
// the code is ran in primary process
// the code is ran in primary proc
return await new Promise((resolve, reject) => {

@@ -458,10 +468,9 @@ begin(total, totalW);

msg.errorLog.forEach((item) => errorLog.push(item));
if (workersDone === totalW) {
if (tasksDone === total) {
finalize(total, startTime);
resolve(tasksDone);
} else {
reject(new Error('internal error: not all tasks have been completed'));
}
}
if (workersDone !== totalW) return;
if (tasksDone !== total)
return reject(new Error('internal error: not all tasks have been completed'));
// @ts-ignore
globalThis.setTimeout(() => {
resolve(finalize(total, startTime));
}, 0);
});

@@ -487,3 +496,3 @@ }

export { it, describe, beforeEach, afterEach, it as should };
export { afterEach, beforeEach, describe, it, it as should };
export default it;
{
"name": "micro-should",
"version": "0.5.0",
"version": "0.5.1",
"description": "Micro testing framework with familiar syntax, multi-env ESM support & parallel execution",

@@ -17,3 +17,3 @@ "type": "module",

"format": "npx prettier --write index.ts test",
"test": "node test/basic.test.js; node test/example.test.js; node test/parallel.test.js"
"test": "node test/example.test.js"
},

@@ -39,3 +39,3 @@ "homepage": "https://github.com/paulmillr/micro-should",

"devDependencies": {
"@paulmillr/jsbt": "0.2.1",
"@paulmillr/jsbt": "0.3.0",
"prettier": "3.3.2",

@@ -42,0 +42,0 @@ "typescript": "5.5.2"

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc