From ac5121ec9aecd054831525af6394fd4cb009681d Mon Sep 17 00:00:00 2001 From: MellyGray Date: Mon, 7 Aug 2023 12:08:18 +0200 Subject: [PATCH 1/9] fix: update js-dataverse version --- dev-env/run-env.sh | 2 +- package-lock.json | 8 ++++---- package.json | 2 +- .../repositories/DatasetJSDataverseRepository.ts | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/dev-env/run-env.sh b/dev-env/run-env.sh index a8a2f09cd..28ebd20c6 100755 --- a/dev-env/run-env.sh +++ b/dev-env/run-env.sh @@ -6,7 +6,7 @@ export DATAVERSE_IMAGE_TAG=$1 export COMPOSE_HTTP_TIMEOUT=200 # Timeout for Dataverse bootstrap configbaker -export DATAVERSE_BOOTSTRAP_TIMEOUT="5m" +export DATAVERSE_BOOTSTRAP_TIMEOUT="10m" echo "INFO - Setting up Dataverse on image tag ${DATAVERSE_IMAGE_TAG}..." diff --git a/package-lock.json b/package-lock.json index 1c3447df2..96d02242d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr67.5dfc70a", + "@iqss/dataverse-client-javascript": "2.0.0-pr80.378cc1e", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", @@ -3700,9 +3700,9 @@ }, "node_modules/@iqss/dataverse-client-javascript": { "name": "@IQSS/dataverse-client-javascript", - "version": "2.0.0-pr67.5dfc70a", - "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr67.5dfc70a/dc27a9a220a347fb9e5d87f6887c8e87427482c1", - "integrity": "sha512-RCBJcdv42hYvWuLDE19/AYpKZr1AL9/VIre4FJm0vd0NMd1CLoPyDjetuK70nkP8fDDWVJLTlyaer8f1RZAfSA==", + "version": "2.0.0-pr80.378cc1e", + "resolved": "https://npm.pkg.github.com/download/@IQSS/dataverse-client-javascript/2.0.0-pr80.378cc1e/2361fc91f5e8618751025871e860062307b1adf4", + "integrity": "sha512-5Omv7ZG+K+B8ddEg0X3MjqbAK/cOPnPtclpBe2sptYRH1zaX1kHwSSTTBDmfNfIZTJUOe7KEP0/FX6Xa6iRG6w==", "license": "MIT", "dependencies": { "@types/node": "^18.15.11", diff --git a/package.json b/package.json index 2b456b355..6c74c74f0 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@faker-js/faker": "7.6.0", - "@iqss/dataverse-client-javascript": "2.0.0-pr67.5dfc70a", + "@iqss/dataverse-client-javascript": "2.0.0-pr80.378cc1e", "@iqss/dataverse-design-system": "*", "@istanbuljs/nyc-config-typescript": "1.0.2", "@tanstack/react-table": "8.9.2", diff --git a/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts b/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts index 206719395..ea25c0aa2 100644 --- a/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts +++ b/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts @@ -1,7 +1,7 @@ import { DatasetRepository } from '../../domain/repositories/DatasetRepository' import { Dataset } from '../../domain/models/Dataset' import { - getDatasetByPersistentId, + getDataset, getDatasetCitation, getDatasetSummaryFieldNames, WriteError, @@ -13,7 +13,7 @@ import { JSDatasetMapper } from '../mappers/JSDatasetMapper' export class DatasetJSDataverseRepository implements DatasetRepository { getByPersistentId(persistentId: string, version?: string): Promise { - return getDatasetByPersistentId + return getDataset .execute(persistentId, this.versionToVersionId(version)) .then((jsDataset) => Promise.all([ From d977dcb2d8bbca97f9279f29dfbd6fbe530112ef Mon Sep 17 00:00:00 2001 From: MellyGray Date: Tue, 8 Aug 2023 09:55:50 +0200 Subject: [PATCH 2/9] feat(MetadataBlockInfo): integrate js-dataverse implementation to getMetadataBlockInfo --- .../domain/models/MetadataBlockInfo.ts | 5 +- .../MetadataBlockInfoJSDataverseRepository.ts | 31 ------- .../mappers/JSMetadataBlockInfoMapper.ts | 51 +++++++++++ .../MetadataBlockInfoJSDataverseRepository.ts | 17 ++++ src/sections/dataset/DatasetFactory.tsx | 2 +- .../DatasetMetadataFieldValue.tsx | 83 ++--------------- .../DatasetMetadataFieldValueFormatted.tsx | 90 +++++++++++++++++++ .../dataset/domain/models/DatasetMother.ts | 11 ++- .../domain/models/MetadataBlockInfoMother.ts | 7 +- .../dataset-metadata/DatasetMetadata.spec.tsx | 61 +++++++++++-- .../dataset-summary/SummaryFields.spec.tsx | 6 +- .../MetadataBlockInfoCitationExample.ts | 83 +++++++++++++++++ ...dataBlockInfoJSDataverseRepository.spec.ts | 25 ++++++ 13 files changed, 346 insertions(+), 126 deletions(-) delete mode 100644 src/metadata-block-info/infrastructure/MetadataBlockInfoJSDataverseRepository.ts create mode 100644 src/metadata-block-info/infrastructure/mappers/JSMetadataBlockInfoMapper.ts create mode 100644 src/metadata-block-info/infrastructure/repositories/MetadataBlockInfoJSDataverseRepository.ts create mode 100644 src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx create mode 100644 tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoCitationExample.ts create mode 100644 tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoJSDataverseRepository.spec.ts diff --git a/src/metadata-block-info/domain/models/MetadataBlockInfo.ts b/src/metadata-block-info/domain/models/MetadataBlockInfo.ts index bffa2bcc8..7fa9e53a3 100644 --- a/src/metadata-block-info/domain/models/MetadataBlockInfo.ts +++ b/src/metadata-block-info/domain/models/MetadataBlockInfo.ts @@ -1,10 +1,13 @@ export interface MetadataBlockInfo { name: string - fields: Record + fields: MetadataBlockInfoFields } +export type MetadataBlockInfoFields = Record + export interface MetadataFieldInfo { displayFormat: string } export const METADATA_FIELD_DISPLAY_FORMAT_PLACEHOLDER = '#VALUE' +export const METADATA_FIELD_DISPLAY_FORMAT_NAME_PLACEHOLDER = '#NAME' diff --git a/src/metadata-block-info/infrastructure/MetadataBlockInfoJSDataverseRepository.ts b/src/metadata-block-info/infrastructure/MetadataBlockInfoJSDataverseRepository.ts deleted file mode 100644 index 6ce2e94c4..000000000 --- a/src/metadata-block-info/infrastructure/MetadataBlockInfoJSDataverseRepository.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { MetadataBlockInfoRepository } from '../domain/repositories/MetadataBlockInfoRepository' -import { MetadataBlockInfo } from '../domain/models/MetadataBlockInfo' -import { MetadataBlockName } from '../../dataset/domain/models/Dataset' - -export class MetadataBlockInfoJSDataverseRepository implements MetadataBlockInfoRepository { - // eslint-disable-next-line unused-imports/no-unused-vars - getByName(name: string): Promise { - // TODO implement using js-dataverse - return Promise.resolve({ - name: MetadataBlockName.CITATION, - fields: { - alternativePersistentId: { displayFormat: '' }, - publicationDate: { displayFormat: '' }, - citationDate: { displayFormat: '' }, - title: { displayFormat: '' }, - subject: { displayFormat: ';' }, - author: { displayFormat: '' }, - authorName: { displayFormat: '#VALUE' }, - authorAffiliation: { displayFormat: '(#VALUE)' }, - authorIdentifierScheme: { displayFormat: '- #VALUE:' }, - authorIdentifier: { displayFormat: '#VALUE' }, - datasetContact: { displayFormat: '#VALUE' }, - datasetContactName: { displayFormat: '#VALUE' }, - datasetContactAffiliation: { displayFormat: '(#VALUE)' }, - datasetContactEmail: { displayFormat: '[#VALUE](mailto:#VALUE)' }, - dsDescription: { displayFormat: '' }, - dsDescriptionValue: { displayFormat: '#VALUE' } - } - }) - } -} diff --git a/src/metadata-block-info/infrastructure/mappers/JSMetadataBlockInfoMapper.ts b/src/metadata-block-info/infrastructure/mappers/JSMetadataBlockInfoMapper.ts new file mode 100644 index 000000000..d345c9c66 --- /dev/null +++ b/src/metadata-block-info/infrastructure/mappers/JSMetadataBlockInfoMapper.ts @@ -0,0 +1,51 @@ +import { + MetadataBlock as JSMetadataBlockInfo, + MetadataFieldInfo as JSMetadataFieldInfo +} from '@iqss/dataverse-client-javascript' +import { MetadataBlockInfo, MetadataBlockInfoFields } from '../../domain/models/MetadataBlockInfo' + +export class JSMetadataBlockInfoMapper { + static toMetadataBlockInfo(jsMetadataBlockInfo: JSMetadataBlockInfo): MetadataBlockInfo { + return { + name: jsMetadataBlockInfo.name, + fields: this.toFields(jsMetadataBlockInfo.metadataFields) + } + } + + static toFields( + jsMetadataBlockInfoFields: Record + ): MetadataBlockInfoFields { + return Object.entries(jsMetadataBlockInfoFields).reduce( + (fields: MetadataBlockInfoFields, [key, value]) => { + fields[key] = { displayFormat: this.toDisplayFormat(value.displayFormat) } + return fields + }, + {} + ) + } + + static toDisplayFormat(jsDisplayFormat: string): string { + const link = 'href="#VALUE"' + if (jsDisplayFormat.includes(link)) { + return '[#VALUE](#VALUE)' + } + + const linkWithUrl = /]*>#VALUE<\/a>/ + const match = jsDisplayFormat.match(linkWithUrl) + if (match) { + return `[#VALUE](${match[1]}/#VALUE)` + } + + const emailFormat = '#EMAIL' + if (jsDisplayFormat === emailFormat) { + return '[#VALUE](mailto:#VALUE)' + } + + const imageFormat = '
' + if (jsDisplayFormat === imageFormat) { + return '![#NAME](#VALUE)' + } + + return jsDisplayFormat + } +} diff --git a/src/metadata-block-info/infrastructure/repositories/MetadataBlockInfoJSDataverseRepository.ts b/src/metadata-block-info/infrastructure/repositories/MetadataBlockInfoJSDataverseRepository.ts new file mode 100644 index 000000000..38e5bb4d4 --- /dev/null +++ b/src/metadata-block-info/infrastructure/repositories/MetadataBlockInfoJSDataverseRepository.ts @@ -0,0 +1,17 @@ +import { MetadataBlockInfoRepository } from '../../domain/repositories/MetadataBlockInfoRepository' +import { MetadataBlockInfo } from '../../domain/models/MetadataBlockInfo' +import { + getMetadataBlockByName, + MetadataBlock as JSMetadataBlockInfo +} from '@iqss/dataverse-client-javascript' +import { JSMetadataBlockInfoMapper } from '../mappers/JSMetadataBlockInfoMapper' + +export class MetadataBlockInfoJSDataverseRepository implements MetadataBlockInfoRepository { + getByName(name: string): Promise { + return getMetadataBlockByName + .execute(name) + .then((jsMetadataBlockInfo: JSMetadataBlockInfo) => + JSMetadataBlockInfoMapper.toMetadataBlockInfo(jsMetadataBlockInfo) + ) + } +} diff --git a/src/sections/dataset/DatasetFactory.tsx b/src/sections/dataset/DatasetFactory.tsx index 875485217..e90f0e0ad 100644 --- a/src/sections/dataset/DatasetFactory.tsx +++ b/src/sections/dataset/DatasetFactory.tsx @@ -6,7 +6,7 @@ import { useAnonymized } from './anonymized/AnonymizedContext' import { AnonymizedProvider } from './anonymized/AnonymizedProvider' import { FileJSDataverseRepository } from '../../files/infrastructure/FileJSDataverseRepository' import { MetadataBlockInfoProvider } from './metadata-block-info/MetadataBlockProvider' -import { MetadataBlockInfoJSDataverseRepository } from '../../metadata-block-info/infrastructure/MetadataBlockInfoJSDataverseRepository' +import { MetadataBlockInfoJSDataverseRepository } from '../../metadata-block-info/infrastructure/repositories/MetadataBlockInfoJSDataverseRepository' const datasetRepository = new DatasetJSDataverseRepository() const fileRepository = new FileJSDataverseRepository() diff --git a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx index 1722b4159..99f4fe514 100644 --- a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx +++ b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx @@ -1,16 +1,10 @@ import { ANONYMIZED_FIELD_VALUE, - DatasetMetadataFieldValue as DatasetMetadataFieldValueModel, - DatasetMetadataSubField + DatasetMetadataFieldValue as DatasetMetadataFieldValueModel } from '../../../../dataset/domain/models/Dataset' -import { MarkdownComponent } from '../../markdown/MarkdownComponent' import { useAnonymized } from '../../anonymized/AnonymizedContext' import { useTranslation } from 'react-i18next' -import { useMetadataBlockInfo } from '../../metadata-block-info/MetadataBlockInfoContext' -import { - METADATA_FIELD_DISPLAY_FORMAT_PLACEHOLDER, - MetadataBlockInfo -} from '../../../../metadata-block-info/domain/models/MetadataBlockInfo' +import { DatasetMetadataFieldValueFormatted } from './DatasetMetadataFieldValueFormatted' interface DatasetMetadataFieldValueProps { metadataFieldName: string @@ -23,19 +17,14 @@ export function DatasetMetadataFieldValue({ }: DatasetMetadataFieldValueProps) { const { anonymizedView } = useAnonymized() const isAnonymizedField = anonymizedView && metadataFieldValue == ANONYMIZED_FIELD_VALUE - const { metadataBlockInfo } = useMetadataBlockInfo() - if (isAnonymizedField) { return } return ( - ) } @@ -44,65 +33,3 @@ const AnonymizedFieldValue = () => { const { t } = useTranslation('dataset') return

{t('anonymizedFieldValue')}

} - -export function metadataFieldValueToString( - metadataFieldName: string, - metadataFieldValue: DatasetMetadataFieldValueModel, - metadataBlockInfo?: MetadataBlockInfo -): string { - const separator = metadataBlockInfo?.fields[metadataFieldName]?.displayFormat ?? '' - - if (isArrayOfObjects(metadataFieldValue)) { - return metadataFieldValue - .map((metadataSubField) => joinSubFields(metadataSubField, metadataBlockInfo)) - .join(' \n \n') - } - - if (Array.isArray(metadataFieldValue)) { - return metadataFieldValue.join(`${separator} `) - } - - if (isAnObject(metadataFieldValue)) { - return Object.values(metadataFieldValue).join(`${separator} `) - } - - return metadataFieldValue -} - -export function isArrayOfObjects(variable: unknown): variable is object[] { - if (!Array.isArray(variable)) { - return false - } - - return variable.every((item) => isAnObject(item)) -} - -function isAnObject(variable: unknown): variable is object { - return typeof variable === 'object' && variable !== null -} - -function joinSubFields( - metadataSubField: DatasetMetadataSubField, - metadataBlockInfo?: MetadataBlockInfo -) { - return Object.entries(metadataSubField) - .map(([subFieldName, subFieldValue]) => - formatSubFieldValue(subFieldValue, metadataBlockInfo?.fields[subFieldName]?.displayFormat) - ) - .join(' ') -} - -function formatSubFieldValue( - subFieldValue: string | undefined, - displayFormat: string | undefined -): string { - if (subFieldValue === undefined) { - return '' - } - - if (displayFormat === undefined) { - return subFieldValue - } - - return displayFormat.replaceAll(METADATA_FIELD_DISPLAY_FORMAT_PLACEHOLDER, subFieldValue) -} diff --git a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx new file mode 100644 index 000000000..c0bc09b14 --- /dev/null +++ b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx @@ -0,0 +1,90 @@ +import { useMetadataBlockInfo } from '../../metadata-block-info/MetadataBlockInfoContext' +import { + METADATA_FIELD_DISPLAY_FORMAT_PLACEHOLDER, + MetadataBlockInfo +} from '../../../../metadata-block-info/domain/models/MetadataBlockInfo' +import { MarkdownComponent } from '../../markdown/MarkdownComponent' +import { + DatasetMetadataFieldValue as DatasetMetadataFieldValueModel, + DatasetMetadataSubField +} from '../../../../dataset/domain/models/Dataset' + +interface DatasetMetadataFieldValueFormattedProps { + metadataFieldName: string + metadataFieldValue: DatasetMetadataFieldValueModel +} +export function DatasetMetadataFieldValueFormatted({ + metadataFieldName, + metadataFieldValue +}: DatasetMetadataFieldValueFormattedProps) { + const { metadataBlockInfo } = useMetadataBlockInfo() + const metadataFieldValueMarkdown = metadataFieldValueToMarkdownFormat( + metadataFieldName, + metadataFieldValue, + metadataBlockInfo + ) + + return +} + +export function metadataFieldValueToMarkdownFormat( + metadataFieldName: string, + metadataFieldValue: DatasetMetadataFieldValueModel, + metadataBlockInfo?: MetadataBlockInfo +): string { + const separator = metadataBlockInfo?.fields[metadataFieldName]?.displayFormat ?? '' + + if (isArrayOfObjects(metadataFieldValue)) { + return metadataFieldValue + .map((metadataSubField) => joinSubFields(metadataSubField, metadataBlockInfo)) + .join(' \n \n') + } + + if (Array.isArray(metadataFieldValue)) { + return metadataFieldValue.join(`${separator} `) + } + + if (isAnObject(metadataFieldValue)) { + return joinObjectValues(metadataFieldValue, separator) + } + + return metadataFieldValue +} + +export function isArrayOfObjects(variable: unknown): variable is object[] { + return Array.isArray(variable) && variable.every(isAnObject) +} + +function isAnObject(variable: unknown): variable is object { + return typeof variable === 'object' && variable !== null +} + +function joinObjectValues(obj: object, separator: string): string { + return Object.values(obj).join(separator) +} + +function joinSubFields( + metadataSubField: DatasetMetadataSubField, + metadataBlockInfo?: MetadataBlockInfo +): string { + return Object.entries(metadataSubField) + .map(([subFieldName, subFieldValue]) => + formatSubFieldValue(subFieldValue, metadataBlockInfo?.fields[subFieldName]?.displayFormat) + ) + .join(' ') +} + +function formatSubFieldValue( + subFieldValue: string | undefined, + displayFormat: string | undefined +): string { + if (subFieldValue === undefined) { + return '' + } + + if (displayFormat === undefined) { + return subFieldValue + } + + return displayFormat.replaceAll(METADATA_FIELD_DISPLAY_FORMAT_PLACEHOLDER, subFieldValue) +} diff --git a/tests/component/dataset/domain/models/DatasetMother.ts b/tests/component/dataset/domain/models/DatasetMother.ts index 0e84fa720..4030c52c0 100644 --- a/tests/component/dataset/domain/models/DatasetMother.ts +++ b/tests/component/dataset/domain/models/DatasetMother.ts @@ -68,13 +68,13 @@ export class DatasetMother { authorName: faker.lorem.sentence(), authorAffiliation: faker.lorem.sentence(), authorIdentifierScheme: faker.lorem.sentence(), - authorIdentifier: faker.lorem.sentence() + authorIdentifier: faker.lorem.word() }, { authorName: faker.lorem.sentence(), authorAffiliation: faker.lorem.sentence(), authorIdentifierScheme: faker.lorem.sentence(), - authorIdentifier: faker.lorem.sentence() + authorIdentifier: faker.lorem.word() } ], datasetContact: [ @@ -87,6 +87,13 @@ export class DatasetMother { { dsDescriptionValue: faker.lorem.sentence() } + ], + producer: [ + { + producerName: faker.lorem.sentence(), + producerURL: faker.internet.url(), + producerLogoURL: faker.image.imageUrl() + } ] } }, diff --git a/tests/component/metadata-block-info/domain/models/MetadataBlockInfoMother.ts b/tests/component/metadata-block-info/domain/models/MetadataBlockInfoMother.ts index 791b5b9a1..c31293d05 100644 --- a/tests/component/metadata-block-info/domain/models/MetadataBlockInfoMother.ts +++ b/tests/component/metadata-block-info/domain/models/MetadataBlockInfoMother.ts @@ -19,9 +19,12 @@ export class MetadataBlockInfoMother { datasetContact: { displayFormat: '#VALUE' }, datasetContactName: { displayFormat: '#VALUE' }, datasetContactAffiliation: { displayFormat: '(#VALUE)' }, - datasetContactEmail: { displayFormat: '#VALUE' }, + datasetContactEmail: { displayFormat: '[#VALUE](mailto:#VALUE)' }, dsDescription: { displayFormat: '' }, - dsDescriptionValue: { displayFormat: '#VALUE' } + dsDescriptionValue: { displayFormat: '#VALUE' }, + producerURL: { displayFormat: '[#VALUE](#VALUE)' }, + producerLogoURL: { displayFormat: '![#NAME](#VALUE)' }, + dateOfCollectionStart: { displayFormat: '#NAME: #VALUE ' } }, ...props } diff --git a/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx b/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx index 7cd582a20..f4718182a 100644 --- a/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx +++ b/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx @@ -7,13 +7,61 @@ import { import { AnonymizedContext } from '../../../../../src/sections/dataset/anonymized/AnonymizedContext' import { isArrayOfObjects, - metadataFieldValueToString -} from '../../../../../src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue' + metadataFieldValueToMarkdownFormat +} from '../../../../../src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted' import { MetadataBlockInfoProvider } from '../../../../../src/sections/dataset/metadata-block-info/MetadataBlockProvider' import { MetadataBlockInfoRepository } from '../../../../../src/metadata-block-info/domain/repositories/MetadataBlockInfoRepository' import { MetadataBlockInfoMother } from '../../../metadata-block-info/domain/models/MetadataBlockInfoMother' +const extractLinksFromText = (text: string): { text: string; link: string }[] => { + const linkFormat = /(? { + const matchResult = match.match(/\[(.*?)\]\((.*?)\)/) + if (matchResult) { + const [, text, link] = matchResult + return { text, link } + } + return null + }) + .filter((match) => match !== null) as { text: string; link: string }[] +} + +const extractImagesFromText = (text: string): string[] => { + return text.match(/!\[(.*?)\]\((.*?)\)/g) || [] +} + describe('DatasetMetadata', () => { + const checkMetadataFieldValue = (metadataFieldName: string, metadataFieldValue: string) => { + const extractedLinks = extractLinksFromText(metadataFieldValue) + const extractedImages = extractImagesFromText(metadataFieldValue) + const notPlainText = extractedLinks.length > 0 || extractedImages + + if (notPlainText) { + if (extractedLinks) { + extractedLinks.forEach(({ text, link }) => { + cy.findByText(text).should('exist') + cy.findByText(text).should('have.attr', 'href', link) + }) + } + if (extractedImages) { + extractedImages.forEach((image) => { + const [, altText, imageUrl] = image.match(/!\[(.*?)\]\((.*?)\)/) || [] + cy.findByAltText(altText).should('exist') + cy.findByAltText(altText).should('have.attr', 'src', imageUrl) + }) + } + } else { + cy.findByText(metadataFieldValue).should('exist') + } + } + it('renders the metadata blocks sections titles correctly', () => { const mockDataset = DatasetMother.create() const mockMetadataBlocks = mockDataset.metadataBlocks @@ -130,7 +178,7 @@ describe('DatasetMetadata', () => { } Object.entries(metadataBlock.fields).forEach(([metadataFieldName, metadataFieldValue]) => { - const metadataFieldValueString = metadataFieldValueToString( + const metadataFieldValueString = metadataFieldValueToMarkdownFormat( metadataFieldName, metadataFieldValue, metadataBlockInfoMock @@ -138,15 +186,12 @@ describe('DatasetMetadata', () => { if (isArrayOfObjects(metadataFieldValue)) { metadataFieldValueString.split(' \n \n').forEach((fieldValue) => { - cy.findAllByText(fieldValue).should('exist') + checkMetadataFieldValue(metadataFieldName, fieldValue) }) return } - const fieldValue = cy.findAllByText(metadataFieldValueString, { - exact: false - }) - fieldValue.should('exist') + checkMetadataFieldValue(metadataFieldName, metadataFieldValueString) }) }) }) diff --git a/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx b/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx index 4124e08b1..1682e93b2 100644 --- a/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx +++ b/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx @@ -3,8 +3,8 @@ import { SummaryFields } from '../../../../../src/sections/dataset/dataset-summa import { DatasetMother } from '../../../dataset/domain/models/DatasetMother' import { isArrayOfObjects, - metadataFieldValueToString -} from '../../../../../src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue' + metadataFieldValueToMarkdownFormat +} from '../../../../../src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted' import { MetadataBlockInfoMother } from '../../../metadata-block-info/domain/models/MetadataBlockInfoMother' import { MetadataBlockInfoRepository } from '../../../../../src/metadata-block-info/domain/repositories/MetadataBlockInfoRepository' import { MetadataBlockInfoProvider } from '../../../../../src/sections/dataset/metadata-block-info/MetadataBlockProvider' @@ -38,7 +38,7 @@ describe('DatasetSummary', () => { ) summaryFieldDescription.should('exist') - const summaryFieldValueString = metadataFieldValueToString( + const summaryFieldValueString = metadataFieldValueToMarkdownFormat( summaryFieldName, summaryFieldValue, metadataBlockInfoMock diff --git a/tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoCitationExample.ts b/tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoCitationExample.ts new file mode 100644 index 000000000..86ae7db65 --- /dev/null +++ b/tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoCitationExample.ts @@ -0,0 +1,83 @@ +export const MetadataBlockInfoCitationExample = { + name: 'citation', + fields: { + title: { displayFormat: '' }, + subtitle: { displayFormat: '' }, + alternativeTitle: { displayFormat: '' }, + alternativeURL: { displayFormat: '[#VALUE](#VALUE)' }, + otherId: { displayFormat: ':' }, + otherIdAgency: { displayFormat: '#VALUE' }, + otherIdValue: { displayFormat: '#VALUE' }, + author: { displayFormat: '' }, + authorName: { displayFormat: '#VALUE' }, + authorAffiliation: { displayFormat: '(#VALUE)' }, + authorIdentifierScheme: { displayFormat: '- #VALUE:' }, + authorIdentifier: { displayFormat: '#VALUE' }, + datasetContact: { displayFormat: '' }, + datasetContactName: { displayFormat: '#VALUE' }, + datasetContactAffiliation: { displayFormat: '(#VALUE)' }, + datasetContactEmail: { displayFormat: '[#VALUE](mailto:#VALUE)' }, + dsDescription: { displayFormat: '' }, + dsDescriptionValue: { displayFormat: '#VALUE' }, + dsDescriptionDate: { displayFormat: '(#VALUE)' }, + subject: { displayFormat: '' }, + keyword: { displayFormat: '' }, + keywordValue: { displayFormat: '#VALUE' }, + keywordVocabulary: { displayFormat: '(#VALUE)' }, + keywordVocabularyURI: { displayFormat: '[#VALUE](#VALUE)' }, + topicClassification: { displayFormat: '' }, + topicClassValue: { displayFormat: '#VALUE' }, + topicClassVocab: { displayFormat: '(#VALUE)' }, + topicClassVocabURI: { displayFormat: '[#VALUE](#VALUE)' }, + publication: { displayFormat: '' }, + publicationCitation: { displayFormat: '#VALUE' }, + publicationIDType: { displayFormat: '#VALUE: ' }, + publicationIDNumber: { displayFormat: '#VALUE' }, + publicationURL: { displayFormat: '[#VALUE](#VALUE)' }, + notesText: { displayFormat: '' }, + language: { displayFormat: '' }, + producer: { displayFormat: '' }, + producerName: { displayFormat: '#VALUE' }, + producerAffiliation: { displayFormat: '(#VALUE)' }, + producerAbbreviation: { displayFormat: '(#VALUE)' }, + producerURL: { displayFormat: '[#VALUE](#VALUE)' }, + producerLogoURL: { displayFormat: '![#NAME](#VALUE)' }, + productionDate: { displayFormat: '' }, + productionPlace: { displayFormat: '' }, + contributor: { displayFormat: ':' }, + contributorType: { displayFormat: '#VALUE ' }, + contributorName: { displayFormat: '#VALUE' }, + grantNumber: { displayFormat: ':' }, + grantNumberAgency: { displayFormat: '#VALUE' }, + grantNumberValue: { displayFormat: '#VALUE' }, + distributor: { displayFormat: '' }, + distributorName: { displayFormat: '#VALUE' }, + distributorAffiliation: { displayFormat: '(#VALUE)' }, + distributorAbbreviation: { displayFormat: '(#VALUE)' }, + distributorURL: { displayFormat: '[#VALUE](#VALUE)' }, + distributorLogoURL: { displayFormat: '![#NAME](#VALUE)' }, + distributionDate: { displayFormat: '' }, + depositor: { displayFormat: '' }, + dateOfDeposit: { displayFormat: '' }, + timePeriodCovered: { displayFormat: ';' }, + timePeriodCoveredStart: { displayFormat: '#NAME: #VALUE ' }, + timePeriodCoveredEnd: { displayFormat: '#NAME: #VALUE ' }, + dateOfCollection: { displayFormat: ';' }, + dateOfCollectionStart: { displayFormat: '#NAME: #VALUE ' }, + dateOfCollectionEnd: { displayFormat: '#NAME: #VALUE ' }, + kindOfData: { displayFormat: '' }, + series: { displayFormat: ':' }, + seriesName: { displayFormat: '#VALUE' }, + seriesInformation: { displayFormat: '#VALUE' }, + software: { displayFormat: ',' }, + softwareName: { displayFormat: '#VALUE' }, + softwareVersion: { displayFormat: '#NAME: #VALUE' }, + relatedMaterial: { displayFormat: '' }, + relatedDatasets: { displayFormat: '' }, + otherReferences: { displayFormat: '' }, + dataSources: { displayFormat: '' }, + originOfSources: { displayFormat: '' }, + characteristicOfSources: { displayFormat: '' }, + accessToSources: { displayFormat: '' } + } +} diff --git a/tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoJSDataverseRepository.spec.ts b/tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoJSDataverseRepository.spec.ts new file mode 100644 index 000000000..5eb1d0636 --- /dev/null +++ b/tests/e2e-integration/integration/metadata-block-info/MetadataBlockInfoJSDataverseRepository.spec.ts @@ -0,0 +1,25 @@ +import chai from 'chai' +import chaiAsPromised from 'chai-as-promised' +import { IntegrationTestsUtils } from '../IntegrationTestsUtils' +import { MetadataBlockInfoJSDataverseRepository } from '../../../../src/metadata-block-info/infrastructure/repositories/MetadataBlockInfoJSDataverseRepository' +import { MetadataBlockInfoCitationExample } from './MetadataBlockInfoCitationExample' + +chai.use(chaiAsPromised) +const expect = chai.expect + +const metadataBlockInfoExpected = MetadataBlockInfoCitationExample +const metadataBlockInfoRepository = new MetadataBlockInfoJSDataverseRepository() +describe('Metadata Block Info JSDataverse Repository', () => { + before(() => IntegrationTestsUtils.setup()) + beforeEach(() => IntegrationTestsUtils.login()) + + it('gets the metadataBlockInfo by name', async () => { + await metadataBlockInfoRepository.getByName('citation').then((metadataBlockInfo) => { + if (!metadataBlockInfo) { + throw new Error('Metadata Block Info not found') + } + + expect(metadataBlockInfo).to.deep.equal(metadataBlockInfoExpected) + }) + }) +}) From 3937954d7d38b194f16f82111f51bf3ae77a4ce8 Mon Sep 17 00:00:00 2001 From: MellyGray Date: Tue, 8 Aug 2023 10:40:04 +0200 Subject: [PATCH 3/9] feat(MetadataBlockInfo): replace #NAME placeholder by the translated name --- .../DatasetMetadataField.tsx | 1 + .../DatasetMetadataFieldValue.tsx | 6 ++++- .../DatasetMetadataFieldValueFormatted.tsx | 18 ++++++++++--- .../dataset-metadata/DatasetMetadata.spec.tsx | 27 +++++++++++++------ .../dataset-summary/SummaryFields.spec.tsx | 4 +-- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataField.tsx b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataField.tsx index 71821add0..e8b6ef7a8 100644 --- a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataField.tsx +++ b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataField.tsx @@ -30,6 +30,7 @@ export function DatasetMetadataField({ metadataFieldName={metadataFieldName} /> diff --git a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx index 99f4fe514..4ec9b80a7 100644 --- a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx +++ b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValue.tsx @@ -1,17 +1,20 @@ import { ANONYMIZED_FIELD_VALUE, - DatasetMetadataFieldValue as DatasetMetadataFieldValueModel + DatasetMetadataFieldValue as DatasetMetadataFieldValueModel, + MetadataBlockName } from '../../../../dataset/domain/models/Dataset' import { useAnonymized } from '../../anonymized/AnonymizedContext' import { useTranslation } from 'react-i18next' import { DatasetMetadataFieldValueFormatted } from './DatasetMetadataFieldValueFormatted' interface DatasetMetadataFieldValueProps { + metadataBlockName: MetadataBlockName metadataFieldName: string metadataFieldValue: DatasetMetadataFieldValueModel } export function DatasetMetadataFieldValue({ + metadataBlockName, metadataFieldName, metadataFieldValue }: DatasetMetadataFieldValueProps) { @@ -23,6 +26,7 @@ export function DatasetMetadataFieldValue({ return ( diff --git a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx index c0bc09b14..b3cb7d7a7 100644 --- a/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx +++ b/src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted.tsx @@ -1,33 +1,43 @@ import { useMetadataBlockInfo } from '../../metadata-block-info/MetadataBlockInfoContext' import { + METADATA_FIELD_DISPLAY_FORMAT_NAME_PLACEHOLDER, METADATA_FIELD_DISPLAY_FORMAT_PLACEHOLDER, MetadataBlockInfo } from '../../../../metadata-block-info/domain/models/MetadataBlockInfo' import { MarkdownComponent } from '../../markdown/MarkdownComponent' import { DatasetMetadataFieldValue as DatasetMetadataFieldValueModel, - DatasetMetadataSubField + DatasetMetadataSubField, + MetadataBlockName } from '../../../../dataset/domain/models/Dataset' +import { useTranslation } from 'react-i18next' interface DatasetMetadataFieldValueFormattedProps { + metadataBlockName: MetadataBlockName metadataFieldName: string metadataFieldValue: DatasetMetadataFieldValueModel } export function DatasetMetadataFieldValueFormatted({ + metadataBlockName, metadataFieldName, metadataFieldValue }: DatasetMetadataFieldValueFormattedProps) { + const { t } = useTranslation(metadataBlockName) const { metadataBlockInfo } = useMetadataBlockInfo() - const metadataFieldValueMarkdown = metadataFieldValueToMarkdownFormat( + const valueFormatted = metadataFieldValueToDisplayFormat( metadataFieldName, metadataFieldValue, metadataBlockInfo ) + const valueFormattedWithNamesTranslated = valueFormatted.replaceAll( + METADATA_FIELD_DISPLAY_FORMAT_NAME_PLACEHOLDER, + t(`${metadataBlockName}.datasetField.${metadataFieldName}.name`) + ) - return + return } -export function metadataFieldValueToMarkdownFormat( +export function metadataFieldValueToDisplayFormat( metadataFieldName: string, metadataFieldValue: DatasetMetadataFieldValueModel, metadataBlockInfo?: MetadataBlockInfo diff --git a/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx b/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx index f4718182a..de70cdffa 100644 --- a/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx +++ b/tests/component/sections/dataset/dataset-metadata/DatasetMetadata.spec.tsx @@ -7,11 +7,12 @@ import { import { AnonymizedContext } from '../../../../../src/sections/dataset/anonymized/AnonymizedContext' import { isArrayOfObjects, - metadataFieldValueToMarkdownFormat + metadataFieldValueToDisplayFormat } from '../../../../../src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted' import { MetadataBlockInfoProvider } from '../../../../../src/sections/dataset/metadata-block-info/MetadataBlockProvider' import { MetadataBlockInfoRepository } from '../../../../../src/metadata-block-info/domain/repositories/MetadataBlockInfoRepository' import { MetadataBlockInfoMother } from '../../../metadata-block-info/domain/models/MetadataBlockInfoMother' +import { METADATA_FIELD_DISPLAY_FORMAT_NAME_PLACEHOLDER } from '../../../../../src/metadata-block-info/domain/models/MetadataBlockInfo' const extractLinksFromText = (text: string): { text: string; link: string }[] => { const linkFormat = /(? { if (notPlainText) { if (extractedLinks) { extractedLinks.forEach(({ text, link }) => { - cy.findByText(text).should('exist') - cy.findByText(text).should('have.attr', 'href', link) + const translatedText = text.replaceAll( + METADATA_FIELD_DISPLAY_FORMAT_NAME_PLACEHOLDER, + metadataFieldName + ) + cy.findByText(translatedText).should('exist') + cy.findByText(translatedText).should('have.attr', 'href', link) }) } if (extractedImages) { extractedImages.forEach((image) => { const [, altText, imageUrl] = image.match(/!\[(.*?)\]\((.*?)\)/) || [] - cy.findByAltText(altText).should('exist') - cy.findByAltText(altText).should('have.attr', 'src', imageUrl) + const translatedAltText = altText.replaceAll( + METADATA_FIELD_DISPLAY_FORMAT_NAME_PLACEHOLDER, + metadataFieldName + ) + cy.findByAltText(translatedAltText).should('exist') + cy.findByAltText(translatedAltText).should('have.attr', 'src', imageUrl) }) } } else { @@ -178,7 +187,9 @@ describe('DatasetMetadata', () => { } Object.entries(metadataBlock.fields).forEach(([metadataFieldName, metadataFieldValue]) => { - const metadataFieldValueString = metadataFieldValueToMarkdownFormat( + const metadataFieldNameTranslated = t[metadataBlock.name].datasetField[metadataFieldName] + .name as string + const metadataFieldValueString = metadataFieldValueToDisplayFormat( metadataFieldName, metadataFieldValue, metadataBlockInfoMock @@ -186,12 +197,12 @@ describe('DatasetMetadata', () => { if (isArrayOfObjects(metadataFieldValue)) { metadataFieldValueString.split(' \n \n').forEach((fieldValue) => { - checkMetadataFieldValue(metadataFieldName, fieldValue) + checkMetadataFieldValue(metadataFieldNameTranslated, fieldValue) }) return } - checkMetadataFieldValue(metadataFieldName, metadataFieldValueString) + checkMetadataFieldValue(metadataFieldNameTranslated, metadataFieldValueString) }) }) }) diff --git a/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx b/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx index 1682e93b2..903d9664e 100644 --- a/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx +++ b/tests/component/sections/dataset/dataset-summary/SummaryFields.spec.tsx @@ -3,7 +3,7 @@ import { SummaryFields } from '../../../../../src/sections/dataset/dataset-summa import { DatasetMother } from '../../../dataset/domain/models/DatasetMother' import { isArrayOfObjects, - metadataFieldValueToMarkdownFormat + metadataFieldValueToDisplayFormat } from '../../../../../src/sections/dataset/dataset-metadata/dataset-metadata-fields/DatasetMetadataFieldValueFormatted' import { MetadataBlockInfoMother } from '../../../metadata-block-info/domain/models/MetadataBlockInfoMother' import { MetadataBlockInfoRepository } from '../../../../../src/metadata-block-info/domain/repositories/MetadataBlockInfoRepository' @@ -38,7 +38,7 @@ describe('DatasetSummary', () => { ) summaryFieldDescription.should('exist') - const summaryFieldValueString = metadataFieldValueToMarkdownFormat( + const summaryFieldValueString = metadataFieldValueToDisplayFormat( summaryFieldName, summaryFieldValue, metadataBlockInfoMock From 35884f1840f8969d08d057eb29d5f74b6ee0fe0a Mon Sep 17 00:00:00 2001 From: MellyGray Date: Tue, 8 Aug 2023 10:53:11 +0200 Subject: [PATCH 4/9] feat(publicationData,citationDate, alternativePersistentId): implement using js-dataverse --- src/dataset/infrastructure/mappers/JSDatasetMapper.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts index f14f4beb3..f63bc52ec 100644 --- a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts +++ b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts @@ -24,7 +24,12 @@ export class JSDatasetMapper { citation, JSDatasetMapper.toSummaryFields(jsDataset.metadataBlocks, summaryFieldsNames), jsDataset.license, - JSDatasetMapper.toMetadataBlocks(jsDataset.metadataBlocks) // TODO Add alternativePersistentId, publicationDate, citationDate + JSDatasetMapper.toMetadataBlocks( + jsDataset.metadataBlocks, + jsDataset.alternativePersistentId, + jsDataset.publicationDate, + jsDataset.citationDate + ) ).build() } From 176518562fc2a62f24f6c570a0a38911ce72350e Mon Sep 17 00:00:00 2001 From: MellyGray Date: Tue, 8 Aug 2023 12:13:25 +0200 Subject: [PATCH 5/9] fix(dev-env): restore configbaker timeout --- dev-env/run-env.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-env/run-env.sh b/dev-env/run-env.sh index 28ebd20c6..a8a2f09cd 100755 --- a/dev-env/run-env.sh +++ b/dev-env/run-env.sh @@ -6,7 +6,7 @@ export DATAVERSE_IMAGE_TAG=$1 export COMPOSE_HTTP_TIMEOUT=200 # Timeout for Dataverse bootstrap configbaker -export DATAVERSE_BOOTSTRAP_TIMEOUT="10m" +export DATAVERSE_BOOTSTRAP_TIMEOUT="5m" echo "INFO - Setting up Dataverse on image tag ${DATAVERSE_IMAGE_TAG}..." From 4e78ee76a85df13e6d6a60e8443bb7bb2b1cd7b3 Mon Sep 17 00:00:00 2001 From: MellyGray Date: Tue, 8 Aug 2023 12:45:07 +0200 Subject: [PATCH 6/9] fix(e2e action): increase wait for containers' timeout --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 001a50659..f6a07776f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,7 +49,7 @@ jobs: run: ./run-env.sh "$E2E_DATAVERSE_IMAGE_TAG" - name: Wait for containers to be ready - run: timeout 300s sh -c 'while ! docker logs dev_dataverse_bootstrap 2>&1 | grep -q "your instance has been configured"; do sleep 2; done' + run: timeout 360s sh -c 'while ! docker logs dev_dataverse_bootstrap 2>&1 | grep -q "your instance has been configured"; do sleep 2; done' - name: Run e2e tests run: npm run test:e2e From 29ed11c6666aaaa55cfdff76414b840fcbb72084 Mon Sep 17 00:00:00 2001 From: MellyGray Date: Tue, 5 Sep 2023 12:09:16 +0200 Subject: [PATCH 7/9] fix: citationDate undefined crashes the Dataset page --- src/dataset/infrastructure/mappers/JSDatasetMapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts index f63bc52ec..53a3a627a 100644 --- a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts +++ b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts @@ -148,7 +148,7 @@ export class JSDatasetMapper { extraFields.publicationDate = publicationDate } - if (publicationDate && citationDate !== publicationDate) { + if (citationDate && citationDate !== publicationDate) { extraFields.citationDate = citationDate } From 599ad3c02320000cc97118f707e66d4a666f6a01 Mon Sep 17 00:00:00 2001 From: MellyGray Date: Tue, 5 Sep 2023 16:49:54 +0200 Subject: [PATCH 8/9] fix: add tests for dataset summary --- .../integration/DataverseApiHelper.ts | 9 ++++- .../integration/datasets/DatasetHelper.ts | 12 ++++++ .../DatasetJSDataverseRepository.spec.ts | 37 ++++++++++++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/tests/e2e-integration/integration/DataverseApiHelper.ts b/tests/e2e-integration/integration/DataverseApiHelper.ts index 742069b78..745729f85 100644 --- a/tests/e2e-integration/integration/DataverseApiHelper.ts +++ b/tests/e2e-integration/integration/DataverseApiHelper.ts @@ -14,13 +14,18 @@ export class DataverseApiHelper { } // eslint-disable-next-line @typescript-eslint/no-explicit-any - static async request(url: string, method: string, data?: any): Promise { + static async request( + url: string, + method: string, + data?: any, + contentType?: string + ): Promise { const config: AxiosRequestConfig = { url: `${this.API_URL}${url}`, method: method, headers: { 'X-Dataverse-key': this.API_TOKEN, - 'Content-Type': 'application/json' + 'Content-Type': contentType ? contentType : 'application/json' }, // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment data: data diff --git a/tests/e2e-integration/integration/datasets/DatasetHelper.ts b/tests/e2e-integration/integration/datasets/DatasetHelper.ts index 270d57fae..e1699112d 100644 --- a/tests/e2e-integration/integration/datasets/DatasetHelper.ts +++ b/tests/e2e-integration/integration/datasets/DatasetHelper.ts @@ -21,4 +21,16 @@ export class DatasetHelper extends DataverseApiHelper { static async createPrivateUrl(id: string): Promise<{ token: string }> { return this.request<{ token: string }>(`/datasets/${id}/privateUrl`, 'POST') } + + static async setCitationDateFieldType( + persistentId: string, + fieldType: string + ): Promise<{ status: string }> { + return this.request<{ status: string }>( + `/datasets/:persistentId/citationdate?persistentId=${persistentId}`, + 'PUT', + fieldType, + 'text/plain' + ) + } } diff --git a/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts b/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts index 0d9dd37ba..2ae873d48 100644 --- a/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts +++ b/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts @@ -8,6 +8,13 @@ import { DatasetStatus, DatasetVersion } from '../../../../src/dataset/domain/mo chai.use(chaiAsPromised) const expect = chai.expect +function getCurrentDateInYYYYMMDDFormat() { + const date = new Date() + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String( + date.getDate() + ).padStart(2, '0')}` +} + const datasetData = (persistentId: string) => { const persistentIdUrl = `https://doi.org/${persistentId.replace('doi:', '')}` return { @@ -86,6 +93,8 @@ describe('Dataset JSDataverse Repository', () => { expect(dataset.metadataBlocks).to.deep.equal(datasetExpected.metadataBlocks) expect(dataset.summaryFields).to.deep.equal(datasetExpected.summaryFields) expect(dataset.version).to.deep.equal(datasetExpected.version) + expect(dataset.metadataBlocks[0].fields.publicationDate).not.to.exist + expect(dataset.metadataBlocks[0].fields.citationDate).not.to.exist }) }) @@ -103,9 +112,13 @@ describe('Dataset JSDataverse Repository', () => { } const datasetExpected = datasetData(dataset.persistentId) const newVersion = new DatasetVersion(1, 0, DatasetStatus.RELEASED) - + const expectedPublicationDate = getCurrentDateInYYYYMMDDFormat() expect(dataset.getTitle()).to.deep.equal(datasetExpected.title) expect(dataset.version).to.deep.equal(newVersion) + expect(dataset.metadataBlocks[0].fields.publicationDate).to.deep.equal( + expectedPublicationDate + ) + expect(dataset.metadataBlocks[0].fields.citationDate).not.to.exist }) }) @@ -139,4 +152,26 @@ describe('Dataset JSDataverse Repository', () => { expect(dataset.version).to.deep.equal(datasetExpected.version) }) }) + + it('gets the dataset after changing the citation date field type', async () => { + const datasetResponse = await DatasetHelper.createDataset() + + await DatasetHelper.publishDataset(datasetResponse.persistentId) + await IntegrationTestsUtils.wait(1500) + + await DatasetHelper.setCitationDateFieldType(datasetResponse.persistentId, 'dateOfDeposit') + + await datasetRepository + .getByPersistentId(datasetResponse.persistentId, '1.0') + .then((dataset) => { + if (!dataset) { + throw new Error('Dataset not found') + } + const expectedPublicationDate = getCurrentDateInYYYYMMDDFormat() + expect(dataset.metadataBlocks[0].fields.publicationDate).to.deep.equal( + expectedPublicationDate + ) + expect(dataset.metadataBlocks[0].fields.citationDate).not.to.exist + }) + }) }) From 3f6699727538727b4b6f6c18fccd9c5b41488b50 Mon Sep 17 00:00:00 2001 From: MellyGray Date: Thu, 7 Sep 2023 16:03:38 +0200 Subject: [PATCH 9/9] fix: add JSDatasetMapper unit tests --- .../mappers/JSDatasetMapper.spec.ts | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts diff --git a/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts b/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts new file mode 100644 index 000000000..4ad8930f1 --- /dev/null +++ b/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts @@ -0,0 +1,214 @@ +import chai from 'chai' +import chaiAsPromised from 'chai-as-promised' +import { JSDatasetMapper } from '../../../../../src/dataset/infrastructure/mappers/JSDatasetMapper' +import { DatasetVersionState } from '@iqss/dataverse-client-javascript' +import { + CitationMetadataBlock, + DatasetMetadataBlock +} from '@iqss/dataverse-client-javascript/dist/datasets/domain/models/Dataset' +import { DatasetStatus, DatasetVersion } from '../../../../../src/dataset/domain/models/Dataset' + +chai.use(chaiAsPromised) +const expect = chai.expect + +const jsDataset = { + id: 505, + persistentId: 'doi:10.5072/FK2/B4B2MJ', + versionId: 101, + versionInfo: { + state: DatasetVersionState.DRAFT, + majorNumber: 0, + minorNumber: 0, + createTime: new Date('2023-09-07T13:40:04.000Z'), + lastUpdateTime: new Date('2023-09-07T13:40:04.000Z'), + releaseTime: undefined + }, + metadataBlocks: [ + { + name: 'citation', + fields: { + title: "Darwin's Finches", + author: [{ authorName: 'Finch, Fiona', authorAffiliation: 'Birds Inc.' }], + datasetContact: [ + { datasetContactName: 'Finch, Fiona', datasetContactEmail: 'finch@mailinator.com' } + ], + dsDescription: [ + { + dsDescriptionValue: + "Darwin's finches (also known as the Galápagos finches) are a group of about fifteen species of passerine birds." + } + ], + subject: ['Medicine, Health and Life Sciences'] + } + } as CitationMetadataBlock + ] as [CitationMetadataBlock, ...DatasetMetadataBlock[]], + license: { + name: 'CC0 1.0', + uri: 'http://creativecommons.org/publicdomain/zero/1.0', + iconUri: 'https://licensebuttons.net/p/zero/1.0/88x31.png' + } +} +const citation = + 'Finch, Fiona, 2023, "Darwin\'s Finches", https://doi.org/10.5072/FK2/B4B2MJ, Root, DRAFT VERSION' +const datasetSummaryFields = ['dsDescription', 'subject', 'keyword', 'publication', 'notesText'] +const expectedDataset = { + persistentId: 'doi:10.5072/FK2/B4B2MJ', + version: new DatasetVersion(0, 0, DatasetStatus.DRAFT), + citation: + 'Finch, Fiona, 2023, "Darwin\'s Finches", https://doi.org/10.5072/FK2/B4B2MJ, Root, DRAFT VERSION', + labels: [ + { semanticMeaning: 'dataset', value: 'Draft' }, + { semanticMeaning: 'warning', value: 'Unpublished' } + ], + summaryFields: [ + { + name: 'citation', + fields: { + dsDescription: [ + { + dsDescriptionValue: + "Darwin's finches (also known as the Galápagos finches) are a group of about fifteen species of passerine birds." + } + ], + subject: ['Medicine, Health and Life Sciences'] + } + } + ], + license: { + name: 'CC0 1.0', + uri: 'http://creativecommons.org/publicdomain/zero/1.0', + iconUri: 'https://licensebuttons.net/p/zero/1.0/88x31.png' + }, + metadataBlocks: [ + { + name: 'citation', + fields: { + title: "Darwin's Finches", + author: [{ authorName: 'Finch, Fiona', authorAffiliation: 'Birds Inc.' }], + datasetContact: [ + { datasetContactName: 'Finch, Fiona', datasetContactEmail: 'finch@mailinator.com' } + ], + dsDescription: [ + { + dsDescriptionValue: + "Darwin's finches (also known as the Galápagos finches) are a group of about fifteen species of passerine birds." + } + ], + subject: ['Medicine, Health and Life Sciences'] + } + } + ] +} + +describe('JS Dataset Mapper', () => { + it('maps jsDataset model to the domain Dataset model', () => { + expect(expectedDataset).to.deep.equal( + JSDatasetMapper.toDataset(jsDataset, citation, datasetSummaryFields) + ) + }) + + it('maps jsDataset model to the domain Dataset model when alternativePersistentId is provided', () => { + const jsDatasetWithAlternativePersistentId = { + ...jsDataset, + alternativePersistentId: 'doi:10.5072/FK2/B4B2MY' + } + const expectedDatasetWithAlternativePersistentId = { + ...expectedDataset, + metadataBlocks: [ + { + name: 'citation', + fields: { + title: "Darwin's Finches", + author: [{ authorName: 'Finch, Fiona', authorAffiliation: 'Birds Inc.' }], + datasetContact: [ + { datasetContactName: 'Finch, Fiona', datasetContactEmail: 'finch@mailinator.com' } + ], + dsDescription: [ + { + dsDescriptionValue: + "Darwin's finches (also known as the Galápagos finches) are a group of about fifteen species of passerine birds." + } + ], + subject: ['Medicine, Health and Life Sciences'], + alternativePersistentId: 'doi:10.5072/FK2/B4B2MY' + } + } + ] + } + + expect(expectedDatasetWithAlternativePersistentId).to.deep.equal( + JSDatasetMapper.toDataset( + jsDatasetWithAlternativePersistentId, + citation, + datasetSummaryFields + ) + ) + }) + + it('maps jsDataset model to the domain Dataset model when citationDate is provided', () => { + const jsDatasetWithCitationDate = { + ...jsDataset, + citationDate: '2023-02-12' + } + const expectedDatasetWithCitationDate = { + ...expectedDataset, + metadataBlocks: [ + { + name: 'citation', + fields: { + title: "Darwin's Finches", + author: [{ authorName: 'Finch, Fiona', authorAffiliation: 'Birds Inc.' }], + datasetContact: [ + { datasetContactName: 'Finch, Fiona', datasetContactEmail: 'finch@mailinator.com' } + ], + dsDescription: [ + { + dsDescriptionValue: + "Darwin's finches (also known as the Galápagos finches) are a group of about fifteen species of passerine birds." + } + ], + subject: ['Medicine, Health and Life Sciences'], + citationDate: '2023-02-12' + } + } + ] + } + + expect(expectedDatasetWithCitationDate).to.deep.equal( + JSDatasetMapper.toDataset(jsDatasetWithCitationDate, citation, datasetSummaryFields) + ) + }) + + it('maps jsDataset model to the domain Dataset model when publicationDate is provided', () => { + const jsDatasetWithPublicationDate = { + ...jsDataset, + publicationDate: '2023-02-12' + } + const expectedDatasetWithPublicationDate = { + ...expectedDataset, + metadataBlocks: [ + { + name: 'citation', + fields: { + title: "Darwin's Finches", + author: [{ authorName: 'Finch, Fiona', authorAffiliation: 'Birds Inc.' }], + datasetContact: [ + { datasetContactName: 'Finch, Fiona', datasetContactEmail: 'finch@mailinator.com' } + ], + dsDescription: [ + { + dsDescriptionValue: + "Darwin's finches (also known as the Galápagos finches) are a group of about fifteen species of passerine birds." + } + ], + subject: ['Medicine, Health and Life Sciences'], + publicationDate: '2023-02-12' + } + } + ] + } + expect(expectedDatasetWithPublicationDate).to.deep.equal( + JSDatasetMapper.toDataset(jsDatasetWithPublicationDate, citation, datasetSummaryFields) + ) + }) +})