Skip to content

Commit

Permalink
feat: preserve error cause
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Aug 1, 2023
1 parent 9a57a89 commit 7c0048b
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 9 deletions.
4 changes: 2 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
eventHandler,
H3Event,
} from "./event";
import { createError } from "./error";
import { H3Error, createError } from "./error";
import {
send,
sendStream,
Expand Down Expand Up @@ -48,7 +48,7 @@ export interface AppUse {

export interface AppOptions {
debug?: boolean;
onError?: (error: Error, event: H3Event) => any;
onError?: (error: H3Error, event: H3Event) => any;
}

export interface App {
Expand Down
19 changes: 14 additions & 5 deletions src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ export class H3Error extends Error {
unhandled = false;
statusMessage?: string;
data?: any;
cause?: Error | unknown;

constructor(message: string, opts: { cause?: unknown } = {}) {
// @ts-ignore https://v8.dev/features/error-cause
super(message, opts);

// Polyfill cause for other runtimes
if (opts.cause && !this.cause) {
this.cause = opts.cause;
}
}

toJSON() {
const obj: Pick<
Expand Down Expand Up @@ -63,11 +74,9 @@ export function createError(
return input;
}

const err = new H3Error(
input.message ?? input.statusMessage ?? "",
// @ts-ignore https://v8.dev/features/error-cause
input.cause ? { cause: input.cause } : undefined
);
const err = new H3Error(input.message ?? input.statusMessage ?? "", {
cause: input.cause || input,
});

if ("stack" in input) {
try {
Expand Down
34 changes: 32 additions & 2 deletions test/error.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import supertest, { SuperTest, Test } from "supertest";
import { describe, it, expect, beforeEach, vi } from "vitest";
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import {
createApp,
App,
createError,
toNodeListener,
eventHandler,
H3Error,
} from "../src";

const consoleMock = ((global.console.error as any) = vi.fn());
Expand All @@ -14,11 +15,22 @@ describe("error", () => {
let app: App;
let request: SuperTest<Test>;

const capturedErrors: H3Error[] = [];

beforeEach(() => {
app = createApp({ debug: false });
app = createApp({
debug: false,
onError(error) {
capturedErrors.push(error);
},
});
request = supertest(toNodeListener(app));
});

afterEach(() => {
capturedErrors.length = 0;
});

it("logs errors", async () => {
app.use(
eventHandler(() => {
Expand Down Expand Up @@ -119,4 +131,22 @@ describe("error", () => {
const res = await request.get("/");
expect(res.status).toBe(501);
});

it("can access original error", async () => {
class CustomError extends Error {
customError: true;
}

app.use(
"/",
eventHandler(() => {
throw createError(new CustomError());
})
);

const res = await request.get("/");
expect(res.status).toBe(500);

expect(capturedErrors[0].cause).toBeInstanceOf(CustomError);
});
});

0 comments on commit 7c0048b

Please sign in to comment.