UNPKG

go-go-try

Version:

Tries to execute a sync/async function, returns a result tuple

401 lines (322 loc) 10.7 kB
import { attest } from '@ark/attest' import { assert, describe, test } from 'vitest' import { type Result, goTry, goTryRaw, isFailure, isSuccess } from './index.js' test(`value returned by callback is used when callback doesn't throw`, async () => { const fn = () => 'value' // Test with function const result1 = goTry(fn) const result2 = goTryRaw(fn) // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 // Test type guards assert.equal(isSuccess(result1), true) assert.equal(isSuccess(result2), true) assert.equal(isFailure(result1), false) assert.equal(isFailure(result2), false) // Test values assert.equal(value, 'value') assert.equal(value2, 'value') assert.equal(err1, undefined) assert.equal(err2, undefined) }) test('if function throws undefined, err should be "undefined"', async () => { const fn = () => { throw undefined } // Test with function that throws undefined const result1 = goTry(fn) const result2 = goTryRaw(fn) // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 // Test type guards assert.equal(isSuccess(result1), false) assert.equal(isSuccess(result2), false) assert.equal(isFailure(result1), true) assert.equal(isFailure(result2), true) // Test values assert.equal(value, undefined) assert.equal(value2, undefined) assert.equal(err1, 'undefined') assert.equal(typeof err2, 'object') }) test('if callback throws, value should be undefined and err should contain the error message', async () => { const fn = () => { return JSON.parse('{/') as string } // Test with function that throws const result1 = goTry(fn) const result2 = goTryRaw(fn) // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 // Test type guards assert.equal(isSuccess(result1), false) assert.equal(isSuccess(result2), false) assert.equal(isFailure(result1), true) assert.equal(isFailure(result2), true) // Test values assert.equal(value, undefined) assert.equal(value2, undefined) assert.equal(typeof err1, 'string') assert.equal(typeof err2, 'object') assert.equal(typeof err2?.message, 'string') }) test('first parameter accepts promises and makes the function async', async () => { const promise = Promise.resolve('value') // Test with promise const result1 = await goTry(promise) const result2 = await goTryRaw(promise) // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 // Test type guards assert.equal(isSuccess(result1), true) assert.equal(isSuccess(result2), true) assert.equal(isFailure(result1), false) assert.equal(isFailure(result2), false) // Test values assert.equal(value, 'value') assert.equal(value2, 'value') assert.equal(err1, undefined) assert.equal(err2, undefined) }) test("if it's a function returning a Promise, should unwrap the value correctly to T", async () => { const fn = () => Promise.resolve('value') // Test with function that returns a promise const result1 = await goTry(fn) const result2 = await goTryRaw(fn) // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 attest<string | undefined>(err1) attest<string | undefined>(value) attest<Error | undefined>(err2) attest<string | undefined>(value2) // Test type guards assert.equal(isSuccess(result1), true) assert.equal(isSuccess(result2), true) assert.equal(isFailure(result1), false) assert.equal(isFailure(result2), false) // Test values assert.equal(value, 'value') assert.equal(value2, 'value') assert.equal(err1, undefined) assert.equal(err2, undefined) }) test('if async callback throws, value should be undefined and err should contain the error message', async () => { const promise = Promise.reject(new Error('error')) // Test with promise that rejects const result1 = await goTry(promise) const result2 = await goTryRaw<Error>(promise) // Test destructuring const [err, value] = result1 const [err2, value2] = result2 // Test type guards assert.equal(isSuccess(result1), false) assert.equal(isSuccess(result2), false) assert.equal(isFailure(result1), true) assert.equal(isFailure(result2), true) // Test values assert.equal(value, undefined) assert.equal(value2, undefined) assert.equal(err, 'error') assert.equal(typeof err2, 'object') assert.equal(err2?.message, 'error') }) test('direct values work too', () => { // Test with direct value const result1 = goTry('value') const result2 = goTryRaw('value') // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 // Test values assert.equal(value, 'value') assert.equal(value2, 'value') assert.equal(err1, undefined) assert.equal(err2, undefined) }) test('async functions work correctly', async () => { // Define an async function function asyncFn() { return Promise.resolve(42) } // Test with async function const result1 = await goTry(asyncFn()) const result2 = await goTryRaw(asyncFn()) // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 // Test values assert.equal(value, 42) assert.equal(value2, 42) assert.equal(err1, undefined) assert.equal(err2, undefined) }) test('async functions that throw work correctly', async () => { // Define an async function that throws async function asyncFnThatThrows() { await 1 throw new Error('async error') } // Test with async function that throws const result1 = await goTry(asyncFnThatThrows()) const result2 = await goTryRaw(asyncFnThatThrows()) // Test destructuring const [err1, value] = result1 const [err2, value2] = result2 // Test values assert.equal(value, undefined) assert.equal(value2, undefined) assert.equal(err1, 'async error') assert.equal(typeof err2, 'object') assert.equal(err2?.message, 'async error') }) describe('goTry type tests', () => { test('synchronous function returns correct types', () => { const fn = () => 'value' const result = goTry(fn) // Check the result type attest<Result<string, string>>(result) // Check the destructured types const [err, value] = result attest<string | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) test('direct value returns correct types', () => { const result = goTry('value') // Check the result type attest<Result<string, string>>(result) // Check the destructured types const [err, value] = result attest<string | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) test('promise returns correct types', async () => { const promise = Promise.resolve('value') const result = await goTry(promise) // Check the result type attest<Result<string, string>>(result) // Check the destructured types const [err, value] = result attest<string | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) test('async function returns correct types', async () => { const asyncFn = async () => 'value' const result = await goTry(asyncFn()) // Check the result type attest<Result<string, string>>(result) // Check the destructured types const [err, value] = result attest<string | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) }) describe('goTryRaw type tests', () => { test('type inference works correctly', () => { const fn = () => 'value' const result = goTryRaw(fn) // Check the result type attest<Result<Error, string>>(result) // Check the destructured types const [err, value] = result attest<Error | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) test('synchronous function returns correct types', () => { const fn = () => 'value' const result = goTryRaw(fn) // Check the result type attest<Result<Error, string>>(result) // Check the destructured types const [err, value] = result attest<Error | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) test('direct value returns correct types', () => { const result = goTryRaw('value') // Check the result type attest<Result<Error, string>>(result) // Check the destructured types const [err, value] = result attest<Error | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) test('promise returns correct types', async () => { const promise = Promise.resolve('value') const result = await goTryRaw(promise) // Check the result type attest<Result<Error, string>>(result) // Check the destructured types const [err, value] = result attest<Error | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) test('async function returns correct types', async () => { const asyncFn = async () => 'value' const result = await goTryRaw(asyncFn()) // Check the result type attest<Result<Error, string>>(result) // Check the destructured types const [err, value] = result attest<Error | undefined>(err) attest<string | undefined>(value) // When destructured, the types should be narrowed correctly if (err === undefined) { attest<string>(value) } else { attest<undefined>(value) } }) })