first commit
This commit is contained in:
12
calcom/apps/api/v1/test/README.md
Normal file
12
calcom/apps/api/v1/test/README.md
Normal 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
|
||||
15
calcom/apps/api/v1/test/docker-compose.yml
Normal file
15
calcom/apps/api/v1/test/docker-compose.yml
Normal 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
|
||||
15
calcom/apps/api/v1/test/jest-resolver.js
Normal file
15
calcom/apps/api/v1/test/jest-resolver.js
Normal 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;
|
||||
},
|
||||
});
|
||||
};
|
||||
6
calcom/apps/api/v1/test/jest-setup.js
Normal file
6
calcom/apps/api/v1/test/jest-setup.js
Normal 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;
|
||||
112
calcom/apps/api/v1/test/lib/attendees/_post.test.ts
Normal file
112
calcom/apps/api/v1/test/lib/attendees/_post.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
108
calcom/apps/api/v1/test/lib/bookings/_get.integration-test.ts
Normal file
108
calcom/apps/api/v1/test/lib/bookings/_get.integration-test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
268
calcom/apps/api/v1/test/lib/bookings/_post.test.ts
Normal file
268
calcom/apps/api/v1/test/lib/bookings/_post.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
143
calcom/apps/api/v1/test/lib/event-types/[id]/_get.test.ts
Normal file
143
calcom/apps/api/v1/test/lib/event-types/[id]/_get.test.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
36
calcom/apps/api/v1/test/lib/middleware/addRequestId.test.ts
Normal file
36
calcom/apps/api/v1/test/lib/middleware/addRequestId.test.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
53
calcom/apps/api/v1/test/lib/middleware/httpMethods.test.ts
Normal file
53
calcom/apps/api/v1/test/lib/middleware/httpMethods.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
146
calcom/apps/api/v1/test/lib/middleware/verifyApiKey.test.ts
Normal file
146
calcom/apps/api/v1/test/lib/middleware/verifyApiKey.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
121
calcom/apps/api/v1/test/lib/selected-calendars/_post.test.ts
Normal file
121
calcom/apps/api/v1/test/lib/selected-calendars/_post.test.ts
Normal 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");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user