247 lines
7.6 KiB
TypeScript
247 lines
7.6 KiB
TypeScript
import {
|
|
MemoryError,
|
|
AuthenticationError,
|
|
RateLimitError,
|
|
ValidationError,
|
|
MemoryNotFoundError,
|
|
NetworkError,
|
|
ConfigurationError,
|
|
MemoryQuotaExceededError,
|
|
createExceptionFromResponse,
|
|
HTTP_STATUS_TO_EXCEPTION,
|
|
} from "./exceptions";
|
|
|
|
describe("MemoryError", () => {
|
|
const error = new MemoryError("test error", "MEM_001", {
|
|
details: { operation: "add" },
|
|
suggestion: "Try again",
|
|
debugInfo: { requestId: "req_123" },
|
|
});
|
|
|
|
test("is an instance of Error", () => {
|
|
expect(error).toBeInstanceOf(Error);
|
|
});
|
|
|
|
test("has correct message", () => {
|
|
expect(error.message).toBe("test error");
|
|
});
|
|
|
|
test("has correct errorCode", () => {
|
|
expect(error.errorCode).toBe("MEM_001");
|
|
});
|
|
|
|
test("has correct details", () => {
|
|
expect(error.details).toEqual({ operation: "add" });
|
|
});
|
|
|
|
test("has correct suggestion", () => {
|
|
expect(error.suggestion).toBe("Try again");
|
|
});
|
|
|
|
test("has correct debugInfo", () => {
|
|
expect(error.debugInfo).toEqual({ requestId: "req_123" });
|
|
});
|
|
|
|
test("defaults details to empty object", () => {
|
|
const err = new MemoryError("test error", "MEM_001");
|
|
expect(err.details).toEqual({});
|
|
});
|
|
|
|
test("defaults suggestion to undefined", () => {
|
|
const err = new MemoryError("test error", "MEM_001");
|
|
expect(err.suggestion).toBeUndefined();
|
|
});
|
|
|
|
test("defaults debugInfo to empty object", () => {
|
|
const err = new MemoryError("test error", "MEM_001");
|
|
expect(err.debugInfo).toEqual({});
|
|
});
|
|
|
|
test("is throwable and catchable", () => {
|
|
expect(() => {
|
|
throw new MemoryError("fail", "MEM_001");
|
|
}).toThrow("fail");
|
|
});
|
|
});
|
|
|
|
describe("Exception subclasses", () => {
|
|
const subclasses = [
|
|
{ Class: AuthenticationError, name: "AuthenticationError" },
|
|
{ Class: RateLimitError, name: "RateLimitError" },
|
|
{ Class: ValidationError, name: "ValidationError" },
|
|
{ Class: MemoryNotFoundError, name: "MemoryNotFoundError" },
|
|
{ Class: NetworkError, name: "NetworkError" },
|
|
{ Class: ConfigurationError, name: "ConfigurationError" },
|
|
{ Class: MemoryQuotaExceededError, name: "MemoryQuotaExceededError" },
|
|
] as const;
|
|
|
|
test.each(subclasses)("$name extends MemoryError", ({ Class }) => {
|
|
const error = new Class("test", "CODE_001");
|
|
expect(error).toBeInstanceOf(MemoryError);
|
|
});
|
|
|
|
test.each(subclasses)("$name extends Error", ({ Class }) => {
|
|
const error = new Class("test", "CODE_001");
|
|
expect(error).toBeInstanceOf(Error);
|
|
});
|
|
|
|
test.each(subclasses)("$name has correct name", ({ Class, name }) => {
|
|
const error = new Class("test", "CODE_001");
|
|
expect(error.name).toBe(name);
|
|
});
|
|
|
|
test.each(subclasses)("$name supports instanceof checks", ({ Class }) => {
|
|
const error = new Class("test", "CODE_001");
|
|
expect(error instanceof Class).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("createExceptionFromResponse", () => {
|
|
test("maps 401 to AuthenticationError", () => {
|
|
const error = createExceptionFromResponse(401, "Unauthorized");
|
|
expect(error).toBeInstanceOf(AuthenticationError);
|
|
});
|
|
|
|
test("maps 401 to errorCode HTTP_401", () => {
|
|
const error = createExceptionFromResponse(401, "Unauthorized");
|
|
expect(error.errorCode).toBe("HTTP_401");
|
|
});
|
|
|
|
test("maps 401 to authentication suggestion", () => {
|
|
const error = createExceptionFromResponse(401, "Unauthorized");
|
|
expect(error.suggestion).toBe(
|
|
"Please check your API key and authentication credentials",
|
|
);
|
|
});
|
|
|
|
test("maps 429 to RateLimitError", () => {
|
|
const error = createExceptionFromResponse(429, "Too many requests", {
|
|
debugInfo: { retryAfter: 60 },
|
|
});
|
|
expect(error).toBeInstanceOf(RateLimitError);
|
|
});
|
|
|
|
test("maps 429 passes debugInfo through", () => {
|
|
const error = createExceptionFromResponse(429, "Too many requests", {
|
|
debugInfo: { retryAfter: 60 },
|
|
});
|
|
expect(error.debugInfo).toEqual({ retryAfter: 60 });
|
|
});
|
|
|
|
test("maps 404 to MemoryNotFoundError", () => {
|
|
const error = createExceptionFromResponse(404, "Not found");
|
|
expect(error).toBeInstanceOf(MemoryNotFoundError);
|
|
});
|
|
|
|
test("maps 400 to ValidationError", () => {
|
|
const error = createExceptionFromResponse(400, "Bad request");
|
|
expect(error).toBeInstanceOf(ValidationError);
|
|
});
|
|
|
|
test("maps 413 to MemoryQuotaExceededError", () => {
|
|
const error = createExceptionFromResponse(413, "Quota exceeded");
|
|
expect(error).toBeInstanceOf(MemoryQuotaExceededError);
|
|
});
|
|
|
|
test.each([502, 503, 504])("maps %i to NetworkError", (code) => {
|
|
const error = createExceptionFromResponse(code, "Service unavailable");
|
|
expect(error).toBeInstanceOf(NetworkError);
|
|
});
|
|
|
|
test("maps 500 to MemoryError", () => {
|
|
const error = createExceptionFromResponse(500, "Internal error");
|
|
expect(error).toBeInstanceOf(MemoryError);
|
|
});
|
|
|
|
test("maps 500 to errorCode HTTP_500", () => {
|
|
const error = createExceptionFromResponse(500, "Internal error");
|
|
expect(error.errorCode).toBe("HTTP_500");
|
|
});
|
|
|
|
test("maps unknown status to MemoryError", () => {
|
|
const error = createExceptionFromResponse(418, "I am a teapot");
|
|
expect(error).toBeInstanceOf(MemoryError);
|
|
});
|
|
|
|
test("maps unknown status to correct errorCode", () => {
|
|
const error = createExceptionFromResponse(418, "I am a teapot");
|
|
expect(error.errorCode).toBe("HTTP_418");
|
|
});
|
|
|
|
test("maps unknown status to retry suggestion", () => {
|
|
const error = createExceptionFromResponse(418, "I am a teapot");
|
|
expect(error.suggestion).toBe("Please try again later");
|
|
});
|
|
|
|
test("uses response text as message", () => {
|
|
const error = createExceptionFromResponse(400, "Invalid user_id format");
|
|
expect(error.message).toBe("Invalid user_id format");
|
|
});
|
|
|
|
test("falls back to generic message when response text is empty", () => {
|
|
const error = createExceptionFromResponse(500, "");
|
|
expect(error.message).toBe("HTTP 500 error");
|
|
});
|
|
|
|
test("passes details through", () => {
|
|
const error = createExceptionFromResponse(400, "Bad request", {
|
|
details: { field: "user_id", value: "" },
|
|
});
|
|
expect(error.details).toEqual({ field: "user_id", value: "" });
|
|
});
|
|
});
|
|
|
|
describe("HTTP_STATUS_TO_EXCEPTION", () => {
|
|
test("maps 400 to ValidationError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[400]).toBe(ValidationError);
|
|
});
|
|
|
|
test("maps 401 to AuthenticationError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[401]).toBe(AuthenticationError);
|
|
});
|
|
|
|
test("maps 403 to AuthenticationError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[403]).toBe(AuthenticationError);
|
|
});
|
|
|
|
test("maps 404 to MemoryNotFoundError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[404]).toBe(MemoryNotFoundError);
|
|
});
|
|
|
|
test("maps 408 to NetworkError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[408]).toBe(NetworkError);
|
|
});
|
|
|
|
test("maps 409 to ValidationError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[409]).toBe(ValidationError);
|
|
});
|
|
|
|
test("maps 413 to MemoryQuotaExceededError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[413]).toBe(MemoryQuotaExceededError);
|
|
});
|
|
|
|
test("maps 422 to ValidationError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[422]).toBe(ValidationError);
|
|
});
|
|
|
|
test("maps 429 to RateLimitError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[429]).toBe(RateLimitError);
|
|
});
|
|
|
|
test("maps 500 to MemoryError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[500]).toBe(MemoryError);
|
|
});
|
|
|
|
test("maps 502 to NetworkError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[502]).toBe(NetworkError);
|
|
});
|
|
|
|
test("maps 503 to NetworkError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[503]).toBe(NetworkError);
|
|
});
|
|
|
|
test("maps 504 to NetworkError", () => {
|
|
expect(HTTP_STATUS_TO_EXCEPTION[504]).toBe(NetworkError);
|
|
});
|
|
});
|