import { describe, test, expect } from "bun:test"; import GenericError from "../../src/Errors/GenericError"; import AuthenticationError from "../../src/Errors/AuthenticationError"; import AuthorizationError from "../../src/Errors/AuthorizationError"; import BodyError from "../../src/Errors/BodyError"; import InsufficientPermission from "../../src/Errors/InsufficientPermission"; import SessionError from "../../src/Errors/SessionError"; import SessionTokenError from "../../src/Errors/SessionTokenError"; import UserError from "../../src/Errors/UserError"; import RoleError from "../../src/Errors/RoleError"; import MissingBodyValue from "../../src/Errors/MissingBodyValue"; import ExpiredAccessTokenError from "../../src/Errors/ExpiredAccessTokenError"; import ExpiredRefreshTokenError from "../../src/Errors/ExpiredRefreshTokenError"; import PermissionsVerificationError from "../../src/Errors/PermissionsVerificationError"; // --------------------------------------------------------------------------- // GenericError // --------------------------------------------------------------------------- describe("GenericError", () => { test("sets name, message, status, and cause", () => { const err = new GenericError({ name: "TestError", message: "Something went wrong", cause: "bad input", status: 422, }); expect(err).toBeInstanceOf(Error); expect(err.name).toBe("TestError"); expect(err.message).toBe("Something went wrong"); expect(err.cause).toBe("bad input"); expect(err.status).toBe(422); }); test("defaults status to 400", () => { const err = new GenericError({ name: "X", message: "Y" }); expect(err.status).toBe(400); }); test("cause is optional", () => { const err = new GenericError({ name: "X", message: "Y" }); expect(err.cause).toBeUndefined(); }); }); // --------------------------------------------------------------------------- // AuthenticationError // --------------------------------------------------------------------------- describe("AuthenticationError", () => { test("sets correct name and message", () => { const err = new AuthenticationError("Invalid credentials"); expect(err).toBeInstanceOf(Error); expect(err.name).toBe("AuthenticationError"); expect(err.message).toBe("Invalid credentials"); }); test("accepts optional cause", () => { const err = new AuthenticationError("Fail", "token expired"); expect(err.cause).toBe("token expired"); }); test("cause defaults to undefined", () => { const err = new AuthenticationError("Fail"); expect(err.cause).toBeUndefined(); }); }); // --------------------------------------------------------------------------- // AuthorizationError // --------------------------------------------------------------------------- describe("AuthorizationError", () => { test("sets correct name and default status", () => { const err = new AuthorizationError("Not authorized"); expect(err).toBeInstanceOf(Error); expect(err.name).toBe("AuthorizationError"); expect(err.message).toBe("Not authorized"); expect(err.status).toBe(401); }); test("allows custom status", () => { const err = new AuthorizationError("Forbidden", "nope", 403); expect(err.status).toBe(403); expect(err.cause).toBe("nope"); }); }); // --------------------------------------------------------------------------- // BodyError // --------------------------------------------------------------------------- describe("BodyError", () => { test("sets name and message", () => { const err = new BodyError("Body is invalid"); expect(err.name).toBe("BodyError"); expect(err.message).toBe("Body is invalid"); }); test("accepts optional cause", () => { const err = new BodyError("Bad", "missing field"); expect(err.cause).toBe("missing field"); }); }); // --------------------------------------------------------------------------- // InsufficientPermission // --------------------------------------------------------------------------- describe("InsufficientPermission", () => { test("always has status 403", () => { const err = new InsufficientPermission("Nope"); expect(err.name).toBe("InsufficientPermission"); expect(err.status).toBe(403); expect(err.message).toBe("Nope"); }); test("accepts optional cause", () => { const err = new InsufficientPermission("Nope", "missing role"); expect(err.cause).toBe("missing role"); }); }); // --------------------------------------------------------------------------- // SessionError // --------------------------------------------------------------------------- describe("SessionError", () => { test("sets name and message", () => { const err = new SessionError("Invalid session"); expect(err.name).toBe("SessionError"); expect(err.message).toBe("Invalid session"); }); }); // --------------------------------------------------------------------------- // SessionTokenError // --------------------------------------------------------------------------- describe("SessionTokenError", () => { test("sets name and message", () => { const err = new SessionTokenError("Token invalid"); expect(err.name).toBe("SessionTokenError"); expect(err.message).toBe("Token invalid"); }); test("accepts cause", () => { const err = new SessionTokenError("Bad", "expired"); expect(err.cause).toBe("expired"); }); }); // --------------------------------------------------------------------------- // UserError // --------------------------------------------------------------------------- describe("UserError", () => { test("sets name and message", () => { const err = new UserError("User not found"); expect(err.name).toBe("UserError"); expect(err.message).toBe("User not found"); }); }); // --------------------------------------------------------------------------- // RoleError // --------------------------------------------------------------------------- describe("RoleError", () => { test("sets name and message", () => { const err = new RoleError("Role conflict"); expect(err.name).toBe("RoleError"); expect(err.message).toBe("Role conflict"); }); test("accepts cause", () => { const err = new RoleError("Conflict", "moniker taken"); expect(err.cause).toBe("moniker taken"); }); }); // --------------------------------------------------------------------------- // MissingBodyValue // --------------------------------------------------------------------------- describe("MissingBodyValue", () => { test("formats message with value name", () => { const err = new MissingBodyValue("email"); expect(err.name).toBe("MissingBodyValue"); expect(err.message).toBe("Value 'email' is missing from the body."); expect(err.cause).toBe( "A value that was required by the body of this request is missing.", ); }); test("works with different value names", () => { const err = new MissingBodyValue("password"); expect(err.message).toContain("password"); }); }); // --------------------------------------------------------------------------- // ExpiredAccessTokenError // --------------------------------------------------------------------------- describe("ExpiredAccessTokenError", () => { test("sets fixed name and message", () => { const err = new ExpiredAccessTokenError(); expect(err.name).toBe("ExpiredAccessTokenError"); expect(err.message).toBe("The provided access token has expired."); }); test("accepts optional cause", () => { const err = new ExpiredAccessTokenError("jwt expired"); expect(err.cause).toBe("jwt expired"); }); }); // --------------------------------------------------------------------------- // ExpiredRefreshTokenError // --------------------------------------------------------------------------- describe("ExpiredRefreshTokenError", () => { test("sets fixed name and message", () => { const err = new ExpiredRefreshTokenError(); expect(err.name).toBe("ExpiredRefreshTokenError"); expect(err.message).toBe("The provided refresh token has expired."); }); test("accepts optional cause", () => { const err = new ExpiredRefreshTokenError("jwt expired"); expect(err.cause).toBe("jwt expired"); }); }); // --------------------------------------------------------------------------- // PermissionsVerificationError // --------------------------------------------------------------------------- describe("PermissionsVerificationError", () => { test("sets name and message", () => { const err = new PermissionsVerificationError("Cannot verify"); expect(err.name).toBe("PermissionsVerificationError"); expect(err.message).toBe("Cannot verify"); }); test("accepts cause", () => { const err = new PermissionsVerificationError("Fail", "key mismatch"); expect(err.cause).toBe("key mismatch"); }); }); // --------------------------------------------------------------------------- // Cross-cutting: all errors are instanceof Error // --------------------------------------------------------------------------- describe("All errors extend Error", () => { const errors = [ new GenericError({ name: "G", message: "g" }), new AuthenticationError("a"), new AuthorizationError("a"), new BodyError("b"), new InsufficientPermission("i"), new SessionError("s"), new SessionTokenError("st"), new UserError("u"), new RoleError("r"), new MissingBodyValue("v"), new ExpiredAccessTokenError(), new ExpiredRefreshTokenError(), new PermissionsVerificationError("p"), ]; test.each(errors.map((e) => [e.constructor.name, e]))( "%s is instanceof Error", (_name, err) => { expect(err).toBeInstanceOf(Error); }, ); });