diff --git a/docs/useCases.md b/docs/useCases.md index 5b0549e7..527f5939 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -1336,8 +1336,8 @@ const updateFileMetadataDTO = { restrict: false } -await updateFileMetadata.execute(fileId, updateFileMetadataDTO).then((fileId) => { - console.log(`File updated successfully with file ID: ${fileId}`) +await updateFileMetadata.execute(fileId, updateFileMetadataDTO).then(() => { + console.log(`File updated successfully`) }) ``` @@ -1345,6 +1345,53 @@ _See [use case](../src/files/domain/useCases/UpdateFileMetadata.ts) implementati The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. +#### Update File Categories + +Updates Categories of a File. + +###### Example call: + +```typescript +import { updateFileCategories } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const fileId: number | string = 123 +const categories = ['category 1', 'category 1'] +const replace = true + +await updateFileCategories.execute(fileId, categories, replace).then(() => { + console.log(`File updated successfully`) +}) +``` + +_See [use case](../src/files/domain/useCases/updateFileCategories.ts) implementation_. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + +#### Update File Tabular Tags + +Updates Tabular Tags of a File. + +###### Example call: + +```typescript +import { updateFileTabularTags } from '@iqss/dataverse-client-javascript' + +/* ... */ + +const fileId: number | string = 123 +const tabularTags = ['Surveys'] + +await updateFileTabularTags.execute(fileId, tabularTags, replace).then(() => { + console.log(`File updated successfully`) +}) +``` + +_See [use case](../src/files/domain/useCases/updateFileTabularTags.ts) implementation_. + +The `fileId` parameter can be a string, for persistent identifiers, or a number, for numeric identifiers. + #### Delete a File Deletes a File. diff --git a/src/files/domain/repositories/IFilesRepository.ts b/src/files/domain/repositories/IFilesRepository.ts index 7d23ba3f..fa473d71 100644 --- a/src/files/domain/repositories/IFilesRepository.ts +++ b/src/files/domain/repositories/IFilesRepository.ts @@ -72,4 +72,16 @@ export interface IFilesRepository { fileId: number | string, updateFileMetadataDTO: UpdateFileMetadataDTO ): Promise + + updateFileTabularTags( + fileId: number | string, + tabularTags: string[], + replace?: boolean + ): Promise + + updateFileCategories( + fileId: number | string, + categories: string[], + replace?: boolean + ): Promise } diff --git a/src/files/domain/useCases/UpdateFileCategories.ts b/src/files/domain/useCases/UpdateFileCategories.ts new file mode 100644 index 00000000..ea568073 --- /dev/null +++ b/src/files/domain/useCases/UpdateFileCategories.ts @@ -0,0 +1,23 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { IFilesRepository } from '../repositories/IFilesRepository' + +export class UpdateFileCategories implements UseCase { + private filesRepository: IFilesRepository + + constructor(filesRepository: IFilesRepository) { + this.filesRepository = filesRepository + } + + /** + * Updates the categories for a particular File. + * More detailed information about updating a file's categories behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#updating-file-metadata + * + * @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string[]} [categories] - The categories to be added to the file. + * @param {boolean} [replace](optional) - If true, replaces the existing categories with the new ones. If false, adds the new categories to the existing ones. + * @returns {Promise} + */ + async execute(fileId: number | string, categories: string[], replace?: boolean): Promise { + await this.filesRepository.updateFileCategories(fileId, categories, replace) + } +} diff --git a/src/files/domain/useCases/UpdateFileTabularTags.ts b/src/files/domain/useCases/UpdateFileTabularTags.ts new file mode 100644 index 00000000..3b777a97 --- /dev/null +++ b/src/files/domain/useCases/UpdateFileTabularTags.ts @@ -0,0 +1,23 @@ +import { UseCase } from '../../../core/domain/useCases/UseCase' +import { IFilesRepository } from '../repositories/IFilesRepository' + +export class UpdateFileTabularTags implements UseCase { + private filesRepository: IFilesRepository + + constructor(filesRepository: IFilesRepository) { + this.filesRepository = filesRepository + } + + /** + * Updates the tabular tabular Tags for a particular File. + * More detailed information about updating a file's tabularTags behavior can be found in https://guides.dataverse.org/en/latest/api/native-api.html#updating-file-metadata + * + * @param {number | string} [fileId] - The file identifier, which can be a string (for persistent identifiers), or a number (for numeric identifiers). + * @param {string[]} [tabularTags] - The tabular tags to be added to the file. + * @param {boolean} [replace](optional) - If true, replaces the existing tabularTags with the new ones. If false, adds the new tabularTags to the existing ones. + * @returns {Promise} + */ + async execute(fileId: number | string, tabularTags: string[], replace?: boolean): Promise { + await this.filesRepository.updateFileTabularTags(fileId, tabularTags, replace) + } +} diff --git a/src/files/index.ts b/src/files/index.ts index 69ce71e2..aac93272 100644 --- a/src/files/index.ts +++ b/src/files/index.ts @@ -15,6 +15,8 @@ import { DeleteFile } from './domain/useCases/DeleteFile' import { ReplaceFile } from './domain/useCases/ReplaceFile' import { RestrictFile } from './domain/useCases/RestrictFile' import { UpdateFileMetadata } from './domain/useCases/UpdateFileMetadata' +import { UpdateFileTabularTags } from './domain/useCases/UpdateFileTabularTags' +import { UpdateFileCategories } from './domain/useCases/UpdateFileCategories' const filesRepository = new FilesRepository() const directUploadClient = new DirectUploadClient(filesRepository) @@ -34,6 +36,8 @@ const deleteFile = new DeleteFile(filesRepository) const replaceFile = new ReplaceFile(filesRepository) const restrictFile = new RestrictFile(filesRepository) const updateFileMetadata = new UpdateFileMetadata(filesRepository) +const updateFileTabularTags = new UpdateFileTabularTags(filesRepository) +const updateFileCategories = new UpdateFileCategories(filesRepository) export { getDatasetFiles, @@ -50,6 +54,8 @@ export { deleteFile, restrictFile, updateFileMetadata, + updateFileTabularTags, + updateFileCategories, replaceFile } diff --git a/src/files/infra/repositories/FilesRepository.ts b/src/files/infra/repositories/FilesRepository.ts index 3d41ba50..41c49b38 100644 --- a/src/files/infra/repositories/FilesRepository.ts +++ b/src/files/infra/repositories/FilesRepository.ts @@ -381,4 +381,38 @@ export class FilesRepository extends ApiRepository implements IFilesRepository { throw error }) } + + public async updateFileTabularTags( + fileId: number | string, + tabularTags: string[], + replace?: boolean + ): Promise { + const queryParams = replace !== undefined ? { replace } : {} + return this.doPost( + this.buildApiEndpoint(this.filesResourceName, 'metadata/tabularTags', fileId), + { tabularTags }, + queryParams + ) + .then(() => undefined) + .catch((error) => { + throw error + }) + } + + public async updateFileCategories( + fileId: number | string, + categories: string[], + replace?: boolean + ): Promise { + const queryParams = replace !== undefined ? { replace } : {} + return this.doPost( + this.buildApiEndpoint(this.filesResourceName, 'metadata/categories', fileId), + { categories }, + queryParams + ) + .then(() => undefined) + .catch((error) => { + throw error + }) + } } diff --git a/test/functional/files/UpdateFileCategories.test.ts b/test/functional/files/UpdateFileCategories.test.ts new file mode 100644 index 00000000..bbb1812e --- /dev/null +++ b/test/functional/files/UpdateFileCategories.test.ts @@ -0,0 +1,146 @@ +import { + ApiConfig, + createDataset, + CreatedDatasetIdentifiers, + WriteError, + updateFileCategories, + getFile, + DatasetNotNumberedVersion, + getDatasetFiles +} from '../../../src' +import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' +import { + createCollectionViaApi, + deleteCollectionViaApi +} from '../../testHelpers/collections/collectionHelper' +import { deleteUnpublishedDatasetViaApi } from '../../testHelpers/datasets/datasetHelper' +import { uploadFileViaApi } from '../../testHelpers/files/filesHelper' +import { TestConstants } from '../../testHelpers/TestConstants' +import { FileModel } from '../../../src/files/domain/models/FileModel' + +describe('execute', () => { + const testCollectionAlias = 'updateFileMetadataFunctionalTest-categories' + let testDatasetIds: CreatedDatasetIdentifiers + const testTextFile1Name = 'test-file-1.txt' + const metadataUpdate = ['file'] + + beforeAll(async () => { + ApiConfig.init( + TestConstants.TEST_API_URL, + DataverseApiAuthMechanism.API_KEY, + process.env.TEST_API_KEY + ) + await createCollectionViaApi(testCollectionAlias) + + try { + testDatasetIds = await createDataset.execute( + TestConstants.TEST_NEW_DATASET_DTO, + testCollectionAlias + ) + } catch (error) { + throw new Error('Tests beforeAll(): Error while creating test dataset') + } + + await uploadFileViaApi(testDatasetIds.numericId, testTextFile1Name).catch(() => { + throw new Error(`Tests beforeAll(): Error while uploading file ${testTextFile1Name}`) + }) + }) + + afterAll(async () => { + try { + await deleteUnpublishedDatasetViaApi(testDatasetIds.numericId) + } catch (error) { + throw new Error('Tests afterAll(): Error while deleting test dataset') + } + + try { + await deleteCollectionViaApi(testCollectionAlias) + } catch (error) { + throw new Error('Tests afterAll(): Error while deleting test collection') + } + }) + + test('should successfully update categories of a file', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + + try { + await updateFileCategories.execute(fileId, metadataUpdate) + } catch (error) { + throw new Error('File metadata should be updated') + } finally { + const fileInfo: FileModel = (await getFile.execute( + fileId, + DatasetNotNumberedVersion.LATEST + )) as FileModel + + expect(fileInfo.categories).toEqual(metadataUpdate) + } + }) + + test('should successfully update categories of a file with replace parameter', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + const newCategories = ['new Category'] + try { + await updateFileCategories.execute(fileId, newCategories, true) + } catch (error) { + throw new Error('File metadata should be updated') + } finally { + const fileInfo: FileModel = (await getFile.execute( + fileId, + DatasetNotNumberedVersion.LATEST + )) as FileModel + + expect(fileInfo.categories).toEqual(newCategories) + } + }) + + test('should not duplicate categories when merging', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + + const initialCategories = ['Category 1', 'Category 2'] + const newCategories = ['Category 2', 'Category 3'] + const expectedMergedCategories = ['Category 1', 'Category 2', 'Category 3'] + + await updateFileCategories.execute(fileId, initialCategories, true) + await updateFileCategories.execute(fileId, newCategories, false) + + const fileInfo = (await getFile.execute(fileId, DatasetNotNumberedVersion.LATEST)) as FileModel + + expect(fileInfo.categories?.sort()).toEqual(expectedMergedCategories.sort()) + }) + + test('should replace categories when replace = true', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + + const initialCategories = ['Category 1', 'Category 2', 'Category 3'] + const newCategories = ['Category 4', 'Category 5', 'Category 6'] + + await updateFileCategories.execute(fileId, initialCategories, true) + await updateFileCategories.execute(fileId, newCategories, true) + + const fileInfo = (await getFile.execute(fileId, DatasetNotNumberedVersion.LATEST)) as FileModel + + expect(fileInfo.categories?.sort()).toEqual(newCategories.sort()) + }) + + test('should throw an error when the file id does not exist', async () => { + let writeError: WriteError | undefined = undefined + const nonExistentFileId = 5 + + try { + await updateFileCategories.execute(nonExistentFileId, metadataUpdate) + throw new Error('Use case should throw an error') + } catch (error) { + writeError = error as WriteError + } finally { + expect(writeError).toBeInstanceOf(WriteError) + expect(writeError?.message).toEqual( + `There was an error when writing the resource. Reason was: [404] File with ID ${nonExistentFileId} not found.` + ) + } + }) +}) diff --git a/test/functional/files/UpdateFileTabularTags.test.ts b/test/functional/files/UpdateFileTabularTags.test.ts new file mode 100644 index 00000000..d3adbc5b --- /dev/null +++ b/test/functional/files/UpdateFileTabularTags.test.ts @@ -0,0 +1,177 @@ +import { + ApiConfig, + createDataset, + CreatedDatasetIdentifiers, + WriteError, + updateFileTabularTags, + getFile, + DatasetNotNumberedVersion, + getDatasetFiles +} from '../../../src' +import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig' +import { + createCollectionViaApi, + deleteCollectionViaApi +} from '../../testHelpers/collections/collectionHelper' +import { deleteUnpublishedDatasetViaApi } from '../../testHelpers/datasets/datasetHelper' +import { uploadFileViaApi } from '../../testHelpers/files/filesHelper' +import { TestConstants } from '../../testHelpers/TestConstants' +import { FileModel } from '../../../src/files/domain/models/FileModel' + +describe('execute', () => { + const testCollectionAlias = 'updateFileMetadataFunctionalTest' + let testDatasetIds: CreatedDatasetIdentifiers + const testTextFile4Name = 'test-file-4.tab' + const tabularTags = ['Event'] + + beforeAll(async () => { + ApiConfig.init( + TestConstants.TEST_API_URL, + DataverseApiAuthMechanism.API_KEY, + process.env.TEST_API_KEY + ) + await createCollectionViaApi(testCollectionAlias) + + try { + testDatasetIds = await createDataset.execute( + TestConstants.TEST_NEW_DATASET_DTO, + testCollectionAlias + ) + } catch (error) { + throw new Error('Tests beforeAll(): Error while creating test dataset') + } + await uploadFileViaApi(testDatasetIds.numericId, testTextFile4Name).catch(() => { + throw new Error(`Tests beforeAll(): Error while uploading file ${testTextFile4Name}`) + }) + }) + + afterAll(async () => { + try { + await deleteUnpublishedDatasetViaApi(testDatasetIds.numericId) + } catch (error) { + throw new Error('Tests afterAll(): Error while deleting test dataset') + } + + try { + await deleteCollectionViaApi(testCollectionAlias) + } catch (error) { + throw new Error('Tests afterAll(): Error while deleting test collection') + } + }) + + test('should successfully update tabular tags of a file', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + + //wait for the tabular file to be ingested + await new Promise((res) => setTimeout(res, 1000)) + try { + await updateFileTabularTags.execute(fileId, tabularTags, false) + } catch (error) { + throw new Error('File tabularTags should be updated') + } finally { + const fileInfo: FileModel = (await getFile.execute( + fileId, + DatasetNotNumberedVersion.LATEST + )) as FileModel + + expect(fileInfo.tabularTags).toEqual(tabularTags) + } + }) + + test('should successfully update tabular tags of a file with replace parameter', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + const newTabularTags = ['Survey'] + try { + await updateFileTabularTags.execute(fileId, newTabularTags, true) + } catch (error) { + throw new Error('File tabularTags should be updated') + } finally { + const fileInfo: FileModel = (await getFile.execute( + fileId, + DatasetNotNumberedVersion.LATEST + )) as FileModel + + expect(fileInfo.tabularTags).toEqual(newTabularTags) + } + }) + + test('should not duplicate tabular tags when merging', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + + const initialTags = ['Survey', 'Panel'] + const newTags = ['Panel', 'Event'] + const expectedMergedTags = ['Survey', 'Panel', 'Event'] + + await updateFileTabularTags.execute(fileId, initialTags, true) + await updateFileTabularTags.execute(fileId, newTags, false) + + const fileInfo = (await getFile.execute(fileId, DatasetNotNumberedVersion.LATEST)) as FileModel + + expect(fileInfo.tabularTags?.sort()).toEqual(expectedMergedTags.sort()) + }) + + test('should replace tabular tags when replace = true', async () => { + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const fileId = datasetFiles.files[0].id + + const initialTags = ['Survey', 'Panel', 'Event'] + const newTags = ['Survey', 'Network'] + + await updateFileTabularTags.execute(fileId, initialTags, true) + await updateFileTabularTags.execute(fileId, newTags, true) + + const fileInfo = (await getFile.execute(fileId, DatasetNotNumberedVersion.LATEST)) as FileModel + + expect(fileInfo.tabularTags?.sort()).toEqual(newTags.sort()) + }) + + test('should throw an error when updating tabular tags on a non-tabular file', async () => { + const nonTabularFileName = 'test-file-1.txt' + + try { + await uploadFileViaApi(testDatasetIds.numericId, nonTabularFileName) + } catch { + throw new Error(`Error uploading non-tabular file: ${nonTabularFileName}`) + } + const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) + const matchingFile = datasetFiles.files.find((f) => f.name === nonTabularFileName) + if (!matchingFile) { + throw new Error('Uploaded non-tabular file not found in dataset') + } + + const fileId = matchingFile.id + + let writeError: WriteError | undefined = undefined + + try { + await updateFileTabularTags.execute(fileId, ['Survey'], false) + } catch (error) { + writeError = error as WriteError + } finally { + expect(writeError).toBeInstanceOf(WriteError) + expect(writeError?.message).toEqual( + `There was an error when writing the resource. Reason was: [400] This operation is only available for tabular files.` + ) + } + }) + + test('should throw an error when the file id does not exist', async () => { + let writeError: WriteError | undefined = undefined + const nonExistentFileId = 5 + + try { + await updateFileTabularTags.execute(nonExistentFileId, tabularTags) + throw new Error('Use case should throw an error') + } catch (error) { + writeError = error as WriteError + } finally { + expect(writeError).toBeInstanceOf(WriteError) + expect(writeError?.message).toEqual( + `There was an error when writing the resource. Reason was: [404] File with ID ${nonExistentFileId} not found.` + ) + } + }) +}) diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index 98cde2b5..2b0b2655 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -655,6 +655,8 @@ describe('FilesRepository', () => { const testFileMetadata = { description: 'My description test.', categories: ['Data'], + label: 'myfile.txt', + directoryLabel: 'mydir', restrict: false } @@ -670,6 +672,8 @@ describe('FilesRepository', () => { expect(fileInfo.description).toBe(testFileMetadata.description) expect(fileInfo.categories).toEqual(testFileMetadata.categories) + expect(fileInfo.name).toBe(testFileMetadata.label) + expect(fileInfo.directoryLabel).toBe(testFileMetadata.directoryLabel) expect(fileInfo.restricted).toBe(testFileMetadata.restrict) }) @@ -687,6 +691,76 @@ describe('FilesRepository', () => { }) }) + describe('updateFileTabularTags', () => { + test('should add a new file tabularTags', async () => { + const datasetFiles = await sut.getDatasetFiles( + testDatasetIds.persistentId, + latestDatasetVersionId, + false, + FileOrderCriteria.NAME_AZ + ) + const tabularDatasetId = datasetFiles.files[3].id + const tag = ['Survey'] + + const actual = await sut.updateFileTabularTags(tabularDatasetId, tag) + + expect(actual).toBeUndefined() + }) + + test('should replace file tabular Tags to new', async () => { + const datasetFiles = await sut.getDatasetFiles( + testDatasetIds.persistentId, + latestDatasetVersionId, + false, + FileOrderCriteria.NAME_AZ + ) + const tabularDatasetId = datasetFiles.files[3].id + const tag = ['Survey'] + + const actual = await sut.updateFileTabularTags(tabularDatasetId, tag, true) + + expect(actual).toBeUndefined() + }) + + test('should return error when file does not exist', async () => { + const tag = ['Data'] + + const errorExpected = new WriteError(`[404] File with ID ${nonExistentFiledId} not found.`) + + await expect(sut.updateFileCategories(nonExistentFiledId, tag, false)).rejects.toThrow( + errorExpected + ) + }) + }) + + describe('updateFileCategories', () => { + test('should update file categories when file exists', async () => { + const categories = ['Data'] + + const actual = await sut.updateFileCategories(testFileId, categories) + + expect(actual).toBeUndefined() + }) + + test('should replace file categories when file exists', async () => { + const categories = ['Data'] + + const actual = await sut.updateFileCategories(testFileId, categories, true) + + expect(actual).toBeUndefined() + }) + + test('should return error when file does not exist', async () => { + const categories = ['Data'] + + const errorExpected = new WriteError(`[404] File with ID ${nonExistentFiledId} not found.`) + + await expect(sut.updateFileCategories(nonExistentFiledId, categories, false)).rejects.toThrow( + errorExpected + ) + }) + }) + describe('deleteFile', () => { let deleFileTestDatasetIds: CreatedDatasetIdentifiers const testTextFile1Name = 'test-file-1.txt' diff --git a/test/unit/files/UpdateFileCategories.test.ts b/test/unit/files/UpdateFileCategories.test.ts new file mode 100644 index 00000000..8e41c456 --- /dev/null +++ b/test/unit/files/UpdateFileCategories.test.ts @@ -0,0 +1,70 @@ +import { UpdateFileCategories } from '../../../src/files/domain/useCases/UpdateFileCategories' +import { IFilesRepository } from '../../../src/files/domain/repositories/IFilesRepository' +import { WriteError } from '../../../src/core/domain/repositories/WriteError' + +describe('UpdateFileCategories', () => { + const testFileCategories = ['category 1', 'category 2'] + test('should updated file tags with correct parameters and id', async () => { + const filesRepositoryStub: IFilesRepository = {} as IFilesRepository + filesRepositoryStub.updateFileCategories = jest.fn().mockResolvedValue(testFileCategories) + + const sut = new UpdateFileCategories(filesRepositoryStub) + + await sut.execute(1, testFileCategories) + + expect(filesRepositoryStub.updateFileCategories).toHaveBeenCalledWith( + 1, + testFileCategories, + undefined + ) + expect(filesRepositoryStub.updateFileCategories).toHaveBeenCalledTimes(1) + }) + + test('should return the updated file tags with correct parameters and persisten Id', async () => { + const filesRepositoryStub: IFilesRepository = { + updateFileCategories: jest.fn().mockResolvedValue(testFileCategories) + } as unknown as IFilesRepository + + const sut = new UpdateFileCategories(filesRepositoryStub) + + await sut.execute('doi:10.5072/FK2/HC6KTB', testFileCategories) + + expect(filesRepositoryStub.updateFileCategories).toHaveBeenCalledWith( + 'doi:10.5072/FK2/HC6KTB', + testFileCategories, + undefined + ) + expect(filesRepositoryStub.updateFileCategories).toHaveBeenCalledTimes(1) + }) + + test('should call the repository with replace parameter', async () => { + const filesRepositoryStub: IFilesRepository = { + updateFileCategories: jest.fn().mockResolvedValue(testFileCategories) + } as unknown as IFilesRepository + + const sut = new UpdateFileCategories(filesRepositoryStub) + + await sut.execute(1, testFileCategories, true) + + expect(filesRepositoryStub.updateFileCategories).toHaveBeenCalledWith( + 1, + testFileCategories, + true + ) + }) + + test('should throw an error if the repository throws an error', async () => { + const filesRepositoryStub: IFilesRepository = { + updateFileCategories: jest.fn().mockRejectedValue(new WriteError()) + } as unknown as IFilesRepository + + const sut = new UpdateFileCategories(filesRepositoryStub) + + await expect(sut.execute(1, testFileCategories)).rejects.toThrow(WriteError) + expect(filesRepositoryStub.updateFileCategories).toHaveBeenCalledWith( + 1, + testFileCategories, + undefined + ) + }) +}) diff --git a/test/unit/files/UpdateFileTabularTags.test.ts b/test/unit/files/UpdateFileTabularTags.test.ts new file mode 100644 index 00000000..b9a71673 --- /dev/null +++ b/test/unit/files/UpdateFileTabularTags.test.ts @@ -0,0 +1,70 @@ +import { UpdateFileTabularTags } from '../../../src/files/domain/useCases/UpdateFileTabularTags' +import { IFilesRepository } from '../../../src/files/domain/repositories/IFilesRepository' +import { WriteError } from '../../../src/core/domain/repositories/WriteError' + +describe('UpdateFileTabularTags', () => { + const testFileTabularTags = ['Survey', 'Event'] + test('should updated file tags with correct parameters and id', async () => { + const filesRepositoryStub: IFilesRepository = {} as IFilesRepository + filesRepositoryStub.updateFileTabularTags = jest.fn().mockResolvedValue(testFileTabularTags) + + const sut = new UpdateFileTabularTags(filesRepositoryStub) + + await sut.execute(1, testFileTabularTags) + + expect(filesRepositoryStub.updateFileTabularTags).toHaveBeenCalledWith( + 1, + testFileTabularTags, + undefined + ) + expect(filesRepositoryStub.updateFileTabularTags).toHaveBeenCalledTimes(1) + }) + + test('should return the updated file tags with correct parameters and persisten Id', async () => { + const filesRepositoryStub: IFilesRepository = { + updateFileTabularTags: jest.fn().mockResolvedValue(testFileTabularTags) + } as unknown as IFilesRepository + + const sut = new UpdateFileTabularTags(filesRepositoryStub) + + await sut.execute('doi:10.5072/FK2/HC6KTB', testFileTabularTags) + + expect(filesRepositoryStub.updateFileTabularTags).toHaveBeenCalledWith( + 'doi:10.5072/FK2/HC6KTB', + testFileTabularTags, + undefined + ) + expect(filesRepositoryStub.updateFileTabularTags).toHaveBeenCalledTimes(1) + }) + + test('should call the repository with replace parameter', async () => { + const filesRepositoryStub: IFilesRepository = { + updateFileTabularTags: jest.fn().mockResolvedValue(testFileTabularTags) + } as unknown as IFilesRepository + + const sut = new UpdateFileTabularTags(filesRepositoryStub) + + await sut.execute(1, testFileTabularTags, true) + + expect(filesRepositoryStub.updateFileTabularTags).toHaveBeenCalledWith( + 1, + testFileTabularTags, + true + ) + }) + + test('should throw an error if the repository throws an error', async () => { + const filesRepositoryStub: IFilesRepository = { + updateFileTabularTags: jest.fn().mockRejectedValue(new WriteError()) + } as unknown as IFilesRepository + + const sut = new UpdateFileTabularTags(filesRepositoryStub) + + await expect(sut.execute(1, testFileTabularTags)).rejects.toThrow(WriteError) + expect(filesRepositoryStub.updateFileTabularTags).toHaveBeenCalledWith( + 1, + testFileTabularTags, + undefined + ) + }) +})