UNPKG

neverthrow-result-utils

Version:

Extra utilities for working with Neverthrow results

359 lines (309 loc) 7.82 kB
import { ResultAsync, errAsync, okAsync } from "neverthrow"; import { ResultUtils } from "../src"; describe("ResultUtils tests", () => { test("combine returns after each method completes", async () => { // Arrange let value = 0; function asyncMethod() { return okAsync<number, Error>(value++); } // Act const result = await ResultUtils.combine([ asyncMethod(), asyncMethod(), asyncMethod(), ]); // Assert expect(result.isErr()).toBeFalsy(); const results = result._unsafeUnwrap(); expect(results).toStrictEqual([0, 1, 2]); expect(value).toBe(3); }); test("combine returns using fromPromise", async () => { // Arrange let value = 0; function asyncMethod() { return ResultAsync.fromSafePromise( new Promise((resolve) => { resolve(value++); }) ); } // Act const result = await ResultUtils.combine([ asyncMethod(), asyncMethod(), asyncMethod(), ]); // Assert expect(result.isErr()).toBeFalsy(); const results = result._unsafeUnwrap(); expect(results).toStrictEqual([0, 1, 2]); expect(value).toBe(3); }); test("combine returns an error if one method fails", async () => { // Arrange let value = 0; function asyncMethod() { return okAsync<number, Error>(value++); } const err = new Error(); function errorMethod() { return errAsync<number, Error>(err); } // Act const result = await ResultUtils.combine([ asyncMethod(), errorMethod(), asyncMethod(), ]); // Assert expect(result.isErr()).toBeTruthy(); const errResult = result._unsafeUnwrapErr(); expect(errResult).toBe(err); }); test("executeSerially executes resultAsyncs sequentially", async () => { // Arrange let value = 0; const asyncMethod = () => { return okAsync<number, Error>(value++); }; // Act const result = await ResultUtils.executeSerially([ asyncMethod, asyncMethod, asyncMethod, ]); // Assert expect(result.isErr()).toBeFalsy(); const results = result._unsafeUnwrap(); expect(results).toStrictEqual([0, 1, 2]); expect(value).toBe(3); }); test("executeSerially stops executing after first error", async () => { // Arrange let value = 0; const asyncMethod = () => { return okAsync<number, Error>(value++); }; const err = new Error("Error!"); const asyncFailed = () => { return errAsync<number, Error>(err); }; // Act const result = await ResultUtils.executeSerially([ asyncMethod, asyncFailed, asyncMethod, ]); // Assert expect(result.isErr()).toBeTruthy(); const resultErr = result._unsafeUnwrapErr(); expect(resultErr).toBe(err); expect(value).toBe(1); }); test("backoffAndRetry works first time", async () => { // Arrange let value = 1; const asyncMethod = () => { return okAsync<number, Error>(value++); }; // Act const result = await ResultUtils.backoffAndRetry( asyncMethod, [], 10, 1 ); // Assert expect(result.isErr()).toBeFalsy(); const results = result._unsafeUnwrap(); expect(results).toStrictEqual(1); expect(value).toBe(2); }); test("backoffAndRetry works second time", async () => { // Arrange let value = 1; const asyncMethod = () => { if (value++ == 1) { return errAsync(new Error()); } return okAsync<number, Error>(value++); }; // Act const result = await ResultUtils.backoffAndRetry( asyncMethod, [Error], 10, 1 ); // Assert expect(result.isErr()).toBeFalsy(); const results = result._unsafeUnwrap(); expect(results).toBe(3); expect(value).toBe(4); }); test("backoffAndRetry max retries exceeded", async () => { // Arrange let value = 0; const err = new Error(); const asyncMethod = () => { value++; return errAsync(err); }; // Act const result = await ResultUtils.backoffAndRetry( asyncMethod, [Error], 3, 1 ); // Assert expect(result.isErr()).toBeTruthy(); const results = result._unsafeUnwrapErr(); expect(results).toBe(err); expect(value).toBe(3); }); test("backoffAndRetry unnaceptable error returned", async () => { // Arrange let value = 0; const err = new Error(); const syncMethod = () => { value++; return errAsync(err); }; // Act const result = await ResultUtils.backoffAndRetry(syncMethod, [], 10, 1); // Assert expect(result.isErr()).toBeTruthy(); const results = result._unsafeUnwrapErr(); expect(results).toBe(err); expect(value).toBe(1); }); test("race returns the first resolved result", async () => { // Arrange let value = 0; const timedPromise = new Promise<number>((resolve, reject) => { setTimeout(() => { value = 2; resolve(2); }, 500); }); const timedResult = ResultAsync.fromPromise( timedPromise, (e) => e as Error ); const asyncMethod = () => { return okAsync<number, Error>(value++); }; // Act const result = await ResultUtils.race([timedResult, asyncMethod()]); // Assert expect(result.isErr()).toBeFalsy(); const resultWrap = result._unsafeUnwrap(); expect(resultWrap).toStrictEqual(0); expect(value).toBe(1); }); test("race stops at the first resolved promise", async () => { // Arrange let value = 0; const timedPromise = new Promise<number>((resolve, reject) => { setTimeout(() => { value = 1; resolve(1); }, 500); }); const timedResult = ResultAsync.fromPromise( timedPromise, (e) => e as Error ); const timedPromise2 = new Promise<number>((resolve, reject) => { setTimeout(() => { resolve(2); }, 100); }); const timedResult2 = ResultAsync.fromPromise( timedPromise2, (e) => e as Error ); // Act const result = await ResultUtils.race([timedResult, timedResult2]); // Assert expect(result.isErr()).toBeFalsy(); const resultWrap = result._unsafeUnwrap(); expect(resultWrap).toStrictEqual(2); expect(value).toBe(0); }); test("filter() returns successfully when no callback has errors", async () => { // Arrange const sourceArr = [1, 2, 3, 4, 5, 6]; // Act const result = await ResultUtils.filter<number, Error>( sourceArr, (val) => { if (val < 3) { return okAsync(true); } return okAsync(false); } ); // Assert expect(result).toBeDefined(); expect(result.isOk()).toBeTruthy(); const filteredResults = result._unsafeUnwrap(); expect(filteredResults.length).toBe(2); expect(filteredResults).toStrictEqual([1, 2]); }); test("filter() returns an error when a single callback has errors", async () => { // Arrange const sourceArr = [1, 2, 3, 4, 5, 6]; // Act const result = await ResultUtils.filter<number, Error>( sourceArr, (val) => { if (val > 3) { return errAsync(new Error()); } return okAsync(false); } ); // Assert expect(result).toBeDefined(); expect(result.isErr()).toBeTruthy(); }); test("map() returns successfully when no callback has errors", async () => { // Arrange const sourceArr = [1, 2, 3, 4, 5, 6]; // Act const result = await ResultUtils.map(sourceArr, (val) => { return okAsync<string, Error>((val * 10).toString()); }); // Assert expect(result).toBeDefined(); expect(result.isOk()).toBeTruthy(); const filteredResults = result._unsafeUnwrap(); expect(filteredResults.length).toBe(6); expect(filteredResults).toStrictEqual([ "10", "20", "30", "40", "50", "60", ]); }); test("map() returns an error when a single callback has errors", async () => { // Arrange const sourceArr = [1, 2, 3, 4, 5, 6]; // Act const result = await ResultUtils.map(sourceArr, (val) => { if (val > 3) { return errAsync(new Error()); } return okAsync<string, Error>((val * 10).toString()); }); // Assert expect(result).toBeDefined(); expect(result.isErr()).toBeTruthy(); }); });