Skip to content

Commit

Permalink
feat: Improve ACMG rating of sequence/small variants (#64) (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
gromdimon authored Sep 18, 2023
1 parent d836edb commit 507ad2c
Show file tree
Hide file tree
Showing 8 changed files with 1,107 additions and 450 deletions.
1,129 changes: 696 additions & 433 deletions frontend/src/components/VariantDetails/AcmgRating.vue

Large diffs are not rendered by default.

25 changes: 19 additions & 6 deletions frontend/src/components/__tests__/AcmgRating.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const smallVariantInfo = {
}

export const AcmgRatingInfo = {
pvs1: false,
pvs1: true,
ps1: false,
ps2: false,
ps3: false,
Expand All @@ -46,7 +46,7 @@ export const AcmgRatingInfo = {
pm3: false,
pm4: false,
pm5: false,
pm6: false,
pm6: true,
pp1: false,
pp2: false,
pp3: false,
Expand All @@ -55,13 +55,13 @@ export const AcmgRatingInfo = {
ba1: false,
bs1: false,
bs2: false,
bs3: false,
bs3: true,
bs4: false,
bp1: false,
bp2: false,
bp3: false,
bp4: false,
bp5: false,
bp5: true,
bp6: false,
bp7: false
}
Expand All @@ -73,13 +73,13 @@ const makeWrapper = () => {
const mockRetrieveAcmgRating = vi.fn().mockImplementation(async () => {
store.storeState = StoreState.Active
store.smallVariant = JSON.parse(JSON.stringify(smallVariantInfo))
store.acmgRating = JSON.parse(JSON.stringify(AcmgRatingInfo))
store.acmgRatingComputed = JSON.parse(JSON.stringify(AcmgRatingInfo))
})
store.retrieveAcmgRating = mockRetrieveAcmgRating

store.storeState = StoreState.Active
store.smallVariant = JSON.parse(JSON.stringify(smallVariantInfo))
store.acmgRating = JSON.parse(JSON.stringify(AcmgRatingInfo))
store.acmgRatingComputed = JSON.parse(JSON.stringify(AcmgRatingInfo))

return mount(AcmgRating, {
props: {
Expand All @@ -103,4 +103,17 @@ describe.concurrent('AcmgRating', async () => {
const switchers = wrapper.findAll('.v-switch')
expect(switchers.length).toBe(28)
})

it('should correctly update the AcmgRating info', async () => {
const wrapper = makeWrapper()
const switchers = wrapper.findAll('.v-switch')
const switcher = switchers[0]
await switcher.trigger('click')

expect(wrapper.text()).toContain('Pathogenic')
expect(wrapper.text()).toContain('Benign')

const updatedSwitchers = wrapper.findAll('.v-switch')
expect(updatedSwitchers.length).toBe(28)
})
})
2 changes: 2 additions & 0 deletions frontend/src/components/__tests__/VegaPlot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ const makeWrapper = () => {
}

describe.concurrent('VegaPlot', async () => {
// Skipping tests due to error with vega-embed
// DataCloneError: #<Object> could not be cloned.
it.skip('renders the VegaPlot info', async () => {
const wrapper = makeWrapper()
console.log(wrapper.html())
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ContactView from '@/views/ContactView.vue'
import GeneDetailView from '@/views/GeneDetailView.vue'
import VariantDetailView from '@/views/VariantDetailView.vue'
import GenesListView from '@/views/GenesListView.vue'
import ACMGCriteriaDocs from '@/views/ACMGCriteriaDocs.vue'

const routes = [
{
Expand Down Expand Up @@ -44,6 +45,11 @@ const routes = [
path: '/genes/search',
name: 'genes',
component: GenesListView
},
{
path: '/acmg-docs',
name: 'acmg-docs',
component: ACMGCriteriaDocs
}
]

Expand Down
13 changes: 7 additions & 6 deletions frontend/src/stores/__tests__/variantAcmgRating.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,21 @@ describe.concurrent('geneInfo Store', () => {
const store = useVariantAcmgRatingStore()

expect(store.storeState).toBe(StoreState.Initial)
expect(store.acmgRating).toBe(null)
expect(store.acmgRatingComputed).toBe(null)
expect(store.acmgRatingCustom).toBe(null)
expect(store.smallVariant).toBe(null)
})

it('should clear state', () => {
const store = useVariantAcmgRatingStore()
store.storeState = StoreState.Active
store.acmgRating = JSON.parse(JSON.stringify({ acmg: 'rating' }))
store.acmgRatingComputed = JSON.parse(JSON.stringify({ acmg: 'rating' }))
store.smallVariant = JSON.parse(JSON.stringify({ gene: 'info' }))

store.clearData()

expect(store.storeState).toBe(StoreState.Initial)
expect(store.acmgRating).toBe(null)
expect(store.acmgRatingComputed).toBe(null)
expect(store.smallVariant).toBe(null)
})

Expand All @@ -53,7 +54,7 @@ describe.concurrent('geneInfo Store', () => {
await store.retrieveAcmgRating(smallVariantInfo)

expect(store.storeState).toBe(StoreState.Active)
expect(store.acmgRating).toStrictEqual(JSON.parse(JSON.stringify({ acmg: 'rating' })))
expect(store.acmgRatingComputed).toStrictEqual(JSON.parse(JSON.stringify({ acmg: 'rating' })))
expect(store.smallVariant).toStrictEqual(JSON.parse(JSON.stringify(smallVariantInfo)))
})

Expand All @@ -66,7 +67,7 @@ describe.concurrent('geneInfo Store', () => {
await store.retrieveAcmgRating(smallVariantInfo)

expect(store.storeState).toBe(StoreState.Error)
expect(store.acmgRating).toBe(null)
expect(store.acmgRatingComputed).toBe(null)
expect(store.smallVariant).toBe(null)
})

Expand All @@ -76,7 +77,7 @@ describe.concurrent('geneInfo Store', () => {
await store.retrieveAcmgRating(smallVariantInfo)

expect(store.storeState).toBe(StoreState.Active)
expect(store.acmgRating).toStrictEqual(JSON.parse(JSON.stringify({ acmg: 'rating' })))
expect(store.acmgRatingComputed).toStrictEqual(JSON.parse(JSON.stringify({ acmg: 'rating' })))
expect(store.smallVariant).toStrictEqual(JSON.parse(JSON.stringify(smallVariantInfo)))

await store.retrieveAcmgRating(store.smallVariant)
Expand Down
14 changes: 9 additions & 5 deletions frontend/src/stores/variantAcmgRating.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ export const useVariantAcmgRatingStore = defineStore('variantAcmgRating', () =>
const smallVariant = ref<SmallVariant | null>(null)

/** The small variants ACMG rating as fetched from API. */
const acmgRating = ref<AcmgRating | null>(null)
const acmgRatingComputed = ref<AcmgRating | null>(null)

/** The small variants ACMG rating updated by user */
const acmgRatingCustom = ref<AcmgRating | null>(null)

function clearData() {
storeState.value = StoreState.Initial
acmgRating.value = null
acmgRatingComputed.value = null
smallVariant.value = null
}

Expand Down Expand Up @@ -55,7 +58,7 @@ export const useVariantAcmgRatingStore = defineStore('variantAcmgRating', () =>
if (!response.ok) {
throw new Error('There was an error loading the ACMG data.')
}
acmgRating.value = await response.json()
acmgRatingComputed.value = await response.json()
smallVariant.value = smallVar
storeState.value = StoreState.Active
} catch (e) {
Expand All @@ -68,13 +71,14 @@ export const useVariantAcmgRatingStore = defineStore('variantAcmgRating', () =>
const submitAcmgRating = async (smallVar: SmallVariant, payload: Object) => {
// TODO: Implement the API call to submit the ACMG rating to ClinVar
smallVariant.value = smallVar
acmgRating.value = payload
acmgRatingComputed.value = payload
}

return {
smallVariant,
storeState,
acmgRating,
acmgRatingComputed,
acmgRatingCustom,
clearData,
retrieveAcmgRating,
submitAcmgRating
Expand Down
Loading

0 comments on commit 507ad2c

Please sign in to comment.