import { AdminService } from './admin.service'; import { PubSubService } from '../pubsub/pubsub.service'; import { mockDeep } from 'jest-mock-extended'; import { InvitedUsers, User as DbUser } from '@prisma/client'; import { UserService } from '../user/user.service'; import { TeamService } from '../team/team.service'; import { TeamEnvironmentsService } from '../team-environments/team-environments.service'; import { TeamRequestService } from '../team-request/team-request.service'; import { TeamInvitationService } from '../team-invitation/team-invitation.service'; import { TeamCollectionService } from '../team-collection/team-collection.service'; import { MailerService } from '../mailer/mailer.service'; import { PrismaService } from 'src/prisma/prisma.service'; import { DUPLICATE_EMAIL, INVALID_EMAIL, ONLY_ONE_ADMIN_ACCOUNT, USER_ALREADY_INVITED, USER_INVITATION_DELETION_FAILED, USER_NOT_FOUND, } from '../errors'; import { ShortcodeService } from 'src/shortcode/shortcode.service'; import { ConfigService } from '@nestjs/config'; import { OffsetPaginationArgs } from 'src/types/input-types.args'; import * as E from 'fp-ts/Either'; const mockPrisma = mockDeep(); const mockPubSub = mockDeep(); const mockUserService = mockDeep(); const mockTeamService = mockDeep(); const mockTeamEnvironmentsService = mockDeep(); const mockTeamRequestService = mockDeep(); const mockTeamInvitationService = mockDeep(); const mockTeamCollectionService = mockDeep(); const mockMailerService = mockDeep(); const mockShortcodeService = mockDeep(); const mockConfigService = mockDeep(); const adminService = new AdminService( mockUserService, mockTeamService, mockTeamCollectionService, mockTeamRequestService, mockTeamEnvironmentsService, mockTeamInvitationService, mockPubSub as any, mockPrisma as any, mockMailerService, mockShortcodeService, mockConfigService, ); const invitedUsers: InvitedUsers[] = [ { adminUid: 'uid1', adminEmail: 'admin1@example.com', inviteeEmail: 'i@example.com', invitedOn: new Date(), }, { adminUid: 'uid2', adminEmail: 'admin2@example.com', inviteeEmail: 'u@example.com', invitedOn: new Date(), }, ]; const dbAdminUsers: DbUser[] = [ { uid: 'uid 1', displayName: 'displayName', email: 'email@email.com', photoURL: 'photoURL', isAdmin: true, refreshToken: 'refreshToken', currentRESTSession: '', currentGQLSession: '', createdOn: new Date(), }, { uid: 'uid 2', displayName: 'displayName', email: 'email@email.com', photoURL: 'photoURL', isAdmin: true, refreshToken: 'refreshToken', currentRESTSession: '', currentGQLSession: '', createdOn: new Date(), }, ]; const dbNonAminUser: DbUser = { uid: 'uid 3', displayName: 'displayName', email: 'email@email.com', photoURL: 'photoURL', isAdmin: false, refreshToken: 'refreshToken', currentRESTSession: '', currentGQLSession: '', createdOn: new Date(), }; describe('AdminService', () => { describe('fetchInvitedUsers', () => { test('should resolve right and apply pagination correctly', async () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mockPrisma.user.findMany.mockResolvedValue([dbAdminUsers[0]]); // @ts-ignore mockPrisma.invitedUsers.findMany.mockResolvedValue(invitedUsers); const paginationArgs: OffsetPaginationArgs = { take: 5, skip: 2 }; const results = await adminService.fetchInvitedUsers(paginationArgs); expect(mockPrisma.invitedUsers.findMany).toHaveBeenCalledWith({ ...paginationArgs, orderBy: { invitedOn: 'desc', }, where: { NOT: { inviteeEmail: { in: [dbAdminUsers[0].email], }, }, }, }); }); test('should resolve right and return an array of invited users', async () => { const paginationArgs: OffsetPaginationArgs = { take: 10, skip: 0 }; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mockPrisma.user.findMany.mockResolvedValue([dbAdminUsers[0]]); // @ts-ignore mockPrisma.invitedUsers.findMany.mockResolvedValue(invitedUsers); const results = await adminService.fetchInvitedUsers(paginationArgs); expect(results).toEqual(invitedUsers); }); test('should resolve left and return an empty array if invited users not found', async () => { const paginationArgs: OffsetPaginationArgs = { take: 10, skip: 0 }; mockPrisma.invitedUsers.findMany.mockResolvedValue([]); const results = await adminService.fetchInvitedUsers(paginationArgs); expect(results).toEqual([]); }); }); describe('inviteUserToSignInViaEmail', () => { test('should resolve right and create a invited user', async () => { mockPrisma.invitedUsers.findFirst.mockResolvedValueOnce(null); mockPrisma.invitedUsers.create.mockResolvedValueOnce(invitedUsers[0]); const result = await adminService.inviteUserToSignInViaEmail( invitedUsers[0].adminUid, invitedUsers[0].adminEmail, invitedUsers[0].inviteeEmail, ); expect(mockPrisma.invitedUsers.create).toHaveBeenCalledWith({ data: { adminUid: invitedUsers[0].adminUid, adminEmail: invitedUsers[0].adminEmail, inviteeEmail: invitedUsers[0].inviteeEmail, }, }); return expect(result).toEqualRight(invitedUsers[0]); }); test('should resolve right, create a invited user and publish a subscription', async () => { mockPrisma.invitedUsers.findFirst.mockResolvedValueOnce(null); mockPrisma.invitedUsers.create.mockResolvedValueOnce(invitedUsers[0]); await adminService.inviteUserToSignInViaEmail( invitedUsers[0].adminUid, invitedUsers[0].adminEmail, invitedUsers[0].inviteeEmail, ); return expect(mockPubSub.publish).toHaveBeenCalledWith( `admin/${invitedUsers[0].adminUid}/invited`, invitedUsers[0], ); }); test('should resolve left and return an error when invalid invitee email is passed', async () => { const result = await adminService.inviteUserToSignInViaEmail( invitedUsers[0].adminUid, invitedUsers[0].adminEmail, 'invalidemail', ); return expect(result).toEqualLeft(INVALID_EMAIL); }); test('should resolve left and return an error when user already invited', async () => { mockPrisma.invitedUsers.findFirst.mockResolvedValueOnce(invitedUsers[0]); const result = await adminService.inviteUserToSignInViaEmail( invitedUsers[0].adminUid, invitedUsers[0].adminEmail, invitedUsers[0].inviteeEmail, ); return expect(result).toEqualLeft(USER_ALREADY_INVITED); }); test('should resolve left and return an error when invitee and admin email is same', async () => { const result = await adminService.inviteUserToSignInViaEmail( invitedUsers[0].adminUid, invitedUsers[0].inviteeEmail, invitedUsers[0].inviteeEmail, ); return expect(result).toEqualLeft(DUPLICATE_EMAIL); }); }); describe('revokeUserInvitations', () => { test('should resolve left and return error if email not invited', async () => { mockPrisma.invitedUsers.deleteMany.mockRejectedValueOnce( 'RecordNotFound', ); const result = await adminService.revokeUserInvitations([ 'test@gmail.com', ]); expect(result).toEqualLeft(USER_INVITATION_DELETION_FAILED); }); test('should resolve right and return deleted invitee email', async () => { const adminUid = 'adminUid'; mockPrisma.invitedUsers.deleteMany.mockResolvedValueOnce({ count: 1 }); const result = await adminService.revokeUserInvitations([ invitedUsers[0].inviteeEmail, ]); expect(mockPrisma.invitedUsers.deleteMany).toHaveBeenCalledWith({ where: { inviteeEmail: { in: [invitedUsers[0].inviteeEmail] }, }, }); expect(result).toEqualRight(true); }); }); describe('removeUsersAsAdmin', () => { test('should resolve right and make admins to users', async () => { mockUserService.fetchAdminUsers.mockResolvedValueOnce(dbAdminUsers); mockUserService.removeUsersAsAdmin.mockResolvedValueOnce(E.right(true)); return expect( await adminService.demoteUsersByAdmin([dbAdminUsers[0].uid]), ).toEqualRight(true); }); test('should resolve left and return error if only one admin in the infra', async () => { mockUserService.fetchAdminUsers.mockResolvedValueOnce(dbAdminUsers); mockUserService.removeUsersAsAdmin.mockResolvedValueOnce(E.right(true)); return expect( await adminService.demoteUsersByAdmin( dbAdminUsers.map((user) => user.uid), ), ).toEqualLeft(ONLY_ONE_ADMIN_ACCOUNT); }); }); describe('getUsersCount', () => { test('should return count of all users in the organization', async () => { mockUserService.getUsersCount.mockResolvedValueOnce(10); const result = await adminService.getUsersCount(); expect(result).toEqual(10); }); }); describe('getTeamsCount', () => { test('should return count of all teams in the organization', async () => { mockTeamService.getTeamsCount.mockResolvedValueOnce(10); const result = await adminService.getTeamsCount(); expect(result).toEqual(10); }); }); describe('getTeamCollectionsCount', () => { test('should return count of all Team Collections in the organization', async () => { mockTeamCollectionService.getTeamCollectionsCount.mockResolvedValueOnce( 10, ); const result = await adminService.getTeamCollectionsCount(); expect(result).toEqual(10); }); }); describe('getTeamRequestsCount', () => { test('should return count of all Team Collections in the organization', async () => { mockTeamRequestService.getTeamRequestsCount.mockResolvedValueOnce(10); const result = await adminService.getTeamRequestsCount(); expect(result).toEqual(10); }); }); });