Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
@pmoo/testy
Advanced tools
A very simple JS testing framework, for educational purposes. Live at npm at @pmoo/testy.
:arrow_right: Documentación en español aquí :construction_worker: Contributing guidelines
npm install --save-dev @pmoo/testy
(if you use npm)
yarn add --dev @pmoo/testy
(if you use yarn)
Supported Node versions: 12.x or higher (versions with active and security support listed here)
A test suite is a file ending _test.js
that looks like this:
// my_test.js
const { suite, test, assert } = require('@pmoo/testy');
suite('a boring test suite', () => {
test('42 is 42, not surprising', () => {
assert.that(42).isEqualTo(42);
});
});
A test suite represents a grouping of tests, and it is implemented as a function call to suite
passing a name and a zero-argument function, which is the suite body.
A test is implemented as a function call to test()
, passing a name and the test body as a zero-argument function.
Inside the test you can call different assertions that are documented in detail later on.
You can run an individual test file using:
$ npx testy my_test.js
Or, you can run it without arguments to run all the tests (by default it looks on a tests
folder located in the project root):
$ npx testy
You can also add it as the test
script for npm/yarn in your package.json
:
{
...
"scripts": {
"test": "npx testy"
},
...
}
And then run the tests using npm test
or yarn test
.
Testy will look for a .testyrc.json
configuration file in the project root directory. You can use this configuration as a template (values here are the defaults):
{
"directory": "./tests", // directory including your test files
"filter": ".*_test.js$", // which convention to use to recognize test files
"language": "en", // language of the output messages. "es" and "en" supported for now
"failFast": false, // enable/disable fail fast mode (stop as soon as a failed test appears)
"randomOrder": false // enable/disable execution of tests in random order
}
These are all the configuration parameters you can set. Feel free to change it according to your needs.
When declaring this configuration, every test suite under the tests
directory (matching files ending with *test.js
) will be executed.
There must be at least one assertion on the test to be valid. These are all the supported assertion types:
assert.that(boolean).isTrue()
or assert.isTrue(boolean)
. It does a strict comparison against true
(object === true
)assert.that(boolean).isFalse()
or assert.isFalse(boolean)
. It does a strict comparison against false
(object === false
)assert.that(actual).isEqualTo(expected)
or assert.areEqual(actual, expected)
.assert.that(actual).isNotEqualTo(expected)
or assert.areNotEqual(actual, expected)
assert
module) and fail if objects under comparison have circular references.isEqualTo(expected, criteria)
or areEqual(actual, expected, criteria)
actual
object understands: isEqualTo(expected, 'myEqMessage')
or areEqual(actual, expected, 'myEqMessage')
actual
has an equals
method it will be used.undefined
with undefined
using isEqualTo()
, it will make the test fail. For explicit check for undefined
, use the isUndefined()
/isNotUndefined()
assertions documented above.assert.that(actual).isIdenticalTo(expected)
or assert.areIdentical(actual, expected)
assert.that(actual).isNotIdenticalTo(expected)
or assert.areNotIdentical(actual, expected)
===
operator.undefined
presence/absence:
assert.that(aValue).isUndefined()
or assert.isUndefined(aValue)
assert.that(aValue).isNotUndefined()
or assert.isNotUndefined(aValue)
null
presence/absence:
assert.that(aValue).isNull()
or assert.isNull(aValue)
assert.that(aValue).isNotNull()
or assert.isNotNull(aValue)
assert.that(() => { ... }).raises(error)
or with regex .raises(/part of message/)
assert.that(() => { ... }).doesNotRaise(error)
assert.that(() => { ... }).doesNotRaiseAnyErrors()
assert.that(aNumber).isNearTo(anotherNumber)
. There's a second optional argument that indicates the number of digits to be used for precision. Default is 4
.assert.that(string).matches(regexOrString)
or assert.isMatching(string, regexOrString)
assert.that(collection).includes(object)
assert.that(collection).doesNotInclude(object)
assert.that(collection).includesExactly(...objects)
assert.that(collection).isEmpty()
or assert.isEmpty(collection)
assert.that(collection).isNotEmpty()
or assert.isNotEmpty(collection)
Array
, a String
or a Set
Please take a look at the tests
folder, you'll find examples of each possible test you can write. Testy is self-tested.
If you don't have a NPM project you can install testy globally using npm install -g testy
and then run testy <files>
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:
const { suite, test, assert, before, after } = require('@pmoo/testy');
suite('using the before() and after() helpers', () => {
let answer;
before(() => {
answer = 42;
});
test('checking the answer', () => {
assert.that(answer).isEqualTo(42);
});
after(() => {
answer = undefined;
});
});
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:
const { suite, test, assert, before } = require('@pmoo/testy');
const promiseOne = async () => Promise.resolve(42);
const promiseTwo = async () => Promise.resolve(21);
suite('using async & await', () => {
let answerOne;
before(async () => {
answerOne = await promiseOne();
});
test('comparing results from promises', async () => {
const answerTwo = await promiseTwo();
assert.that(answerOne).isEqualTo(42);
assert.that(answerTwo).isEqualTo(21);
});
});
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.
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.
Strict check for assertions: if a test does not evaluate any assertion while it is executed, the result is considered an error. Basically, a test with no assertion is considered a "bad" test.
Explicitly failing or marking a test as pending: there's a possibility of marking a test as failed or pending, for example:
const { suite, test, fail, pending } = require('@pmoo/testy');
suite('marking tests as failed and pending', () => {
test('marking as failed', () =>
fail.with('should not be here'));
test('marking as pending', () =>
pending.dueTo('did not have time to finish'));
});
The output includes the messages provided:
[FAIL] marking as failed
=> should not be here
[WIP] marking as pending
=> did not have time to finish
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.
"Design Principles Behind Smalltalk" is a source of inspiration for this work. We try to follow the same principles here.
Please take a look at the Contributing section.
Thanks goes to these wonderful people (emoji key):
Facundo Javier Gelatti ⚠️ 💻 | Tomer Ben-Rachel ⚠️ 💻 | Abraão Duarte 💻 | adico 💻 ⚠️ | Askar Imran 💻 ⚠️ | Nigel Yong 💻 | Chelsie Ng 💻 |
Pablo T ⚠️ 💻 | Francisco Jaimes Freyre 💻 ⚠️ 📖 | giovannipessiva 🌍 | Abhishek Khatri 💻 |
This project follows the all-contributors specification. Contributions of any kind welcome!
[6.1.0] - 2022-07-13
async
/await
in test definitions.[bug] multiple before() or after() empty blocks can be added to a test suite
[bug] swallowed/not precise exception when before() or after() fails
FAQs
A minimal testing framework, for educational purposes.
We found that @pmoo/testy demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.