@pmoo/testy
Advanced tools
Comparing version 5.0.1 to 5.0.2
@@ -11,2 +11,16 @@ # Changelog | ||
## [5.0.2] - 2020-10-13 | ||
A hacktoberfest release! 5 bugs fixed and two new contributors! :muscle: | ||
It also includes an improvement in the contribution guidelines, and records of architectural decisions (ADRs). | ||
### Fixed | ||
* [[bug] isEmpty / isNotEmpty failing when passing an undefined value](https://github.com/ngarbezza/testy/issues/125): thank you, @abraaoduarte for your first contribution! | ||
* [[bug] validate argument types of test()](https://github.com/ngarbezza/testy/issues/137): thank you, @adico1 for your first contribution! | ||
* [[bug] raises() does not pass when throwing a non-primitive object](https://github.com/ngarbezza/testy/issues/140) | ||
* [[bug] toString() is not honored when printing objects](https://github.com/ngarbezza/testy/issues/143) | ||
* [[bug] cannot run testy binary using npx](https://github.com/ngarbezza/testy/issues/148) | ||
## [5.0.1] - 2020-08-02 | ||
@@ -125,3 +139,3 @@ | ||
* [Remove `require-dir` dependency](https://github.com/ngarbezza/testy/issues/36): Zero dependencies goal reached! :muscle: | ||
* [Increased "debuggability"](https://github.com/ngarbezza/testy/issues/33): Nobody should be afraid of debugging inside this library! If something is not understandable, let's change it. | ||
* [Increased "debuggability"](https://github.com/ngarbezza/testy/issues/33): Nobody should be afraid of debugging inside the code of this tool! If something is not understandable, let's change it. | ||
@@ -196,3 +210,4 @@ ## [4.0.1] - 2019-07-19 | ||
[Unreleased]: https://github.com/ngarbezza/testy/compare/v5.0.1...HEAD | ||
[Unreleased]: https://github.com/ngarbezza/testy/compare/v5.0.2...HEAD | ||
[5.0.2]: https://github.com/ngarbezza/testy/compare/v5.0.1...v5.0.2 | ||
[5.0.1]: https://github.com/ngarbezza/testy/compare/v5.0.0...v5.0.1 | ||
@@ -199,0 +214,0 @@ [5.0.0]: https://github.com/ngarbezza/testy/compare/v4.4.0...v5.0.0 |
@@ -11,7 +11,7 @@ 'use strict'; | ||
} | ||
report(result) { | ||
this._runner.setResultForCurrentTest(result); | ||
} | ||
translated(key) { | ||
@@ -38,7 +38,7 @@ return this._runner._i18n.translate(key); | ||
} | ||
isTrue(actual) { | ||
return this.that(actual).isTrue(); | ||
} | ||
isFalse(actual) { | ||
@@ -55,27 +55,27 @@ return this.that(actual).isFalse(); | ||
} | ||
isNull(actual) { | ||
return this.that(actual).isNull(); | ||
} | ||
isNotNull(actual) { | ||
return this.that(actual).isNotNull(); | ||
} | ||
areEqual(actual, expected, criteria) { | ||
return this.that(actual).isEqualTo(expected, criteria); | ||
} | ||
areNotEqual(actual, expected) { | ||
return this.that(actual).isNotEqualTo(expected); | ||
} | ||
isEmpty(actual) { | ||
return this.that(actual).isEmpty(); | ||
} | ||
isNotEmpty(actual) { | ||
return this.that(actual).isNotEmpty(); | ||
} | ||
isMatching(actual, regex) { | ||
@@ -91,9 +91,9 @@ return this.that(actual).matches(regex); | ||
} | ||
// Boolean assertions | ||
isTrue() { | ||
this._booleanAssertion(true, this.translated('be_true')); | ||
} | ||
isFalse() { | ||
@@ -112,25 +112,25 @@ this._booleanAssertion(false, this.translated('be_false')); | ||
} | ||
// Null value assertions | ||
isNull() { | ||
this._nullAssertion(this.translated('be_null')); | ||
} | ||
isNotNull() { | ||
this._notNullAssertion(this.translated('be_not_null')); | ||
} | ||
// Equality assertions | ||
isEqualTo(expected, criteria) { | ||
this._equalityAssertion(expected, criteria, true); | ||
} | ||
isNotEqualTo(expected, criteria) { | ||
this._equalityAssertion(expected, criteria, false); | ||
} | ||
// Collection assertions | ||
includes(expectedObject, equalityCriteria) { | ||
@@ -142,3 +142,3 @@ const resultIsSuccessful = this._actual.find(element => | ||
} | ||
doesNotInclude(expectedObject, equalityCriteria) { | ||
@@ -150,3 +150,3 @@ const resultIsSuccessful = !this._actual.find(element => | ||
} | ||
includesExactly(...objects) { | ||
@@ -157,25 +157,28 @@ const resultIsSuccessful = this._haveElementsConsideredEqual(this._actual, objects); | ||
} | ||
isEmpty() { | ||
const resultIsSuccessful = Utils.numberOfElements(this._actual) === 0; | ||
const resultIsSuccessful = Utils.numberOfElements(this._actual || {}) === 0 | ||
&& Utils.notNullOrUndefined(this._actual); | ||
const failureMessage = this.translated('be_empty'); | ||
this._reportAssertionResult(resultIsSuccessful, failureMessage); | ||
} | ||
isNotEmpty() { | ||
const resultIsSuccessful = Utils.numberOfElements(this._actual) > 0; | ||
const setValueWhenUndefined = this._actual || {}; | ||
const resultIsSuccessful = Utils.numberOfElements(setValueWhenUndefined) > 0; | ||
const failureMessage = this.translated('be_not_empty'); | ||
this._reportAssertionResult(resultIsSuccessful, failureMessage); | ||
} | ||
// Exception assertions | ||
raises(errorExpectation) { | ||
this._exceptionAssertion(errorExpectation, true); | ||
} | ||
doesNotRaise(notExpectedError) { | ||
this._exceptionAssertion(notExpectedError, false); | ||
} | ||
doesNotRaiseAnyErrors() { | ||
@@ -194,5 +197,5 @@ let noErrorsOccurred = false; | ||
} | ||
// Numeric assertions | ||
isNearTo(number, precisionDigits = 4) { | ||
@@ -203,5 +206,5 @@ const result = Number.parseFloat((this._actual).toFixed(precisionDigits)) === number; | ||
} | ||
// String assertions | ||
matches(regex) { | ||
@@ -212,9 +215,9 @@ const result = this._actual.match(regex); | ||
} | ||
// Private | ||
_equalityAssertion(expected, criteria, shouldBeEqual) { | ||
const { comparisonResult, additionalFailureMessage, overrideFailureMessage } = | ||
EqualityAssertionStrategy.evaluate(this._actual, expected, criteria); | ||
const resultIsSuccessful = shouldBeEqual ? comparisonResult : !comparisonResult; | ||
@@ -229,7 +232,7 @@ if (overrideFailureMessage) { | ||
} | ||
_areConsideredEqual(objectOne, objectTwo, equalityCriteria) { | ||
return EqualityAssertionStrategy.evaluate(objectOne, objectTwo, equalityCriteria).comparisonResult; | ||
} | ||
_booleanAssertion(expectedBoolean, failureMessage) { | ||
@@ -249,3 +252,3 @@ const resultIsSuccessful = this._actual === expectedBoolean; | ||
} | ||
_nullAssertion(failureMessage) { | ||
@@ -255,3 +258,3 @@ const resultIsSuccessful = this._actual === null; | ||
} | ||
_notNullAssertion(failureMessage) { | ||
@@ -261,3 +264,3 @@ const resultIsSuccessful = this._actual !== null; | ||
} | ||
_exceptionAssertion(errorExpectation, shouldFail) { | ||
@@ -281,12 +284,11 @@ let hasFailed = false; | ||
} | ||
_checkIfErrorMatchesExpectation(errorExpectation, actualError) { | ||
const expectationIsRegex = Object.hasOwnProperty.call(errorExpectation.__proto__, 'test'); | ||
if (expectationIsRegex) { | ||
if (Utils.isRegex(errorExpectation)) { | ||
return errorExpectation.test(actualError); | ||
} else { | ||
return actualError === errorExpectation; | ||
return this._areConsideredEqual(actualError, errorExpectation); | ||
} | ||
} | ||
_reportAssertionResult(wasSuccess, matcherFailureMessage, overrideFailureMessage) { | ||
@@ -300,7 +302,7 @@ if (wasSuccess) { | ||
} | ||
_actualResultAsString() { | ||
return Utils.prettyPrint(this._actual); | ||
} | ||
_haveElementsConsideredEqual(collectionOne, collectionTwo) { | ||
@@ -307,0 +309,0 @@ const collectionOneArray = Array.from(collectionOne); |
@@ -19,3 +19,3 @@ 'use strict'; | ||
const defaultConfiguration = require('./default_configuration'); | ||
return new Configuration(userConfiguration, defaultConfiguration); | ||
return new this(userConfiguration, defaultConfiguration); | ||
} | ||
@@ -22,0 +22,0 @@ |
@@ -70,3 +70,3 @@ 'use strict'; | ||
_comparisonCanBeMade(actual, expected, criteria) { | ||
return Utils.hasMethodDefined(actual, criteria) && Utils.hasMethodDefined(expected, criteria); | ||
return Utils.respondsTo(actual, criteria) && Utils.respondsTo(expected, criteria); | ||
}, | ||
@@ -93,3 +93,3 @@ | ||
appliesTo(actual, _expected) { | ||
return Utils.hasMethodDefined(actual, 'equals'); | ||
return Utils.respondsTo(actual, 'equals'); | ||
}, | ||
@@ -96,0 +96,0 @@ |
@@ -5,5 +5,13 @@ 'use strict'; | ||
static default() { | ||
return new FailFast(false); | ||
return this.disabled(); | ||
} | ||
static disabled() { | ||
return new this(false); | ||
} | ||
static enabled() { | ||
return new this(true); | ||
} | ||
constructor(enabled) { | ||
@@ -10,0 +18,0 @@ this._enabled = enabled; |
@@ -63,3 +63,3 @@ 'use strict'; | ||
static handle(test) { | ||
test.markSkipped(new SkippedTest()); | ||
test.markSkipped(new this()); | ||
} | ||
@@ -78,3 +78,3 @@ | ||
static handle(test) { | ||
test.markPending(new TestWithoutDefinition()); | ||
test.markPending(new this()); | ||
} | ||
@@ -158,3 +158,3 @@ | ||
static handle(test, failFastMode) { | ||
test.setResult(new TestWithoutAssertion()); | ||
test.setResult(new this()); | ||
super.handle(test, failFastMode); | ||
@@ -161,0 +161,0 @@ } |
'use strict'; | ||
const TestResult = require('./test_result'); | ||
const FailFast = require('./fail_fast'); | ||
const { isString, isFunction, isUndefined } = require('./utils'); | ||
class Test { | ||
constructor(name, body, callbacks) { | ||
this._name = name; | ||
this._body = body; | ||
this._initializeName(name); | ||
this._initializeBody(body); | ||
this._callbacks = callbacks; | ||
@@ -15,3 +17,3 @@ this._result = undefined; | ||
run(failFastMode) { | ||
run(failFastMode = FailFast.default()) { | ||
TestResult.evaluate(this, failFastMode); | ||
@@ -106,4 +108,28 @@ } | ||
} | ||
// Private - Validations | ||
_initializeBody(body) { | ||
this._ensureBodyIsValid(body); | ||
this._body = body; | ||
} | ||
_initializeName(name) { | ||
this._ensureNameIsValid(name); | ||
this._name = name; | ||
} | ||
_ensureNameIsValid(name) { | ||
if (!isString(name)) { | ||
throw 'Test does not have a valid name'; | ||
} | ||
} | ||
_ensureBodyIsValid(body) { | ||
if (!isUndefined(body) && !isFunction(body)) { | ||
throw 'Test does not have a valid body'; | ||
} | ||
} | ||
} | ||
module.exports = Test; |
@@ -11,3 +11,3 @@ 'use strict'; | ||
const seenObjects = []; | ||
function detect(obj) { | ||
@@ -21,12 +21,6 @@ if (typeof obj === 'object') { | ||
} | ||
return detect(object); | ||
}; | ||
const notNullOrUndefined = object => | ||
object !== undefined && object !== null; | ||
const hasMethodDefined = (object, method) => | ||
notNullOrUndefined(object) && isFunction(object[method]); | ||
const deepStrictEqual = (objectOne, objectTwo) => { | ||
@@ -48,3 +42,3 @@ try { | ||
} | ||
fs.readdirSync(dir).forEach(entry => | ||
@@ -56,5 +50,2 @@ results.push(...allFilesMatching(path.join(dir, entry), regex, results)) | ||
const prettyPrint = object => | ||
util.inspect(object); | ||
const shuffle = array => { | ||
@@ -82,2 +73,20 @@ let currentIndex = array.length; | ||
const isUndefined = object => | ||
typeof object === 'undefined'; | ||
const notNullOrUndefined = object => | ||
!isUndefined(object) && object !== null; | ||
const respondsTo = (object, methodName) => | ||
notNullOrUndefined(object) && isFunction(object[methodName]); | ||
const isRegex = object => | ||
respondsTo(object, 'test'); | ||
const prettyPrint = object => { | ||
const excludedToStrings = [Object.prototype.toString, String.prototype.toString, Array.prototype.toString]; | ||
const shouldUseToStringMethod = notNullOrUndefined(object) && !excludedToStrings.includes(object.toString); | ||
return shouldUseToStringMethod ? object.toString() : util.inspect(object); | ||
}; | ||
const numberOfElements = object => | ||
@@ -87,12 +96,20 @@ Array.from(object).length; | ||
module.exports = { | ||
// comparison on objects | ||
isCyclic, | ||
hasMethodDefined, | ||
deepStrictEqual, | ||
resolvePathFor, | ||
allFilesMatching, | ||
// printing | ||
prettyPrint, | ||
shuffle, | ||
// types | ||
isString, | ||
isFunction, | ||
isUndefined, | ||
isRegex, | ||
notNullOrUndefined, | ||
respondsTo, | ||
// collections | ||
shuffle, | ||
numberOfElements, | ||
// files | ||
resolvePathFor, | ||
allFilesMatching, | ||
}; |
{ | ||
"name": "@pmoo/testy", | ||
"version": "5.0.1", | ||
"description": "A minimal testing library, for educational purposes.", | ||
"version": "5.0.2", | ||
"description": "A minimal testing framework, for educational purposes.", | ||
"homepage": "https://ngarbezza.github.io/testy/", | ||
@@ -15,8 +15,11 @@ "repository": { | ||
"scripts": { | ||
"test": "lib/testy_cli.js" | ||
"coverage": "npx nyc@latest --reporter=lcov --reporter=text-summary npm test", | ||
"lint": "npx eslint@6.8.0 .", | ||
"test": "bin/testy_cli.js" | ||
}, | ||
"bin": "lib/testy_cli.js", | ||
"bin": "bin/testy_cli.js", | ||
"files": [ | ||
"testy.js", | ||
"lib" | ||
"bin", | ||
"lib", | ||
"testy.js" | ||
], | ||
@@ -23,0 +26,0 @@ "directories": { |
@@ -5,4 +5,5 @@ # Testy | ||
\ | ||
[![maintainability](https://img.shields.io/codeclimate/maintainability/ngarbezza/testy?logo=code-climate)](https://codeclimate.com/github/ngarbezza/testy/maintainability) | ||
![tech-debt](https://img.shields.io/codeclimate/tech-debt/ngarbezza/testy?logo=code-climate) | ||
[![maintainability](https://img.shields.io/codeclimate/maintainability/ngarbezza/testy?logo=code-climate)](https://codeclimate.com/github/ngarbezza/testy) | ||
[![tech-debt](https://img.shields.io/codeclimate/tech-debt/ngarbezza/testy?logo=code-climate)](https://codeclimate.com/github/ngarbezza/testy) | ||
[![coverage](https://img.shields.io/codeclimate/coverage/ngarbezza/testy?logo=code-climate)](https://codeclimate.com/github/ngarbezza/testy) | ||
\ | ||
@@ -23,3 +24,3 @@ ![open-issues](https://img.shields.io/github/issues-raw/ngarbezza/testy?logo=github) | ||
A very simple JS testing library, for educational purposes. Live at npm at [@pmoo/testy](https://www.npmjs.com/package/@pmoo/testy). | ||
A very simple JS testing framework, for educational purposes. Live at npm at [@pmoo/testy](https://www.npmjs.com/package/@pmoo/testy). | ||
@@ -196,8 +197,10 @@ :arrow_right: [v4 (legacy version) documentation here](README_v4.md) \ | ||
Why another testing library? The main reason is that we want to keep simplicity, something it's hard to see in the main testing tools out there. | ||
Why another testing tool? The main reason is that we want to keep simplicity, something it's hard to see in the main testing tools out there. | ||
* **Zero dependencies:** right now, this library does not depend on any npm package, making the library easy to install, and fast: essential to have immediate feedback while doing TDD. This is also good for installing on places where the internet connection is not good and we don't want to download hundreds of libraries. | ||
* **Zero dependencies:** right now, this project does not depend on any npm package, making the tool easy to install, and fast: essential to have immediate feedback while doing TDD. This is also good for installing on places where the internet connection is not good and we don't want to download hundreds of libraries. | ||
* **Understandable object-oriented code:** we want to use this tool for teaching, so eventually we'll look at the code during lessons, and students should be able to see what is going on, and even contributing at it, with no dark magic involved. Also, we try to follow good OO practices. | ||
* **Unique set of features:** we are not following any specification nor trying to copy behavior from other approaches (like the "xUnit" or "xSpec" way). | ||
["Design Principles Behind Smalltalk"](https://www.cs.virginia.edu/~evans/cs655/readings/smalltalk.html) is a source of inspiration for this work. We try to follow the same principles here. | ||
## Contributing | ||
@@ -212,12 +215,17 @@ | ||
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> | ||
<!-- prettier-ignore --> | ||
<!-- prettier-ignore-start --> | ||
<!-- markdownlint-disable --> | ||
<table> | ||
<tr> | ||
<td align="center"><a href="https://github.com/JavierGelatti"><img src="https://avatars2.githubusercontent.com/u/993337?v=4" width="100px;" alt="Facundo Javier Gelatti"/><br /><sub><b>Facundo Javier Gelatti</b></sub></a><br /><a href="https://github.com/ngarbezza/testy/commits?author=JavierGelatti" title="Tests">⚠️</a> <a href="https://github.com/ngarbezza/testy/commits?author=JavierGelatti" title="Code">💻</a></td> | ||
<td align="center"><a href="https://codepen.io/TomerBenRachel/"><img src="https://avatars2.githubusercontent.com/u/23402988?v=4" width="100px;" alt="Tomer Ben-Rachel"/><br /><sub><b>Tomer Ben-Rachel</b></sub></a><br /><a href="https://github.com/ngarbezza/testy/commits?author=TomerPacific" title="Tests">⚠️</a> <a href="https://github.com/ngarbezza/testy/commits?author=TomerPacific" title="Code">💻</a></td> | ||
<td align="center"><a href="https://github.com/JavierGelatti"><img src="https://avatars2.githubusercontent.com/u/993337?v=4" width="100px;" alt=""/><br /><sub><b>Facundo Javier Gelatti</b></sub></a><br /><a href="https://github.com/ngarbezza/testy/commits?author=JavierGelatti" title="Tests">⚠️</a> <a href="https://github.com/ngarbezza/testy/commits?author=JavierGelatti" title="Code">💻</a></td> | ||
<td align="center"><a href="https://codepen.io/TomerBenRachel/"><img src="https://avatars2.githubusercontent.com/u/23402988?v=4" width="100px;" alt=""/><br /><sub><b>Tomer Ben-Rachel</b></sub></a><br /><a href="https://github.com/ngarbezza/testy/commits?author=TomerPacific" title="Tests">⚠️</a> <a href="https://github.com/ngarbezza/testy/commits?author=TomerPacific" title="Code">💻</a></td> | ||
<td align="center"><a href="https://github.com/abraaoduarte"><img src="https://avatars2.githubusercontent.com/u/6676804?v=4" width="100px;" alt=""/><br /><sub><b>Abraão Duarte</b></sub></a><br /><a href="https://github.com/ngarbezza/testy/commits?author=abraaoduarte" title="Code">💻</a></td> | ||
<td align="center"><a href="http://adico.tech"><img src="https://avatars0.githubusercontent.com/u/5412270?v=4" width="100px;" alt=""/><br /><sub><b>adico</b></sub></a><br /><a href="https://github.com/ngarbezza/testy/commits?author=adico1" title="Code">💻</a></td> | ||
</tr> | ||
</table> | ||
<!-- markdownlint-enable --> | ||
<!-- prettier-ignore-end --> | ||
<!-- ALL-CONTRIBUTORS-LIST:END --> | ||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! |
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
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
68340
1389
228