From c9ef8d55c17f2136ff5aedc376b48ef4eb443cf3 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Wed, 26 Jun 2024 22:30:15 +0200 Subject: [PATCH] refactor: duplicate project --- apps/server/src/api-data/db/db.controller.ts | 18 ++++---- .../project-service/ProjectService.ts | 14 ++++-- .../__tests__/ProjectService.test.ts | 45 ++++++++++++------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/apps/server/src/api-data/db/db.controller.ts b/apps/server/src/api-data/db/db.controller.ts index 0ab6035b8..d3f923407 100644 --- a/apps/server/src/api-data/db/db.controller.ts +++ b/apps/server/src/api-data/db/db.controller.ts @@ -175,16 +175,12 @@ export async function loadProject(req: Request, res: Response) { + // file to copy from + const { filename } = req.params; + // new file name + const { newFilename } = req.body; + try { - const { filename } = req.params; - const { newFilename } = req.body; - - const errors = validateProjectFiles({ filename, newFilename }); - - if (errors.length) { - return res.status(409).send({ message: errors.join(', ') }); - } - await projectService.duplicateProjectFile(filename, newFilename); res.status(201).send({ @@ -192,6 +188,10 @@ export async function duplicateProjectFile(req: Request, res: Response { /** * Duplicates an existing project file */ -export async function duplicateProjectFile(existingProjectFile: string, newProjectFile: string) { - const projectFilePath = getPathToProject(existingProjectFile); - const duplicateProjectFilePath = getPathToProject(newProjectFile); +export async function duplicateProjectFile(originalFile: string, newFileName: string) { + if (!doesProjectExist(originalFile)) { + throw new Error('Project file not found'); + } + + if (doesProjectExist(newFileName)) { + throw new Error(`Project file with name ${newFileName} already exists`); + } + + const projectFilePath = getPathToProject(originalFile); + const duplicateProjectFilePath = getPathToProject(newFileName); return copyFile(projectFilePath, duplicateProjectFilePath); } diff --git a/apps/server/src/services/project-service/__tests__/ProjectService.test.ts b/apps/server/src/services/project-service/__tests__/ProjectService.test.ts index e15f1e968..d9bb401d5 100644 --- a/apps/server/src/services/project-service/__tests__/ProjectService.test.ts +++ b/apps/server/src/services/project-service/__tests__/ProjectService.test.ts @@ -1,24 +1,30 @@ -import { deleteProjectFile } from '../ProjectService.js'; +import { deleteProjectFile, duplicateProjectFile } from '../ProjectService.js'; import { appStateProvider } from '../../app-state-service/AppStateService.js'; -import { doesProjectExist, getPathToProject } from '../projectServiceUtils.js'; +import { doesProjectExist } from '../projectServiceUtils.js'; import { Mock } from 'vitest'; -import { deleteFile } from '../../../utils/parserUtils.js'; -vi.mock('./appStateProvider'); -vi.mock('./fileSystem'); +// stop the database loading from initiating +vi.mock('../../../setup/loadDb.js', () => { + return { + switchDb: vi.fn(), + }; +}); + vi.mock('../../app-state-service/AppStateService.js', () => ({ appStateProvider: { isLastLoadedProject: vi.fn(), }, })); + vi.mock('../projectServiceUtils.js', () => ({ doesProjectExist: vi.fn(), getPathToProject: vi.fn(), })); -vi.mock('../../../utils/parserUtils.js', () => ({ - deleteFile: vi.fn(), -})); +/** + * tests only assert errors since the + * controller depend on these to send the right responses + */ describe('deleteProjectFile', () => { it('throws an error if trying to delete the currently loaded project', async () => { (appStateProvider.isLastLoadedProject as Mock).mockResolvedValue(true); @@ -30,16 +36,21 @@ describe('deleteProjectFile', () => { (doesProjectExist as Mock).mockReturnValue(false); await expect(deleteProjectFile('nonexistentProject')).rejects.toThrow('Project file not found'); }); +}); - it('deletes the project file successfully', async () => { - (appStateProvider.isLastLoadedProject as Mock).mockResolvedValue(false); - (doesProjectExist as Mock).mockReturnValue(true); - (getPathToProject as Mock).mockReturnValue('/path/to/project'); - (deleteFile as Mock).mockResolvedValue(undefined); +describe('duplicateProjectFile', () => { + it('throws an error if origin project does not exist', async () => { + (doesProjectExist as Mock).mockReturnValue(false); + await expect(duplicateProjectFile('does not exist', 'doesnt matter')).rejects.toThrow('Project file not found'); + }); - await deleteProjectFile('existingProject'); - - expect(getPathToProject).toHaveBeenCalledWith('existingProject'); - expect(deleteFile).toHaveBeenCalledWith('/path/to/project'); + it('throws an error if new file name is already a project', async () => { + // current project exists + (doesProjectExist as Mock).mockReturnValueOnce(true); + // new project exists + (doesProjectExist as Mock).mockReturnValueOnce(true); + expect(duplicateProjectFile('nonexistentProject', 'existingproject')).rejects.toThrow( + 'Project file with name existingproject already exists', + ); }); });