Files
cal.diy/packages/trpc/server/routers/viewer/organizations/intentToCreateOrg.handler.test.ts
T
837349e3d3 feat: Organization onboarding improvement - Payment before creation of org but onboarding doesn't require payment (#18990)
* create seed for org upgrade

* migrate about/new pages

* pages refactor + use persistant zustand store

* invited members view + confirm button

* add check to org slug

* check reserved subdomain

* remove quotes from subdomain env var

* intro to creation + billing

* create price

* fix types

* createWithPaymentIntent + permission check on teams

* open stripe link in popup

* intro to tests

* organization price and seat override tests

* move permissions to a new permission service

* update env and permission check

* intro to paid invoice trigger

* dont use subId

* wip

* Get e2e working with migration of teams and members

* fix ts errors

* Get flow working again

* Fix various issues and refactor

* Some more fixes

* Fix wrong page route link

* Platform onboarding fix and moving members of team to org rix

* Platform onboarding fix and moving members of team to org rix

* Fix tests, found a bug

* Get custom price flow working

* Get admin impersonation flow working for a non-existent user

* Fix unit test

* Admin onboarding handover

* fix admin onboarding tests

* fix ts error

* Get updateQuantity working

* More fixes

* fix test

* fix schema name

* Add tests

* Add missing file

* More tests

* Add more tests

* fix mt-2 moving down input into overflow

* fix handover layout removing HOC

* Update PR_TODO.md

* fix ts error due to merge conflict

---------

Co-authored-by: Hariom Balhara <hariombalhara@gmgmail.com>
Co-authored-by: Hariom <hariombalhara@gmail.com>
Co-authored-by: Omar López <zomars@me.com>
2025-03-13 11:17:43 +00:00

216 lines
5.8 KiB
TypeScript

import prismock from "../../../../../../tests/libs/__mocks__/prisma";
import { describe, expect, it, vi, beforeEach } from "vitest";
import { UserPermissionRole } from "@calcom/prisma/enums";
import { TRPCError } from "@trpc/server";
import { intentToCreateOrgHandler } from "./intentToCreateOrg.handler";
const mockInput = {
name: "Test Org",
slug: "test-org",
orgOwnerEmail: "test@example.com",
billingPeriod: "MONTHLY",
seats: 5,
pricePerSeat: 20,
isPlatform: false,
};
// Helper functions for creating test data
async function createTestUser(data: {
email: string;
name?: string;
username?: string;
role?: UserPermissionRole;
completedOnboarding?: boolean;
emailVerified?: Date | null;
}) {
return prismock.user.create({
data: {
email: data.email,
name: data.name || "Test User",
username: data.username || "testuser",
role: data.role || UserPermissionRole.USER,
completedOnboarding: data.completedOnboarding ?? false,
emailVerified: data.emailVerified ?? null,
},
});
}
describe("intentToCreateOrgHandler", () => {
beforeEach(async () => {
vi.resetAllMocks();
// @ts-expect-error reset is a method on Prismock
await prismock.reset();
});
it("should allow admin user to create org for another user", async () => {
// Create admin user
const adminUser = await createTestUser({
email: "admin@example.com",
role: UserPermissionRole.ADMIN,
});
// Create target org owner with completed onboarding and verified email
await createTestUser({
email: mockInput.orgOwnerEmail,
completedOnboarding: true,
emailVerified: new Date(),
});
const result = await intentToCreateOrgHandler({
input: mockInput,
ctx: {
user: adminUser,
},
});
// Verify the result shape
expect(result).toEqual({
userId: expect.any(Number),
orgOwnerEmail: mockInput.orgOwnerEmail,
name: mockInput.name,
slug: mockInput.slug,
seats: mockInput.seats,
pricePerSeat: mockInput.pricePerSeat,
billingPeriod: mockInput.billingPeriod,
isPlatform: mockInput.isPlatform,
organizationOnboardingId: expect.any(String),
});
// Verify organization onboarding was created
const organizationOnboarding = await prismock.organizationOnboarding.findFirst({
where: {
slug: mockInput.slug,
},
});
expect(organizationOnboarding).toBeDefined();
expect(organizationOnboarding?.name).toBe(mockInput.name);
expect(organizationOnboarding?.slug).toBe(mockInput.slug);
expect(organizationOnboarding?.orgOwnerEmail).toBe(mockInput.orgOwnerEmail);
});
it("should allow user to create org for themselves", async () => {
// Create user
const user = await createTestUser({
email: mockInput.orgOwnerEmail,
completedOnboarding: true,
emailVerified: new Date(),
});
const result = await intentToCreateOrgHandler({
input: {
...mockInput,
// Use default payment settings
seats: undefined,
pricePerSeat: undefined,
},
ctx: {
user,
},
});
expect(result.userId).toBe(user.id);
expect(result.orgOwnerEmail).toBe(user.email);
});
it("should throw unauthorized error when no user is logged in", async () => {
await expect(
intentToCreateOrgHandler({
input: mockInput,
ctx: {
user: null as any,
},
})
).rejects.toThrow(new TRPCError({ code: "UNAUTHORIZED", message: "You are not authorized." }));
});
it("should throw forbidden error when non-admin tries to create org for another user", async () => {
// Create non-admin user
const nonAdminUser = await createTestUser({
email: "nonadmin@example.com",
role: UserPermissionRole.USER,
});
await expect(
intentToCreateOrgHandler({
input: mockInput,
ctx: {
user: nonAdminUser,
},
})
).rejects.toThrow(
new TRPCError({
code: "FORBIDDEN",
message: "You can only create organization where you are the owner",
})
);
});
it("should throw error when target user is not found", async () => {
// Create admin user
const adminUser = await createTestUser({
email: "admin@example.com",
role: UserPermissionRole.ADMIN,
});
await expect(
intentToCreateOrgHandler({
input: mockInput,
ctx: {
user: adminUser,
},
})
).rejects.toThrow(
new TRPCError({
code: "BAD_REQUEST",
message: `No user found with email ${mockInput.orgOwnerEmail}`,
})
);
});
it("should throw error when organization onboarding already exists", async () => {
// Create admin user
const adminUser = await createTestUser({
email: "admin@example.com",
role: UserPermissionRole.ADMIN,
});
// Create target org owner
await createTestUser({
email: mockInput.orgOwnerEmail,
completedOnboarding: true,
emailVerified: new Date(),
});
// Create existing organization onboarding
await prismock.organizationOnboarding.create({
data: {
name: mockInput.name,
slug: mockInput.slug,
orgOwnerEmail: mockInput.orgOwnerEmail,
billingPeriod: mockInput.billingPeriod,
seats: mockInput.seats,
pricePerSeat: mockInput.pricePerSeat,
createdById: adminUser.id,
},
});
await expect(
intentToCreateOrgHandler({
input: mockInput,
ctx: {
user: adminUser,
},
})
).rejects.toThrow("organization_onboarding_already_exists");
});
// This endpoint doesn't handle platform organizations as that is completely different flow at the moment
// eslint-disable-next-line playwright/no-skipped-test
describe.skip("platform organization tests");
});