Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"permissions": {
"allow": [
"Bash(git checkout:*)",
"Bash(git add:*)",
"Bash(git commit:*)",
"Bash(git push:*)",
"Bash(gh pr create:*)",
"Bash(bun test:*)"
]
}
}
94 changes: 94 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -456,3 +456,97 @@ describe('sum()', () => {
});
});
```

## Bun

[Bun](https://bun.sh/) has a fast, built-in test runner that is Jest-compatible. Riteway provides a Bun adapter so you can use the familiar `assert` API with Bun's test runner.

### Installing

First, make sure you have Bun installed. Then install Riteway into your project:

```shell
bun add --dev riteway
```

### Setup

Before using `assert`, you need to call `setupRitewayBun()` once to register the custom matcher. We recommend doing this in a global setup file using Bun's `preload` option.

Create a setup file (e.g., `test/setup.ts`):

```ts
import { setupRitewayBun } from 'riteway/bun';

setupRitewayBun();
```

Then configure Bun to preload it. Add to your `bunfig.toml`:

```toml
[test]
preload = ["./test/setup.ts"]
```

Or specify it via CLI:

```shell
bun test --preload ./test/setup.ts
```

### Usage

In your test files, import `test`, `describe`, and `assert` from `riteway/bun`:

```ts
import { test, describe, assert } from 'riteway/bun';
```

Then run your tests with `bun test`:

```shell
bun test
```

### Example

```ts
import { test, describe, assert } from 'riteway/bun';

// a function to test
const sum = (...args) => {
if (args.some(v => Number.isNaN(v))) throw new TypeError('NaN');
return args.reduce((acc, n) => acc + n, 0);
};

describe('sum()', () => {
test('given: no arguments, should: return 0', () => {
assert({
given: 'no arguments',
should: 'return 0',
actual: sum(),
expected: 0
});
});

test('given: two numbers, should: return the correct sum', () => {
assert({
given: 'two numbers',
should: 'return the correct sum',
actual: sum(2, 3),
expected: 5
});
});
});
```

### Failure Output

When a test fails, the error message includes the `given` and `should` context:

```
error: Given two different numbers: should be equal

Expected: 43
Received: 42
```
19 changes: 19 additions & 0 deletions bun.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
declare module 'riteway/bun' {
interface Assertion<T> {
readonly given: string;
readonly should: string;
readonly actual: T;
readonly expected: T;
}

export function assert<T>(assertion: Assertion<T>): void;

/**
* Setup function to extend Bun's expect with a custom RITEway matcher.
* Call this once in your test setup file or at the top of test files.
*/
export function setupRitewayBun(): void;

// Re-export test and describe from bun:test
export { test, describe } from 'bun:test';
}
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"import": "./source/vitest.js",
"types": "./vitest.d.ts"
},
"./bun": {
"import": "./source/bun.js",
"types": "./bun.d.ts"
},
"./match": {
"import": "./source/match.js",
"types": "./match.d.ts"
Expand Down
43 changes: 43 additions & 0 deletions source/bun.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect, test, describe } from 'bun:test';

export { test, describe };

const requiredKeys = ['given', 'should', 'actual', 'expected'];

/**
* Setup function to extend Bun's expect with a custom RITEway matcher.
* Call this once in your test setup file or at the top of test files.
*/
export const setupRitewayBun = () => {
expect.extend({
toRitewayEqual(received, expected, given, should) {
const pass = this.equals(received, expected);

if (pass) {
return { pass: true };
}

return {
pass: false,
message: () =>
`Given ${given}: should ${should}\n\nExpected: ${this.utils.printExpected(expected)}\nReceived: ${this.utils.printReceived(received)}`,
};
},
});
};

/**
* Assert function compatible with Bun's expect, using the custom matcher.
* @param {Object} args - Assertion object with given, should, actual, expected.
*/
export const assert = (args = {}) => {
const missing = requiredKeys.filter((k) => !Object.keys(args).includes(k));
if (missing.length) {
throw new Error(
`The following parameters are required by \`assert\`: ${missing.join(', ')}`
);
}

const { given, should, actual, expected } = args;
expect(actual).toRitewayEqual(expected, given, should);
};
50 changes: 50 additions & 0 deletions source/bun.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { test, describe, assert, setupRitewayBun } from './bun.js';

setupRitewayBun();

describe('riteway/bun', () => {
test('given: matching primitives, should: pass', () => {
assert({
given: 'two identical numbers',
should: 'be equal',
actual: 42,
expected: 42,
});
});

test('given: matching strings, should: pass', () => {
assert({
given: 'two identical strings',
should: 'be equal',
actual: 'hello',
expected: 'hello',
});
});

test('given: matching objects, should: pass', () => {
assert({
given: 'two identical objects',
should: 'be deeply equal',
actual: { name: 'Bun', version: 1.1 },
expected: { name: 'Bun', version: 1.1 },
});
});

test('given: matching arrays, should: pass', () => {
assert({
given: 'two identical arrays',
should: 'be deeply equal',
actual: [1, 2, 3],
expected: [1, 2, 3],
});
});

test('given: nested structures, should: pass', () => {
assert({
given: 'two identical nested structures',
should: 'be deeply equal',
actual: { users: [{ name: 'Alice' }, { name: 'Bob' }] },
expected: { users: [{ name: 'Alice' }, { name: 'Bob' }] },
});
});
});