import type { DismissBannerRequestDto, OwnerSetupRequestDto } from '@n8n/api-types'; import type { Logger } from '@n8n/backend-common'; import type { User } from '@n8n/db'; import type { PublicUser, SettingsRepository } from '@n8n/db'; import type { UserRepository } from '@n8n/db'; import type { Response } from 'express'; import { mock } from 'jest-mock-extended'; import type { AuthService } from '@/auth/auth.service'; import config from '@/config'; import { OwnerController } from '@/controllers/owner.controller'; import { BadRequestError } from '@/errors/response-errors/bad-request.error'; import type { EventService } from '@/events/event.service'; import type { AuthenticatedRequest } from '@/requests'; import type { BannerService } from '@/services/banner.service'; import type { PasswordUtility } from '@/services/password.utility'; import type { UserService } from '@/services/user.service'; describe('OwnerController', () => { const configGetSpy = jest.spyOn(config, 'getEnv'); const configSetSpy = jest.spyOn(config, 'set'); const logger = mock(); const eventService = mock(); const authService = mock(); const bannerService = mock(); const userService = mock(); const userRepository = mock(); const settingsRepository = mock(); const passwordUtility = mock(); const controller = new OwnerController( logger, eventService, settingsRepository, authService, bannerService, userService, passwordUtility, mock(), userRepository, ); describe('setupOwner', () => { it('should throw a BadRequestError if the instance owner is already setup', async () => { configGetSpy.mockReturnValue(true); await expect(controller.setupOwner(mock(), mock(), mock())).rejects.toThrowError( new BadRequestError('Instance owner already setup'), ); expect(userRepository.findOneOrFail).not.toHaveBeenCalled(); expect(userRepository.save).not.toHaveBeenCalled(); expect(authService.issueCookie).not.toHaveBeenCalled(); expect(settingsRepository.update).not.toHaveBeenCalled(); expect(configSetSpy).not.toHaveBeenCalled(); expect(eventService.emit).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledWith( 'Request to claim instance ownership failed because instance owner already exists', ); }); it('should setup the instance owner successfully', async () => { const user = mock({ id: 'userId', role: 'global:owner', authIdentities: [], }); const browserId = 'test-browser-id'; const req = mock({ user, browserId }); const res = mock(); const payload = mock({ email: 'valid@email.com', password: 'NewPassword123', firstName: 'Jane', lastName: 'Doe', }); configGetSpy.mockReturnValue(false); userRepository.findOneOrFail.mockResolvedValue(user); userRepository.save.mockResolvedValue(user); userService.toPublic.mockResolvedValue(mock({ id: 'newUserId' })); const result = await controller.setupOwner(req, res, payload); expect(userRepository.findOneOrFail).toHaveBeenCalledWith({ where: { role: 'global:owner' }, }); expect(userRepository.save).toHaveBeenCalledWith(user, { transaction: false }); expect(authService.issueCookie).toHaveBeenCalledWith(res, user, browserId); expect(settingsRepository.update).toHaveBeenCalledWith( { key: 'userManagement.isInstanceOwnerSetUp' }, { value: JSON.stringify(true) }, ); expect(configSetSpy).toHaveBeenCalledWith('userManagement.isInstanceOwnerSetUp', true); expect(eventService.emit).toHaveBeenCalledWith('instance-owner-setup', { userId: 'userId' }); expect(result.id).toEqual('newUserId'); }); }); describe('dismissBanner', () => { it('should not call dismissBanner if no banner is provided', async () => { const payload = mock({ banner: undefined }); const result = await controller.dismissBanner(mock(), mock(), payload); expect(bannerService.dismissBanner).not.toHaveBeenCalled(); expect(result).toBeUndefined(); }); it('should call dismissBanner with the correct banner name', async () => { const payload = mock({ banner: 'TRIAL' }); await controller.dismissBanner(mock(), mock(), payload); expect(bannerService.dismissBanner).toHaveBeenCalledWith('TRIAL'); }); }); });