Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions test/api-endpoints/availability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@

import type { APIContext } from "astro";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { hashPassword } from "#/src/lib/server_helpers.ts";

vi.mock("drizzle-orm", () => {
// Mock `drizzle-orm`'s `eq` function
vi.mock("drizzle-orm", async (importOriginal) => {
const actual = await importOriginal<typeof import("drizzle-orm")>();
return {
...actual,
eq: (left: unknown, right: unknown) => ({ left, right }),
};
});


vi.mock("nanoid", () => {
return {
nanoid: () => "fixed-nanoid",
Expand Down Expand Up @@ -79,23 +84,38 @@ vi.mock("drizzle-orm/d1", async () => {

// Import the mocked module statically (vi.mock is hoisted so this is our mock)
import * as mockD1 from "drizzle-orm/d1";
//import { hash } from "node:crypto";

function makeApiContext(opts: {
params?: Record<string, string | undefined>;
jsonBody?: unknown;
url?: string;
meetingIdForCookie?: string;
authCookieValue?: string;
}) {
const {
params = {},
jsonBody = undefined,
url = "https://example.test/",
meetingIdForCookie = params.meetingId ?? "test-meeting-id",
authCookieValue = "test-cookie",
} = opts;

const request = {
json: async () => jsonBody,
url,
} as unknown as Request;

const cookies = {
get: (name: string) => {
const expected = `auth-cookie-for-meeting-${meetingIdForCookie}`;
if (name === expected) {
return { value: authCookieValue };
}
return undefined;
},
} as any;

const context = {
params,
locals: {
Expand All @@ -104,6 +124,7 @@ function makeApiContext(opts: {
},
},
request,
cookies,
} as unknown as APIContext;

return context;
Expand All @@ -122,13 +143,23 @@ describe("PUT /api/meetings/[meetingId]/availability/[memberId] (server handler)

it("Creates availability for existing member & meeting -> returns 201 and availability body", async () => {
// existing member row
const memberRow = { id: "aaaaaaaaaaaaaaaaaaaaa", defaultName: "Sam" };
const memberRow = {
id: "aaaaaaaaaaaaaaaaaaaaa",
defaultName: "Sam",
hashedPassword: await hashPassword("test-hash" as any),
authCookie: "aaaaaaaaaaaaaaaaaaaaa" as any
};

// existing meeting without this member's availability
const meeting = {
name: "Weekly",
availability: {}, // empty
members: [{ memberId: memberRow.id, name: memberRow.defaultName }],
members: [{
memberId: memberRow.id,
name: memberRow.defaultName,
hashedPassword: memberRow.hashedPassword,
authCookie: memberRow.authCookie
}],
availabilityBounds: {
availableDayConstraints: { type: "daysOfWeek", days: ["monday"] },
timeRangeForEachDay: {
Expand Down Expand Up @@ -165,6 +196,8 @@ describe("PUT /api/meetings/[meetingId]/availability/[memberId] (server handler)
params: { meetingId: "m1", memberId: memberRow.id },
jsonBody: newAvailability,
url: "https://example.test/api/meetings/m1/availability/aaaaaaaaaaaaaaaaaaaaa",
meetingIdForCookie: "m1",
authCookieValue: memberRow.authCookie,
});

const { PUT } = await import(
Expand Down
6 changes: 4 additions & 2 deletions test/api-endpoints/meetings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
import type { APIContext } from "astro";
import { beforeEach, describe, expect, it, vi } from "vitest";

// Mock `drizzle-orm`'s `eq` to return a plain object we can inspect in the fake DB.
vi.mock("drizzle-orm", () => {
// Mock `drizzle-orm`'s `eq` function
vi.mock("drizzle-orm", async (importOriginal) => {
const actual = await importOriginal<typeof import("drizzle-orm")>();
return {
...actual,
eq: (left: unknown, right: unknown) => ({ left, right }),
};
});
Expand Down
9 changes: 8 additions & 1 deletion test/library-functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import * as usersApi from "../src/lib/api/users";
* - Fallback to JSON parsing when content-type is wrong but body is JSON.
* - Throws when content-type unsupported and JSON parse fails.
*/

vi.stubGlobal("window", { location: { origin: "http://localhost" } });

describe("handleApiResponse", () => {
it("returns undefined for 204 No Content", async () => {
const res = new Response(null, {
Expand Down Expand Up @@ -180,6 +183,7 @@ describe("meetings API client", () => {
const sampleMeeting = {
name: "Team Sync",
availability: {},
members: [],
availabilityBounds: {
availableDayConstraints: { type: "daysOfWeek", days: ["monday"] },
timeRangeForEachDay: {
Expand All @@ -206,7 +210,10 @@ describe("meetings API client", () => {
const meetingPartial = { name: "x" };
const fakeResponse = new Response(JSON.stringify({ id: "m1" }), {
status: 201,
headers: { "content-type": "application/json" },
headers: {
"content-type": "application/json",
Location: "/api/meeetings/m1",
},
});

globalThis.fetch = vi.fn(async (input: RequestInfo, init?: RequestInit) => {
Expand Down