@stackbuilders/assertive-ts v1.4.0
AssertiveTS
A type-safe fluent assertion library written in TypeScript and inspired by Jest assertions and the popular AssertJ.
This library is designed to work in the browser and in Node.js. It ships with a rich set of expressive and flexible matchers that allows chaining multiple assertions. AssertiveTS is framework agnostic and should be used with a test framework such as Jest, Mocha, or Ava.
Type-safe library
A distinctive feature of AssertiveTS with other assertion libraries is that it leverages the TypeScript compiler to avoid type coercions and mismatches. It also infers the static type of the value you want to assert and provides you with intelligent matcher completion and signature help so that you can write code more quickly and correctly.
Features
- Type safety and intelligent matcher completion
- Rich set of expressive and flexible matchers
- Concise, chainable interface inspired by AssertJ
- Works with any test runner and framework such as Jest, Mocha, or Ava
- Well tested: more than 300 tests!
Install
npm install --save-dev @stackbuilders/assertive-ts
Or:
yarn add --dev @stackbuilders/assertive-ts
Usage
Import the library in your test script:
import { expect } from "@stackbuilders/assertive-ts"
Use the expect
function along with a "matcher" function on the value you want to assert:
expect(sum(1, 2)).toBeEqual(3);
To assert the opposite, just add .not
before a matcher:
expect(sum(1, 2)).not.toBeNull();
With assertive-ts
you can use fluent assertions, which means you can chain multiple matcher functions to the same value under test:
expect("assertive-ts is awesome!")
.toStartWith("assertive-ts")
.not.toContain("unsafe")
.toEndWith("awesome!");
The matcher functions depend on the type of the value on the expect
. If you're using TypeScript, the compiler will let you know if something is not available for that assertion:
// Boolean assertion
expect(isEven(2)).toBeTrue();
// String assertion
expect("foobar").toStartWith("foo");
// Number assertion
expect(sum(1, 2)).toBePositive();
expect(14).toEndWith("4");
^ ? type error: `toEndWith` does not exist in `NumberAssertion`
For a list of all matchers and extended documentation, please refer to the API documentation.
Type Factory 🏭
A great feature of AssertiveTS is the type safety across the API. But, what should you do if you want to check the value under test is of some specific type during runtime? The answer is simple, AssertiveTS provides a .asType(TypeFactory)
method, where the TypeFactory parameter lets you check for the specific type and narrow the assertion instance to a more specific one. To make things simpler, AssertiveTS provides TypeFactories for the basic types:
import { expect, TypeFactories } from "@stackbuilders/assertive-ts";
expect(value)
.asType(TypeFactories.String)
.toBeEmpty();
expect(list)
.asType(TypeFactories.array(TypeFactories.Number))
.toHaveSameMembers([1, 2, 3, 4, 5]);
If the built-in type factories are not enough to assert your specific type, you can always create your own factory. A TypeFactory<S, A>
is nothing more than an object with 3 properties:
Factory: new(actual: S) => A
- The specific assertion constructor to return if the predicate is true. WhereS
is the actual value type, andA
is the type of the assertion to return (A
should extend fromAssertion<S>
).predicate(value: unknown): value is S
- A predicate function that checks if the value is of the expected type.typeName: string
- The name of the checked type. Used to make the assertion error message clearer.
So, using a custom TypeFactory
can look like the following:
interface Point3D {
x: number;
y: number;
z: number;
}
expect(maybePoint).asType({
Factory: ObjectAssertion<Point3D>,
predicate: (value): value is Point3D => {
return typeof value === "object"
&& value !== null
&& "x" in value
&& "y" in value
&& "z" in value
&& Object.values(value).every(v => typeof v === "number");
},
typeName: "Point3D"
});
Handling TypeScript Unions
Union types are a TypeScript concept that is only applicable at type level. During runtime, the value can only be one of the types. For instance, if we say const foo: number | string = ...
, at runtime foo
will be either a number
or a string
. If you want to use a more specific assertion on a union type, you can use .asType(..)
to first assert the expected type, and then move forward with more assertions:
const foo: number | string = 5;
expect(foo)
.asType(TypeFactories.Number)
.toBePositive();
Help! The value can also be null
or undefined
When a value can be also null
or undefined
, we're going over the same concept as Union types. So if you want to make more specific assertions over a value that can be null | undefined
, just use .asType(..)
first:
const bar: string | null | undefined = " ";
expect(bar)
.asType(TypeFactories.String)
.toBeBlank();
Test Runner Integration
API Reference
You can find the full API reference here
Coming Soon
- Extension mechanism ⚙️
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
License
MIT, see the LICENSE file.
Contributing
Do you want to contribute to this project? Please take a look at our contributing guideline to know how you can help us build it.