Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5a739b9
Work in progress, initial thoughts
otchet-broad Oct 23, 2025
5ec656b
Refactoring and cleanup.
otchet-broad Oct 23, 2025
f483f3f
Lint and simplification of options.
otchet-broad Oct 24, 2025
28b0f61
Implemented what we discussed in mobbing within the NihAnvilUseRelate…
otchet-broad Oct 24, 2025
ac517a6
Add date support, apply to properties in the GeneralStudyInformation …
otchet-broad Oct 24, 2025
e51c6c6
Move constants into NihAnivlUse class as read only static values to b…
otchet-broad Oct 24, 2025
0c8cf46
Continues form refactor.
otchet-broad Oct 28, 2025
dce8426
Adding components.
otchet-broad Oct 28, 2025
21ea6f6
Refactoring to standardize on approach with classes.
otchet-broad Oct 29, 2025
81edbcd
Merge branch 'develop' into otchet-dt-2381-s4r-study-to-new-form-arch…
otchet-broad Oct 29, 2025
f6f4d04
Make reference class static members readonly; use DataTypes class for…
otchet-broad Oct 29, 2025
2a2d407
WIP
otchet-broad Oct 30, 2025
e2c266a
WIP
otchet-broad Oct 30, 2025
3317287
WIP
otchet-broad Oct 31, 2025
3701f03
Merge branch 'develop' into otchet-dt-2381-s4r-study-to-new-form-arch…
otchet-broad Oct 31, 2025
eac55aa
Finish all standard fields, update page styling to match current form…
otchet-broad Oct 31, 2025
67f20dd
Clean up checkboxes when top level box is unselected. Clean up eventing
otchet-broad Oct 31, 2025
e1d771f
Clears set irrelevant values when form controls change due to user in…
otchet-broad Nov 3, 2025
e8e8b8b
Style adjustment to deal with typescript and our theme.
otchet-broad Nov 3, 2025
9fa3648
Remove duplicate field.
otchet-broad Nov 3, 2025
bdf5d72
Refactor file state management to pattern used for study
otchet-broad Nov 4, 2025
8052b91
Subcomponent rendering tests.
otchet-broad Nov 4, 2025
1202bd9
Subcomponent rendering tests.
otchet-broad Nov 4, 2025
7c6548b
Merge branch 'develop' into otchet-dt-2381-s4r-study-to-new-form-arch…
otchet-broad Nov 5, 2025
d78b982
lint: Remove unused import.
otchet-broad Nov 5, 2025
abe8583
Allow route only in local or dev for now.
otchet-broad Nov 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React from 'react'
import { mount } from 'cypress/react'
import { cloneDeep } from 'lodash'
import { Study, NihAnvilUse, StudyProperty } from 'src/pages/data_submission/v2/v2-models'
import {
NihAdministrativeInformation,
NihAdministrativeInformationProps,
} from 'src/pages/data_submission/v2/NihAdministrativeInformation'
import { InstitutionInterface } from 'src/types/model'

let propCopy = { study: { properties: [] as StudyProperty[] } as Study } as NihAdministrativeInformationProps

const props = {
setStudy: () => {},
study: { properties: [] },
setFiles: () => {},
}

const mockInstitutions = [
{
id: 1,
name: 'Test Institution 1',
domains: ['test1.edu'],
signingOfficials: [{ userId: '1', displayName: 'User 1', email: 'email1' }],
createDate: 'Feb 1, 2023',
createUser: 1,
createUserId: 1,
} as unknown as InstitutionInterface,
{
id: 2,
name: 'Test Institution 2',
domains: ['test2.edu'],
signingOfficials: [{ userId: '2', displayName: 'User 2', email: 'email2' }],
createDate: 'Jul 1, 2025',
createUser: 1,
createUserId: 1,
updateDate: 'Jul 2, 2025',
updateUser: 1,
updateUserId: 1,
} as unknown as InstitutionInterface,
]

beforeEach(() => {
propCopy = cloneDeep(props)
cy.initApplicationConfig()
cy.intercept('GET', '/api/institutions', (req) => {
req.reply({
delay: 1000, // Simulate a delay to show loading state
body: mockInstitutions,
})
})
})

describe('NihAdministrativeInformation - Tests', () => {
it('should mount without any fields in the NihAdministrativeInformation', () => {
mount(<NihAdministrativeInformation {...propCopy} />)
cy.get('.formField-container').should('not.exist')
})

it('fields should be visible if the user selected I am NHGRI funded and I have a dbGaP PHS ID already', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_YES_PHS_ID))
mount(<NihAdministrativeInformation {...propCopy} />)
cy.get('#piInstitution').should('be.visible')
cy.get('#nihGrantContractNumber').should('be.visible')
cy.get('#nihICsSupportingStudy').should('be.visible')
cy.get('#nihProgramOfficerName').should('be.visible')
cy.get('#nihInstitutionCenterSubmission').should('be.visible')
cy.get('#nihGenomicProgramAdministratorName').should('be.visible')
cy.get('#multiCenterStudy').should('be.visible')
cy.get('#controlledAccessRequiredForGenomicSummaryResultsGSR').should('be.visible')
})

it('fields should be visible if the user selected I am NHGRI funded and I do not have a dbGaP PHS ID', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_NO_PHS_ID))
mount(<NihAdministrativeInformation {...propCopy} />)
cy.get('#piInstitution').should('be.visible')
cy.get('#nihGrantContractNumber').should('be.visible')
cy.get('#nihICsSupportingStudy').should('be.visible')
cy.get('#nihProgramOfficerName').should('be.visible')
cy.get('#nihInstitutionCenterSubmission').should('be.visible')
cy.get('#nihGenomicProgramAdministratorName').should('be.visible')
cy.get('#multiCenterStudy').should('be.visible')
cy.get('#controlledAccessRequiredForGenomicSummaryResultsGSR').should('be.visible')
})

it('should hide dbGaP form fields if the user selected I am not NHGRI funded but I am seeking to submit data to AnVIL', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.NO_NHGRI_YES_ANVIL))
mount(<NihAdministrativeInformation {...propCopy} />)
cy.get('#piInstitution').should('be.visible')
cy.get('#nihGrantContractNumber').should('be.visible')
cy.get('#nihICsSupportingStudy').should('be.visible')
cy.get('#nihProgramOfficerName').should('be.visible')
cy.get('#nihInstitutionCenterSubmission').should('be.visible')
cy.get('#nihGenomicProgramAdministratorName').should('be.visible')
cy.get('#multiCenterStudy').should('be.visible')
cy.get('#controlledAccessRequiredForGenomicSummaryResultsGSR').should('be.visible')
})

it('should hide dbGaP form fields if the user selected I am not NHGRI funded and do not plan to store data in AnVIL', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.NO_NHGRI_NO_ANVIL))
mount(<NihAdministrativeInformation {...propCopy} />)
cy.get('.formField-container').should('not.exist')
cy.get('#piInstitution').should('not.exist')
cy.get('#nihGrantContractNumber').should('not.exist')
cy.get('#nihICsSupportingStudy').should('not.exist')
cy.get('#nihProgramOfficerName').should('not.exist')
cy.get('#nihInstitutionCenterSubmission').should('not.exist')
cy.get('#nihGenomicProgramAdministratorName').should('not.exist')
cy.get('#multiCenterStudy').should('not.exist')
cy.get('#controlledAccessRequiredForGenomicSummaryResultsGSR').should('not.exist')
})
})
73 changes: 73 additions & 0 deletions cypress/component/DataSubmission/v2/ds_nih_anvil_use.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from 'react'
import { mount } from 'cypress/react'
import { cloneDeep } from 'lodash'
import { NihAnvilUseRelated, NihAnvilUseRelatedProps } from 'src/pages/data_submission/v2/NihAnvilUseRelated'
import { Study, NihAnvilUse, StudyProperty } from 'src/pages/data_submission/v2/v2-models'

let propCopy = { study: { properties: [] as StudyProperty[] } as Study } as NihAnvilUseRelatedProps

const props = {
setStudy: () => {},
study: { properties: [] },
setFiles: () => {},
}

beforeEach(() => {
propCopy = cloneDeep(props)
})

describe('NihAnvilUseRelated - Tests', () => {
it('should mount with only the nihAnvilUse form field displayed', () => {
mount(<NihAnvilUseRelated {...propCopy} />)
cy.get('.formField-container').should('exist')

cy.get('#nihAnvilUse').should('exist')
cy.get('#dbGaPPhsID').should('not.exist')
cy.get('#dbGaPStudyRegistrationName').should('not.exist')
cy.get('#embargoReleaseDate').should('not.exist')
cy.get('#sequencingCenter').should('not.exist')
})

it('should show dbGaP form fields if NHGRI funded and has dbGaP ID', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_YES_PHS_ID))
mount(<NihAnvilUseRelated {...propCopy} />)
cy.get(':nth-child(1) > [style="font-family: Montserrat; font-size: 14px;"] > label > [style="float: left;"] > span').click()
cy.get('#dbGaPPhsID').should('exist')
cy.get('#dbGaPStudyRegistrationName').should('exist')
cy.get('#embargoReleaseDate').should('exist')
cy.get('#sequencingCenter').should('exist')
})

it('should hide dbGaP form fields if NHGRI funded and no dbGaP ID', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_NO_PHS_ID))
mount(<NihAnvilUseRelated {...propCopy} />)
cy.get(':nth-child(2) > [style="font-family: Montserrat; font-size: 14px;"] > label > [style="float: left;"] > span').click()

cy.get('#dbGaPPhsID').should('not.exist')
cy.get('#dbGaPStudyRegistrationName').should('not.exist')
cy.get('#embargoReleaseDate').should('not.exist')
cy.get('#sequencingCenter').should('not.exist')
})

it('should hide dbGaP form fields if not NHGRI funded and submitting to AnVIL ', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.NO_NHGRI_YES_ANVIL))
mount(<NihAnvilUseRelated {...propCopy} />)
cy.get(':nth-child(3) > [style="font-family: Montserrat; font-size: 14px;"] > label > [style="float: left;"] > span').click()

cy.get('#dbGaPPhsID').should('not.exist')
cy.get('#dbGaPStudyRegistrationName').should('not.exist')
cy.get('#embargoReleaseDate').should('not.exist')
cy.get('#sequencingCenter').should('not.exist')
})

it('should hide dbGaP form fields if not NHGRI funded and not submitting to AnVIL', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.NO_NHGRI_NO_ANVIL))
mount(<NihAnvilUseRelated {...propCopy} />)
cy.get(':nth-child(4) > [style="font-family: Montserrat; font-size: 14px;"] > label > [style="float: left;"] > span').click()

cy.get('#dbGaPPhsID').should('not.exist')
cy.get('#dbGaPStudyRegistrationName').should('not.exist')
cy.get('#embargoReleaseDate').should('not.exist')
cy.get('#sequencingCenter').should('not.exist')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react'
import { mount } from 'cypress/react'
import { cloneDeep } from 'lodash'
import {
Study,
NihAnvilUse,
StudyProperty,
AlternativeDataSharingPlan,
AlternativeDataSharingPlanReasons,
} from 'src/pages/data_submission/v2/v2-models'
import { NihDataManagement, NihDataManagementProps } from 'src/pages/data_submission/v2/NihDataManagement'
import { FileProperty } from 'src/pages/data_submission/v2/DataSubmissionFormV2'

let propCopy = { study: { properties: [] as StudyProperty[] } as Study } as NihDataManagementProps

const props = {
setStudy: () => {},
study: { properties: [] },
files: {} as FileProperty,
setFiles: () => {},
}

beforeEach(() => {
propCopy = cloneDeep(props)
})

function verifySharingPlanTopLevelDisabled() {
cy.get('#legalRestrictions').should('not.exist')
cy.get('#isInformedConsentProcessesInadequate').should('not.exist')
cy.get('#alternativeDataSharingPlanExplanation').should('not.exist')
cy.get('#alternativeDataSharingPlanFile_fileName').should('not.exist')
cy.get('#alternativeDataSharingPlanDataSubmitted').should('not.exist')
cy.get('#alternativeDataSharingPlanDataReleased').should('not.exist')
}

describe('NihAdministrativeInformation - Tests', () => {
it('should mount without any fields in the NihAdministrativeInformation', () => {
mount(<NihDataManagement {...propCopy} />)
cy.get('.formField-container').should('not.exist')
cy.get('#alternativeDataSharingPlan').should('not.exist')
})

it('fields should be visible if the user selected I am NHGRI funded and I have a dbGaP PHS ID already', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_YES_PHS_ID))
mount(<NihDataManagement {...propCopy} />)
cy.get('#alternativeDataSharingPlan').should('be.visible')
verifySharingPlanTopLevelDisabled()
cy.get('#alternativeDataSharingPlan > :nth-child(1) > [style="font-family: Montserrat; font-size: 14px;"] > label').click()
})
it('fields should appear as user selects Yes to an Alternative Data Sharing Plan', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_YES_PHS_ID))
propCopy.study.properties?.push(new AlternativeDataSharingPlan(true))
mount(<NihDataManagement {...propCopy} />)
cy.get('#legalRestrictions').should('be.visible')
cy.get('#isInformedConsentProcessesInadequate').should('be.visible')
cy.get('#alternativeDataSharingPlanExplanation').should('be.visible')
cy.get('#alternativeDataSharingPlanFile_fileName').should('be.visible')
cy.get('#alternativeDataSharingPlanDataSubmitted').should('be.visible')
cy.get('#alternativeDataSharingPlanDataReleased').should('be.visible')
})
it('fields should appear if the user selects yes to inadequate consent process', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_YES_PHS_ID))
propCopy.study.properties?.push(new AlternativeDataSharingPlan(true))
propCopy.study.properties?.push(new AlternativeDataSharingPlanReasons([AlternativeDataSharingPlanReasons.VALUES.isInformedConsentProcessesInadequate]))
mount(<NihDataManagement {...propCopy} />)
cy.get('#consentFormsUnavailable').should('be.visible')
cy.get('#consentProcessDidNotAddressFutureUseOrBroadSharing').should('be.visible')
cy.get('#consentProcessPrecludesFutureUseOrBroadSharing').should('be.visible')
cy.get('#otherInformedConsentLimitationsOrConcerns').should('be.visible')
cy.get('#otherReasonForRequest').should('be.visible')
})

it('fields should appear as user selects No to an Alternative Data Sharing Plan', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_YES_PHS_ID))
propCopy.study.properties?.push(new AlternativeDataSharingPlan(false))
mount(<NihDataManagement {...propCopy} />)
verifySharingPlanTopLevelDisabled()
})

it('fields should be visible if the user selected I am NHGRI funded and I do not have a dbGaP PHS ID', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.YES_NHGRI_NO_PHS_ID))
mount(<NihDataManagement {...propCopy} />)
cy.get('#alternativeDataSharingPlan').should('be.visible')
})

it('should hide dbGaP form fields if the user selected I am not NHGRI funded but I am seeking to submit data to AnVIL', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.NO_NHGRI_YES_ANVIL))
mount(<NihDataManagement {...propCopy} />)
cy.get('#alternativeDataSharingPlan').should('be.visible')
})

it('should hide dbGaP form fields if the user selected I am not NHGRI funded and do not plan to store data in AnVIL', () => {
propCopy?.study?.properties?.push(new NihAnvilUse(NihAnvilUse.NO_NHGRI_NO_ANVIL))
mount(<NihDataManagement {...propCopy} />)
cy.get('#alternativeDataSharingPlan').should('not.exist')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react'
import { mount } from 'cypress/react'
import { cloneDeep } from 'lodash'
import {
GeneralStudyInformation, GeneralStudyInformationProps,
} from 'src/pages/data_submission/v2/GeneralStudyInformation'

let propCopy = {} as GeneralStudyInformationProps

const props = {
setStudy: () => {},
study: {},
}

beforeEach(() => {
propCopy = cloneDeep(props)
})

describe('GeneralStudyInformation - Tests', () => {
it('should mount with all the fields', () => {
mount(<GeneralStudyInformation {...propCopy} />)
cy.get('.formField-container').should('have.length', 11)

cy.get('.formField-studyName').should('have.length', 1)
cy.get('.formField-studyType').should('have.length', 1)
cy.get('.formField-studyDescription').should('have.length', 1)
cy.get('.formField-dataTypes').should('have.length', 1)
cy.get('.formField-phenotypeIndication').should('have.length', 1)
cy.get('.formField-species').should('have.length', 1)
cy.get('.formField-piName').should('have.length', 1)
cy.get('.formField-dataCustodianEmail').should('have.length', 1)
cy.get('#alternativeDataSharingPlanTargetDeliveryDate').should('exist')
cy.get('#alternativeDataSharingPlanTargetPublicReleaseDate').should('exist')
cy.get('.formField-publicVisibility').should('have.length', 1)
})

it('should allow edit in all fields', () => {
cy.spy(propCopy, 'setStudy').as('setStudySpy')
mount(<GeneralStudyInformation {...propCopy} />)
cy.get('.formField-studyName').type('A Study Name')
cy.get('@setStudySpy').its('callCount').should('eq', 12)
cy.get('.formField-studyType').type('Observational{enter}')
cy.get('@setStudySpy').its('callCount').should('eq', 13)
cy.get('.formField-studyDescription').type('My description')
cy.get('@setStudySpy').its('callCount').should('eq', 27)
cy.get('.formField-dataTypes').type('dt{enter}')
cy.get('@setStudySpy').its('callCount').should('eq', 28)
cy.get('.formField-phenotypeIndication').type('pi')
cy.get('@setStudySpy').its('callCount').should('eq', 30)
cy.get('.formField-species').type('species')
cy.get('@setStudySpy').its('callCount').should('eq', 37)
cy.get('.formField-piName').type('name')
cy.get('@setStudySpy').its('callCount').should('eq', 41)
cy.get('#dataCustodianEmail > .css-13cymwt-control > .css-hlgwow > .css-19bb58m').type('[email protected]{enter}')
cy.get('@setStudySpy').its('callCount').should('eq', 42)
cy.get('#alternativeDataSharingPlanTargetDeliveryDate').type('2025-04-01')
cy.get('@setStudySpy').its('callCount').should('eq', 43)
cy.get('#alternativeDataSharingPlanTargetPublicReleaseDate').type('2025-04-01')
cy.get('@setStudySpy').its('callCount').should('eq', 44)
cy.get(':nth-child(2) > [style="font-family: Montserrat; font-size: 14px;"] > label > [style="float: left;"] > span').click()
cy.get('@setStudySpy').its('callCount').should('eq', 45)
cy.get(':nth-child(1) > [style="font-family: Montserrat; font-size: 14px;"] > label > [style="float: left;"] > span').click()
cy.get('@setStudySpy').its('callCount').should('eq', 46)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { mount } from 'cypress/react'
import AdminManageInstitutions from 'src/pages/AdminManageInstitutions'
import { BrowserRouter } from 'react-router-dom'
import { Institution as InstitutionAPI } from 'src/libs/ajax/Institution'
import { DuosUser, Institution } from 'src/types/model'
import { DuosUser, InstitutionInterface } from 'src/types/model'

const createUser: DuosUser = {
createDate: new Date(),
Expand Down Expand Up @@ -58,7 +58,7 @@ const mockInstitutions = [
createDate: 'Feb 1, 2023',
createUser: createUser,
createUserId: createUser.userId,
} as unknown as Institution,
} as unknown as InstitutionInterface,
{
id: 2,
name: 'Test Institution 2',
Expand All @@ -70,7 +70,7 @@ const mockInstitutions = [
updateDate: 'Jul 2, 2025',
updateUser: updateUser,
updateUserId: updateUser.userId,
} as unknown as Institution,
} as unknown as InstitutionInterface,
]

describe('AdminManageInstitutions', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React from 'react'
import { mount } from 'cypress/react'
import { InstitutionDomainEditor } from 'src/components/institution_table/components/InstitutionDomainEditor'
import { Institution } from 'src/types/model'
import { InstitutionInterface } from 'src/types/model'

describe('Institution Domain Editor Tests', () => {
const testDomains = ['example.com', 'test.edu', 'domain.org']
Expand Down Expand Up @@ -171,7 +171,7 @@ describe('Institution Domain Editor Tests', () => {
{ id: 1, name: 'Institution A', domains: ['a.com', 'b.com'] },
{ id: 2, name: 'Institution B', domains: ['c.com'] },
{ id: 3, name: 'Institution C' },
] as Institution[]
] as InstitutionInterface[]
const onDomainsChange = cy.stub().as('domainsChangeHandler')

mount(
Expand Down
Loading
Loading