From 803633e0746feef46884e9f230ccae7dadc21534 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 11 Apr 2025 12:17:18 -0400 Subject: [PATCH 1/9] feat: update use case for tags --- docs/useCases.md | 47 +++++++ .../domain/repositories/IFilesRepository.ts | 12 ++ .../domain/useCases/UpdateFileCategories.ts | 23 ++++ .../domain/useCases/UpdateFileTabularTags.ts | 23 ++++ src/files/index.ts | 6 + .../infra/repositories/FilesRepository.ts | 32 +++++ .../files/UpdateFileCategories.test.ts | 115 +++++++++++++++++ .../files/UpdateFileTabularTags.test.ts | 117 ++++++++++++++++++ .../integration/files/FilesRepository.test.ts | 70 +++++++++++ test/unit/files/UpdateFileCategories.test.ts | 70 +++++++++++ test/unit/files/UpdateFileTabularTags.test.ts | 70 +++++++++++ 11 files changed, 585 insertions(+) create mode 100644 src/files/domain/useCases/UpdateFileCategories.ts create mode 100644 src/files/domain/useCases/UpdateFileTabularTags.ts create mode 100644 test/functional/files/UpdateFileCategories.test.ts create mode 100644 test/functional/files/UpdateFileTabularTags.test.ts create mode 100644 test/unit/files/UpdateFileCategories.test.ts create mode 100644 test/unit/files/UpdateFileTabularTags.test.ts diff --git a/docs/useCases.md b/docs/useCases.md index 5b0549e7..df6e2dda 100644 --- a/docs/useCases.md +++ b/docs/useCases.md @@ -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((fileId) => { + console.log(`File updated successfully with file ID: ${fileId}`) +}) +``` + +_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((fileId) => { + console.log(`File updated successfully with file ID: ${fileId}`) +}) +``` + +_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..ac12f603 --- /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] - 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..6efad753 --- /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] - 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..36b9c390 100644 --- a/src/files/infra/repositories/FilesRepository.ts +++ b/src/files/infra/repositories/FilesRepository.ts @@ -381,4 +381,36 @@ export class FilesRepository extends ApiRepository implements IFilesRepository { throw error }) } + + public async updateFileTabularTags( + fileId: number | string, + tabularTags: string[], + replace?: boolean + ): Promise { + return this.doPost( + this.buildApiEndpoint(this.filesResourceName, 'metadata/tabularTags', fileId), + { tabularTags }, + { replace: replace ?? false } + ) + .then(() => undefined) + .catch((error) => { + throw error + }) + } + + public async updateFileCategories( + fileId: number | string, + categories: string[], + replace?: boolean + ): Promise { + return this.doPost( + this.buildApiEndpoint(this.filesResourceName, 'metadata/categories', fileId), + { categories }, + { replace: replace ?? false } + ) + .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..c17460a8 --- /dev/null +++ b/test/functional/files/UpdateFileCategories.test.ts @@ -0,0 +1,115 @@ +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' + 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 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..8f26e818 --- /dev/null +++ b/test/functional/files/UpdateFileTabularTags.test.ts @@ -0,0 +1,117 @@ +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 = ['Survey', '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 + const tabularTags = ['Event', 'Survey'] + + //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(['Event', 'Survey']) + } + }) + + 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 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..f29e6d1b 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -687,6 +687,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 + ) + }) +}) From 9483ed84efb9b3c998fca173fc14e942ad72ca45 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 11 Apr 2025 12:36:35 -0400 Subject: [PATCH 2/9] fix: optional replace --- src/files/domain/useCases/UpdateFileCategories.ts | 2 +- src/files/domain/useCases/UpdateFileTabularTags.ts | 2 +- src/files/infra/repositories/FilesRepository.ts | 6 ++++-- test/integration/files/FilesRepository.test.ts | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/files/domain/useCases/UpdateFileCategories.ts b/src/files/domain/useCases/UpdateFileCategories.ts index ac12f603..ea568073 100644 --- a/src/files/domain/useCases/UpdateFileCategories.ts +++ b/src/files/domain/useCases/UpdateFileCategories.ts @@ -14,7 +14,7 @@ export class UpdateFileCategories implements UseCase { * * @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] - If true, replaces the existing categories with the new ones. If false, adds the new categories to the existing ones. + * @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 { diff --git a/src/files/domain/useCases/UpdateFileTabularTags.ts b/src/files/domain/useCases/UpdateFileTabularTags.ts index 6efad753..3b777a97 100644 --- a/src/files/domain/useCases/UpdateFileTabularTags.ts +++ b/src/files/domain/useCases/UpdateFileTabularTags.ts @@ -14,7 +14,7 @@ export class UpdateFileTabularTags implements UseCase { * * @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] - If true, replaces the existing tabularTags with the new ones. If false, adds the new tabularTags to the existing ones. + * @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 { diff --git a/src/files/infra/repositories/FilesRepository.ts b/src/files/infra/repositories/FilesRepository.ts index 36b9c390..41c49b38 100644 --- a/src/files/infra/repositories/FilesRepository.ts +++ b/src/files/infra/repositories/FilesRepository.ts @@ -387,10 +387,11 @@ export class FilesRepository extends ApiRepository implements IFilesRepository { tabularTags: string[], replace?: boolean ): Promise { + const queryParams = replace !== undefined ? { replace } : {} return this.doPost( this.buildApiEndpoint(this.filesResourceName, 'metadata/tabularTags', fileId), { tabularTags }, - { replace: replace ?? false } + queryParams ) .then(() => undefined) .catch((error) => { @@ -403,10 +404,11 @@ export class FilesRepository extends ApiRepository implements IFilesRepository { categories: string[], replace?: boolean ): Promise { + const queryParams = replace !== undefined ? { replace } : {} return this.doPost( this.buildApiEndpoint(this.filesResourceName, 'metadata/categories', fileId), { categories }, - { replace: replace ?? false } + queryParams ) .then(() => undefined) .catch((error) => { diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index f29e6d1b..d724f746 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -398,7 +398,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) + const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) await expect(sut.getFileDownloadCount(nonExistentFiledId)).rejects.toThrow(expectedError) }) From b0e3bc93d35e64e442eb538b9f6b147808e7e727 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 11 Apr 2025 12:51:07 -0400 Subject: [PATCH 3/9] fix: test --- test/functional/files/UpdateFileTabularTags.test.ts | 3 +-- test/integration/files/FilesRepository.test.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/functional/files/UpdateFileTabularTags.test.ts b/test/functional/files/UpdateFileTabularTags.test.ts index 8f26e818..653ea4cf 100644 --- a/test/functional/files/UpdateFileTabularTags.test.ts +++ b/test/functional/files/UpdateFileTabularTags.test.ts @@ -22,7 +22,7 @@ describe('execute', () => { const testCollectionAlias = 'updateFileMetadataFunctionalTest' let testDatasetIds: CreatedDatasetIdentifiers const testTextFile4Name = 'test-file-4.tab' - const tabularTags = ['Survey', 'Event'] + const tabularTags = ['Event', 'Survey'] beforeAll(async () => { ApiConfig.init( @@ -62,7 +62,6 @@ describe('execute', () => { test('should successfully update tabular tags of a file', async () => { const datasetFiles = await getDatasetFiles.execute(testDatasetIds.numericId) const fileId = datasetFiles.files[0].id - const tabularTags = ['Event', 'Survey'] //wait for the tabular file to be ingested await new Promise((res) => setTimeout(res, 1000)) diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index d724f746..ac1c702a 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -421,7 +421,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) + const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) await expect(sut.getFileUserPermissions(nonExistentFiledId)).rejects.toThrow(errorExpected) }) From 5c733118ab98907a8b1224bc38ccc0c3f950f46e Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 11 Apr 2025 13:08:11 -0400 Subject: [PATCH 4/9] fix: test remove . for all error cases --- .../files/UpdateFileTabularTags.test.ts | 4 ++-- test/integration/files/FilesRepository.test.ts | 16 +++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/test/functional/files/UpdateFileTabularTags.test.ts b/test/functional/files/UpdateFileTabularTags.test.ts index 653ea4cf..1b1400f5 100644 --- a/test/functional/files/UpdateFileTabularTags.test.ts +++ b/test/functional/files/UpdateFileTabularTags.test.ts @@ -22,7 +22,7 @@ describe('execute', () => { const testCollectionAlias = 'updateFileMetadataFunctionalTest' let testDatasetIds: CreatedDatasetIdentifiers const testTextFile4Name = 'test-file-4.tab' - const tabularTags = ['Event', 'Survey'] + const tabularTags = ['Event'] beforeAll(async () => { ApiConfig.init( @@ -75,7 +75,7 @@ describe('execute', () => { DatasetNotNumberedVersion.LATEST )) as FileModel - expect(fileInfo.tabularTags).toEqual(['Event', 'Survey']) + expect(fileInfo.tabularTags).toEqual(tabularTags) } }) diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index ac1c702a..121751bd 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -170,7 +170,7 @@ describe('FilesRepository', () => { test('should return error when dataset does not exist', async () => { const nonExistentTestDatasetId = 100 const errorExpected: ReadError = new ReadError( - `[404] Dataset with ID ${nonExistentTestDatasetId} not found.` + `[404] Dataset with ID ${nonExistentTestDatasetId} not found` ) await expect( @@ -496,7 +496,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) + const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) await expect( sut.getFile(nonExistentFiledId, DatasetNotNumberedVersion.LATEST, false) @@ -527,7 +527,7 @@ describe('FilesRepository', () => { test('should return error when file does not exist', async () => { const nonExistentFiledPersistentId = 'nonExistentFiledPersistentId' const expectedError = new ReadError( - `[404] Datafile with Persistent ID ${nonExistentFiledPersistentId} not found.` + `[404] Datafile with Persistent ID ${nonExistentFiledPersistentId} not found` ) await expect( @@ -571,7 +571,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) + const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) await expect( sut.getFileCitation(nonExistentFiledId, DatasetNotNumberedVersion.LATEST, false) @@ -630,9 +630,7 @@ describe('FilesRepository', () => { test('should return error when dataset does not exist', async () => { const nonExistentDatasetId = 400000 - const errorExpected = new ReadError( - `[404] Dataset with ID ${nonExistentDatasetId} not found.` - ) + const errorExpected = new ReadError(`[404] Dataset with ID ${nonExistentDatasetId} not found`) await expect( sut.getFileUploadDestination(nonExistentDatasetId, singlepartFile) @@ -721,7 +719,7 @@ describe('FilesRepository', () => { test('should return error when file does not exist', async () => { const tag = ['Data'] - const errorExpected = new WriteError(`[404] File with ID ${nonExistentFiledId} not found.`) + const errorExpected = new WriteError(`[404] File with ID ${nonExistentFiledId} not found`) await expect(sut.updateFileCategories(nonExistentFiledId, tag, false)).rejects.toThrow( errorExpected @@ -830,7 +828,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const expectedError = new WriteError(`[404] File with ID ${nonExistentFiledId} not found.`) + const expectedError = new WriteError(`[404] File with ID ${nonExistentFiledId} not found`) await expect(sut.deleteFile(nonExistentFiledId)).rejects.toThrow(expectedError) }) From c949dc5e1c7159a2dc8baa9fe33950e9277666fd Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 11 Apr 2025 13:22:44 -0400 Subject: [PATCH 5/9] fix: test . --- .../integration/files/FilesRepository.test.ts | 88 +++---------------- 1 file changed, 11 insertions(+), 77 deletions(-) diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index 121751bd..7de5ef03 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -170,7 +170,7 @@ describe('FilesRepository', () => { test('should return error when dataset does not exist', async () => { const nonExistentTestDatasetId = 100 const errorExpected: ReadError = new ReadError( - `[404] Dataset with ID ${nonExistentTestDatasetId} not found` + `[404] Dataset with ID ${nonExistentTestDatasetId} not found.` ) await expect( @@ -398,7 +398,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) + const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) await expect(sut.getFileDownloadCount(nonExistentFiledId)).rejects.toThrow(expectedError) }) @@ -421,7 +421,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) + const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) await expect(sut.getFileUserPermissions(nonExistentFiledId)).rejects.toThrow(errorExpected) }) @@ -496,7 +496,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) + const expectedError = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) await expect( sut.getFile(nonExistentFiledId, DatasetNotNumberedVersion.LATEST, false) @@ -527,7 +527,7 @@ describe('FilesRepository', () => { test('should return error when file does not exist', async () => { const nonExistentFiledPersistentId = 'nonExistentFiledPersistentId' const expectedError = new ReadError( - `[404] Datafile with Persistent ID ${nonExistentFiledPersistentId} not found` + `[404] Datafile with Persistent ID ${nonExistentFiledPersistentId} not found.` ) await expect( @@ -571,7 +571,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found`) + const errorExpected = new ReadError(`[404] File with ID ${nonExistentFiledId} not found.`) await expect( sut.getFileCitation(nonExistentFiledId, DatasetNotNumberedVersion.LATEST, false) @@ -653,6 +653,8 @@ describe('FilesRepository', () => { const testFileMetadata = { description: 'My description test.', categories: ['Data'], + label: 'myfile.txt', + directoryLabel: 'mydir', restrict: false } @@ -668,6 +670,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) }) @@ -685,76 +689,6 @@ 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' @@ -828,7 +762,7 @@ describe('FilesRepository', () => { }) test('should return error when file does not exist', async () => { - const expectedError = new WriteError(`[404] File with ID ${nonExistentFiledId} not found`) + const expectedError = new WriteError(`[404] File with ID ${nonExistentFiledId} not found.`) await expect(sut.deleteFile(nonExistentFiledId)).rejects.toThrow(expectedError) }) From b0c6e5b53a23e01c93860258e31a53489752eda7 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 11 Apr 2025 13:28:49 -0400 Subject: [PATCH 6/9] fix: test . --- test/integration/files/FilesRepository.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index 7de5ef03..c8b81803 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -630,7 +630,9 @@ describe('FilesRepository', () => { test('should return error when dataset does not exist', async () => { const nonExistentDatasetId = 400000 - const errorExpected = new ReadError(`[404] Dataset with ID ${nonExistentDatasetId} not found`) + const errorExpected = new ReadError( + `[404] Dataset with ID ${nonExistentDatasetId} not found.` + ) await expect( sut.getFileUploadDestination(nonExistentDatasetId, singlepartFile) From 783f8ad3720f1c6f9433ee141e4cbac020e926ac Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Fri, 11 Apr 2025 13:42:15 -0400 Subject: [PATCH 7/9] fix: add integreation test --- .../integration/files/FilesRepository.test.ts | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/test/integration/files/FilesRepository.test.ts b/test/integration/files/FilesRepository.test.ts index c8b81803..2b0b2655 100644 --- a/test/integration/files/FilesRepository.test.ts +++ b/test/integration/files/FilesRepository.test.ts @@ -691,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' From fa0684a36633bc3e5b781133fdc6e4e64753fa36 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Tue, 22 Apr 2025 10:38:56 -0400 Subject: [PATCH 8/9] feat: add more testcases --- docs/useCases.md | 12 ++-- .../files/UpdateFileCategories.test.ts | 31 ++++++++++ .../files/UpdateFileTabularTags.test.ts | 61 +++++++++++++++++++ 3 files changed, 98 insertions(+), 6 deletions(-) diff --git a/docs/useCases.md b/docs/useCases.md index df6e2dda..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`) }) ``` @@ -1360,8 +1360,8 @@ const fileId: number | string = 123 const categories = ['category 1', 'category 1'] const replace = true -await updateFileCategories.execute(fileId, categories, replace).then((fileId) => { - console.log(`File updated successfully with file ID: ${fileId}`) +await updateFileCategories.execute(fileId, categories, replace).then(() => { + console.log(`File updated successfully`) }) ``` @@ -1383,8 +1383,8 @@ import { updateFileTabularTags } from '@iqss/dataverse-client-javascript' const fileId: number | string = 123 const tabularTags = ['Surveys'] -await updateFileTabularTags.execute(fileId, tabularTags, replace).then((fileId) => { - console.log(`File updated successfully with file ID: ${fileId}`) +await updateFileTabularTags.execute(fileId, tabularTags, replace).then(() => { + console.log(`File updated successfully`) }) ``` diff --git a/test/functional/files/UpdateFileCategories.test.ts b/test/functional/files/UpdateFileCategories.test.ts index c17460a8..43f0cdbe 100644 --- a/test/functional/files/UpdateFileCategories.test.ts +++ b/test/functional/files/UpdateFileCategories.test.ts @@ -96,6 +96,37 @@ describe('execute', () => { } }) + 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 diff --git a/test/functional/files/UpdateFileTabularTags.test.ts b/test/functional/files/UpdateFileTabularTags.test.ts index 1b1400f5..d3adbc5b 100644 --- a/test/functional/files/UpdateFileTabularTags.test.ts +++ b/test/functional/files/UpdateFileTabularTags.test.ts @@ -97,6 +97,67 @@ describe('execute', () => { } }) + 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 From 7d226737d1c9b04b4d5bdf1b0109e576ebf30fe5 Mon Sep 17 00:00:00 2001 From: Cheng Shi Date: Tue, 22 Apr 2025 10:59:41 -0400 Subject: [PATCH 9/9] fix: update the collection name to prevent duplicate collection --- test/functional/files/UpdateFileCategories.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/files/UpdateFileCategories.test.ts b/test/functional/files/UpdateFileCategories.test.ts index 43f0cdbe..bbb1812e 100644 --- a/test/functional/files/UpdateFileCategories.test.ts +++ b/test/functional/files/UpdateFileCategories.test.ts @@ -19,7 +19,7 @@ import { TestConstants } from '../../testHelpers/TestConstants' import { FileModel } from '../../../src/files/domain/models/FileModel' describe('execute', () => { - const testCollectionAlias = 'updateFileMetadataFunctionalTest' + const testCollectionAlias = 'updateFileMetadataFunctionalTest-categories' let testDatasetIds: CreatedDatasetIdentifiers const testTextFile1Name = 'test-file-1.txt' const metadataUpdate = ['file']