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
66 changes: 66 additions & 0 deletions src/errors.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';

import {
ensureError,
getErrorMessage,
isErrorWithCode,
isErrorWithMessage,
Expand Down Expand Up @@ -320,3 +321,68 @@ describe('getErrorMessage', () => {
expect(getErrorMessage(undefined)).toBe('');
});
});

describe('ensureError', () => {
it('returns Error instance unchanged', () => {
const originalError = new Error('original message');
const result = ensureError(originalError);

expect(result).toBe(originalError);
expect(result.message).toBe('original message');
});

it('returns fs.promises-style error unchanged', async () => {
let originalError;
try {
await fs.promises.readFile('/tmp/nonexistent', 'utf8');
} catch (error: unknown) {
originalError = error;
}

const result = ensureError(originalError);

expect(result).toBe(originalError);
});

it('converts string to Error and preserves original as cause', () => {
const result = ensureError('something went wrong');

expect(result).toBeInstanceOf(Error);
expect(result.message).toBe('Unknown error');
expect(result.cause).toBe('something went wrong');
});

it('converts object to Error and preserves original as cause', () => {
const originalObject = { some: 'object' };
const result = ensureError(originalObject);

expect(result).toBeInstanceOf(Error);
expect(result.message).toBe('Unknown error');
expect(result.cause).toBe(originalObject);
});

it('handles null with descriptive message', () => {
const result = ensureError(null);

expect(result).toBeInstanceOf(Error);
expect(result.message).toBe('Unknown error');
expect(result.cause).toBeNull();
});

it('handles undefined with descriptive message', () => {
const result = ensureError(undefined);

expect(result).toBeInstanceOf(Error);
expect(result.message).toBe('Unknown error');
expect(result.cause).toBeUndefined();
});

it('preserves stack trace for Error instances', () => {
const originalError = new Error('original message');
const originalStack = originalError.stack;

const result = ensureError(originalError);

expect(result.stack).toBe(originalStack);
});
});
19 changes: 19 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,22 @@ export function wrapError<Throwable>(

return new Error(String(originalError));
}

/**
* Ensures we have a proper Error object.
* If the input is already an Error, returns it unchanged.
* Otherwise, converts to an Error with an appropriate message and preserves
* the original value as the cause.
*
* @param error - The caught error (could be Error, string, or unknown).
* @returns A proper Error instance.
*/
export function ensureError(error: unknown): Error {
if (isError(error)) {
return error;
}

const newError: Error & { cause?: unknown } = new Error('Unknown error');
newError.cause = error;
return newError;
}
1 change: 1 addition & 0 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ describe('index', () => {
"createNumber",
"createProjectLogger",
"definePattern",
"ensureError",
"exactOptional",
"fromWei",
"getChecksumAddress",
Expand Down
1 change: 1 addition & 0 deletions src/node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ describe('node', () => {
"definePattern",
"directoryExists",
"ensureDirectoryStructureExists",
"ensureError",
"exactOptional",
"fileExists",
"forceRemove",
Expand Down
Loading