Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@pmoo/testy

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pmoo/testy - npm Package Compare versions

Comparing version 6.0.0 to 6.1.0

22

lib/console_ui.js

@@ -10,3 +10,3 @@ 'use strict';

}
static failedExitCode() {

@@ -23,5 +23,5 @@ return 1;

}
// Callbacks for runner/suite/test
testCallbacks() {

@@ -41,3 +41,3 @@ return {

}
suiteCallbacks() {

@@ -51,3 +51,3 @@ return {

}
testRunnerCallbacks() {

@@ -65,10 +65,10 @@ return {

// application events
start(configuration, paths, runnerBlock) {
async start(configuration, paths, runnerBlock) {
this._formatter.start();
this._formatter.displayInitialInformation(configuration, paths);
runnerBlock.call();
await runnerBlock.call();
this._formatter.end();
}
useLanguage(language) {

@@ -78,3 +78,3 @@ const i18n = new I18n(language);

}
exitWithError(...errorMessages) {

@@ -88,3 +88,3 @@ errorMessages.forEach(errorMessage =>

// private
_exitWithCode(exitCode) {

@@ -91,0 +91,0 @@ this._process.exit(exitCode);

@@ -17,3 +17,3 @@ 'use strict';

},
evaluate(actual, expected, criteria) {

@@ -28,7 +28,7 @@ return this.availableStrategies()

__proto__: EqualityAssertionStrategy,
appliesTo(actual, expected) {
return isUndefined(actual) && isUndefined(expected);
},
evaluate() {

@@ -44,7 +44,7 @@ return {

__proto__: EqualityAssertionStrategy,
appliesTo(actual, expected, criteria) {
appliesTo(_actual, _expected, criteria) {
return isFunction(criteria);
},
evaluate(actual, expected, criteria) {

@@ -60,7 +60,7 @@ return {

__proto__: EqualityAssertionStrategy,
appliesTo(actual, expected, criteria) {
appliesTo(_actual, _expected, criteria) {
return isString(criteria);
},
evaluate(actual, expected, criteria) {

@@ -73,7 +73,7 @@ if (this._comparisonCanBeMade(actual, expected, criteria)) {

},
_comparisonCanBeMade(actual, expected, criteria) {
return respondsTo(actual, criteria) && respondsTo(expected, criteria);
},
_compareUsingCustomCriteria(actual, expected, criteria) {

@@ -85,3 +85,3 @@ return {

},
_failWithCriteriaNotFoundMessage(criteria) {

@@ -97,7 +97,7 @@ return {

__proto__: EqualityAssertionStrategy,
appliesTo(actual, _expected) {
return respondsTo(actual, 'equals');
},
evaluate(actual, expected) {

@@ -113,7 +113,7 @@ return {

__proto__: EqualityAssertionStrategy,
appliesTo(actual, expected) {
return isCyclic(actual) || isCyclic(expected);
},
evaluate(_actual, _expected) {

@@ -129,7 +129,7 @@ return {

__proto__: EqualityAssertionStrategy,
appliesTo(_actual, _expected) {
return true;
},
evaluate(actual, expected) {

@@ -136,0 +136,0 @@ return {

@@ -10,19 +10,19 @@ 'use strict';

},
for(params) {
return this.availableActions().find(action => action.appliesTo(params));
},
firstParamMatches(params, ...expressions) {
return expressions.includes(params[0]);
},
_packageData() {
return require('../package.json');
},
_exitSuccessfully() {
process.exit(0);
},
_exitWithFailure() {

@@ -35,8 +35,8 @@ process.exit(1);

__proto__: ScriptAction,
appliesTo(params) {
return this.firstParamMatches(params, '-v', '--version');
},
execute(_params) {
async execute(_params) {
const { version, description, homepage } = this._packageData();

@@ -50,8 +50,8 @@ console.log(`Testy version: ${version}\n${description}\n${homepage}`);

__proto__: ScriptAction,
appliesTo(params) {
return this.firstParamMatches(params, '-h', '--help');
},
execute(_params) {
async execute(_params) {
const { description } = this._packageData();

@@ -70,11 +70,11 @@ console.log(`Testy: ${description}\n`);

__proto__: ScriptAction,
appliesTo(_params) {
return true; // we want to run tests by default
},
execute(params) {
async execute(params) {
try {
const testyInstance = Testy.configuredWith(Configuration.current());
testyInstance.run(params);
await testyInstance.run(params);
this._exitSuccessfully();

@@ -81,0 +81,0 @@ } catch (error) {

@@ -5,22 +5,22 @@ 'use strict';

// instance creation messages
static success() {
return new TestSucceeded();
}
static failure(description) {
return new TestFailed(description);
}
static error(errorCause) {
return new TestErrored(errorCause);
}
static explicitlyMarkedAsPending(reason) {
return new TestExplicitlyMarkedPending(reason);
}
// checking for test status
static evaluate(test, context) {
static async evaluate(test, context) {
return [SkippedTest, TestWithoutDefinition, TestWithDefinition]

@@ -30,25 +30,25 @@ .find(result => result.canHandle(test, context))

}
// statuses
isSuccess() {
return false;
}
isPending() {
return false;
}
isExplicitlyMarkedPending() {
return false;
}
isError() {
return false;
}
isFailure() {
return false;
}
isSkipped() {

@@ -60,10 +60,10 @@ return false;

class SkippedTest extends TestResult {
static canHandle(test, context) {
static canHandle(_test, context) {
return context.failFastMode.hasFailed();
}
static handle(test) {
static async handle(test) {
test.markSkipped(new this());
}
isSkipped() {

@@ -78,7 +78,7 @@ return true;

}
static handle(test) {
static async handle(test) {
test.markPending(new this());
}
isPending() {

@@ -93,6 +93,7 @@ return true;

}
static handle(test, context) {
test.evaluate();
static async handle(test, context) {
await test.evaluate(context);
const possibleResults = [TestWithoutAssertion, TestErrored, TestExplicitlyMarkedPending, TestSucceeded, TestFailed];
// All results evaluate synchronously at this point, so we don't need to async/await this part of the code.
possibleResults

@@ -108,7 +109,7 @@ .find(result => result.canHandle(test))

}
static handle(test) {
test.finishWithPendingStatus();
}
constructor(reason) {

@@ -118,11 +119,11 @@ super();

}
reason() {
return this._reason;
}
isPending() {
return true;
}
isExplicitlyMarkedPending() {

@@ -137,3 +138,3 @@ return true;

}
static handle(test, context) {

@@ -143,3 +144,3 @@ context.failFastMode.registerFailure();

}
constructor(errorCause) {

@@ -149,7 +150,7 @@ super();

}
isError() {
return true;
}
failureMessage() {

@@ -164,3 +165,3 @@ return this._errorCause.stack || this._errorCause;

}
static handle(test, context) {

@@ -170,3 +171,3 @@ test.setResult(new this());

}
constructor() {

@@ -181,7 +182,7 @@ super('This test does not have any assertions');

}
static handle(test) {
test.finishWithSuccess();
}
isSuccess() {

@@ -196,3 +197,3 @@ return true;

}
static handle(test, context) {

@@ -202,3 +203,3 @@ context.failFastMode.registerFailure();

}
constructor(failureMessage) {

@@ -208,7 +209,7 @@ super();

}
isFailure() {
return true;
}
failureMessage() {

@@ -215,0 +216,0 @@ return this._failureMessage;

@@ -14,5 +14,5 @@ 'use strict';

}
// Configuration
registerSuite(name, suiteBody, callbacks) {

@@ -22,3 +22,3 @@ const suiteToAdd = new TestSuite(name, suiteBody, callbacks);

}
registerTest(name, testBody, callbacks) {

@@ -28,7 +28,7 @@ const testToAdd = new Test(name, testBody, callbacks);

}
registerBefore(beforeBlock) {
this._currentSuite.before(beforeBlock);
}
registerAfter(afterBlock) {

@@ -43,22 +43,23 @@ this._currentSuite.after(afterBlock);

}
setFailFastMode(failFastMode) {
this._failFastMode = failFastMode;
}
setTestRandomness(randomnessEnabled) {
this._randomOrder = randomnessEnabled;
}
// Executing
run() {
async run() {
this._randomizeSuites();
this._suites.forEach(suite => {
// eslint-disable-next-line no-restricted-syntax
for (const suite of this._suites) {
this._setCurrentSuite(suite);
suite.run(this._executionContext());
});
await suite.run(this._executionContext());
}
this._callbacks.onFinish(this);
}
_executionContext() {

@@ -70,7 +71,7 @@ return {

}
setResultForCurrentTest(result) {
this._currentSuite.currentTest().setResult(result);
}
finish() {

@@ -83,29 +84,29 @@ if (this.hasErrorsOrFailures()) {

}
// Counting
successCount() {
return this._countEach('successCount');
}
pendingCount() {
return this._countEach('pendingCount');
}
errorsCount() {
return this._countEach('errorsCount');
}
failuresCount() {
return this._countEach('failuresCount');
}
skippedCount() {
return this._countEach('skippedCount');
}
totalCount() {
return this._countEach('totalCount');
}
allFailuresAndErrors() {

@@ -116,13 +117,13 @@ return this._suites.reduce((failures, suite) =>

}
hasErrorsOrFailures() {
return this.allFailuresAndErrors().length > 0;
}
// Private
_setCurrentSuite(suite) {
this._currentSuite = suite;
}
_countEach(property) {

@@ -133,3 +134,3 @@ return this._suites.reduce((count, suite) =>

}
_randomizeSuites() {

@@ -136,0 +137,0 @@ if (this._randomOrder) {

@@ -6,2 +6,25 @@ 'use strict';

class TestSuite {
static BEFORE_HOOK_NAME = 'before';
static AFTER_HOOK_NAME = 'after';
// Error messages
static invalidSuiteNameErrorMessage() {
return 'Suite does not have a valid name. Please enter a non-empty string to name this suite.';
}
static invalidSuiteDefinitionBodyErrorMessage() {
return 'Suite does not have a valid body. Please provide a function to declare the suite body.';
}
static alreadyDefinedHookErrorMessage(hookName) {
return `There is already a ${hookName}() block. Please leave just one ${hookName}() block and run again the tests.`;
}
static hookWasNotInitializedWithAFunctionErrorMessage(hookName) {
return `The ${hookName}() hook must include a function. Please provide a function or remove the ${hookName}() and run again the tests.`;
}
// Instance creation
constructor(name, body, callbacks) {

@@ -15,31 +38,29 @@ this._initializeName(name);

}
// Initializing / Configuring
addTest(test) {
this._tests.push(test);
}
before(initializationBlock) {
if (isUndefined(this._before)) {
this._before = initializationBlock;
} else {
throw new Error('There is already a before() block. Please leave just one before() block and run again the tests.');
}
this._validateTheHookIsNotAlreadyDeclared(this._before, TestSuite.BEFORE_HOOK_NAME);
this._validateTheHookBlockIsAFunction(initializationBlock, TestSuite.BEFORE_HOOK_NAME);
this._before = initializationBlock;
}
after(releasingBlock) {
if (isUndefined(this._after)) {
this._after = releasingBlock;
} else {
throw new Error('There is already an after() block. Please leave just one after() block and run again the tests.');
}
this._validateTheHookIsNotAlreadyDeclared(this._after, TestSuite.AFTER_HOOK_NAME);
this._validateTheHookBlockIsAFunction(releasingBlock, TestSuite.AFTER_HOOK_NAME);
this._after = releasingBlock;
}
// Executing
run(context) {
async run(context) {
this._callbacks.onStart(this);
this._evaluateSuiteDefinition();
this._runTests(context);
await this._runTests(context);
this._callbacks.onFinish(this);

@@ -49,47 +70,47 @@ }

// Counting
totalCount() {
return this.tests().length;
}
successCount() {
return this.tests().filter(test => test.isSuccess()).length;
}
pendingCount() {
return this.tests().filter(test => test.isPending()).length;
}
errorsCount() {
return this.tests().filter(test => test.isError()).length;
}
skippedCount() {
return this.tests().filter(test => test.isSkipped()).length;
}
failuresCount() {
return this.totalCount() - this.successCount() - this.pendingCount() - this.errorsCount() - this.skippedCount();
}
// Accessing
name() {
return this._name;
}
currentTest() {
return this._currentTest;
}
tests() {
return this._tests;
}
allFailuresAndErrors() {
return this.tests().filter(test => test.isFailure() || test.isError());
}
// Private - Validations
_initializeBody(body) {

@@ -99,3 +120,3 @@ this._ensureBodyIsValid(body);

}
_initializeName(name) {

@@ -105,43 +126,53 @@ this._ensureNameIsValid(name);

}
_ensureNameIsValid(name) {
if (!isStringWithContent(name)) {
throw new Error('Suite does not have a valid name');
throw new Error(TestSuite.invalidSuiteNameErrorMessage());
}
}
_ensureBodyIsValid(body) {
if (!isFunction(body)) {
throw new Error('Suite does not have a valid body');
throw new Error(TestSuite.invalidSuiteDefinitionBodyErrorMessage());
}
}
_validateTheHookIsNotAlreadyDeclared(hookBlock, hookName) {
if (!isUndefined(hookBlock)) {
throw new Error(TestSuite.alreadyDefinedHookErrorMessage(hookName));
}
}
_validateTheHookBlockIsAFunction(hookBlock, hookName) {
if (!isFunction(hookBlock)) {
throw new Error(TestSuite.hookWasNotInitializedWithAFunctionErrorMessage(hookName));
}
}
// Private - Running
_randomizeTests() {
shuffle(this.tests());
}
_evaluateSuiteDefinition() {
this._body.call();
}
_evaluateBeforeBlock() {
this._before && this._before.call();
}
_evaluateAfterBlock() {
this._after && this._after.call();
}
_runTests(context) {
async _runTests(context) {
if (context.randomOrderMode) {
this._randomizeTests();
}
this.tests().forEach(test => {
context.hooks = {
[TestSuite.BEFORE_HOOK_NAME]: this._before,
[TestSuite.AFTER_HOOK_NAME]: this._after,
};
// eslint-disable-next-line no-restricted-syntax
for (const test of this.tests()) {
this._currentTest = test;
this._evaluateBeforeBlock();
test.run(context);
this._evaluateAfterBlock();
});
await test.run(context);
}
}

@@ -148,0 +179,0 @@ }

@@ -13,17 +13,20 @@ 'use strict';

}
// Execution
run(context) {
TestResult.evaluate(this, context);
async run(context) {
await TestResult.evaluate(this, context);
}
evaluate() {
async evaluate(context) {
await this._evaluateHook(context.hooks.before);
try {
this.body().call();
await this.body().call();
} catch (error) {
this.setResult(TestResult.error(error));
} finally {
await this._evaluateHook(context.hooks.after);
}
}
markPending(pendingResult) {

@@ -33,3 +36,3 @@ this.setResult(pendingResult);

}
markSkipped(skippedResult) {

@@ -39,3 +42,3 @@ this.setResult(skippedResult);

}
setResult(result) {

@@ -46,63 +49,63 @@ if (this.hasNoResult() || this.isSuccess()) {

}
finishWithSuccess() {
this._callbacks.whenSuccess(this);
}
finishWithFailure() {
this._callbacks.whenFailed(this);
}
finishWithError() {
this._callbacks.whenErrored(this);
}
finishWithPendingStatus() {
this._callbacks.whenPending(this);
}
// Testing
hasDefinition() {
return !isUndefined(this.body());
}
hasNoResult() {
return isUndefined(this.result());
}
isSuccess() {
return this.result().isSuccess();
}
isPending() {
return this.result().isPending();
}
isExplicitlyMarkedPending() {
return this.result().isExplicitlyMarkedPending();
}
isSkipped() {
return this.result().isSkipped();
}
isError() {
return this.result().isError();
}
isFailure() {
return this.result().isFailure();
}
// Accessing
name() {
return this._name;
}
result() {
return this._result;
}
body() {

@@ -113,3 +116,3 @@ return this._body;

// Private - Validations
_initializeBody(body) {

@@ -119,3 +122,3 @@ this._ensureBodyIsValid(body);

}
_initializeName(name) {

@@ -125,3 +128,3 @@ this._ensureNameIsValid(name);

}
_ensureNameIsValid(name) {

@@ -132,3 +135,3 @@ if (!isStringWithContent(name)) {

}
_ensureBodyIsValid(body) {

@@ -139,4 +142,12 @@ if (!isUndefined(body) && !isFunction(body)) {

}
async _evaluateHook(hook) {
try {
hook && await hook.call();
} catch (error) {
this.setResult(TestResult.error(error));
}
}
}
module.exports = Test;

@@ -116,2 +116,4 @@ 'use strict';

const errorDetailOf = thrownObject => (thrownObject instanceof Error) ? thrownObject.stack : thrownObject.toString();
module.exports = {

@@ -140,2 +142,4 @@ // comparison on objects

subclassResponsibility,
// errors
errorDetailOf,
};
{
"name": "@pmoo/testy",
"version": "6.0.0",
"version": "6.1.0",
"description": "A minimal testing framework, for educational purposes.",

@@ -21,4 +21,4 @@ "homepage": "https://ngarbezza.github.io/testy/",

"generate-dependencies-graph": "npx madge -i testy-dependencies.png lib/ bin/",
"lint": "npx eslint .",
"lint-fix": "npx eslint . --fix",
"lint": "npx eslint@latest .",
"lint-fix": "npx eslint@latest . --fix",
"test": "bin/testy_cli.js"

@@ -25,0 +25,0 @@ },

@@ -33,2 +33,6 @@ # Testy

## Sponsors
<a href="https://10pines.com"><img alt="10Pines logo" src="https://10pines.com/static/media/10Pines-logo_reducido.f830b358.svg" width="300" height="100" /></a>
## Getting started

@@ -161,8 +165,10 @@

* **Running code before every test**: just like many testing frameworks have, there is a way to execute some code before every test in a suite using the `before()` function. Example:
* **Running code before/after every test**: just like many testing frameworks have, there is a way to execute some code
before or after each test in a suite using the `before()` and `after()` functions, respectively. You can use only one
definition of `before()` and `after()` per suite, and they always receive a function as argument. Example:
```javascript
const { suite, test, before, assert } = require('@pmoo/testy');
const { suite, test, assert, before, after } = require('@pmoo/testy');
suite('using the before() helper', () => {
suite('using the before() and after() helpers', () => {
let answer;

@@ -177,22 +183,32 @@

});
after(() => {
answer = undefined;
});
});
```
* **Running code after every test**: just like many testing frameworks have, there is a way to execute some code after (cleanp) every test in a suite using the `after()` function. Example:
* **Support for pending tests**: if a test has no body, it will be reported as `[WIP]` and it won't be considered a failure.
* **Support for asynchronous tests**: if the code you are testing has `async` logic, you can `await` inside the test
definition and make assertions later. You can also use it on `before()` and `after()` declarations. Example:
```javascript
const { suite, test, before, after, assert } = require('@pmoo/testy');
const { suite, test, assert, before } = require('@pmoo/testy');
suite('using the after() helper', () => {
let answer;
const promiseOne = async () => Promise.resolve(42);
const promiseTwo = async () => Promise.resolve(21);
suite('using async & await', () => {
let answerOne;
before(() => {
answer = 42;
before(async () => {
answerOne = await promiseOne();
});
after(() => {
answer = undefined;
test('comparing results from promises', async () => {
const answerTwo = await promiseTwo();
assert.that(answerOne).isEqualTo(42);
assert.that(answerTwo).isEqualTo(21);
});
});
```
* **Support for pending tests**: if a test has no body, it will be reported as `[WIP]` and it won't be considered a failure.
* **Fail-Fast mode**: if enabled, it stops execution in the first test that fails (or has an error). Remaining tests will be marked as skipped.

@@ -199,0 +215,0 @@ * **Run tests and suites in random order**: a good test suite does not depend on a particular order. Enabling this setting is a good way to ensure that.

@@ -7,3 +7,3 @@ 'use strict';

const ConsoleUI = require(`${libDir}/console_ui`);
const { allFilesMatching, resolvePathFor } = require(`${libDir}/utils`);
const { allFilesMatching, resolvePathFor, errorDetailOf } = require(`${libDir}/utils`);
const { I18nMessage } = require(`${libDir}/i18n`);

@@ -35,21 +35,21 @@

// instance creation
static configuredWith(configuration) {
return new Testy(configuration);
}
constructor(configuration) {
this._initializeConfiguredWith(configuration);
}
// running
run(requestedPaths) {
async run(requestedPaths) {
this._requestedPaths = requestedPaths;
this._loadAllRequestedFiles();
ui.start(this._configuration, this._testFilesPathsToRun(), () => {
await ui.start(this._configuration, this._testFilesPathsToRun(), async() => {
try {
testRunner.run();
await testRunner.run();
} catch (err) {
ui.exitWithError(I18nMessage.of('error_running_suites'), err.stack);
ui.exitWithError(I18nMessage.of('error_running_suites'), errorDetailOf(err));
}

@@ -59,5 +59,5 @@ });

}
// initialization
_initializeConfiguredWith(configuration) {

@@ -68,9 +68,9 @@ this._configuration = configuration;

}
// private
_requestedPathsToRun() {
return this._requestedPaths;
}
_loadAllRequestedFiles() {

@@ -97,3 +97,3 @@ try {

ui.exitWithError(
I18nMessage.of('error_loading_suite', file), err.stack,
I18nMessage.of('error_loading_suite', file), errorDetailOf(err),
I18nMessage.of('feedback_for_error_loading_suite'),

@@ -108,11 +108,11 @@ );

}
_resolvedTestFilesPathsToRun() {
return this._testFilesPathsToRun().map(path => resolvePathFor(path));
}
_pathForAllTests() {
return this._configuration.directory();
}
_testFilesFilter() {

@@ -119,0 +119,0 @@ return this._configuration.filter();

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