You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[Guide: How to Create a Custom Assertion][create-a-custom-assertion]
17
+
11
18
## Motivation
12
19
20
+
> "_Another_ assertion library? Are you daft? My test framework has its own assertions!"
21
+
>
22
+
> ‒sickos, probably
23
+
13
24
Look, I'm ~~old~~~~wizened~~~~experienced~~ knowledegable and I've written a lot of tests. I've used a lot of assertion libraries. There are ones I prefer and ones I don't.
14
25
15
26
But none of them do quite what _this_ does. The main goals of this library are:
@@ -20,15 +31,15 @@ But none of them do quite what _this_ does. The main goals of this library are:
20
31
21
32
A chainable API may provide type safety. But it seems to _guarantee_ implementing a custom assertion will be complicated. The API surface is necessarily a combinatoric explosion of methods.
22
33
23
-
> [!WARNING]
34
+
> ⚠️ **Caution!**
24
35
>
25
-
> Because chainable APIs are familiar, you may hate _BUPKIS_ once you see some examples. You don't have to use it, but please: _don't confuse familiarity with usability_.
36
+
> Because chainable APIs are familiar, you may hate _BUPKIS_ once you see some examples. Nobody's making you use it. But please, keep an open mind & give me this grace: _don't confuse familiarity with usability_.
26
37
27
-
To achieve these goals, I've adopted the following design principles:
38
+
To achieve these goals, _BUPKIS_ makes the following design choices.
28
39
29
-
### Natural-Language Assertions
40
+
### Assertions are Natural Language
30
41
31
-
In `bupkis` (stylized as "_BUPKIS_"), you **don't** write this:
42
+
When you're using _BUPKIS_, you **don't** write this:
32
43
33
44
```js
34
45
expect(actual).toEqual(expected);
@@ -60,98 +71,115 @@ Then _BUPKIS_ wants you to write:
60
71
61
72
```js
62
73
expect(actual, 'to be a string');
63
-
// it is tolerant of poor/ironic grammar
74
+
// it is tolerant of poor/ironic grammar, sometimes
64
75
expect(actual, 'to be an string');
65
76
```
66
77
67
-
Can't remember the string? Did you forget a word or make a typo? Maybe you also forgot _BUPKIS_ is type-safe? You'll get a nice squiggly for your trouble.
78
+
Can't remember the string? Did you forget a word or make a typo? Maybe you also forgot **_BUPKIS_ is type-safe?** You'll get a nice squiggly for your trouble. This isn't black magic. It ain't a _cauldron_. We're not just _throwing rat tails and `string`s in there._
79
+
80
+
> "Preposterous! Codswallop!"
81
+
>
82
+
> ‒the reader and/or more sickos
83
+
84
+
Right—how could this be anything by loosey-goosey _senselessness_? I beg to differ; _BUPKIS_ is nothing if not _intentional_.
85
+
86
+
The first parameter to a _BUPKIS_ assertion is always the _subject_ ([def.](https://bupkis.zip/documents/Reference.Glossary_of_Terms#subject)).
68
87
69
-
The "string" part of an expectation is known as a _phrase_. Every expectation will contain, at minimum, one phrase. As you can see from the above example, phrases often have aliases.
88
+
The "string" part of a _BUPKIS_ assertion is known as a _phrase_. Every expectation will contain_at minimum_ one (1) phrase. As you can see from the above "to be a string" example, phrases often have aliases.
70
89
71
-
You can negate just about any phrase:
90
+
Assertions may have multiple phrases or parameters, but the simplest assertions always look like this:
One more convention worth mentioning is _negation_.
103
+
104
+
You can _negate_ just about any phrase by prepending it with `not` and a space. For example:
72
105
73
106
```js
74
107
expect(actual, 'to be', expected);
75
-
// did they not teach grammar in nerd school??
76
-
expect(actual, 'not is', expected);
108
+
expect(actual, 'not to be', expected);
77
109
78
110
expect(
79
111
() =>thrownewTypeError('aww, shucks'),
80
-
'to throw a',
112
+
'not to throw a',
81
113
TypeError,
82
-
'not satisfying',
114
+
'satisfying',
83
115
/gol durn/,
84
116
);
85
117
```
86
118
87
-
### Custom Assertions
119
+
### Custom Assertions by Zod
88
120
89
-
In _BUPKIS_, custom assertions are _first-class citizens_. You can create your own assertions with minimal boilerplate. You don't have to learn a new API or a new DSL (maybe); you just use [Zod][]. _It's so easy, even a **archaic human** could do it!_
121
+
[Zod][] is a popular object validation library which does some heavy lifting for _BUPKIS_. In fact, its fundamentals get us _most_ of the way to a type-safe assertion library!
90
122
91
-
Read [Guide: How to Create a Custom Assertion](https://boneskull.github.io/bupkis/documents/Guides.How_to_Create_a_Custom_Assertion) to learn more.
123
+
So We recognized that many (most?) custom assertions can be _implemented as Zod schemas._
92
124
93
-
## Prerequisites
125
+
Here's a ~~stupid~~ ~~quick~~ _stupid_ example of a creating and "registering" a basic assertion _which can be invoked using two different phrases_:
126
+
127
+
```ts
128
+
import { z, use, createAssertion } from'bupkis';
94
129
95
-
_BUPKIS_ requires **Node.js ^20.19.0 || ^22.12.0 || >=23** and ships as a dual CJS/ESM package.
130
+
conststringAssertion=createAssertion(
131
+
z.string(),
132
+
[['to be based', 'to be bussin']],
133
+
z.string(),
134
+
);
96
135
97
-
The library has been designed for Node.js environments and testing frameworks.
136
+
const { expect } =use([stringAssertion]);
98
137
99
-
## Installation
138
+
expect('chat', 'to be based');
139
+
expect('fam', 'to be bussin');
100
140
101
-
```bash
102
-
npm install bupkis -D
141
+
// did you know? includes all builtin assertions!
142
+
expect('skiball lavatory', 'to be a string');
103
143
```
104
144
105
-
## Usage
145
+
**If you can express it in Zod, you can make it an assertion.** There's also a [function-based API][custom-assertion-function] for use with [parametric][] and behavioral assertions.
106
146
107
-
Here:
147
+
👉 For a thorough guide on creating assertions, read [Guide: How to Create a Custom Assertion][create-a-custom-assertion].
108
148
109
-
```ts
110
-
import { expect } from'bupkis';
111
-
112
-
// Basic type assertions
113
-
expect('hello', 'to be a string');
114
-
expect(42, 'to be a number');
115
-
expect(true, 'to be a boolean');
116
-
117
-
// Value comparisons
118
-
expect(10, 'to equal', 10);
119
-
expect('hello world', 'to contain', 'world');
120
-
expect([1, 2, 3], 'to have length', 3);
121
-
122
-
// Negation
123
-
expect(42, 'not to be a string');
124
-
expect('hello', 'not to equal', 'goodbye');
125
-
126
-
// Object assertions
127
-
const user = { name: 'Alice', age: 30 };
128
-
expect(user, 'to be an object');
129
-
expect(user, 'to have property', 'name');
130
-
expect(user, 'to satisfy', { name: 'Alice' });
131
-
```
149
+
## Prerequisites
132
150
133
-
For comprehensive documentation and guides, visit the [project documentation](https://boneskull.github.io/bupkis/).
151
+
**Node.js**: ^20.19.0, ^22.12.0, >=23
134
152
135
-
### Worth Mentioning Right Now
153
+
_BUPKIS_ has a peer dependency on [Zod][] v4+, but will install it as an optional dependency if you are not already using it.
136
154
137
-
_BUPKIS_has two main exports:
155
+
_BUPKIS_ ships as a dual CJS/ESM package.
138
156
139
-
-`expect()`: the main entrypoint for synchronous assertions
140
-
-`expectAsync()`: the main entrypoint for asynchronous assertions
157
+
> Disclaimer: _BUPKIS_ has been designed to run on Node.js in a development environment. Anyone attempting to deploy _BUPKIS_ to some server somewhere will get what is coming to them.
141
158
142
-
> [!IMPORTANT]
143
-
>
144
-
> As of this writing, the assertions available in `expectAsync()` are all `Promise`-related (and custom assertions can even use an async schema for the subject); they are completely disjoint from the assertions available in `expect()`. **This will likely change in the future.**
159
+
## Installation
145
160
146
-
## Project Scope
161
+
```bash
162
+
npminstallbupkis-D
163
+
```
147
164
148
-
1. It's an assertion library
165
+
## Usage
149
166
150
-
## Prior Art & Appreciation
167
+
👉 See the [Basic Usage Guide](https://bupkis.zip/documents/guides.basic_usage) for a quick introduction.
168
+
169
+
📖 Visit [https://bupkis.zip](https://bupkis.zip) for comprehensive guides and reference.
170
+
171
+
## Acknowledgements
151
172
152
173
- [Unexpected][] is the main inspiration for _BUPKIS_. However, creating types for this library is exceedingly difficult (and was in fact the first thing I tried). Despite that drawback, I find it more usable than any other assertion library I've tried.
153
-
-[Zod][] is a popular object validation library which does most of the heavy lifting for _BUPKIS_. It's not an assertion library, but there's enough overlap in its use case that it makes sense to leverage it.
154
-
-[fast-check][]: A big thanks to Nicholas Dubien for this library. There is **no better library** for an assertion library to use to test itself! Well, besides itself, I mean. How about _in addition to_ itself? Yes. Thank you!
174
+
- [Zod][] is a popular object validation library upon which _BUPKIS_ builds many of its own assertions.
175
+
- [fast-check][]: Thanks to Nicholas Dubien for this library. There is **no better library** for an assertion library to use to test itself! Well, besides itself, I mean. How about _in addition to_ itself? Yes. Thank you!
176
+
- [tshy][] from Isaac Schlueter. Thanks for making dual ESM/CJS packages easy and not too fancy.
177
+
- [TypeDoc][] it really documents the hell out of TypeScript projects.
178
+
- [@cjihrig](https://github.com/cjihrig) and other Node.js contributors for the thoughtfulness put into [`node:test`](https://nodejs.org/api/test.html) that make it my current test-runner-of-choice.
179
+
180
+
## Why is it called _BUPKIS_?
181
+
182
+
TODO: think of good reason and fill in later
155
183
156
184
## A Note From The Author
157
185
@@ -164,5 +192,13 @@ _BUPKIS_ has two main exports:
0 commit comments