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.
banana-shark
Advanced tools
Readme
A JavaScript unit test runner.
Designed to be:
banana-shark tests are expressed as JavaScript modules that export a single
function with one describe
parameter:
module.exports = describe => {
describe(
'one hundred and twenty three', // name (optional)
() => 123, // factory
it => it.equals(123) // assertion
)
}
describe
takes an optional name as its first argument, followed by a factory
function that creates a subject, followed by any number of assertions against
the subject, or nested describe blocks.
it
is used to express assertions about the subject
it
provides assertions:
it.equals(expectedValue)
it.deeplyEquals(expectedValue)
it.isGreaterThan(expectedValue)
it.isLessThan(expectedValue)
it.has(propertyName)
it.has(propertyName).that.equals(expectedValue)
it.has(propertyName).that.deeplyEquals(expectedValue)
it.throws()
it.throws(expectedErrorType)
it.throws(expectedErrorType, expectedErrorMessage)
Nested describe
blocks take a another factory (after an optional string name),
which changes the subject by doing something to the result of the outer
block's subject, for example:
describe(
() => 1, // factory
it => it.equals(1), // assertion
describe(
x => x + 2, // factory
it => it.equals(3), // assertion
describe(
x => typeof x, // factory
it => it.equals('string') // assertion
)
)
)
aspects
are abstract specs, in the sense that they have no factories, but
only consist of assertions. Aspects allow specs to be composed of reusable
blocks, for example:
describe(
() => new Man(),
it => it.has('legs')
)
describe(
() => new Dog(),
it => it.has('legs')
)
...can be reduced to:
describe(
() => new Man(),
'is legged'
)
describe(
() => new Dog(),
'is legged'
)
describe.aspect(
'is legged',
it => it.has('legs')
)
Sometimes you need to assert about the same subject after performing some
action on it. describe.after
allows you to express this without awkward return
statements. For example:
describe(
() => [],
describe.after(
array => array.push(123),
it => it.deeplyEquals([123])
)
)
...is equivalent to:
describe(
() => [],
describe(
array => {
array.push(123)
return array
},
it => it.deeplyEquals([123])
)
)
module.exports = describe => {
describe(
() => [],
'is like an empty stack',
describe(
'pushing an item',
stack => stack.push('whatever'),
it => it.equals(1)
),
describe.after(
'pushing undefined',
stack => stack.push(undefined),
'is like a stack with a single undefined item'
),
describe.after(
'pushing 66',
stack => stack.push(66),
'is like a stack with only 66'
)
)
describe(
() => [undefined],
'is like a stack with a single undefined item',
describe.after(
'pushing 66',
stack => stack.push(66),
'is like a stack whose last pushed item was 66'
)
)
describe.aspect(
'is like a stack with a single undefined item',
'can push an item',
'is like a stack with one item',
'returns undefined when popped'
)
describe.aspect(
'is like an empty stack',
'can push an item',
'returns undefined when popped',
'has no items'
)
describe.aspect(
'can push an item',
describe(
'the result of pushing an item',
stack => stack.push(-1),
it => it.isGreaterThan(0)
),
describe.after(
'pushing 66',
stack => stack.push(66),
'is like a stack whose last pushed item was 66'
)
)
describe.aspect(
'returns undefined when popped',
describe(
stack => stack.pop(),
it => it.equals(undefined)
)
)
describe.aspect(
'is like a stack with one item',
'has one item',
describe.after(
'popping an item',
stack => stack.pop(),
'is like an empty stack'
),
describe(
'pushing another item',
stack => stack.push(11),
it => it.equals(2)
),
describe.after(
'pushing another item',
stack => stack.push(77),
it => it.has('length').that.equals(2)
)
)
describe.aspect(
'is like a stack with only 66',
'is like a stack with one item',
'can push an item',
'is like a stack whose last pushed item was 66',
'has one item'
)
describe.aspect(
'is like a stack whose last pushed item was 66',
'has more than zero items',
describe(
stack => stack.pop(),
it => it.equals(66)
)
)
describe.aspect(
'has no items',
it => it.has('length').that.equals(0)
)
describe.aspect(
'has one item',
it => it.has('length').that.equals(1)
)
describe.aspect(
'has more than zero items',
it => it.has('length').that.isGreaterThan(0)
)
}
Running bs
against this spec generates the following output:
() => []
is like an empty stack
can push an item
the result of pushing an item
stack => stack.push(-1)
✔ it => it.isGreaterThan(0)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
returns undefined when popped
stack => stack.pop()
✔ it => it.equals(undefined)
has no items
✔ it => it.has('length').that.equals(0)
pushing an item
stack => stack.push('whatever')
✔ it => it.equals(1)
pushing undefined
after: stack => stack.push(undefined)
is like a stack with a single undefined item
can push an item
the result of pushing an item
stack => stack.push(-1)
✔ it => it.isGreaterThan(0)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
is like a stack with one item
has one item
✔ it => it.has('length').that.equals(1)
popping an item
after: stack => stack.pop()
is like an empty stack
can push an item
the result of pushing an item
stack => stack.push(-1)
✔ it => it.isGreaterThan(0)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
returns undefined when popped
stack => stack.pop()
✔ it => it.equals(undefined)
has no items
✔ it => it.has('length').that.equals(0)
pushing another item
stack => stack.push(11)
✔ it => it.equals(2)
after: stack => stack.push(77)
✔ it => it.has('length').that.equals(2)
returns undefined when popped
stack => stack.pop()
✔ it => it.equals(undefined)
pushing 66
after: stack => stack.push(66)
is like a stack with only 66
is like a stack with one item
has one item
✔ it => it.has('length').that.equals(1)
popping an item
after: stack => stack.pop()
is like an empty stack
can push an item
the result of pushing an item
stack => stack.push(-1)
✔ it => it.isGreaterThan(0)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
returns undefined when popped
stack => stack.pop()
✔ it => it.equals(undefined)
has no items
✔ it => it.has('length').that.equals(0)
pushing another item
stack => stack.push(11)
✔ it => it.equals(2)
after: stack => stack.push(77)
✔ it => it.has('length').that.equals(2)
can push an item
the result of pushing an item
stack => stack.push(-1)
✔ it => it.isGreaterThan(0)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
has one item
✔ it => it.has('length').that.equals(1)
() => [undefined]
is like a stack with a single undefined item
can push an item
the result of pushing an item
stack => stack.push(-1)
✔ it => it.isGreaterThan(0)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
is like a stack with one item
has one item
✔ it => it.has('length').that.equals(1)
popping an item
after: stack => stack.pop()
is like an empty stack
can push an item
the result of pushing an item
stack => stack.push(-1)
✔ it => it.isGreaterThan(0)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
returns undefined when popped
stack => stack.pop()
✔ it => it.equals(undefined)
has no items
✔ it => it.has('length').that.equals(0)
pushing another item
stack => stack.push(11)
✔ it => it.equals(2)
after: stack => stack.push(77)
✔ it => it.has('length').that.equals(2)
returns undefined when popped
stack => stack.pop()
✔ it => it.equals(undefined)
pushing 66
after: stack => stack.push(66)
is like a stack whose last pushed item was 66
has more than zero items
✔ it => it.has('length').that.isGreaterThan(0)
stack => stack.pop()
✔ it => it.equals(66)
46 passed
Asynchronous tests are difficult to express and reason about and have the inherent potential to run slowly and non-deterministically. Synchronous tests take control of time, so they are guaranteed to be deterministic and are generally faster and easier to reason about. In other words, synchronous tests are cheaper to create and maintain than asynchronous tests.
Just because your code is asynchronous it doesn't mean your tests have to be. You just need to avoid depending on global implementations of asynchronous constructs, and use synchronous equivalents in tests.
Unlike other testing tools that support nested contexts, describe
blocks in
banana-shark are not expressed as functions themselves. In other words,
describe
takes the result of describe
as an argument. This subtle
difference means tests are less likely to access shared state and can therefore
be executed concurrently.
// mocha
var assert = require('assert');
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
assert.equal(-1, [1,2,3].indexOf(4));
})
})
})
// banana-shark
describe('Array',
describe('#indexOf()',
describe(
'should return -1 when the value is not present',
() => [1,2,3].indexOf(4),
it => it.equals(-1)
)
)
)
More mocha like-for-like examples can be found under examples
FAQs
A JavaScript unit test runner
The npm package banana-shark receives a total of 3 weekly downloads. As such, banana-shark popularity was classified as not popular.
We found that banana-shark demonstrated a not healthy version release cadence and project activity because the last version was released 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
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.