import { describe, expect, beforeAll, afterAll, beforeEach, it } from "vitest"; import prisma from "@calcom/prisma"; import type { AppFlags } from "./config"; import { FeaturesRepository } from "./features.repository"; const featuresRepository = new FeaturesRepository(prisma); // Access private clearCache method through type assertion const clearCache = () => { (featuresRepository as any).clearCache(); }; describe("FeaturesRepository Integration Tests", () => { let testUser: { id: number }; let testTeam: { id: number }; const testFeature = "teams" as keyof AppFlags; beforeAll(async () => { // Create test user testUser = await prisma.user.create({ data: { email: `test-${Date.now()}@example.com`, username: `test-${Date.now()}`, }, }); // Create test team testTeam = await prisma.team.create({ data: { name: `Test Team ${Date.now()}`, slug: `test-team-${Date.now()}`, }, }); }); afterAll(async () => { // Clean up test data in correct order to respect foreign key constraints await prisma.userFeatures.deleteMany({ where: { userId: testUser.id }, }); await prisma.teamFeatures.deleteMany({ where: { teamId: testTeam.id }, }); await prisma.feature.deleteMany({ where: { slug: testFeature }, }); await prisma.membership.deleteMany({ where: { userId: testUser.id }, }); await prisma.team.deleteMany({ where: { id: testTeam.id }, }); await prisma.user.delete({ where: { id: testUser.id }, }); }); beforeEach(async () => { // Reset feature state before each test await prisma.feature.deleteMany({ where: { slug: testFeature }, }); await prisma.userFeatures.deleteMany({ where: { userId: testUser.id }, }); await prisma.teamFeatures.deleteMany({ where: { teamId: testTeam.id }, }); await prisma.membership.deleteMany({ where: { teamId: testTeam.id }, }); await prisma.team.deleteMany({ where: { id: testTeam.id }, }); // Recreate test team testTeam = await prisma.team.create({ data: { name: `Test Team ${Date.now()}`, slug: `test-team-${Date.now()}`, }, }); // Clear the feature flag cache clearCache(); }); describe("checkIfFeatureIsEnabledGlobally", () => { it("should return false when feature is not enabled globally", async () => { // Verify database state const dbFeature = await prisma.feature.findUnique({ where: { slug: testFeature }, }); expect(dbFeature).toBeNull(); // First call to initialize cache await featuresRepository.checkIfFeatureIsEnabledGlobally(testFeature); // Second call to get actual result const result = await featuresRepository.checkIfFeatureIsEnabledGlobally(testFeature); expect(result).toBe(false); }); it("should return true when feature is enabled globally", async () => { // Create the feature with enabled set to true await prisma.feature.create({ data: { slug: testFeature, enabled: true, type: "OPERATIONAL", }, }); // Clear the feature flag cache clearCache(); // Verify database state const dbFeature = await prisma.feature.findUnique({ where: { slug: testFeature }, }); expect(dbFeature).not.toBeNull(); expect(dbFeature?.enabled).toBe(true); // First call to initialize cache await featuresRepository.checkIfFeatureIsEnabledGlobally(testFeature); // Second call to get actual result const result = await featuresRepository.checkIfFeatureIsEnabledGlobally(testFeature); expect(result).toBe(true); }); }); describe("checkIfUserHasFeature", () => { it("should return false when user does not have feature", async () => { const result = await featuresRepository.checkIfUserHasFeature(testUser.id, testFeature); expect(result).toBe(false); }); it("should return true when user has feature directly assigned", async () => { await prisma.feature.create({ data: { slug: testFeature, enabled: true, type: "OPERATIONAL", }, }); await prisma.userFeatures.create({ data: { userId: testUser.id, featureId: testFeature, assignedBy: "test", }, }); const result = await featuresRepository.checkIfUserHasFeature(testUser.id, testFeature); expect(result).toBe(true); }); it("should return true when user belongs to team with feature", async () => { await prisma.feature.create({ data: { slug: testFeature, enabled: true, type: "OPERATIONAL", }, }); await prisma.teamFeatures.create({ data: { teamId: testTeam.id, featureId: testFeature, assignedBy: "test", }, }); await prisma.membership.create({ data: { teamId: testTeam.id, userId: testUser.id, role: "MEMBER", accepted: true, }, }); const result = await featuresRepository.checkIfUserHasFeature(testUser.id, testFeature); expect(result).toBe(true); }); it("should return true when user belongs to team where parent team has feature", async () => { // Create an organization const org = await prisma.team.create({ data: { name: `Test Org ${Date.now()}`, slug: `test-org-${Date.now()}`, isOrganization: true, }, }); // Make the test team part of the organization await prisma.team.update({ where: { id: testTeam.id }, data: { parentId: org.id }, }); // Create the feature await prisma.feature.create({ data: { slug: testFeature, enabled: true, type: "OPERATIONAL", }, }); // Clear the feature flag cache clearCache(); // Assign feature to the organization await prisma.teamFeatures.create({ data: { teamId: org.id, featureId: testFeature, assignedBy: "test", }, }); // Check if user is already a member of the team const existingMembership = await prisma.membership.findFirst({ where: { teamId: testTeam.id, userId: testUser.id, }, }); // Only create membership if it doesn't exist if (!existingMembership) { await prisma.membership.create({ data: { teamId: testTeam.id, userId: testUser.id, role: "MEMBER", accepted: true, }, }); } const result = await featuresRepository.checkIfUserHasFeature(testUser.id, testFeature); expect(result).toBe(true); // Clean up organization await prisma.teamFeatures.deleteMany({ where: { teamId: org.id }, }); await prisma.team.delete({ where: { id: org.id }, }); }); }); describe("checkIfTeamHasFeature", () => { it("should return false when team does not have feature", async () => { const result = await featuresRepository.checkIfTeamHasFeature(testTeam.id, testFeature); expect(result).toBe(false); }); it("should return true when team has feature directly assigned", async () => { await prisma.feature.create({ data: { slug: testFeature, enabled: true, type: "OPERATIONAL", }, }); await prisma.teamFeatures.create({ data: { teamId: testTeam.id, featureId: testFeature, assignedBy: "test", }, }); const result = await featuresRepository.checkIfTeamHasFeature(testTeam.id, testFeature); expect(result).toBe(true); }); it("should return true when parent team has feature", async () => { const parentTeam = await prisma.team.create({ data: { name: `Parent Team ${Date.now()}`, slug: `parent-team-${Date.now()}`, }, }); await prisma.team.update({ where: { id: testTeam.id }, data: { parentId: parentTeam.id }, }); await prisma.feature.create({ data: { slug: testFeature, enabled: true, type: "OPERATIONAL", }, }); await prisma.teamFeatures.create({ data: { teamId: parentTeam.id, featureId: testFeature, assignedBy: "test", }, }); const result = await featuresRepository.checkIfTeamHasFeature(testTeam.id, testFeature); expect(result).toBe(true); // Clean up parent team await prisma.teamFeatures.deleteMany({ where: { teamId: parentTeam.id }, }); await prisma.team.delete({ where: { id: parentTeam.id }, }); }); }); });