2
0

first commit

This commit is contained in:
2024-08-09 00:39:27 +02:00
commit 79688abe2e
5698 changed files with 497838 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
# Unit and Integration Tests
Make sure you have copied .env.test.example to .env.test
You can run all jest tests as
`yarn test`
You can run tests matching specific description by following command
`yarn test -t _post`
Tip: Use `--watchAll` flag to run tests on every change

View File

@@ -0,0 +1,15 @@
# Set the version of docker compose to use
version: "3.9"
# The containers that compose the project
services:
db:
image: postgres:13
restart: always
container_name: integration-tests-prisma
ports:
- "5433:5432"
environment:
POSTGRES_USER: prisma
POSTGRES_PASSWORD: prisma
POSTGRES_DB: tests

View File

@@ -0,0 +1,15 @@
module.exports = (path, options) => {
// Call the defaultResolver, so we leverage its cache, error handling, etc.
return options.defaultResolver(path, {
...options,
// Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
packageFilter: (pkg) => {
// See https://github.com/microsoft/accessibility-insights-web/blob/40416a4ae6b91baf43102f58e069eff787de4de2/src/tests/common/resolver.js
if (pkg.name === "uuid" || pkg.name === "nanoid") {
delete pkg["exports"];
delete pkg["module"];
}
return pkg;
},
});
};

View File

@@ -0,0 +1,6 @@
// This is a workaround for https://github.com/jsdom/jsdom/issues/2524#issuecomment-902027138
// See https://github.com/microsoft/accessibility-insights-web/blob/40416a4ae6b91baf43102f58e069eff787de4de2/src/tests/unit/jest-setup.ts
const { TextEncoder, TextDecoder } = require("util");
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;

View File

@@ -0,0 +1,112 @@
import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, test } from "vitest";
import handler from "../../../pages/api/attendees/_post";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
describe("POST /api/attendees", () => {
describe("Errors", () => {
test("Returns 403 if user is not admin and has no booking", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
bookingId: 1,
email: "test@example.com",
name: "Test User",
timeZone: "UTC",
},
});
prismaMock.booking.findFirst.mockResolvedValue(null);
req.userId = 123;
// req.isAdmin = false;
await handler(req, res);
expect(res.statusCode).toBe(403);
expect(JSON.parse(res._getData()).message).toBe("Forbidden");
});
test("Returns 200 if user is admin", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
bookingId: 1,
email: "test@example.com",
name: "Test User",
timeZone: "UTC",
},
});
const attendeeData = {
id: 1,
email: "test@example.com",
name: "Test User",
timeZone: "UTC",
bookingId: 1,
};
prismaMock.attendee.create.mockResolvedValue(attendeeData);
req.isSystemWideAdmin = true;
req.userId = 123;
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData()).attendee).toEqual(attendeeData);
expect(JSON.parse(res._getData()).message).toBe("Attendee created successfully");
});
test("Returns 200 if user is not admin but has a booking", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
bookingId: 1,
email: "test@example.com",
name: "Test User",
timeZone: "UTC",
},
});
const userBooking = { id: 1 };
prismaMock.booking.findFirst.mockResolvedValue(userBooking);
const attendeeData = {
id: 1,
email: "test@example.com",
name: "Test User",
timeZone: "UTC",
bookingId: 1,
};
prismaMock.attendee.create.mockResolvedValue(attendeeData);
req.userId = 123;
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData()).attendee).toEqual(attendeeData);
expect(JSON.parse(res._getData()).message).toBe("Attendee created successfully");
});
test("Returns 400 if request body is invalid", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
// Missing required fields
},
});
req.userId = 123;
await handler(req, res);
expect(res.statusCode).toBe(400);
});
});
});

View File

@@ -0,0 +1,87 @@
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, it, expect } from "vitest";
import prisma from "@calcom/prisma";
import handler from "../../../../pages/api/bookings/[id]/_patch";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
describe("PATCH /api/bookings", () => {
it("Returns 403 when user has no permission to the booking", async () => {
const memberUser = await prisma.user.findFirstOrThrow({ where: { email: "member2-acme@example.com" } });
const proUser = await prisma.user.findFirstOrThrow({ where: { email: "pro@example.com" } });
const booking = await prisma.booking.findFirstOrThrow({ where: { userId: proUser.id } });
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "PATCH",
body: {
title: booking.title,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
userId: memberUser.id,
},
query: {
id: booking.id,
},
});
req.userId = memberUser.id;
await handler(req, res);
expect(res.statusCode).toBe(403);
});
it("Allows PATCH when user is system-wide admin", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "admin@example.com" } });
const proUser = await prisma.user.findFirstOrThrow({ where: { email: "pro@example.com" } });
const booking = await prisma.booking.findFirstOrThrow({ where: { userId: proUser.id } });
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "PATCH",
body: {
title: booking.title,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
userId: proUser.id,
},
query: {
id: booking.id,
},
});
req.userId = adminUser.id;
req.isSystemWideAdmin = true;
await handler(req, res);
expect(res.statusCode).toBe(200);
});
it("Allows PATCH when user is org-wide admin", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const memberUser = await prisma.user.findFirstOrThrow({ where: { email: "member1-acme@example.com" } });
const booking = await prisma.booking.findFirstOrThrow({ where: { userId: memberUser.id } });
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "PATCH",
body: {
title: booking.title,
startTime: booking.startTime.toISOString(),
endTime: booking.endTime.toISOString(),
userId: memberUser.id,
},
query: {
id: booking.id,
},
});
req.userId = adminUser.id;
req.isOrganizationOwnerOrAdmin = true;
await handler(req, res);
expect(res.statusCode).toBe(200);
});
});

View File

@@ -0,0 +1,136 @@
import prismaMock from "../../../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, test, vi, afterEach } from "vitest";
import {
getRecordingsOfCalVideoByRoomName,
getDownloadLinkOfCalVideoByRecordingId,
} from "@calcom/core/videoClient";
import { buildBooking } from "@calcom/lib/test/builder";
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
import authMiddleware from "../../../../../pages/api/bookings/[id]/_auth-middleware";
import handler from "../../../../../pages/api/bookings/[id]/recordings/_get";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
const adminUserId = 1;
const memberUserId = 10;
vi.mock("@calcom/core/videoClient", () => {
return {
getRecordingsOfCalVideoByRoomName: vi.fn(),
getDownloadLinkOfCalVideoByRecordingId: vi.fn(),
};
});
vi.mock("~/lib/utils/retrieveScopedAccessibleUsers", () => {
return {
getAccessibleUsers: vi.fn(),
};
});
afterEach(() => {
vi.resetAllMocks();
});
const mockGetRecordingsAndDownloadLink = () => {
const download_link = "https://URL";
const recordingItem = {
id: "TEST_ID",
room_name: "0n22w24AQ5ZFOtEKX2gX",
start_ts: 1716215386,
status: "finished",
max_participants: 1,
duration: 11,
share_token: "TEST_TOKEN",
};
vi.mocked(getRecordingsOfCalVideoByRoomName).mockResolvedValue({ data: [recordingItem], total_count: 1 });
vi.mocked(getDownloadLinkOfCalVideoByRecordingId).mockResolvedValue({
download_link,
});
return [{ ...recordingItem, download_link }];
};
describe("GET /api/bookings/[id]/recordings", () => {
test("Returns recordings if user is system-wide admin", async () => {
const userId = 2;
const bookingId = 1111;
prismaMock.booking.findUnique.mockResolvedValue(
buildBooking({
id: bookingId,
userId,
references: [
{
id: 1,
type: "daily_video",
uid: "17OHkCH53pBa03FhxMbw",
meetingId: "17OHkCH53pBa03FhxMbw",
meetingPassword: "password",
meetingUrl: "https://URL",
},
],
})
);
const mockedRecordings = mockGetRecordingsAndDownloadLink();
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: bookingId,
},
});
req.isSystemWideAdmin = true;
req.userId = adminUserId;
await authMiddleware(req);
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData())).toEqual(mockedRecordings);
});
test("Allows GET recordings when user is org-wide admin", async () => {
const bookingId = 3333;
prismaMock.booking.findUnique.mockResolvedValue(
buildBooking({
id: bookingId,
userId: memberUserId,
references: [
{ id: 1, type: "daily_video", uid: "17OHkCH53pBa03FhxMbw", meetingId: "17OHkCH53pBa03FhxMbw" },
],
})
);
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: bookingId,
},
});
req.userId = adminUserId;
req.isOrganizationOwnerOrAdmin = true;
const mockedRecordings = mockGetRecordingsAndDownloadLink();
vi.mocked(getAccessibleUsers).mockResolvedValue([memberUserId]);
await authMiddleware(req);
await handler(req, res);
expect(res.statusCode).toBe(200);
});
});

View File

@@ -0,0 +1,129 @@
import prismaMock from "../../../../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, test, vi, afterEach } from "vitest";
import {
getTranscriptsAccessLinkFromRecordingId,
checkIfRoomNameMatchesInRecording,
} from "@calcom/core/videoClient";
import { buildBooking } from "@calcom/lib/test/builder";
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
import authMiddleware from "../../../../../../pages/api/bookings/[id]/_auth-middleware";
import handler from "../../../../../../pages/api/bookings/[id]/transcripts/[recordingId]/_get";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
vi.mock("@calcom/core/videoClient", () => {
return {
getTranscriptsAccessLinkFromRecordingId: vi.fn(),
checkIfRoomNameMatchesInRecording: vi.fn(),
};
});
vi.mock("~/lib/utils/retrieveScopedAccessibleUsers", () => {
return {
getAccessibleUsers: vi.fn(),
};
});
afterEach(() => {
vi.resetAllMocks();
});
const mockGetTranscripts = () => {
const downloadLinks = [{ format: "json", link: "https://URL1" }];
vi.mocked(getTranscriptsAccessLinkFromRecordingId).mockResolvedValue(downloadLinks);
vi.mocked(checkIfRoomNameMatchesInRecording).mockResolvedValue(true);
return downloadLinks;
};
const recordingId = "abc-xyz";
describe("GET /api/bookings/[id]/transcripts/[recordingId]", () => {
test("Returns transcripts if user is system-wide admin", async () => {
const adminUserId = 1;
const userId = 2;
const bookingId = 1111;
prismaMock.booking.findUnique.mockResolvedValue(
buildBooking({
id: bookingId,
userId,
references: [
{
id: 1,
type: "daily_video",
uid: "17OHkCH53pBa03FhxMbw",
meetingId: "17OHkCH53pBa03FhxMbw",
meetingPassword: "password",
meetingUrl: "https://URL",
},
],
})
);
const mockedTranscripts = mockGetTranscripts();
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: bookingId,
recordingId,
},
});
req.isSystemWideAdmin = true;
req.userId = adminUserId;
await authMiddleware(req);
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData())).toEqual(mockedTranscripts);
});
test("Allows GET transcripts when user is org-wide admin", async () => {
const adminUserId = 1;
const memberUserId = 10;
const bookingId = 3333;
prismaMock.booking.findUnique.mockResolvedValue(
buildBooking({
id: bookingId,
userId: memberUserId,
references: [
{ id: 1, type: "daily_video", uid: "17OHkCH53pBa03FhxMbw", meetingId: "17OHkCH53pBa03FhxMbw" },
],
})
);
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: bookingId,
recordingId,
},
});
req.userId = adminUserId;
req.isOrganizationOwnerOrAdmin = true;
mockGetTranscripts();
vi.mocked(getAccessibleUsers).mockResolvedValue([memberUserId]);
await authMiddleware(req);
await handler(req, res);
expect(res.statusCode).toBe(200);
});
});

View File

@@ -0,0 +1,120 @@
import prismaMock from "../../../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, test, vi, afterEach } from "vitest";
import { getAllTranscriptsAccessLinkFromRoomName } from "@calcom/core/videoClient";
import { buildBooking } from "@calcom/lib/test/builder";
import { getAccessibleUsers } from "~/lib/utils/retrieveScopedAccessibleUsers";
import authMiddleware from "../../../../../pages/api/bookings/[id]/_auth-middleware";
import handler from "../../../../../pages/api/bookings/[id]/transcripts/_get";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
vi.mock("@calcom/core/videoClient", () => {
return {
getAllTranscriptsAccessLinkFromRoomName: vi.fn(),
};
});
vi.mock("~/lib/utils/retrieveScopedAccessibleUsers", () => {
return {
getAccessibleUsers: vi.fn(),
};
});
afterEach(() => {
vi.resetAllMocks();
});
const mockGetTranscripts = () => {
const downloadLinks = ["https://URL1", "https://URL2"];
vi.mocked(getAllTranscriptsAccessLinkFromRoomName).mockResolvedValue(downloadLinks);
return downloadLinks;
};
describe("GET /api/bookings/[id]/transcripts", () => {
test("Returns transcripts if user is system-wide admin", async () => {
const adminUserId = 1;
const userId = 2;
const bookingId = 1111;
prismaMock.booking.findUnique.mockResolvedValue(
buildBooking({
id: bookingId,
userId,
references: [
{
id: 1,
type: "daily_video",
uid: "17OHkCH53pBa03FhxMbw",
meetingId: "17OHkCH53pBa03FhxMbw",
meetingPassword: "password",
meetingUrl: "https://URL",
},
],
})
);
const mockedTranscripts = mockGetTranscripts();
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: bookingId,
},
});
req.isSystemWideAdmin = true;
req.userId = adminUserId;
await authMiddleware(req);
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData())).toEqual(mockedTranscripts);
});
test("Allows GET transcripts when user is org-wide admin", async () => {
const adminUserId = 1;
const memberUserId = 10;
const bookingId = 3333;
prismaMock.booking.findUnique.mockResolvedValue(
buildBooking({
id: bookingId,
userId: memberUserId,
references: [
{ id: 1, type: "daily_video", uid: "17OHkCH53pBa03FhxMbw", meetingId: "17OHkCH53pBa03FhxMbw" },
],
})
);
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: bookingId,
},
});
req.userId = adminUserId;
req.isOrganizationOwnerOrAdmin = true;
mockGetTranscripts();
vi.mocked(getAccessibleUsers).mockResolvedValue([memberUserId]);
await authMiddleware(req);
await handler(req, res);
expect(res.statusCode).toBe(200);
});
});

View File

@@ -0,0 +1,92 @@
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, it, expect } from "vitest";
import type { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import authMiddleware from "../../../pages/api/bookings/[id]/_auth-middleware";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
describe("Bookings auth middleware", () => {
it("Returns 403 when user has no permission to the booking", async () => {
const trialUser = await prisma.user.findFirstOrThrow({ where: { email: "trial@example.com" } });
const proUser = await prisma.user.findFirstOrThrow({ where: { email: "pro@example.com" } });
const booking = await prisma.booking.findFirstOrThrow({ where: { userId: proUser.id } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: booking.id,
},
});
req.userId = trialUser.id;
try {
await authMiddleware(req);
} catch (error) {
const httpError = error as HttpError;
expect(httpError.statusCode).toBe(403);
}
});
it("No error is thrown when user is the booking user", async () => {
const proUser = await prisma.user.findFirstOrThrow({ where: { email: "pro@example.com" } });
const booking = await prisma.booking.findFirstOrThrow({ where: { userId: proUser.id } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: booking.id,
},
});
req.userId = proUser.id;
await authMiddleware(req);
});
it("No error is thrown when user is system-wide admin", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "admin@example.com" } });
const proUser = await prisma.user.findFirstOrThrow({ where: { email: "pro@example.com" } });
const booking = await prisma.booking.findFirstOrThrow({ where: { userId: proUser.id } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: booking.id,
},
});
req.userId = adminUser.id;
req.isSystemWideAdmin = true;
await authMiddleware(req);
});
it("No error is thrown when user is org-wide admin", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const memberUser = await prisma.user.findFirstOrThrow({ where: { email: "member1-acme@example.com" } });
const booking = await prisma.booking.findFirstOrThrow({ where: { userId: memberUser.id } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: booking.id,
},
});
req.userId = adminUser.id;
req.isOrganizationOwnerOrAdmin = true;
await authMiddleware(req);
});
});

View File

@@ -0,0 +1,108 @@
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, it } from "vitest";
import prisma from "@calcom/prisma";
import { handler } from "../../../pages/api/bookings/_get";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
const DefaultPagination = {
take: 10,
skip: 0,
};
describe("GET /api/bookings", async () => {
const proUser = await prisma.user.findFirstOrThrow({ where: { email: "pro@example.com" } });
const proUserBooking = await prisma.booking.findFirstOrThrow({ where: { userId: proUser.id } });
it("Does not return bookings of other users when user has no permission", async () => {
const memberUser = await prisma.user.findFirstOrThrow({ where: { email: "member2-acme@example.com" } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
query: {
userId: proUser.id,
},
pagination: DefaultPagination,
});
req.userId = memberUser.id;
const responseData = await handler(req);
const groupedUsers = new Set(responseData.bookings.map((b) => b.userId));
expect(responseData.bookings.find((b) => b.userId === memberUser.id)).toBeDefined();
expect(groupedUsers.size).toBe(1);
expect(groupedUsers.entries().next().value[0]).toBe(memberUser.id);
});
it("Returns bookings for regular user", async () => {
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
pagination: DefaultPagination,
});
req.userId = proUser.id;
const responseData = await handler(req);
expect(responseData.bookings.find((b) => b.id === proUserBooking.id)).toBeDefined();
expect(responseData.bookings.find((b) => b.userId !== proUser.id)).toBeUndefined();
});
it("Returns bookings for specified user when accessed by system-wide admin", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
pagination: DefaultPagination,
query: {
userId: proUser.id,
},
});
req.isSystemWideAdmin = true;
req.userId = adminUser.id;
const responseData = await handler(req);
expect(responseData.bookings.find((b) => b.id === proUserBooking.id)).toBeDefined();
expect(responseData.bookings.find((b) => b.userId !== proUser.id)).toBeUndefined();
});
it("Returns bookings for all users when accessed by system-wide admin", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
pagination: {
take: 100,
skip: 0,
},
});
req.isSystemWideAdmin = true;
req.userId = adminUser.id;
const responseData = await handler(req);
const groupedUsers = new Set(responseData.bookings.map((b) => b.userId));
expect(responseData.bookings.find((b) => b.id === proUserBooking.id)).toBeDefined();
expect(groupedUsers.size).toBeGreaterThan(2);
});
it("Returns bookings for org users when accessed by org admin", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
pagination: DefaultPagination,
});
req.userId = adminUser.id;
req.isOrganizationOwnerOrAdmin = true;
const responseData = await handler(req);
const groupedUsers = new Set(responseData.bookings.map((b) => b.userId));
expect(responseData.bookings.find((b) => b.id === proUserBooking.id)).toBeUndefined();
expect(groupedUsers.size).toBeGreaterThanOrEqual(2);
});
});

View File

@@ -0,0 +1,268 @@
// TODO: Fix tests (These test were never running due to the vitest workspace config)
import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, test, vi } from "vitest";
import dayjs from "@calcom/dayjs";
import sendPayload from "@calcom/features/webhooks/lib/sendOrSchedulePayload";
import { ErrorCode } from "@calcom/lib/errorCodes";
import { buildBooking, buildEventType, buildWebhook } from "@calcom/lib/test/builder";
import prisma from "@calcom/prisma";
import handler from "../../../pages/api/bookings/_post";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
vi.mock("@calcom/features/webhooks/lib/sendPayload");
vi.mock("@calcom/lib/server/i18n", () => {
return {
getTranslation: (key: string) => key,
};
});
describe.skipIf(true)("POST /api/bookings", () => {
describe("Errors", () => {
test("Missing required data", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
await handler(req, res);
expect(res.statusCode).toBe(400);
expect(JSON.parse(res._getData())).toEqual(
expect.objectContaining({
message:
"invalid_type in 'eventTypeId': Required; invalid_type in 'title': Required; invalid_type in 'startTime': Required; invalid_type in 'startTime': Required; invalid_type in 'endTime': Required; invalid_type in 'endTime': Required",
})
);
});
test("Invalid eventTypeId", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
title: "test",
eventTypeId: 2,
startTime: dayjs().toDate(),
endTime: dayjs().add(1, "day").toDate(),
},
prisma,
});
prismaMock.eventType.findUnique.mockResolvedValue(null);
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
expect(JSON.parse(res._getData())).toEqual(
expect.objectContaining({
message:
"'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required",
})
);
});
test("Missing recurringCount", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
title: "test",
eventTypeId: 2,
startTime: dayjs().toDate(),
endTime: dayjs().add(1, "day").toDate(),
},
prisma,
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } })
);
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
expect(JSON.parse(res._getData())).toEqual(
expect.objectContaining({
message:
"'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required",
})
);
});
test("Invalid recurringCount", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
title: "test",
eventTypeId: 2,
startTime: dayjs().toDate(),
endTime: dayjs().add(1, "day").toDate(),
recurringCount: 15,
},
prisma,
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } })
);
await handler(req, res);
expect(res._getStatusCode()).toBe(400);
expect(JSON.parse(res._getData())).toEqual(
expect.objectContaining({
message:
"'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required",
})
);
});
test("No available users", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
name: "test",
start: dayjs().format(),
end: dayjs().add(1, "day").format(),
eventTypeId: 2,
email: "test@example.com",
location: "Cal.com Video",
timeZone: "America/Montevideo",
language: "en",
customInputs: [],
metadata: {},
userId: 4,
},
prisma,
});
prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType());
await handler(req, res);
console.log({ statusCode: res._getStatusCode(), data: JSON.parse(res._getData()) });
expect(res._getStatusCode()).toBe(500);
expect(JSON.parse(res._getData())).toEqual(
expect.objectContaining({
message: ErrorCode.NoAvailableUsersFound,
})
);
});
});
describe("Success", () => {
describe("Regular event-type", () => {
test("Creates one single booking", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
name: "test",
start: dayjs().format(),
end: dayjs().add(1, "day").format(),
eventTypeId: 2,
email: "test@example.com",
location: "Cal.com Video",
timeZone: "America/Montevideo",
language: "en",
customInputs: [],
metadata: {},
userId: 4,
},
prisma,
});
prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType());
prismaMock.booking.findMany.mockResolvedValue([]);
await handler(req, res);
console.log({ statusCode: res._getStatusCode(), data: JSON.parse(res._getData()) });
expect(prismaMock.booking.create).toHaveBeenCalledTimes(1);
});
});
describe("Recurring event-type", () => {
test("Creates multiple bookings", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
title: "test",
eventTypeId: 2,
startTime: dayjs().toDate(),
endTime: dayjs().add(1, "day").toDate(),
recurringCount: 12,
},
prisma,
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } })
);
Array.from(Array(12).keys()).map(async () => {
prismaMock.booking.create.mockResolvedValue(buildBooking());
});
prismaMock.webhook.findMany.mockResolvedValue([]);
await handler(req, res);
const data = JSON.parse(res._getData());
expect(prismaMock.booking.create).toHaveBeenCalledTimes(12);
expect(res._getStatusCode()).toBe(201);
expect(data.message).toEqual("Bookings created successfully.");
expect(data.bookings.length).toEqual(12);
});
});
test("Notifies multiple bookings", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
title: "test",
eventTypeId: 2,
startTime: dayjs().toDate(),
endTime: dayjs().add(1, "day").toDate(),
recurringCount: 12,
},
prisma,
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } })
);
const createdAt = new Date();
Array.from(Array(12).keys()).map(async () => {
prismaMock.booking.create.mockResolvedValue(buildBooking({ createdAt }));
});
const mockedWebhooks = [
buildWebhook({
subscriberUrl: "http://mockedURL1.com",
createdAt,
eventTypeId: 1,
secret: "secret1",
}),
buildWebhook({
subscriberUrl: "http://mockedURL2.com",
createdAt,
eventTypeId: 2,
secret: "secret2",
}),
];
prismaMock.webhook.findMany.mockResolvedValue(mockedWebhooks);
await handler(req, res);
const data = JSON.parse(res._getData());
expect(sendPayload).toHaveBeenCalledTimes(24);
expect(data.message).toEqual("Bookings created successfully.");
expect(data.bookings.length).toEqual(12);
});
});
});

View File

@@ -0,0 +1,143 @@
import prismaMock from "../../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, test } from "vitest";
import { buildEventType } from "@calcom/lib/test/builder";
import { MembershipRole } from "@calcom/prisma/enums";
import handler from "../../../../pages/api/event-types/[id]/_get";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
describe("GET /api/event-types/[id]", () => {
describe("Errors", () => {
test("Returns 403 if user not admin/team member/event owner", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: 123456,
},
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({
id: 123456,
userId: 444444,
})
);
req.userId = 333333;
await handler(req, res);
expect(res.statusCode).toBe(403);
});
});
describe("Success", async () => {
test("Returns event type if user is admin", async () => {
const eventTypeId = 123456;
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: eventTypeId,
},
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({
id: eventTypeId,
})
);
req.isSystemWideAdmin = true;
req.userId = 333333;
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData()).event_type.id).toEqual(eventTypeId);
});
test("Returns event type if user is in team associated with event type", async () => {
const eventTypeId = 123456;
const teamId = 9999;
const userId = 333333;
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: eventTypeId,
},
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({
id: eventTypeId,
teamId,
})
);
prismaMock.team.findFirst.mockResolvedValue({
id: teamId,
members: [
{
userId,
},
],
});
req.isSystemWideAdmin = false;
req.userId = userId;
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData()).event_type.id).toEqual(eventTypeId);
expect(prismaMock.team.findFirst).toHaveBeenCalledWith({
where: {
id: teamId,
members: {
some: {
userId: req.userId,
role: {
in: [MembershipRole.OWNER, MembershipRole.ADMIN, MembershipRole.MEMBER],
},
},
},
},
});
});
test("Returns event type if user is the event type owner", async () => {
const eventTypeId = 123456;
const userId = 333333;
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "GET",
body: {},
query: {
id: eventTypeId,
},
});
prismaMock.eventType.findUnique.mockResolvedValue(
buildEventType({
id: eventTypeId,
userId,
scheduleId: 1111,
})
);
req.isSystemWideAdmin = false;
req.userId = userId;
await handler(req, res);
expect(res.statusCode).toBe(200);
expect(JSON.parse(res._getData()).event_type.id).toEqual(eventTypeId);
expect(prismaMock.team.findFirst).not.toHaveBeenCalled();
});
});
});

View File

@@ -0,0 +1,36 @@
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, vi, it, expect, afterEach } from "vitest";
import { addRequestId } from "../../../lib/helpers/addRequestid";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
afterEach(() => {
vi.resetAllMocks();
});
describe("Adds a request ID", () => {
it("Should attach a request ID to the request", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const middleware = {
fn: addRequestId,
};
const serverNext = vi.fn((next: void) => Promise.resolve(next));
const middlewareSpy = vi.spyOn(middleware, "fn");
await middleware.fn(req, res, serverNext);
expect(middlewareSpy).toBeCalled();
expect(res.statusCode).toBe(200);
expect(res.getHeader("Calcom-Response-ID")).toBeDefined();
});
});

View File

@@ -0,0 +1,53 @@
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, vi, it, expect, afterEach } from "vitest";
import { httpMethod } from "../../../lib/helpers/httpMethods";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
afterEach(() => {
vi.resetAllMocks();
});
describe("HTTP Methods function only allows the correct HTTP Methods", () => {
it("Should allow the passed in Method", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const middleware = {
fn: httpMethod("POST"),
};
const serverNext = vi.fn((next: void) => Promise.resolve(next));
const middlewareSpy = vi.spyOn(middleware, "fn");
await middleware.fn(req, res, serverNext);
expect(middlewareSpy).toBeCalled();
expect(res.statusCode).toBe(200);
});
it("Should allow the passed in Method", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const middleware = {
fn: httpMethod("GET"),
};
const serverNext = vi.fn((next: void) => Promise.resolve(next));
const middlewareSpy = vi.spyOn(middleware, "fn");
await middleware.fn(req, res, serverNext);
expect(middlewareSpy).toBeCalled();
expect(res.statusCode).toBe(405);
});
});

View File

@@ -0,0 +1,146 @@
import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, vi, it, expect, afterEach } from "vitest";
import checkLicense from "@calcom/features/ee/common/server/checkLicense";
import prisma from "@calcom/prisma";
import { isAdminGuard } from "~/lib/utils/isAdmin";
import { verifyApiKey } from "../../../lib/helpers/verifyApiKey";
import { ScopeOfAdmin } from "../../../lib/utils/scopeOfAdmin";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
afterEach(() => {
vi.resetAllMocks();
});
vi.mock("@calcom/features/ee/common/server/checkLicense", () => {
return {
default: vi.fn(),
};
});
vi.mock("~/lib/utils/isAdmin", () => {
return {
isAdminGuard: vi.fn(),
};
});
describe("Verify API key", () => {
it("It should throw an error if the api key is not valid", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const middleware = {
fn: verifyApiKey,
};
vi.mocked(checkLicense).mockResolvedValue(false);
vi.mocked(isAdminGuard).mockResolvedValue({ isAdmin: false, scope: null });
const serverNext = vi.fn((next: void) => Promise.resolve(next));
const middlewareSpy = vi.spyOn(middleware, "fn");
await middleware.fn(req, res, serverNext);
expect(middlewareSpy).toBeCalled();
expect(res.statusCode).toBe(401);
});
it("It should throw an error if no api key is provided", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const middleware = {
fn: verifyApiKey,
};
vi.mocked(checkLicense).mockResolvedValue(true);
vi.mocked(isAdminGuard).mockResolvedValue({ isAdmin: false, scope: null });
const serverNext = vi.fn((next: void) => Promise.resolve(next));
const middlewareSpy = vi.spyOn(middleware, "fn");
await middleware.fn(req, res, serverNext);
expect(middlewareSpy).toBeCalled();
expect(res.statusCode).toBe(401);
});
it("It should set correct permissions for system-wide admin", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
query: {
apiKey: "cal_test_key",
},
prisma,
});
prismaMock.apiKey.findUnique.mockResolvedValue({
id: 1,
userId: 2,
});
const middleware = {
fn: verifyApiKey,
};
vi.mocked(checkLicense).mockResolvedValue(true);
vi.mocked(isAdminGuard).mockResolvedValue({ isAdmin: true, scope: ScopeOfAdmin.SystemWide });
const serverNext = vi.fn((next: void) => Promise.resolve(next));
const middlewareSpy = vi.spyOn(middleware, "fn");
await middleware.fn(req, res, serverNext);
expect(middlewareSpy).toBeCalled();
expect(req.isSystemWideAdmin).toBe(true);
expect(req.isOrganizationOwnerOrAdmin).toBe(false);
});
it("It should set correct permissions for org-level admin", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
query: {
apiKey: "cal_test_key",
},
prisma,
});
prismaMock.apiKey.findUnique.mockResolvedValue({
id: 1,
userId: 2,
});
const middleware = {
fn: verifyApiKey,
};
vi.mocked(checkLicense).mockResolvedValue(true);
vi.mocked(isAdminGuard).mockResolvedValue({ isAdmin: true, scope: ScopeOfAdmin.OrgOwnerOrAdmin });
const serverNext = vi.fn((next: void) => Promise.resolve(next));
const middlewareSpy = vi.spyOn(middleware, "fn");
await middleware.fn(req, res, serverNext);
expect(middlewareSpy).toBeCalled();
expect(req.isSystemWideAdmin).toBe(false);
expect(req.isOrganizationOwnerOrAdmin).toBe(true);
});
});

View File

@@ -0,0 +1,121 @@
import prismaMock from "../../../../../../tests/libs/__mocks__/prismaMock";
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, expect, test } from "vitest";
import { HttpError } from "@calcom/lib/http-error";
import handler from "../../../pages/api/selected-calendars/_post";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
describe("POST /api/selected-calendars", () => {
describe("Errors", () => {
test("Returns 403 if non-admin user tries to set userId in body", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
integration: "google",
externalId: "ext123",
userId: 444444,
},
});
req.userId = 333333;
try {
await handler(req, res);
} catch (e) {
expect(e).toBeInstanceOf(HttpError);
expect((e as HttpError).statusCode).toBe(403);
expect((e as HttpError).message).toBe("ADMIN required for userId");
}
});
test("Returns 400 if request body is invalid", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {
integration: "google",
},
});
req.userId = 333333;
req.isSystemWideAdmin = true;
await handler(req, res);
expect(res.statusCode).toBe(400);
expect(JSON.parse(res._getData()).message).toBe("invalid_type in 'externalId': Required");
});
});
describe("Success", () => {
test("Creates selected calendar if user is admin and sets bodyUserId", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
query: {
apiKey: "validApiKey",
},
body: {
integration: "google",
externalId: "ext123",
userId: 444444,
},
});
req.userId = 333333;
req.isSystemWideAdmin = true;
prismaMock.user.findFirstOrThrow.mockResolvedValue({
id: 444444,
} as any);
prismaMock.selectedCalendar.create.mockResolvedValue({
credentialId: 1,
integration: "google",
externalId: "ext123",
userId: 444444,
});
await handler(req, res);
expect(res.statusCode).toBe(200);
const responseData = JSON.parse(res._getData());
expect(responseData.selected_calendar.credentialId).toBe(1);
expect(responseData.message).toBe("Selected Calendar created successfully");
});
test("Creates selected calendar if user is non-admin and does not set bodyUserId", async () => {
const { req, res } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
query: {
apiKey: "validApiKey",
},
body: {
integration: "google",
externalId: "ext123",
},
});
req.userId = 333333;
prismaMock.selectedCalendar.create.mockResolvedValue({
credentialId: 1,
integration: "google",
externalId: "ext123",
userId: 333333,
});
await handler(req, res);
expect(res.statusCode).toBe(200);
const responseData = JSON.parse(res._getData());
expect(responseData.selected_calendar.credentialId).toBe(1);
expect(responseData.message).toBe("Selected Calendar created successfully");
});
});
});

View File

@@ -0,0 +1,76 @@
import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { createMocks } from "node-mocks-http";
import { describe, it, expect } from "vitest";
import prisma from "@calcom/prisma";
import { isAdminGuard } from "../../../lib/utils/isAdmin";
import { ScopeOfAdmin } from "../../../lib/utils/scopeOfAdmin";
type CustomNextApiRequest = NextApiRequest & Request;
type CustomNextApiResponse = NextApiResponse & Response;
describe("isAdmin guard", () => {
it("Returns false when user does not exist in the system", async () => {
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
req.userId = 0;
const { isAdmin, scope } = await isAdminGuard(req);
expect(isAdmin).toBe(false);
expect(scope).toBe(null);
});
it("Returns false when org user is a member", async () => {
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const memberUser = await prisma.user.findFirstOrThrow({ where: { email: "member2-acme@example.com" } });
req.userId = memberUser.id;
const { isAdmin, scope } = await isAdminGuard(req);
expect(isAdmin).toBe(false);
expect(scope).toBe(null);
});
it("Returns system-wide admin when user is marked as such", async () => {
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "admin@example.com" } });
req.userId = adminUser.id;
const { isAdmin, scope } = await isAdminGuard(req);
expect(isAdmin).toBe(true);
expect(scope).toBe(ScopeOfAdmin.SystemWide);
});
it("Returns org-wide admin when user is set as such", async () => {
const { req } = createMocks<CustomNextApiRequest, CustomNextApiResponse>({
method: "POST",
body: {},
});
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
req.userId = adminUser.id;
const { isAdmin, scope } = await isAdminGuard(req);
expect(isAdmin).toBe(true);
expect(scope).toBe(ScopeOfAdmin.OrgOwnerOrAdmin);
});
});

View File

@@ -0,0 +1,90 @@
import { describe, it, expect } from "vitest";
import prisma from "@calcom/prisma";
import {
getAccessibleUsers,
retrieveOrgScopedAccessibleUsers,
} from "../../../lib/utils/retrieveScopedAccessibleUsers";
describe("retrieveScopedAccessibleUsers tests", () => {
describe("getAccessibleUsers", () => {
it("Does not return members when only admin user ID is supplied", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const accessibleUserIds = await getAccessibleUsers({
memberUserIds: [],
adminUserId: adminUser.id,
});
expect(accessibleUserIds.length).toBe(0);
});
it("Does not return members when admin user ID is not an admin of the user", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-dunder@example.com" } });
const memberOneUser = await prisma.user.findFirstOrThrow({
where: { email: "member1-acme@example.com" },
});
const accessibleUserIds = await getAccessibleUsers({
memberUserIds: [memberOneUser.id],
adminUserId: adminUser.id,
});
expect(accessibleUserIds.length).toBe(0);
});
it("Returns members when admin user ID is supplied and members IDs are supplied", async () => {
const adminUser = await prisma.user.findFirstOrThrow({ where: { email: "owner1-acme@example.com" } });
const memberOneUser = await prisma.user.findFirstOrThrow({
where: { email: "member1-acme@example.com" },
});
const memberTwoUser = await prisma.user.findFirstOrThrow({
where: { email: "member2-acme@example.com" },
});
const accessibleUserIds = await getAccessibleUsers({
memberUserIds: [memberOneUser.id, memberTwoUser.id],
adminUserId: adminUser.id,
});
expect(accessibleUserIds.length).toBe(2);
expect(accessibleUserIds).toContain(memberOneUser.id);
expect(accessibleUserIds).toContain(memberTwoUser.id);
});
});
describe("retrieveOrgScopedAccessibleUsers", () => {
it("Does not return members when admin user ID is an admin of an org", async () => {
const memberOneUser = await prisma.user.findFirstOrThrow({
where: { email: "member1-acme@example.com" },
});
const accessibleUserIds = await retrieveOrgScopedAccessibleUsers({
adminId: memberOneUser.id,
});
expect(accessibleUserIds.length).toBe(0);
});
it("Returns members when admin user ID is an admin of an org", async () => {
const adminUser = await prisma.user.findFirstOrThrow({
where: { email: "owner1-acme@example.com" },
});
const accessibleUserIds = await retrieveOrgScopedAccessibleUsers({
adminId: adminUser.id,
});
const memberOneUser = await prisma.user.findFirstOrThrow({
where: { email: "member1-acme@example.com" },
});
const memberTwoUser = await prisma.user.findFirstOrThrow({
where: { email: "member2-acme@example.com" },
});
expect(accessibleUserIds.length).toBe(3);
expect(accessibleUserIds).toContain(memberOneUser.id);
expect(accessibleUserIds).toContain(memberTwoUser.id);
expect(accessibleUserIds).toContain(adminUser.id);
});
});
});