[Closes #8] Added authentication
This commit is contained in:
parent
6eefa137bb
commit
97211cdccd
65 changed files with 5831 additions and 440 deletions
366
tests/server/api/[...auth].test.ts
Normal file
366
tests/server/api/[...auth].test.ts
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||
import type { H3Event } from "h3";
|
||||
|
||||
// Mock the auth utility
|
||||
const mocks = vi.hoisted(() => ({
|
||||
authHandler: vi.fn(),
|
||||
defineEventHandler: vi.fn((handler) => handler),
|
||||
toWebRequest: vi.fn((event: H3Event) => {
|
||||
// Create a mock Request object
|
||||
const url = event.node.req.url || "/";
|
||||
const method = event.node.req.method || "GET";
|
||||
return new Request(`http://localhost${url}`, {
|
||||
method,
|
||||
headers: event.node.req.headers as HeadersInit,
|
||||
});
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("~~/shared/utils/auth", () => ({
|
||||
auth: {
|
||||
handler: mocks.authHandler,
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock H3 utilities
|
||||
vi.mock("h3", async () => {
|
||||
const actual = await vi.importActual<typeof import("h3")>("h3");
|
||||
return {
|
||||
...actual,
|
||||
defineEventHandler: mocks.defineEventHandler,
|
||||
toWebRequest: mocks.toWebRequest,
|
||||
};
|
||||
});
|
||||
|
||||
describe("Auth API Handler", () => {
|
||||
let handler: any;
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
// Set up global functions for Nuxt auto-imports
|
||||
(globalThis as any).defineEventHandler = mocks.defineEventHandler;
|
||||
(globalThis as any).toWebRequest = mocks.toWebRequest;
|
||||
|
||||
// Dynamically import the handler after mocks are set up
|
||||
const module = await import("../../../server/api/[...auth]");
|
||||
handler = module.default;
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(handler).toBeDefined();
|
||||
expect(typeof handler).toBe("function");
|
||||
});
|
||||
|
||||
it("should call auth.handler with converted web request", async () => {
|
||||
// Mock H3Event
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "POST",
|
||||
url: "/api/auth/sign-in",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
// Mock the response from auth.handler
|
||||
const mockResponse = new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
// Call the handler
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
// Verify auth.handler was called
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Verify the result
|
||||
expect(result).toBe(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle GET requests", async () => {
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "GET",
|
||||
url: "/api/auth/session",
|
||||
headers: {},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(JSON.stringify({ user: null }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle POST requests for sign-in", async () => {
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "POST",
|
||||
url: "/api/auth/sign-in/email",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(
|
||||
JSON.stringify({
|
||||
user: {
|
||||
id: "123",
|
||||
email: "test@example.com",
|
||||
name: "Test User",
|
||||
},
|
||||
session: { token: "abc123" },
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
}
|
||||
);
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle POST requests for sign-up", async () => {
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "POST",
|
||||
url: "/api/auth/sign-up/email",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(
|
||||
JSON.stringify({
|
||||
user: {
|
||||
id: "456",
|
||||
email: "newuser@example.com",
|
||||
name: "New User",
|
||||
},
|
||||
session: { token: "xyz789" },
|
||||
}),
|
||||
{
|
||||
status: 201,
|
||||
headers: { "content-type": "application/json" },
|
||||
}
|
||||
);
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle POST requests for sign-out", async () => {
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "POST",
|
||||
url: "/api/auth/sign-out",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle error responses from auth.handler", async () => {
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "POST",
|
||||
url: "/api/auth/sign-in/email",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockErrorResponse = new Response(
|
||||
JSON.stringify({
|
||||
error: "Invalid credentials",
|
||||
}),
|
||||
{
|
||||
status: 401,
|
||||
headers: { "content-type": "application/json" },
|
||||
}
|
||||
);
|
||||
mocks.authHandler.mockResolvedValue(mockErrorResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockErrorResponse);
|
||||
});
|
||||
|
||||
it("should handle different HTTP methods", async () => {
|
||||
const methods = ["GET", "POST", "PUT", "DELETE", "PATCH"];
|
||||
|
||||
for (const method of methods) {
|
||||
vi.clearAllMocks();
|
||||
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method,
|
||||
url: "/api/auth/test",
|
||||
headers: {},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(JSON.stringify({ method }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockResponse);
|
||||
}
|
||||
});
|
||||
|
||||
it("should convert H3Event to Web Request correctly", async () => {
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "POST",
|
||||
url: "/api/auth/test",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
authorization: "Bearer token123",
|
||||
},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
await handler(mockEvent);
|
||||
|
||||
// Verify that auth.handler was called with a Request object
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
const callArg = mocks.authHandler.mock.calls[0][0];
|
||||
|
||||
// The argument should be a Request object (from toWebRequest conversion)
|
||||
expect(callArg).toBeDefined();
|
||||
});
|
||||
|
||||
it("should handle requests with query parameters", async () => {
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "GET",
|
||||
url: "/api/auth/session?redirect=/dashboard",
|
||||
headers: {},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(JSON.stringify({ user: null }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockResponse);
|
||||
});
|
||||
|
||||
it("should handle requests with different content types", async () => {
|
||||
const contentTypes = ["application/json", "application/x-www-form-urlencoded", "multipart/form-data"];
|
||||
|
||||
for (const contentType of contentTypes) {
|
||||
vi.clearAllMocks();
|
||||
|
||||
const mockEvent = {
|
||||
node: {
|
||||
req: {
|
||||
method: "POST",
|
||||
url: "/api/auth/sign-in",
|
||||
headers: {
|
||||
"content-type": contentType,
|
||||
},
|
||||
},
|
||||
res: {},
|
||||
},
|
||||
context: {},
|
||||
} as unknown as H3Event;
|
||||
|
||||
const mockResponse = new Response(JSON.stringify({ success: true }), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
mocks.authHandler.mockResolvedValue(mockResponse);
|
||||
|
||||
const result = await handler(mockEvent);
|
||||
|
||||
expect(mocks.authHandler).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe(mockResponse);
|
||||
}
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue