From fcab386647dc5c9bbcfd3a37855e7edc7b88ad25 Mon Sep 17 00:00:00 2001 From: wsdt Date: Thu, 20 Mar 2025 14:47:27 +0100 Subject: [PATCH] chore: Add more CrossmintAuth tests, add isEmailValid tests --- .../common/auth/src/CrossmintAuth.test.ts | 161 ++++++++++++++++++ .../auth/src/utils/isEmailValid.test.ts | 33 ++++ 2 files changed, 194 insertions(+) create mode 100644 packages/common/auth/src/utils/isEmailValid.test.ts diff --git a/packages/common/auth/src/CrossmintAuth.test.ts b/packages/common/auth/src/CrossmintAuth.test.ts index db7832c6c..45e396b35 100644 --- a/packages/common/auth/src/CrossmintAuth.test.ts +++ b/packages/common/auth/src/CrossmintAuth.test.ts @@ -35,4 +35,165 @@ describe("CrossmintAuth", () => { expect(crossmintAuth.getJwksUri()).toBe("https://api.crossmint.com/.well-known/jwks.json"); }); }); + + describe("refreshAuthMaterial", () => { + it("should throw an error when refresh token is missing and no custom route is set", async () => { + await expect( + (crossmintAuth as any).refreshAuthMaterial() + ).rejects.toThrow("Refresh token missing from parameters"); + }); + + it("should call refresh method when refresh token is provided", async () => { + const refreshSpy = vi.spyOn(crossmintAuth as any, "refresh").mockResolvedValue({ + jwt: "test-jwt", + refreshToken: "test-refresh-token", + user: { id: "user-id" } + }); + + await (crossmintAuth as any).refreshAuthMaterial("test-refresh-token"); + + expect(refreshSpy).toHaveBeenCalledWith("test-refresh-token"); + }); + + it("should call refreshFromCustomRoute when custom route is set", async () => { + const customRouteAuth = CrossmintAuth.from( + mockCrossmint as unknown as Crossmint, + { refreshRoute: "https://custom-route.com/refresh" } + ); + + const refreshCustomSpy = vi.spyOn(customRouteAuth as any, "refreshFromCustomRoute").mockResolvedValue({ + jwt: "test-jwt", + refreshToken: "test-refresh-token", + user: { id: "user-id" } + }); + + await (customRouteAuth as any).refreshAuthMaterial("test-refresh-token"); + + expect(refreshCustomSpy).toHaveBeenCalledWith("test-refresh-token"); + }); + }); + + describe("refresh", () => { + it("should call the API client with correct parameters", async () => { + mockApiClient.post.mockResolvedValue({ + ok: true, + json: async () => ({ + jwt: "test-jwt", + refresh: "test-refresh-token", + user: { id: "user-id" } + }) + }); + + const result = await (crossmintAuth as any).refresh("test-refresh-token"); + + expect(mockApiClient.post).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + body: JSON.stringify({ refresh: "test-refresh-token" }), + headers: { "Content-Type": "application/json" } + }) + ); + expect(result).toEqual({ + jwt: "test-jwt", + refreshToken: "test-refresh-token", + user: { id: "user-id" } + }); + }); + + it("should throw an error when the API response is not ok", async () => { + mockApiClient.post.mockResolvedValue({ + ok: false, + statusText: "Unauthorized" + }); + + await expect( + (crossmintAuth as any).refresh("test-refresh-token") + ).rejects.toThrow("Unauthorized"); + }); + }); + + describe("refreshFromCustomRoute", () => { + it("should throw an error when custom refresh route is not set", async () => { + await expect( + (crossmintAuth as any).refreshFromCustomRoute("test-refresh-token") + ).rejects.toThrow("Custom refresh route is not set"); + }); + + it("should fetch from the custom route when set", async () => { + const customRouteAuth = CrossmintAuth.from( + mockCrossmint as unknown as Crossmint, + { refreshRoute: "https://custom-route.com/refresh" } + ); + + global.fetch = vi.fn().mockResolvedValue({ + ok: true, + json: async () => ({ + jwt: "test-jwt", + refreshToken: "test-refresh-token", + user: { id: "user-id" } + }) + }); + + const result = await (customRouteAuth as any).refreshFromCustomRoute("test-refresh-token"); + + expect(global.fetch).toHaveBeenCalledWith( + "https://custom-route.com/refresh", + expect.objectContaining({ + method: "POST", + body: JSON.stringify({ refresh: "test-refresh-token" }), + headers: { "Content-Type": "application/json" } + }) + ); + expect(result).toEqual({ + jwt: "test-jwt", + refreshToken: "test-refresh-token", + user: { id: "user-id" } + }); + }); + + it("should throw an error when the custom route response is not ok", async () => { + const customRouteAuth = CrossmintAuth.from( + mockCrossmint as unknown as Crossmint, + { refreshRoute: "https://custom-route.com/refresh" } + ); + + global.fetch = vi.fn().mockResolvedValue({ + ok: false, + json: async () => ({ message: "Authentication failed" }) + }); + + await expect( + (customRouteAuth as any).refreshFromCustomRoute("test-refresh-token") + ).rejects.toThrow("Authentication failed"); + }); + }); + + describe("logoutFromDefaultRoute", () => { + it("should call the API client with correct parameters", async () => { + mockApiClient.post.mockResolvedValue({ ok: true }); + + await (crossmintAuth as any).logoutFromDefaultRoute("test-refresh-token"); + + expect(mockApiClient.post).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + body: JSON.stringify({ refresh: "test-refresh-token" }), + headers: { "Content-Type": "application/json" } + }) + ); + }); + }); + + describe("defaultApiClient", () => { + it("should create a new CrossmintApiClient with the correct parameters", () => { + CrossmintAuth.defaultApiClient(mockCrossmint as unknown as Crossmint); + + expect(CrossmintApiClient).toHaveBeenCalledWith( + mockCrossmint, + expect.objectContaining({ + internalConfig: expect.anything() + }) + ); + }); + }); }); diff --git a/packages/common/auth/src/utils/isEmailValid.test.ts b/packages/common/auth/src/utils/isEmailValid.test.ts new file mode 100644 index 000000000..78f5ca415 --- /dev/null +++ b/packages/common/auth/src/utils/isEmailValid.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "vitest"; +import { isEmailValid } from "./isEmailValid"; + +describe("isEmailValid", () => { + it("should return true for valid email addresses", () => { + expect(isEmailValid("test@example.com")).toBe(true); + expect(isEmailValid("user.name@example.com")).toBe(true); + expect(isEmailValid("user+tag@example.com")).toBe(true); + expect(isEmailValid("user@sub.domain.example.com")).toBe(true); + expect(isEmailValid("123@example.com")).toBe(true); + expect(isEmailValid("user@example.co.uk")).toBe(true); + }); + + it("should return false for invalid email addresses", () => { + expect(isEmailValid("")).toBe(false); + expect(isEmailValid("test")).toBe(false); + expect(isEmailValid("test@")).toBe(false); + expect(isEmailValid("@example.com")).toBe(false); + expect(isEmailValid("test@example")).toBe(false); + expect(isEmailValid("test@.com")).toBe(false); + expect(isEmailValid("test@example.")).toBe(false); + expect(isEmailValid("test@exam ple.com")).toBe(false); + expect(isEmailValid(" test@example.com")).toBe(false); + expect(isEmailValid("test@example.com ")).toBe(false); + }); + + it("should handle edge cases correctly", () => { + expect(isEmailValid("a@b.c")).toBe(true); // Minimal valid email + expect(isEmailValid("test@localhost")).toBe(false); // Missing TLD + expect(isEmailValid("test.example.com")).toBe(false); // Missing @ symbol + expect(isEmailValid("test@@example.com")).toBe(false); // Double @ symbol + }); +}); \ No newline at end of file