import { AxiosError } from "axios"; import { handleApiError, parseApiError } from "../apiErrorHandler"; describe("API Error Handler", () => { describe("parseApiError", () => { it("should return default message for non-Error objects", () => { const result = parseApiError("string error"); expect(result.generalMessage).toBe("Something went wrong. Please try again."); expect(result.fieldErrors).toEqual({}); }); it("should handle network errors (no response)", () => { const error = new Error("Network Error") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = undefined; const result = parseApiError(error); expect(result.generalMessage).toContain("Unable to connect"); }); it("should parse 400 errors with field-level errors", () => { const error = new Error("Bad Request") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 400, data: { errors: { email: "Invalid email format", full_name: ["Name is too short", "Name contains invalid characters"], }, }, statusText: "Bad Request", headers: {}, config: {} as any, }; const result = parseApiError(error); expect(result.generalMessage).toContain("Validation error"); expect(result.fieldErrors.email).toBe("Invalid email format"); expect(result.fieldErrors.full_name).toContain("Name is too short"); }); it("should parse 400 errors with message only", () => { const error = new Error("Bad Request") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 400, data: { message: "Custom validation error message", }, statusText: "Bad Request", headers: {}, config: {} as any, }; const result = parseApiError(error); expect(result.generalMessage).toBe("Custom validation error message"); }); it("should handle 401 unauthorized errors", () => { const error = new Error("Unauthorized") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 401, data: {}, statusText: "Unauthorized", headers: {}, config: {} as any, }; const result = parseApiError(error); expect(result.generalMessage).toContain("Authentication required"); }); it("should handle 422 unprocessable entity errors", () => { const error = new Error("Unprocessable Entity") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 422, data: { errors: { phone: "invalid_phone", }, }, statusText: "Unprocessable Entity", headers: {}, config: {} as any, }; const result = parseApiError(error); expect(result.generalMessage).toContain("Validation error"); expect(result.fieldErrors.phone).toContain("phone number"); }); it("should handle 429 rate limit errors", () => { const error = new Error("Too Many Requests") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 429, data: {}, statusText: "Too Many Requests", headers: {}, config: {} as any, }; const result = parseApiError(error); expect(result.generalMessage).toContain("Too many requests"); }); it("should handle 500 server errors", () => { const error = new Error("Internal Server Error") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 500, data: {}, statusText: "Internal Server Error", headers: {}, config: {} as any, }; const result = parseApiError(error); expect(result.generalMessage).toContain("Server error"); }); }); describe("handleApiError", () => { it("should call setError for each field error", () => { const mockSetError = jest.fn(); const mockShowToast = jest.fn(); const error = new Error("Bad Request") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 400, data: { errors: { email: "Invalid email", phone: "Invalid phone", }, }, statusText: "Bad Request", headers: {}, config: {} as any, }; handleApiError(error, mockSetError, mockShowToast, ["email", "phone"]); expect(mockSetError).toHaveBeenCalledTimes(2); expect(mockSetError).toHaveBeenCalledWith("email", { type: "server", message: "Invalid email", }); expect(mockSetError).toHaveBeenCalledWith("phone", { type: "server", message: "Invalid phone", }); expect(mockShowToast).toHaveBeenCalledWith( "Please correct the errors in the highlighted fields." ); }); it("should only set errors for fields in formFields list", () => { const mockSetError = jest.fn(); const mockShowToast = jest.fn(); const error = new Error("Bad Request") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 400, data: { errors: { email: "Invalid email", unknown_field: "Unknown error", }, }, statusText: "Bad Request", headers: {}, config: {} as any, }; handleApiError(error, mockSetError, mockShowToast, ["email"]); expect(mockSetError).toHaveBeenCalledTimes(1); expect(mockSetError).toHaveBeenCalledWith("email", { type: "server", message: "Invalid email", }); }); it("should show general message when no field errors", () => { const mockSetError = jest.fn(); const mockShowToast = jest.fn(); const error = new Error("Internal Server Error") as AxiosError; error.isAxiosError = true; (error as AxiosError).response = { status: 500, data: {}, statusText: "Internal Server Error", headers: {}, config: {} as any, }; handleApiError(error, mockSetError, mockShowToast, ["email"]); expect(mockSetError).not.toHaveBeenCalled(); expect(mockShowToast).toHaveBeenCalledWith(expect.stringContaining("Server error")); }); }); });