#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 | undefinedOptions for Vitest
test : {
InlineConfig.setupFiles?: string | string[] | undefinedPath 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[] | undefinedPath 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: TestAPIDefines 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: TestAPIDefines 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) => voidChecks 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: TestAPIDefines 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: TestAPIDefines 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) => voidChecks 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');
});
});