From a157355d9f8164e27e955dc62980e6f96f333f53 Mon Sep 17 00:00:00 2001 From: gromdimon Date: Wed, 4 Oct 2023 15:30:28 +0200 Subject: [PATCH 1/3] fix: rendering info for invalid variants --- .../VariantDetails/VariationLandscape.vue | 3 ++ frontend/src/lib/utils.ts | 2 +- frontend/src/stores/variantInfo.ts | 41 ++++++++----------- frontend/src/views/VariantDetailView.vue | 32 +++++++++++++-- 4 files changed, 49 insertions(+), 29 deletions(-) diff --git a/frontend/src/components/VariantDetails/VariationLandscape.vue b/frontend/src/components/VariantDetails/VariationLandscape.vue index a55ad8d9..18703185 100644 --- a/frontend/src/components/VariantDetails/VariationLandscape.vue +++ b/frontend/src/components/VariantDetails/VariationLandscape.vue @@ -46,6 +46,9 @@ const convertClinvarSignificance = (input: number): number => { } const vegaData = computed(() => { + if (!props.clinvar) { + return [] + } let clinvarInfo = [] if (props.genomeRelease == 'grch37') { clinvarInfo = props.clinvar.variants[0].variants diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 2e0e8f92..a4de3e02 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -110,7 +110,7 @@ export const search = (searchTerm: string, genomeRelease: string) => { }) ], [ - /^chr\d+:\d+:[A-Z]:[A-Z]$/, + /^chr\d+:\d+:[ACGT]{1,50}:[ACGT]{1,50}$/, (): RouteLocationFragment => ({ name: 'variant', params: { diff --git a/frontend/src/stores/variantInfo.ts b/frontend/src/stores/variantInfo.ts index e860c0db..8d8af84b 100644 --- a/frontend/src/stores/variantInfo.ts +++ b/frontend/src/stores/variantInfo.ts @@ -66,6 +66,7 @@ export const useVariantInfoStore = defineStore('variantInfo', () => { // Load data via API storeState.value = StoreState.Loading try { + let hgnc_id: string = '' const { chromosome, pos, reference, alternative } = infoFromQuery(variantQuery) const annonarsClient = new AnnonarsClient() @@ -78,15 +79,7 @@ export const useVariantInfoStore = defineStore('variantInfo', () => { reference, alternative ) - if ( - variantData.result.cadd === null && - variantData.result.dbnsfp === null && - variantData.result.dbscsnv === null - ) { - throw new Error('No variant data found.') - } else { - varAnnos.value = variantData.result - } + varAnnos.value = variantData.result const txCsqData = await mehariClient.retrieveSeqvarsCsq( genomeRelease, @@ -95,25 +88,25 @@ export const useVariantInfoStore = defineStore('variantInfo', () => { reference, alternative ) + if (txCsqData.result.length === 0) { - throw new Error('No transcript consequence data found.') + txCsq.value = txCsqData } else { + hgnc_id = txCsqData.result[0]['gene_id'] + const geneData = await annonarsClient.fetchGeneInfo(hgnc_id) + if (geneData?.genes === null) { + throw new Error('No gene data found.') + } + geneInfo.value = geneData['genes'][hgnc_id] + + const geneClinvarData = await annonarsClient.fetchGeneClinvarInfo(hgnc_id) + if (geneClinvarData?.genes === null) { + throw new Error('No gene clinvar data found.') + } + geneClinvar.value = geneClinvarData['genes'][hgnc_id] txCsq.value = txCsqData.result } - const hgncId: string = txCsqData.result[0]['gene_id'] - const geneData = await annonarsClient.fetchGeneInfo(hgncId) - if (geneData?.genes === null) { - throw new Error('No gene data found.') - } - geneInfo.value = geneData['genes'][hgncId] - - const geneClinvarData = await annonarsClient.fetchGeneClinvarInfo(hgncId) - if (geneClinvarData?.genes === null) { - throw new Error('No gene clinvar data found.') - } - geneClinvar.value = geneClinvarData['genes'][hgncId] - variantTerm.value = variantQuery smallVariant.value = { release: genomeRelease, @@ -122,7 +115,7 @@ export const useVariantInfoStore = defineStore('variantInfo', () => { end: (Number(pos) + reference.length - 1).toString(), reference: reference, alternative: alternative, - hgnc_id: hgncId + hgnc_id: hgnc_id } storeState.value = StoreState.Active } catch (e) { diff --git a/frontend/src/views/VariantDetailView.vue b/frontend/src/views/VariantDetailView.vue index 3924a031..cf5cd59e 100644 --- a/frontend/src/views/VariantDetailView.vue +++ b/frontend/src/views/VariantDetailView.vue @@ -100,7 +100,7 @@ const genomeReleaseRef = ref(props.genomeRelease)
-
+

Gene

Link to @@ -119,8 +119,16 @@ const genomeReleaseRef = ref(props.genomeRelease)

+
+

Gene

+

No gene information available

+
-
+

Gene-wide Variation landscape

+
+

Gene-wide Variation landscape

+

No gene information available

+

Beacon Network

@@ -166,17 +178,29 @@ const genomeReleaseRef = ref(props.genomeRelease)
-
+

Consequences

+
+

Consequences

+

No consequence information available

+
-
+

Conservation

+
+

Conservation

+

No conservation information available

+

Variant Validator

From 5b02dd9cd63f60151bcab5e2b8759185c75a7e01 Mon Sep 17 00:00:00 2001 From: gromdimon Date: Wed, 4 Oct 2023 15:53:13 +0200 Subject: [PATCH 2/3] fix: tests --- .../src/stores/__tests__/variantInfo.spec.ts | 61 ++++++++++++------- frontend/src/stores/variantInfo.ts | 2 +- .../views/__tests__/VariantDetailView.spec.ts | 2 +- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/frontend/src/stores/__tests__/variantInfo.spec.ts b/frontend/src/stores/__tests__/variantInfo.spec.ts index 63da8ce1..d7dbee6f 100644 --- a/frontend/src/stores/__tests__/variantInfo.spec.ts +++ b/frontend/src/stores/__tests__/variantInfo.spec.ts @@ -101,7 +101,7 @@ describe.concurrent('geneInfo Store', () => { expect(store.txCsq).toBe(null) }) - it('should fail to load data with invalid fetchVariantInfo response', async () => { + it('should handle loading data with invalid fetchVariantInfo response', async () => { // Disable error logging vi.spyOn(console, 'error').mockImplementation(() => {}) const store = useVariantInfoStore() @@ -123,20 +123,29 @@ describe.concurrent('geneInfo Store', () => { await store.loadData('chr17:43044295:G:A', 'grch37') - expect(console.error).toHaveBeenCalled() - expect(console.error).toHaveBeenCalledWith( - 'There was an error loading the variant data.', - new Error('No variant data found.') + expect(store.storeState).toBe(StoreState.Active) + expect(store.variantTerm).toBe('chr17:43044295:G:A') + expect(store.smallVariant).toStrictEqual({ + alternative: 'A', + chromosome: 'chr17', + end: '43044295', + hgnc_id: 'HGNC:1100', + reference: 'G', + release: 'grch37', + start: '43044295' + }) + expect(store.varAnnos).toStrictEqual({ + cadd: null, + dbnsfp: null, + dbscsnv: null + }) + expect(store.geneInfo).toStrictEqual( + JSON.parse(JSON.stringify(BRCA1GeneInfo)).genes['HGNC:1100'] ) - expect(store.storeState).toBe(StoreState.Error) - expect(store.variantTerm).toBe(null) - expect(store.smallVariant).toBe(null) - expect(store.varAnnos).toBe(null) - expect(store.geneInfo).toBe(null) - expect(store.txCsq).toBe(null) + expect(store.txCsq).toStrictEqual(JSON.parse(JSON.stringify(BRCA1TxInfo)).result) }) - it('should fail to load data with invalid retrieveSeqvarsCsq response', async () => { + it('should handle loading data with invalid retrieveSeqvarsCsq response', async () => { // Disable error logging vi.spyOn(console, 'error').mockImplementation(() => {}) const store = useVariantInfoStore() @@ -156,17 +165,23 @@ describe.concurrent('geneInfo Store', () => { await store.loadData('chr17:43044295:G:A', 'grch37') - expect(console.error).toHaveBeenCalled() - expect(console.error).toHaveBeenCalledWith( - 'There was an error loading the variant data.', - new Error('No transcript consequence data found.') - ) - expect(store.storeState).toBe(StoreState.Error) - expect(store.variantTerm).toBe(null) - expect(store.smallVariant).toBe(null) - expect(store.varAnnos).toBe(null) - expect(store.geneInfo).toBe(null) - expect(store.txCsq).toBe(null) + expect(store.storeState).toBe(StoreState.Active) + expect(store.variantTerm).toBe('chr17:43044295:G:A') + + expect(store.smallVariant).toStrictEqual({ + alternative: 'A', + chromosome: 'chr17', + end: '43044295', + hgnc_id: '', + reference: 'G', + release: 'grch37', + start: '43044295' + }) + expect(store.varAnnos).toStrictEqual(BRCA1VariantInfo.result) + expect(store.geneInfo).toEqual(null) + expect(store.txCsq).toStrictEqual({ + result: [] + }) }) it('should fail to load data with invalid fetchGeneInfo response', async () => { diff --git a/frontend/src/stores/variantInfo.ts b/frontend/src/stores/variantInfo.ts index 8d8af84b..77475a7b 100644 --- a/frontend/src/stores/variantInfo.ts +++ b/frontend/src/stores/variantInfo.ts @@ -66,11 +66,11 @@ export const useVariantInfoStore = defineStore('variantInfo', () => { // Load data via API storeState.value = StoreState.Loading try { - let hgnc_id: string = '' const { chromosome, pos, reference, alternative } = infoFromQuery(variantQuery) const annonarsClient = new AnnonarsClient() const mehariClient = new MehariClient() + let hgnc_id = '' const variantData = await annonarsClient.fetchVariantInfo( genomeRelease, diff --git a/frontend/src/views/__tests__/VariantDetailView.spec.ts b/frontend/src/views/__tests__/VariantDetailView.spec.ts index bbd87ed7..8948d59d 100644 --- a/frontend/src/views/__tests__/VariantDetailView.spec.ts +++ b/frontend/src/views/__tests__/VariantDetailView.spec.ts @@ -42,7 +42,7 @@ const variantData = { varAnnos: JSON.parse(JSON.stringify(BRCA1VariantInfo)).result, geneInfo: JSON.parse(JSON.stringify(BRCA1GeneInfo)).genes['HGNC:1100'], clinvar: JSON.parse(JSON.stringify(BRCA1ClinVar)).genes['HGNC:1100'], - txCsq: JSON.parse(JSON.stringify(BRCA1TxInfo)).result + txCsq: JSON.parse(JSON.stringify(BRCA1TxInfo)) } const makeWrapper = () => { From a27752974721f3497fb995ce6ebaa0a362bc78ab Mon Sep 17 00:00:00 2001 From: gromdimon Date: Wed, 4 Oct 2023 16:16:10 +0200 Subject: [PATCH 3/3] fix: deps inline --- frontend/src/stores/__tests__/variantInfo.spec.ts | 4 +--- frontend/src/stores/variantInfo.ts | 2 +- frontend/src/views/VariantDetailView.vue | 4 ++-- frontend/src/views/__tests__/VariantDetailView.spec.ts | 2 +- frontend/vitest.config.ts | 6 ++++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/stores/__tests__/variantInfo.spec.ts b/frontend/src/stores/__tests__/variantInfo.spec.ts index d7dbee6f..e7ff1d7d 100644 --- a/frontend/src/stores/__tests__/variantInfo.spec.ts +++ b/frontend/src/stores/__tests__/variantInfo.spec.ts @@ -179,9 +179,7 @@ describe.concurrent('geneInfo Store', () => { }) expect(store.varAnnos).toStrictEqual(BRCA1VariantInfo.result) expect(store.geneInfo).toEqual(null) - expect(store.txCsq).toStrictEqual({ - result: [] - }) + expect(store.txCsq).toStrictEqual([]) }) it('should fail to load data with invalid fetchGeneInfo response', async () => { diff --git a/frontend/src/stores/variantInfo.ts b/frontend/src/stores/variantInfo.ts index 77475a7b..748e5862 100644 --- a/frontend/src/stores/variantInfo.ts +++ b/frontend/src/stores/variantInfo.ts @@ -90,7 +90,7 @@ export const useVariantInfoStore = defineStore('variantInfo', () => { ) if (txCsqData.result.length === 0) { - txCsq.value = txCsqData + txCsq.value = txCsqData.result } else { hgnc_id = txCsqData.result[0]['gene_id'] const geneData = await annonarsClient.fetchGeneInfo(hgnc_id) diff --git a/frontend/src/views/VariantDetailView.vue b/frontend/src/views/VariantDetailView.vue index cf5cd59e..74714e09 100644 --- a/frontend/src/views/VariantDetailView.vue +++ b/frontend/src/views/VariantDetailView.vue @@ -178,7 +178,7 @@ const genomeReleaseRef = ref(props.genomeRelease)
-
+

Consequences

@@ -189,7 +189,7 @@ const genomeReleaseRef = ref(props.genomeRelease)
diff --git a/frontend/src/views/__tests__/VariantDetailView.spec.ts b/frontend/src/views/__tests__/VariantDetailView.spec.ts index 8948d59d..bbd87ed7 100644 --- a/frontend/src/views/__tests__/VariantDetailView.spec.ts +++ b/frontend/src/views/__tests__/VariantDetailView.spec.ts @@ -42,7 +42,7 @@ const variantData = { varAnnos: JSON.parse(JSON.stringify(BRCA1VariantInfo)).result, geneInfo: JSON.parse(JSON.stringify(BRCA1GeneInfo)).genes['HGNC:1100'], clinvar: JSON.parse(JSON.stringify(BRCA1ClinVar)).genes['HGNC:1100'], - txCsq: JSON.parse(JSON.stringify(BRCA1TxInfo)) + txCsq: JSON.parse(JSON.stringify(BRCA1TxInfo)).result } const makeWrapper = () => { diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts index 5e666fde..01751cbb 100644 --- a/frontend/vitest.config.ts +++ b/frontend/vitest.config.ts @@ -9,8 +9,10 @@ export default mergeConfig( defineConfig({ test: { setupFiles: ['./src/vitest.setup.ts'], - deps: { - inline: ['vuetify', 'vitest-canvas-mock'] + server: { + deps: { + inline: ['vuetify', 'vitest-canvas-mock'] + } }, coverage: { provider: 'istanbul'