diff --git a/sample-data/BBMRI-ERIC_model.xlsx b/sample-data/BBMRI-ERIC_model.xlsx index 0b62af70..7e660b1d 100755 Binary files a/sample-data/BBMRI-ERIC_model.xlsx and b/sample-data/BBMRI-ERIC_model.xlsx differ diff --git a/src/components/cards/CollectionReportInfoCard.vue b/src/components/cards/CollectionReportInfoCard.vue index 8aac13b1..415eb51f 100644 --- a/src/components/cards/CollectionReportInfoCard.vue +++ b/src/components/cards/CollectionReportInfoCard.vue @@ -98,6 +98,25 @@ + + Study + + + Name: + {{ info.study.title }} + + + + + {{ uiText["view"] }} {{ info.study.title }} study + + + + + + Quality diff --git a/src/components/cards/StudyReportInfoCard.vue b/src/components/cards/StudyReportInfoCard.vue new file mode 100644 index 00000000..0bdc1e07 --- /dev/null +++ b/src/components/cards/StudyReportInfoCard.vue @@ -0,0 +1,46 @@ + + + + + + + External link + + + + {{ also_known.system }} + + + + + + + + + + + + + diff --git a/src/components/report-components/ReportStudyDetails.vue b/src/components/report-components/ReportStudyDetails.vue new file mode 100644 index 00000000..012dda88 --- /dev/null +++ b/src/components/report-components/ReportStudyDetails.vue @@ -0,0 +1,39 @@ + + + + + + + + + + diff --git a/src/config/configManager.js b/src/config/configManager.js index ffc2ba38..49e6b389 100644 --- a/src/config/configManager.js +++ b/src/config/configManager.js @@ -1,5 +1,6 @@ import initialBiobankColumns from './initialBiobankColumns' import initialCollectionColumns from './initialCollectionColumns' +import initialStudyColumns from './initialStudyColumns' import initialFilterFacets from './initialFilterFacets' import initialLandingpage from './initialLandingpage' import i18n from './i18n.js' @@ -11,6 +12,7 @@ export const bbmriConfig = () => { negotiatorType: 'eric-negotiator', collectionColumns: initialCollectionColumns, biobankColumns: initialBiobankColumns, + studyColumns: initialStudyColumns, filterFacets: initialFilterFacets, filterMenuInitiallyFolded: false, removeFreemarkerMargin: false, diff --git a/src/config/initialStudyColumns.js b/src/config/initialStudyColumns.js new file mode 100644 index 00000000..d70b0423 --- /dev/null +++ b/src/config/initialStudyColumns.js @@ -0,0 +1,11 @@ +const initialStudyColumns = [ + { label: 'Id:', column: 'id', type: 'string', showCopyIcon: true }, + { label: 'Title:', column: 'title', type: 'string' }, + { label: 'Type:', column: 'type', type: 'string' }, + { label: 'Sex:', column: 'sex', type: 'categoricalmref' }, + { label: 'Description:', column: 'description', type: 'string' }, + { label: 'Number of subjects:', column: 'number_of_subjects', type: 'int' }, + { label: 'Age:', type: 'range', min: 'age_low', max: 'age_high', unit: 'age_unit' } +] + +module.exports = initialStudyColumns diff --git a/src/router/index.js b/src/router/index.js index f2aa0a1e..f7c4545d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -6,6 +6,7 @@ import BiobankReport from '../views/BiobankReport' import CollectionReport from '../views/CollectionReport' import NetworkReportCard from '../components/cards/NetworkReportCard' import state, { INITIAL_STATE } from '../store/state' +import StudyReport from '../views/StudyReport' import api from '@molgenis/molgenis-api-client' Vue.use(VueRouter) @@ -36,6 +37,11 @@ const router = new VueRouter({ name: 'network', component: NetworkReportCard }, + { + path: '/study/:id', + name: 'study', + component: StudyReport + }, { path: '/configuration', component: () => import(/* webpackChunkName: "configuration-screen" */ '../views/ConfigurationScreen'), diff --git a/src/store/actions.js b/src/store/actions.js index 30915073..0c798544 100644 --- a/src/store/actions.js +++ b/src/store/actions.js @@ -8,8 +8,11 @@ import { biobankActions } from './biobank/biobankActions' import { configurationActions } from './configuration/configurationActions' import { collectionActions, COLLECTION_REPORT_ATTRIBUTE_SELECTOR } from './collection/collectionActions' +import { studyActions } from './study/studyActions' + const BIOBANK_API_PATH = '/api/v2/eu_bbmri_eric_biobanks' export const COLLECTION_API_PATH = '/api/v2/eu_bbmri_eric_collections' +export const STUDY_API_PATH = '/api/v2/eu_bbmri_eric_studies' const NETWORK_API_PATH = '/api/v2/eu_bbmri_eric_networks' /**/ @@ -18,6 +21,7 @@ export default { ...collectionActions, ...biobankActions, ...configurationActions, + ...studyActions, async GetNetworkReport ({ commit }, networkId) { commit('SetNetworkBiobanks', undefined) commit('SetNetworkCollections', undefined) diff --git a/src/store/collection/collectionActions.js b/src/store/collection/collectionActions.js index 44386324..e838bcd6 100644 --- a/src/store/collection/collectionActions.js +++ b/src/store/collection/collectionActions.js @@ -13,7 +13,7 @@ export const COLLECTION_REPORT_ATTRIBUTE_SELECTOR = () => { rsqlStart += collectionRsql.join(',') } - return `${rsqlStart},biobank(id,name,juridical_person,country,url,contact,withdrawn),head(first_name,last_name,role),contact(title_before_name,first_name,last_name,title_after_name,email,phone),sub_collections(name,id,sub_collections(*),parent_collection,order_of_magnitude,materials(label,uri),data_categories),facts(*)` + return `${rsqlStart},biobank(id,name,juridical_person,country,url,contact,withdrawn),head(first_name,last_name,role),contact(title_before_name,first_name,last_name,title_after_name,email,phone),sub_collections(name,id,sub_collections(*),parent_collection,order_of_magnitude,materials(label,uri),data_categories),facts(*),also_known(*),study(*)` } export const collectionActions = { diff --git a/src/store/configuration/configurationState.js b/src/store/configuration/configurationState.js index 576598f5..943db3fc 100644 --- a/src/store/configuration/configurationState.js +++ b/src/store/configuration/configurationState.js @@ -9,6 +9,7 @@ export const configurationState = { filterMenuInitiallyFolded: config.filterMenuInitiallyFolded, biobankColumns: config.biobankColumns, collectionColumns: config.collectionColumns, + studyColumns: config.studyColumns, filterFacets: config.filterFacets, applicationNotification: config.applicationNotification || '', isPodium: config.negotiatorType === 'podium', diff --git a/src/store/mutations.js b/src/store/mutations.js index 6377bc09..aa577581 100644 --- a/src/store/mutations.js +++ b/src/store/mutations.js @@ -4,6 +4,7 @@ import { createFilters } from '../config/facetConfigurator' import { collectionMutations } from './collection/collectionMutations' import { biobankMutations } from './biobank/biobankMutations' import { configurationMutations } from './configuration/configurationMutations' +import { studyMutations } from './study/studyMutations' function mapLegacyFilterToNewFilter (state, query, oldFilterName, newFilterName) { const queryValues = decodeURIComponent(query[oldFilterName]).split(',') @@ -19,6 +20,7 @@ export default { ...biobankMutations, ...collectionMutations, ...configurationMutations, + ...studyMutations, /** * Updates filter and keeps a history of searches * @param {*} state; diff --git a/src/store/state.js b/src/store/state.js index 5aad9ba4..44631023 100644 --- a/src/store/state.js +++ b/src/store/state.js @@ -22,6 +22,7 @@ export default { collectionInfo: undefined, /** IDs of collections matching the collection filters */ biobankReport: undefined, /** A single biobank object which is fetched by ID for showing the BiobankReport view */ collectionReport: undefined, + studyReport: undefined, networkReport: { network: undefined, collections: undefined, diff --git a/src/store/study/studyActions.js b/src/store/study/studyActions.js new file mode 100644 index 00000000..bda13297 --- /dev/null +++ b/src/store/study/studyActions.js @@ -0,0 +1,30 @@ +import api from '@molgenis/molgenis-api-client' +import { STUDY_API_PATH } from '../actions' +/**/ +import initialStudyColumns from '../../config/initialStudyColumns' + +export const STUDY_REPORT_ATTRIBUTE_SELECTOR = () => { + const studyRsql = initialStudyColumns.filter(isc => isc.rsql).map(prop => prop.rsql) + + let rsqlStart = '*,' + + if (studyRsql.length) { + rsqlStart += studyRsql.join(',') + } + + return `${rsqlStart}collections(*),also_known(*)` +} + +export const studyActions = { + + GetStudyReport ({ commit }, studyId) { + commit('SetLoading', true) + api.get(`${STUDY_API_PATH}/${studyId}?attrs=${STUDY_REPORT_ATTRIBUTE_SELECTOR()}`).then(response => { + commit('SetStudyReport', response) + commit('SetLoading', false) + }, error => { + commit('SetError', error) + commit('SetLoading', false) + }) + } +} diff --git a/src/store/study/studyMutations.js b/src/store/study/studyMutations.js new file mode 100644 index 00000000..cfdf8ed1 --- /dev/null +++ b/src/store/study/studyMutations.js @@ -0,0 +1,6 @@ + +export const studyMutations = { + SetStudyReport (state, study) { + state.studyReport = study + } +} diff --git a/src/utils/templateMapper.js b/src/utils/templateMapper.js index 8f5aa0ed..1ea44771 100644 --- a/src/utils/templateMapper.js +++ b/src/utils/templateMapper.js @@ -169,6 +169,14 @@ export const getCollectionDetails = collection => { } } +export const getStudyDetails = study => { + const viewmodel = getViewmodel(study, state.studyColumns) + return { + ...study, + viewmodel + } +} + /** * Get all the types available within the collection tree */ @@ -255,6 +263,23 @@ export const collectionReportInformation = collection => { }) } + if (collection.also_known) { + collectionReport.also_known = collection.also_known.map(ak => { + return { + label: ak.label, + system: ak.name_system, + url: ak.url + } + }) + } + + if (collection.study) { + collectionReport.study = { + title: collection.study.title, + report: `/study/${collection.study.id}` + } + } + collectionReport.certifications = mapObjArray(collection.quality) collectionReport.collaboration = [] @@ -269,6 +294,23 @@ export const collectionReportInformation = collection => { return collectionReport } + +export const studyReportInformation = study => { + const studyReport = {} + + if (study.also_known) { + studyReport.also_known = study.also_known.map(ak => { + return { + label: ak.label, + system: ak.name_system, + url: ak.url + } + }) + } + + return studyReport +} + export const mapNetworkInfo = data => { return data.network.map(network => { return { diff --git a/src/views/BiobankReport.vue b/src/views/BiobankReport.vue index ec74b53d..abbacd8f 100644 --- a/src/views/BiobankReport.vue +++ b/src/views/BiobankReport.vue @@ -6,7 +6,7 @@ + type="application/ld+json"> + type="application/ld+json"> + :collection="collection" /> @@ -90,7 +90,7 @@ import Loading from 'vue-loading-overlay' import 'vue-loading-overlay/dist/vue-loading.css' import ReportTitle from '../components/report-components/ReportTitle' import CollectionReportInfoCard from '../components/cards/CollectionReportInfoCard' -import { collectionReportInformation } from '../utils/templateMapper' +import { collectionReportInformation, getStudyDetails } from '../utils/templateMapper' import { mapCollectionToBioschemas } from '../utils/bioschemasMapper' import ReportCollectionDetails from '../components/report-components/ReportCollectionDetails.vue' import FactsTable from '../components/generators/custom-view-components/FactsTable.vue' @@ -115,6 +115,9 @@ export default { computed: { ...mapState({ collection: 'collectionReport', isLoading: 'isLoading' }), ...mapGetters(['uiText']), + collectionDataAvailable () { + return Object.keys(this.collection).length + }, info () { return collectionReportInformation(this.collection) }, @@ -130,6 +133,11 @@ export default { factsData () { // TODO rework this so that facts are stand-alone, this is a workaround because @ReportCollectionDetails return { value: this.collection.facts } + }, + studyData () { + return this.collectionDataAvailable && this.collection.study + ? getStudyDetails(this.collection.study) + : undefined } }, /** needed because if we route back the component is not destroyed but its props are updated for other collection */ diff --git a/src/views/StudyReport.vue b/src/views/StudyReport.vue new file mode 100644 index 00000000..71649a52 --- /dev/null +++ b/src/views/StudyReport.vue @@ -0,0 +1,121 @@ + + + + + + + + + + + + {{ uiText["back"] }} + + + + + + + + + + + + + + + + + Collections with samples of the study + + + + + + + + + + + + + + + + {{ study }} + + + + + + diff --git a/tests/unit/specs/components/cards/StudyReportInfoCard.spec.js b/tests/unit/specs/components/cards/StudyReportInfoCard.spec.js new file mode 100644 index 00000000..cd19a061 --- /dev/null +++ b/tests/unit/specs/components/cards/StudyReportInfoCard.spec.js @@ -0,0 +1,37 @@ +import { createLocalVue, shallowMount } from '@vue/test-utils' +import StudyReportInfoCard from '@/components/cards/StudyReportInfoCard' + +const localVue = createLocalVue() + +describe('StudyReportInfoCard', () => { + let propsData + + beforeEach(() => { + propsData = { + info: { + id: 's-001', + name: 'Dummy study', + also_known: [{ + id: 'extcat-s-001', + url: 'http://external-catalog/study/extcat-s-001', + system: 'External Catalog' + }, { + id: 'anextcat-s-001', + url: 'http://another-external-catalog/study/ak-s-001', + system: 'Another External Catalog' + }] + } + } + }) + + it('shows link to external catalogues', () => { + const wrapper = shallowMount(StudyReportInfoCard, { localVue, propsData }) + expect(wrapper.html()).toContain('class="col-md-4') + expect(wrapper.html()).toContain('class="card') + expect(wrapper.html()).toContain('class="card-body') + expect(wrapper.html()).toContain('class="card-text') + // expect(wrapper.html()).toContain('class="mt-4">External Link') + expect(wrapper.findAll('ul')).toHaveLength(2) // one for each also known + expect(wrapper.findAll('a')).toHaveLength(2) // one for each also known + }) +}) diff --git a/tests/unit/specs/config/configManager.spec.js b/tests/unit/specs/config/configManager.spec.js index 68358719..0ea7b871 100644 --- a/tests/unit/specs/config/configManager.spec.js +++ b/tests/unit/specs/config/configManager.spec.js @@ -1,6 +1,7 @@ import { bbmriConfig } from '../../../../src/config/configManager' import initialBiobankColumns from '../../../../src/config/initialBiobankColumns' import initialCollectionColumns from '../../../../src/config/initialCollectionColumns' +import initialStudyColumns from '../../../../src/config/initialStudyColumns' import filterDefinitions from '../../../../src/config/initialFilterFacets' import initialLandingpage from '../../../../src/config/initialLandingpage' import i18n from '../../../../src/config/i18n' @@ -10,6 +11,7 @@ let windowSpy const initialState = { collectionColumns: initialCollectionColumns, biobankColumns: initialBiobankColumns, + studyColumns: initialStudyColumns, biobankCardShowCollections: true, filterFacets: filterDefinitions, removeFreemarkerMargin: true, diff --git a/tests/unit/specs/mockData.js b/tests/unit/specs/mockData.js index b2359026..add02f6e 100644 --- a/tests/unit/specs/mockData.js +++ b/tests/unit/specs/mockData.js @@ -123,3 +123,73 @@ export const mockCollectionResponse = { } }] } + +export const mockStudyResponse = { + id: 's-001', + title: 'Important study', + description: 'An important clinical study', + type: 'Observational', + age_unit: [ + { + _href: '/api/v2/eu_bbmri_eric_age_units/YEAR', + id: 'YEAR', + label: 'Year' + } + ], + also_known: [ + { + _href: '/api/v2/eu_bbmri_eric_also_known_in/s001-aka-cs-001', + id: 'id:001', + name_system: 'Another catalog', + pid: 'cs-001', + url: 'https://another-catalog.eu/study/cs-001', + withdrawn: false, + label: 'Another Catalog' + } + ], + collections: [ + { + id: 'c-001', + name: 'beautiful collection', + description: 'beautiful samples', + order_of_magnitude: { + _href: '/api/v2/eu_bbmri_eric_biobank_size/3', + size: '777' + }, + country: { + name: 'Genovia' + }, + network: [ + { + id: 'network-x', + name: 'Network x' + }, + { + id: 'network-y', + name: 'Network y' + } + ], + biobank: { + id: 'b-001', + name: 'beautiful biobank', + juridical_person: 'Is this even a person?', + email: 'info@beautiful-biobank.gnv', + url: 'https://beautiful-biobank.gnv' + } + } + ], + age_low: 16, + number_of_subjects: 373, + sex: [ + { + _href: '/api/v2/eu_bbmri_eric_sex_types/MALE', + id: 'MALE', + label: 'Male' + }, + { + _href: '/api/v2/eu_bbmri_eric_sex_types/FEMALE', + id: 'FEMALE', + label: 'Female' + } + ] +} diff --git a/tests/unit/specs/store/actions.spec.js b/tests/unit/specs/store/actions.spec.js index 926adee7..e2ff0be9 100644 --- a/tests/unit/specs/store/actions.spec.js +++ b/tests/unit/specs/store/actions.spec.js @@ -288,7 +288,7 @@ describe('store', () => { const response = { page: { totalElements: 2 } } - + api.get.mockResolvedValueOnce(response) const filterName = 'country' @@ -302,7 +302,7 @@ describe('store', () => { }) it('should not call SetFIlterLoading if the constructed query url equals the last constructed query url for the same filter', async () => { - + const filterName = 'country' const activeFilters = {'materials' : ['DNA']} state.filterOptionDictionary = mockFilterOptionDictionary @@ -324,4 +324,38 @@ describe('store', () => { expect(commit).toBeCalledWith('SetError', filterReductionError) }) }) + + describe('GetStudyReport', () => { + it('should retrieve a single study entity from the server based on a study id and store it in the state', async () => { + const response = { + _meta: { + name: 'meta' + }, + id: 's-001', + name: 'beautiful study', + description: 'beautiful study' + } + + api.get.mockResolvedValueOnce(response) + const studyId = 's-001' + + await actions.GetStudyReport({ commit, state }, studyId) + expect(api.get).toHaveBeenLastCalledWith(`/api/v2/eu_bbmri_eric_studies/${studyId}?attrs=*,collections(*),also_known(*)`) + expect(commit).toHaveBeenNthCalledWith(1, 'SetLoading', true) + expect(commit).toHaveBeenNthCalledWith(2, 'SetStudyReport', response) + expect(commit).toHaveBeenNthCalledWith(3, 'SetLoading', false) + }) + + it('should set an error if the server respond with an error', async () => { + const studyId = 's-001' + const error = new Error('Error from server') + api.get.mockRejectedValue(error) + + await actions.GetStudyReport({ commit, state }, studyId) + + expect(commit).toHaveBeenNthCalledWith(1, 'SetLoading', true) + expect(commit).toHaveBeenNthCalledWith(2, 'SetError', error) + expect(commit).toHaveBeenNthCalledWith(3, 'SetLoading', false) + }) + }) }) diff --git a/tests/unit/specs/store/study/studyMutations.spec.js b/tests/unit/specs/store/study/studyMutations.spec.js new file mode 100644 index 00000000..c18e5125 --- /dev/null +++ b/tests/unit/specs/store/study/studyMutations.spec.js @@ -0,0 +1,13 @@ +import { studyMutations } from '@/store/study/studyMutations' +import { mockStudyResponse, mockState } from '../../mockData' +let state + +describe('Study mutations', () => { + beforeEach(() => { + state = mockState() + }) + + it('can SetStudyReport', () => { + studyMutations.SetStudyReport(state, mockStudyResponse) + }) +}) diff --git a/tests/unit/specs/views/StudyReport.spec.js b/tests/unit/specs/views/StudyReport.spec.js new file mode 100644 index 00000000..1b5592de --- /dev/null +++ b/tests/unit/specs/views/StudyReport.spec.js @@ -0,0 +1,231 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils' +import Vuex from 'vuex' +import Loading from 'vue-loading-overlay' +import StudyReport from '@/views/StudyReport' +import ReportTitle from '@/components/report-components/ReportTitle' +import CollectionTitle from '@/components/report-components/CollectionTitle' +import ReportStudyDetails from '@/components/report-components/ReportStudyDetails' +import StudyReportInfoCard from '@/components/cards/StudyReportInfoCard' +import { baseGetters } from '../mockData' + +const localVue = createLocalVue() +localVue.use(Vuex) + +describe('StudyReport', () => { + let store + let stubs + let mocks + let studyReport + + beforeEach(() => { + studyReport = { + _meta: { + name: 'meta' + }, + id: 's-001', + title: 'Important study', + description: 'An important clinical study', + type: 'Observational', + age_unit: [ + { + _href: '/api/v2/eu_bbmri_eric_age_units/YEAR', + id: 'YEAR', + label: 'Year' + } + ], + also_known: [ + { + _href: '/api/v2/eu_bbmri_eric_also_known_in/s001-aka-cs-001', + id: 'id:001', + name_system: 'Another catalog', + pid: 'cs-001', + url: 'https://another-catalog.eu/study/cs-001', + withdrawn: false, + label: 'Another Catalog' + } + ], + collections: [ + { + id: 'c-001', + name: 'beautiful collection', + description: 'beautiful samples', + order_of_magnitude: { + _href: '/api/v2/eu_bbmri_eric_biobank_size/3', + size: '777' + }, + country: { + name: 'Genovia' + }, + network: [ + { + id: 'network-x', + name: 'Network x' + }, + { + id: 'network-y', + name: 'Network y' + } + ], + biobank: { + id: 'b-001', + name: 'beautiful biobank', + juridical_person: 'Is this even a person?', + email: 'info@beautiful-biobank.gnv', + url: 'https://beautiful-biobank.gnv' + } + } + ], + age_low: 16, + number_of_subjects: 373, + sex: [ + { + _href: '/api/v2/eu_bbmri_eric_sex_types/MALE', + id: 'MALE', + label: 'Male' + }, + { + _href: '/api/v2/eu_bbmri_eric_sex_types/FEMALE', + id: 'FEMALE', + label: 'Female' + } + ] + } + + store = new Vuex.Store({ + state: { + studyReport, + isLoading: false + }, + actions: { + GetStudyReport: () => { } + }, + getters: { + ...baseGetters + } + }) + mocks = { + $route: { + fullPath: '/study/s-001' + } + } + stubs = ['router-link', 'router-view'] + }) + + it('should initialize component', () => { + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.html()).toContain('class="container mg-collection-report-card') + }) + + it('checks for components if loaded', () => { + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.findComponent(Loading).exists()) + expect(wrapper.findComponent(Loading).props().active).toBe(false) + expect(wrapper.findComponent(ReportTitle).exists()).toBe(true) + expect(wrapper.findComponent(ReportStudyDetails).exists()).toBe(true) + expect(wrapper.findComponent(CollectionTitle).exists()).toBe(true) + expect(wrapper.findComponent(StudyReportInfoCard).exists()).toBe(true) + }) + + it('checks for components when loading', () => { + store.state.isLoading = true + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.findComponent(Loading).props().active).toBe(true) + expect(wrapper.findComponent(ReportTitle).exists()).toBe(false) + expect(wrapper.findComponent(ReportStudyDetails).exists()).toBe(false) + expect(wrapper.findComponent(CollectionTitle).exists()).toBe(false) + expect(wrapper.findComponent(StudyReportInfoCard).exists()).toBe(false) + }) + + describe('computed', () => { + describe('studyId', () => { + it('computes the study id based on URL', () => { + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.studyId).toBe('s-001') + }) + }) + + describe('studyDataAvailable', () => { + it('computes study data availability to true when the study is loaded', () => { + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.studyDataAvailable).toBe(true) + }) + + it('computes study data availability to false when the study is loaded', () => { + store.state.studyReport = {} + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.studyDataAvailable).toBe(false) + }) + }) + + describe('info', () => { + it('computes the info to pass to StudyReportInfoCard', () => { + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.info).toStrictEqual({ + also_known: [{ + label: studyReport.also_known[0].label, + system: studyReport.also_known[0].name_system, + url: studyReport.also_known[0].url + }] + }) + }) + }) + + describe('collectionsData', () => { + it('computes the collectionsData based on the data in the study', () => { + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.collectionsData).toHaveLength(1) + expect(wrapper.vm.collectionsData[0]).toHaveProperty('viewmodel') + }) + + it('checks that subcollections are not included', () => { + const collections = [ + { + id: 'c-001', + name: 'beautiful collection' + }, + { + id: 'c-001', + name: 'beautiful collection', + parent_collection: { + _href: '/var/v2/eu_bbmri_collections/c-001' + } + } + ] + store.state.studyReport.collections = collections + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.collectionsData).toHaveLength(1) + expect(wrapper.vm.collectionsData[0]).toHaveProperty('viewmodel') + }) + + it('checks that collections are sorted by name', () => { + const collections = [ + { + id: 'c-001', + name: 'beautiful collection' + }, + { + id: 'c-002', + name: 'Another beautiful collection' + } + ] + store.state.studyReport.collections = collections + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.collectionsData).toHaveLength(2) + expect(wrapper.vm.collectionsData[0].id).toBe('c-002') + expect(wrapper.vm.collectionsData[1].id).toBe('c-001') + }) + + it('computes the collectionsData to empty list when study data is not available', () => { + store.state.studyReport = {} + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.collectionsData).toStrictEqual([]) + }) + + it('computes the collectionsData to empty list when study data does not contain collections', () => { + delete store.state.studyReport.collections + const wrapper = shallowMount(StudyReport, { mocks, stubs, store, localVue }) + expect(wrapper.vm.collectionsData).toStrictEqual([]) + }) + }) + }) +}) diff --git a/vue.config.js b/vue.config.js index e1bce087..c2e602da 100644 --- a/vue.config.js +++ b/vue.config.js @@ -23,6 +23,7 @@ BUILD: ${process.env.BUILD_NUMBER}` const initialCollectionColumns = require('./src/config/initialCollectionColumns') const initialBiobankColumns = require('./src/config/initialBiobankColumns') +const initialStudyColumns = require('./src/config/initialStudyColumns') const initialFilterFacets = require('./src/config/initialFilterFacets') const i18n = require('./src/config/i18n') const initialLandingpage = require('./src/config/initialLandingpage') @@ -91,6 +92,7 @@ module.exports = { filterFacets: initialFilterFacets, collectionColumns: initialCollectionColumns, biobankColumns: initialBiobankColumns, + studyColumns: initialStudyColumns, biobankCardShowCollections: true, googleAnalyticsKey: '', removeFreemarkerMargin: true,