@terreno/api 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,156 @@
1
+ import {describe, expect, it} from "bun:test";
2
+ import mongoose from "mongoose";
3
+
4
+ import {
5
+ APIError,
6
+ apiUnauthorizedMiddleware,
7
+ errorsPlugin,
8
+ getAPIErrorBody,
9
+ getDisableExternalErrorTracking,
10
+ isAPIError,
11
+ } from "./errors";
12
+
13
+ describe("errors module", () => {
14
+ describe("APIError", () => {
15
+ it("sets default status to 500 when not provided", () => {
16
+ const error = new APIError({title: "Test error"});
17
+ expect(error.status).toBe(500);
18
+ });
19
+
20
+ it("sets status to 500 for invalid status codes below 400", () => {
21
+ const error = new APIError({status: 200, title: "Test error"});
22
+ expect(error.status).toBe(500);
23
+ });
24
+
25
+ it("sets status to 500 for invalid status codes above 599", () => {
26
+ const error = new APIError({status: 600, title: "Test error"});
27
+ expect(error.status).toBe(500);
28
+ });
29
+
30
+ it("includes error stack in message when error is provided", () => {
31
+ const originalError = new Error("Original error");
32
+ const apiError = new APIError({
33
+ error: originalError,
34
+ title: "Wrapped error",
35
+ });
36
+ expect(apiError.message).toContain("Wrapped error");
37
+ expect(originalError.stack).toBeDefined();
38
+ expect(apiError.message).toContain(originalError.stack as string);
39
+ });
40
+
41
+ it("includes detail in message when provided", () => {
42
+ const error = new APIError({
43
+ detail: "More details here",
44
+ title: "Test error",
45
+ });
46
+ expect(error.message).toContain("Test error");
47
+ expect(error.message).toContain("More details here");
48
+ });
49
+
50
+ it("sets fields in meta when provided", () => {
51
+ const error = new APIError({
52
+ fields: {email: "Invalid email format"},
53
+ title: "Validation error",
54
+ });
55
+ expect(error.meta?.fields).toEqual({email: "Invalid email format"});
56
+ });
57
+ });
58
+
59
+ describe("errorsPlugin", () => {
60
+ it("adds apiErrors field to schema", async () => {
61
+ const testSchema = new mongoose.Schema({name: String});
62
+ errorsPlugin(testSchema);
63
+
64
+ expect(testSchema.path("apiErrors")).toBeDefined();
65
+ });
66
+ });
67
+
68
+ describe("isAPIError", () => {
69
+ it("returns true for APIError instances", () => {
70
+ const error = new APIError({title: "Test"});
71
+ expect(isAPIError(error)).toBe(true);
72
+ });
73
+
74
+ it("returns false for regular Error instances", () => {
75
+ const error = new Error("Test");
76
+ expect(isAPIError(error)).toBe(false);
77
+ });
78
+ });
79
+
80
+ describe("getDisableExternalErrorTracking", () => {
81
+ it("returns undefined for non-objects", () => {
82
+ expect(getDisableExternalErrorTracking(null)).toBeUndefined();
83
+ expect(getDisableExternalErrorTracking("string")).toBeUndefined();
84
+ });
85
+
86
+ it("returns value from APIError", () => {
87
+ const error = new APIError({disableExternalErrorTracking: true, title: "Test"});
88
+ expect(getDisableExternalErrorTracking(error)).toBe(true);
89
+ });
90
+
91
+ it("returns value from plain object with property", () => {
92
+ const obj = {disableExternalErrorTracking: true};
93
+ expect(getDisableExternalErrorTracking(obj)).toBe(true);
94
+ });
95
+ });
96
+
97
+ describe("getAPIErrorBody", () => {
98
+ it("includes all non-undefined fields", () => {
99
+ const error = new APIError({
100
+ code: "TEST_CODE",
101
+ detail: "Test detail",
102
+ id: "error-123",
103
+ links: {about: "http://example.com"},
104
+ meta: {extra: "data"},
105
+ source: {parameter: "id"},
106
+ status: 400,
107
+ title: "Test error",
108
+ });
109
+ const body = getAPIErrorBody(error);
110
+
111
+ expect(body.title).toBe("Test error");
112
+ expect(body.status).toBe(400);
113
+ expect(body.code).toBe("TEST_CODE");
114
+ expect(body.detail).toBe("Test detail");
115
+ expect(body.id).toBe("error-123");
116
+ expect(body.links).toEqual({about: "http://example.com"});
117
+ expect(body.source).toEqual({parameter: "id"});
118
+ expect(body.meta).toEqual({extra: "data"});
119
+ });
120
+ });
121
+
122
+ describe("apiUnauthorizedMiddleware", () => {
123
+ it("returns 401 for Unauthorized errors", () => {
124
+ const err = new Error("Unauthorized");
125
+ const res = {
126
+ json: function (data: any) {
127
+ (this as any).body = data;
128
+ return this;
129
+ },
130
+ send: function () {
131
+ return this;
132
+ },
133
+ status: function (code: number) {
134
+ (this as any).statusCode = code;
135
+ return this;
136
+ },
137
+ };
138
+ const next = () => {};
139
+
140
+ apiUnauthorizedMiddleware(err, {} as any, res as any, next);
141
+ expect((res as any).statusCode).toBe(401);
142
+ expect((res as any).body.title).toBe("Unauthorized");
143
+ });
144
+
145
+ it("calls next for non-Unauthorized errors", () => {
146
+ const err = new Error("Some other error");
147
+ let nextCalled = false;
148
+ const next = () => {
149
+ nextCalled = true;
150
+ };
151
+
152
+ apiUnauthorizedMiddleware(err, {} as any, {} as any, next);
153
+ expect(nextCalled).toBe(true);
154
+ });
155
+ });
156
+ });