Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
brittle
Advanced tools
Readme
tap à la mode
A TAP test runner built for modern times.
First install brittle from npm
npm i brittle
Then start writing tests
import test from 'brittle'
test('basic', function (t) {
t.is(typeof Date.now(), 'number')
t.not(typeof Date.now(), 'string')
t.ok(Date.now() > 0)
t.absent(null)
t.comment('text')
t.alike({ a: 1 }, { a: 1 })
t.unlike({ a: 2 }, { a: 3 })
t.pass()
t.fail()
})
test('asynchronous', async function (t) {
await new Promise(r => setTimeout(r, 250))
t.pass()
})
test('plans', function (t) {
t.plan(2)
t.pass()
setTimeout(() => t.pass(), 250)
})
test('classic subtest', function (t) {
t.test('subtest', function (sub) {
sub.plan(1)
sub.pass()
})
})
test('inverted subtest', function (t) {
const sub = t.test('subtest')
sub.plan(1)
sub.pass()
})
test('executions', async function (t) {
t.execution(() => 'should not throw')
await t.execution(async () => 'should not reject')
})
test('exceptions', async function (t) {
t.exception(() => { throw Error('expected to throw') })
await t.exception(async () => { throw Error('expected to reject') })
})
const a = test('inverted test without plan needs end()')
a.pass()
a.end()
const b = test('inverted test with plan')
b.plan(1)
b.pass()
const c = test('inverted tests can be awaited')
c.plan(1)
setTimeout(() => c.pass(), 250)
await c
Every assertion can have a message, i.e. t.pass('msg')
, t.ok(false, 'should be true')
, etc.
There are also utilities like t.timeout(ms)
, t.teardown(fn)
, etc.
Check the API but also all the assertions here and utilities here.
import { test, solo, skip, todo, configure } from 'brittle'
test([name], [options], callback)
Create a classic test with an optional name
.
options
for any test creation:timeout
(30000
) - milliseconds to wait before ending a stalling test.solo
(false
) - Skip all other tests except the solo()
ones.skip
(false
) - skip this test, alternatively use the skip()
function.todo
(false
) - mark this test as todo and skip it, alternatively use the todo()
function.The callback
function (can be async) receives an object called assert
.
assert
(or t
) provides the assertions and utilities interface.
import test from 'brittle'
test('basic', function (t) {
t.pass()
})
Test files can be executed directly with node
, as they're normal Node.js programs.
The test
method is conveniently both the default export and named exported method:
import { test } from 'brittle'
Classic tests will run sequentially, buffering pending tests until any prior test catches up.
Any test function returns a promise so you can optionally await for its result:
const isOk = await test('basic', function (t) {
t.pass()
})
test([name], [options]) => assert
Create an inverted test with an optional name
.
All options
for inverted tests are listed here.
An object called assert
(or t
) is returned, the same as the classic test.
This time it's also a promise, it can be awaited and it resolves at test completion.
import test from 'brittle'
const t = test('basic')
t.plan(1)
setTimeout(() => {
t.pass()
}, 1000)
await t // Won't proceed past here until plan is fulfilled
For inverted tests without a plan, the end
method must be called:
const t = test('basic')
setTimeout(() => {
t.pass()
t.end()
}, 1000)
await t
The end()
method can be called inline, for inverted tests without a plan:
const t = test('basic')
t.pass()
t.end()
Control flow of inverted is entirely dependent on where its assert
is awaited.
The following executes one test after another:
const a = test('first test')
const b = test('second test')
a.plan(1)
b.plan(1)
a.pass()
await a
b.pass()
await b
Awaiting the promise gives you its result:
const t = test('first test')
t.plan(1)
t.pass()
const isOk = await t
t.test([name], [options], callback)
t.test([name], [options]) => assert
A subtest can be created by calling test
on an assert
(or t
) object.
This will provide a new sub-assert object.
All options
for subtests are listed here.
Using this in inverted style can be very useful for flow control within a test:
test('basic', async function (t) {
const a = t.test('sub test')
const b = t.test('other sub test')
a.plan(1)
b.plan(1)
setTimeout(() => a.ok(true), Math.random() * 1000)
setTimeout(() => b.ok(true), Math.random() * 1000)
// Won't proceed past here until both a and b plans are fulfilled
await a
await b
t.pass()
})
Subtest test options can be set by passing an object to the test
function:
test('parent', { timeout: 1000 }, function (t) {
t.test('basic using parent config', async function (t) {
await new Promise(r => setTimeout(r, 500))
t.pass()
})
t.test('another basic using parent config', function (t) {
t.pass()
})
})
You can also await for its result as well:
test('basic', async function (t) {
t.plan(1)
t.pass()
const isOk = await t
console.log(isOk)
})
solo([name], [options], callback)
solo([name], [options]) => assert
Filter out other tests by using the solo
method:
import { test, solo } from 'brittle'
test('this test is skipped', function (t) {
t.pass()
})
solo('some test', function (t) {
t.pass()
})
If a solo
function is used, test
functions will not execute.\
If solo
is used in a future tick (for example, in a setTimeout
callback),
after test
has already been used those tests won't be filtered.
A few ways to enable solo
functions:
configure({ solo: true })
before any tests.solo()
without callback underneath the imports.--solo
flag with the brittle
test runner.It can also be used as an inverted test:
const t = test.solo('inverted some test')
t.pass()
t.end()
skip([name], [options], callback)
Skip a test:
import { test, skip } from 'brittle'
skip('this test is skipped', function (t) {
t.pass()
})
test('middle test', function (t) {
t.pass()
})
test.skip('another skipped test', function (t) {
t.pass()
})
Only the middle test
will be executed.
configure([options])
The configure
function can be used to set options for all tests (including child tests).
It must be executed before any tests.
timeout
(30000
) - milliseconds to wait before ending a stalling testbail
(false
) - exit the process on first test failuresolo
(false
) - skip all other tests except the solo()
onessource
(true
) - shows error source
informationimport { configure } from 'brittle'
configure({ timeout: 15000 }) // All tests will have a 15 seconds timeout
t.is(actual, expected, [message])
Compare actual
to expected
with ===
t.not(actual, expected, [message])
Compare actual
to expected
with !==
t.alike(actual, expected, [message])
Object comparison, comparing all primitives on the
actual
object to those on the expected
object
using ===
.
t.unlike(actual, expected, [message])
Object comparison, comparing all primitives on the
actual
object to those on the expected
object
using !==
.
t.ok(value, [message])
Checks that value
is truthy: !!value === true
t.absent(value, [message])
Checks that value
is falsy: !!value === false
t.pass([message])
Asserts success. Useful for explicitly confirming that a function was called, or that behavior is as expected.
t.fail([message])
Asserts failure. Useful for explicitly checking that a function should not be called.
t.exception(Promise|function|async function, [error], [message])
Verify that a function throws, or a promise rejects.
t.exception(() => { throw Error('an err') }, /an err/)
await t.exception(async () => { throw Error('an err') }, /an err/)
await t.exception(Promise.reject(Error('an err')), /an err/)
If the error is an instance of any of the following native error constructors, then this will still result in failure since native errors often tend to be unintentational.
SyntaxError
ReferenceError
TypeError
EvalError
RangeError
If a t.exception
is async, then you're supposed to await it.
t.exception.all(Promise|function|async function, [error], [message])
Verify that a function throws, or a promise rejects, including native errors.
t.exception.all(() => { throw Error('an err') }, /an err/)
await t.exception.all(async () => { throw Error('an err') }, /an err/)
await t.exception.all(Promise.reject(new SyntaxError('native error')), /native error/)
The t.exception.all
method is an escape-hatch so it can be used with the
normally filtered native errors.
If a t.exception.all
is async, then you're supposed to await it.
t.execution(Promise|function|async function, [message])
Assert that a function executes instead of throwing or that a promise resolves instead of rejecting. Resolves to the execution time, in milliseconds, of the function or promise.
t.execution(() => {})
await t.execution(async () => {})
await t.execution(Promise.resolve('cool'))
If a t.execution
is async, then you're supposed to await it
t.is.coercively(actual, expected, [message])
Compare actual
to expected
with ==
.
t.not.coercively(actual, expected, [message])
Compare actual
to expected
with !=
.
t.alike.coercively(actual, expected, [message])
Object comparison, comparing all primitives on the
actual
object to those on the expected
object
using ==
.
t.unlike.coercively(actual, expected, [message])
Object comparison, comparing all primitives on the
actual
object to those on the expected
object
using !=
.
t.plan(n)
Constrain a test to an explicit amount of assertions.
t.teardown(function|async function, [options])
options
for teardowns:order
(0
) - set the ascending position priority for a teardown to be executed.The function passed to teardown
is called right after a test ends:
test('basic', function (t) {
const timeoutId = setTimeout(() => {}, 1000)
t.teardown(async function () {
clearTimeout(timeoutId)
await doMoreCleanUp()
})
t.ok('cool')
})
If teardown
is called multiple times in a test, every function passed will be called after the test ends:
test('basic', function (t) {
t.teardown(doSomeCleanUp)
const timeoutId = setTimeout(() => {}, 1000)
t.teardown(() => clearTimeout(timeoutId))
t.ok('again, cool')
})
Set order: -Infinity
to always be in first place, and vice versa with order: Infinity
.
If two teardowns have the same order
they are ordered per time of invocation within that order group.
test('teardown order', function (t) {
t.teardown(async function () {
await new Promise(r => setTimeout(r, 200))
console.log('teardown B')
})
t.teardown(async function () {
await new Promise(r => setTimeout(r, 200))
console.log('teardown A')
}, { order: -1 })
t.teardown(async function () {
await new Promise(r => setTimeout(r, 200))
console.log('teardown C')
}, { order: 1 })
t.pass()
})
The A
teardown is executed first, then B
, and finally C
due to the order
option.
t.timeout(ms)
Fail the test after a given timeout.
t.comment(message)
Inject a TAP comment into the output.
t.end()
Force end a test.
end
is determined by assert
resolution or when a containing async function completes.
In case of inverted tests, they're required to be explicitly called.
The default timeout is 30 seconds.
package.json
with test
scriptThe following would run all .js
files in the test folder:
{
"name": "my-app",
"version": "1.0.0",
"scripts": {
"test": "brittle test/*.js"
},
"devDependencies": {
"brittle": "^3.0.0-alpha.3"
}
}
npm install -g brittle@next
brittle [flags] [<files>]
Flags:
-cov, --coverage Turn on coverage
--bail Bail out on first assert failure
--solo Engage solo mode
-r, --runner <out> <targets> Generates an out file that contains all target tests
Note globbing is supported:
brittle --coverage path/to/test/*.js
Auto generate a single file containing "all tests":
brittle -r test/all.js test/*.js
node test/all.js
You can use an environment variable to also set flags:
BRITTLE="--coverage --bail" brittle test.js
Force disable coverage with an environment variable:
BRITTLE_COVERAGE=false brittle test.js
Apache-2.0
FAQs
A TAP test runner built for modern times
The npm package brittle receives a total of 1,446 weekly downloads. As such, brittle popularity was classified as popular.
We found that brittle demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers 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
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.