Testing

@praha/byethrow-testing provides custom test matchers for asserting Result types, making your tests more expressive and readable.

Installation

npm install -D @praha/byethrow-testing

Setup

Jest

Add the following to your Jest setup file (e.g. jest.setup.ts):

// jest.setup.ts
import { 
const expect: JestExpect
expect
} from '@jest/globals';
import {
import resultMatchers
resultMatchers
} from '@praha/byethrow-testing';
import type {
interface ResultMatchers<T>
ResultMatchers
} from '@praha/byethrow-testing';
declare module 'expect' { interface
interface Matchers<R extends void | Promise<void>, T = unknown>
Matchers
<
function (type parameter) R in Matchers<R extends void | Promise<void>, T = unknown>
R
> extends
interface ResultMatchers<T>
ResultMatchers
<
function (type parameter) R in Matchers<R extends void | Promise<void>, T = unknown>
R
> {}
}
const expect: JestExpect
expect
.
BaseExpect.extend(matchers: MatchersObject): void
extend
(
import resultMatchers
resultMatchers
);

Then reference the setup file in your Jest config:

// jest.config.ts
export default {
  
setupFilesAfterEnv: string[]
setupFilesAfterEnv
: ['./jest.setup.ts'],
};

Vitest

Add the following to your Vitest setup file (e.g. vitest.setup.ts):

// vitest.setup.ts
import { 
import resultMatchers
resultMatchers
} from '@praha/byethrow-testing';
import {
const expect: ExpectStatic
expect
} from 'vitest';
import type {
interface ResultMatchers<T>
ResultMatchers
} from '@praha/byethrow-testing';
declare module 'vitest' { interface
interface Matchers<T = any>
Matchers
<
function (type parameter) T in Matchers<T = any>
T
> extends
interface ResultMatchers<T>
ResultMatchers
<
function (type parameter) T in Matchers<T = any>
T
> {}
}
const expect: ExpectStatic
expect
.
ExpectStatic.extend: (expects: MatchersObject) => void
extend
(
import resultMatchers
resultMatchers
);

Then reference the setup file in your Vitest config:

// vitest.config.ts
import { 
function defineConfig(config: UserConfig): UserConfig (+4 overloads)
defineConfig
} from 'vitest/config';
export default
function defineConfig(config: UserConfig): UserConfig (+4 overloads)
defineConfig
({
UserConfig.test?: InlineConfig | undefined

Options for Vitest

test
: {
InlineConfig.setupFiles?: string | string[] | undefined

Path to setup files

setupFiles
: ['./vitest.setup.ts'],
}, });

Rstest

Add the following to your Rstest setup file (e.g. rstest.setup.ts):

// rstest.setup.ts
import { 
import resultMatchers
resultMatchers
} from '@praha/byethrow-testing';
import {
const expect: ExpectStatic
expect
} from '@rstest/core';
import type {
interface ResultMatchers<T>
ResultMatchers
} from '@praha/byethrow-testing';
declare module '@rstest/core' { interface
interface Matchers<T>
Matchers
<
function (type parameter) T in Matchers<T>
T
> extends
interface ResultMatchers<T>
ResultMatchers
<
function (type parameter) T in Matchers<T>
T
> {}
}
const expect: ExpectStatic
expect
.
ExpectStatic_2.extend: (expects: MatchersObject<MatcherState>) => void
extend
(
import resultMatchers
resultMatchers
);

Then reference the setup file in your Rstest config:

// rstest.config.ts
import { 
function defineConfig(config: RstestConfig): RstestConfig (+3 overloads)

This function helps you to autocomplete configuration types. It accepts a Rstest config object, or a function that returns a config.

defineConfig
} from '@rstest/core';
export default
function defineConfig(config: RstestConfig): RstestConfig (+3 overloads)

This function helps you to autocomplete configuration types. It accepts a Rstest config object, or a function that returns a config.

defineConfig
({
RstestConfig.setupFiles?: string | string[] | undefined

Path to setup files. They will be run before each test file.

setupFiles
: ['./rstest.setup.ts'],
});

Matchers

toBeSuccess(callback?)

Asserts that the received value is a success Result. An optional callback receives the success value for further assertions.

Without a callback, it only checks that the result is a success:

import { 
import Result
Result
} from '@praha/byethrow';
import {
const test: TestAPI

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
,
const expect: ExpectStatic
expect
} from 'vitest';
test<object>(name: string | Function, fn?: TestFunction<object> | undefined, options?: number): void (+1 overload)

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
('result is success', () => {
const
const result: Result.Result<42, never>
result
=
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42);
expect<Result.Result<42, never>>(actual: Result.Result<42, never>, message?: string): Assertion<Result.Result<42, never>> (+1 overload)
expect
(
const result: Result.Result<42, never>
result
).
ResultMatchers<Result<42, never>>.toBeSuccess: (callback?: ((value: 42) => void) | undefined) => void
toBeSuccess
();
});

With a callback, the success value is passed to it for further assertions:

import { 
import Result
Result
} from '@praha/byethrow';
import {
const test: TestAPI

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
,
const expect: ExpectStatic
expect
} from 'vitest';
test<object>(name: string | Function, fn?: TestFunction<object> | undefined, options?: number): void (+1 overload)

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
('result is success with value', () => {
const
const result: Result.Result<42, never>
result
=
import Result
Result
.
const succeed: <42>(value: 42) => Result.Result<42, never> (+1 overload)
succeed
(42);
expect<Result.Result<42, never>>(actual: Result.Result<42, never>, message?: string): Assertion<Result.Result<42, never>> (+1 overload)
expect
(
const result: Result.Result<42, never>
result
).
ResultMatchers<Result<42, never>>.toBeSuccess: (callback?: ((value: 42) => void) | undefined) => void
toBeSuccess
((
value: 42
value
) => {
expect<42>(actual: 42, message?: string): Assertion<42> (+1 overload)
expect
(
value: 42
value
).
JestAssertion<42>.toBe: <number>(expected: number) => void

Checks that a value is what you expect. It calls Object.is to compare values. Don't use toBe with floating-point numbers.

@exampleexpect (result).toBe(42); expect(status).toBe(true);
toBe
(42);
}); });

toBeFailure(callback?)

Asserts that the received value is a failure Result. An optional callback receives the error value for further assertions.

Without a callback, it only checks that the result is a failure:

import { 
import Result
Result
} from '@praha/byethrow';
import {
const test: TestAPI

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
,
const expect: ExpectStatic
expect
} from 'vitest';
test<object>(name: string | Function, fn?: TestFunction<object> | undefined, options?: number): void (+1 overload)

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
('result is failure', () => {
const
const result: Result.Result<never, Error>
result
=
import Result
Result
.
const fail: <Error>(error: Error) => Result.Result<never, Error> (+1 overload)
fail
(new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('something went wrong'));
expect<Result.Result<never, Error>>(actual: Result.Result<never, Error>, message?: string): Assertion<Result.Result<never, Error>> (+1 overload)
expect
(
const result: Result.Result<never, Error>
result
).
ResultMatchers<Result<never, Error>>.toBeFailure: (callback?: ((error: Error) => void) | undefined) => void
toBeFailure
();
});

With a callback, the error value is passed to it for further assertions:

import { 
import Result
Result
} from '@praha/byethrow';
import {
const test: TestAPI

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
,
const expect: ExpectStatic
expect
} from 'vitest';
test<object>(name: string | Function, fn?: TestFunction<object> | undefined, options?: number): void (+1 overload)

Defines a test case with a given name and test function. The test function can optionally be configured with test options.

@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example
// Define a simple test
test('should add two numbers', () => {
  expect(add(1, 2)).toBe(3);
});
@example
// Define a test with options
test('should subtract two numbers', { retry: 3 }, () => {
  expect(subtract(5, 2)).toBe(3);
});
test
('result is failure with error', () => {
const
const result: Result.Result<never, Error>
result
=
import Result
Result
.
const fail: <Error>(error: Error) => Result.Result<never, Error> (+1 overload)
fail
(new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
('something went wrong'));
expect<Result.Result<never, Error>>(actual: Result.Result<never, Error>, message?: string): Assertion<Result.Result<never, Error>> (+1 overload)
expect
(
const result: Result.Result<never, Error>
result
).
ResultMatchers<Result<never, Error>>.toBeFailure: (callback?: ((error: Error) => void) | undefined) => void
toBeFailure
((
error: Error
error
) => {
expect<string>(actual: string, message?: string): Assertion<string> (+1 overload)
expect
(
error: Error
error
.
Error.message: string
message
).
JestAssertion<string>.toBe: <string>(expected: string) => void

Checks that a value is what you expect. It calls Object.is to compare values. Don't use toBe with floating-point numbers.

@exampleexpect (result).toBe(42); expect(status).toBe(true);
toBe
('something went wrong');
}); });