Skip to content

Commit

Permalink
feat: cleanup front-end tests (#355) (#363)
Browse files Browse the repository at this point in the history
  • Loading branch information
holtgrewe authored Jan 3, 2024
1 parent 25c825f commit 161da9e
Show file tree
Hide file tree
Showing 79 changed files with 385 additions and 422 deletions.
15 changes: 15 additions & 0 deletions docs/dev_frontend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ Import order should be (and is also enforced by prettier):

Overall, restrict relative include order for tests to include code to be tested with ``../``.

-----
Types
-----

- For the Vue reactive stores, explicitely specify the type in the creating function, e.g., `ref<string>` or `ref<string | undefined>`.
- In many places in the UI, using `undefined` is more appropriate than `null` as this is the value before the data is loaded from the backend.

--------------
Test Structure
--------------
Expand All @@ -29,6 +36,7 @@ Consider the following structure, an example is given below.
- put larger fixture data into ``.json`` files within the ``__tests__`` folders (will go to LFS by our ``.gitattributes`` configuration)
- define the tests
- use assemble, act, assert structure e.g., `as described here <http://wiki.c2.com/?AssembleActivateAssert>`__
- guard assertions are OK
- use ``describe.concurrent`` to describe the tests, usually one block per ``.spec.ts`` file
- use ``it`` to define the tests
- use ``async () => { ... }`` only when necessary, e.g., for ``await nextTick()``
Expand All @@ -37,3 +45,10 @@ Consider the following structure, an example is given below.
.. literalinclude:: ../frontend/src/components/__tests__/UserProfileButton.spec.ts
:language: typescript

Note that there is a separation between views and components (cf. https://stackoverflow.com/a/50866150/84349) that is also reflected in the tests.

- The main purpose of views is to handle the routing.
- The actual work happens in components.

In tests, we thus use stubbed out of nested components in views but not components.
This keeps the load time acceptable while testing the components in isolation.
33 changes: 33 additions & 0 deletions frontend/src/api/intervar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { API_INTERNAL_BASE_PREFIX } from '@/api/common'
import type { Seqvar } from '@/lib/genomicVars'
import type { AcmgRatingBackend } from '@/stores/seqVarAcmgRating'

const API_BASE_URL = `${API_INTERNAL_BASE_PREFIX}/`

export class InterVarClient {
private apiBaseUrl: string
private csrfToken: string | null

constructor(apiBaseUrl?: string, csrfToken?: string) {
this.apiBaseUrl = apiBaseUrl ?? API_BASE_URL
this.csrfToken = csrfToken ?? null
}

/**
* Fetch ACMG rating from InterVar via proxy.
*/
async fetchAcmgRating(seqvar: Seqvar): Promise<AcmgRatingBackend> {
const { genomeBuild, chrom, pos, del, ins } = seqvar
const release = genomeBuild === 'grch37' ? 'hg19' : 'hg38'
const url =
`${API_BASE_URL}remote/acmg/?release=${release}&chromosome=${chrom}` +
`&position=${pos}&reference=${del}&alternative=${ins}`
const response = await fetch(url, { method: 'GET' })

if (!response.ok) {
throw new Error(`Failed to fetch ACMG rating for ${seqvar.userRepr}`)
}

return await response.json()
}
}
11 changes: 10 additions & 1 deletion frontend/src/components/SeqvarDetails/BeaconNetworkCard.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
<!--
This component allows to trigger a query to the Beacon Network for a given variant.

The query is performed using the `<iframe>` feature of `beacon-network.org`.
-->
<script setup lang="ts">
import { ref } from 'vue'

import DocsLink from '@/components/DocsLink.vue'
import { type Seqvar } from '@/lib/genomicVars'

/** Interface for this component's props. */
interface Props {
seqvar?: Seqvar
}

/** This component's props. */
const props = defineProps<Props>()

const beaconAddress = ref('')
/** The beacon iframe address; when set the iframe is loaded. */
const beaconAddress = ref<string>('')

/** Update `beaconAddress.value` to the URL indicated by `props.seqvar`. */
const loadBeacon = () => {
if (!props.seqvar) {
return
Expand Down
13 changes: 7 additions & 6 deletions frontend/src/components/VarDetails/ClinvarsubCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import { type SubmittingOrgRead } from '@/api/clinvarsub'
import DocsLink from '@/components/DocsLink.vue'
import ClinvarsubThreadList from '@/components/VarDetails/ClinvarsubThreadList.vue'
import { type Seqvar, type Strucvar } from '@/lib/genomicVars'
import { deepCopy } from '@/lib/utils'
import { useClinvarsubStore } from '@/stores/clinvarsub'
import { StoreState } from '@/stores/misc'
import { useTermsStore } from '@/stores/terms'
Expand Down Expand Up @@ -132,7 +131,7 @@ const prepareModelStateDefaults: PrepareModel = {
scv: undefined
}
/** Current state of preparation step. */
const prepareModelState = ref<PrepareModel>(deepCopy(prepareModelStateDefaults))
const prepareModelState = ref<PrepareModel>(structuredClone(prepareModelStateDefaults))
/** Rules for the prepare model state. */
const prepareModelRules = {
scv: {
Expand Down Expand Up @@ -223,7 +222,9 @@ const createDefaultModelStateDefault: CreateUpdateModel = {
structVarMethod: null
}
/** The model for the create/update data. */
const createUpdateModelState = ref<CreateUpdateModel>(deepCopy(createDefaultModelStateDefault))
const createUpdateModelState = ref<CreateUpdateModel>(
structuredClone(createDefaultModelStateDefault)
)
/** Rules for the prepare model state. */
const createUpdateModelRules = {
dateLastEvaluated: {
Expand Down Expand Up @@ -334,7 +335,7 @@ const constructCreateUpdatePayload = (
prepareModel: PrepareModel,
createUpdateModel: CreateUpdateModel
): SubmissionContainer => {
const modelCopy: CreateUpdateModel = deepCopy(createUpdateModel)
const modelCopy: CreateUpdateModel = structuredClone(createUpdateModel)
let submissionVariant: SubmissionVariant
if (props.seqvar) {
submissionVariant = constructSeqvarVariant(props.seqvar)
Expand Down Expand Up @@ -407,8 +408,8 @@ const constructDeletePayload = (
const onClickCancel = async () => {
display.value = Display.List
currentStep.value = 1
prepareModelState.value = deepCopy(prepareModelStateDefaults)
createUpdateModelState.value = deepCopy(createDefaultModelStateDefault)
prepareModelState.value = structuredClone(prepareModelStateDefaults)
createUpdateModelState.value = structuredClone(createDefaultModelStateDefault)
}
/** Handler for click on "previous". */
const onClickPrevious = async () => {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/__tests__/BookmarkListItem.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { StoreState } from '@/stores/misc'
describe.concurrent('BookmarkListItem.vue', () => {
it('renders information with StoreState Active', async () => {
const { wrapper } = await setupMountedComponents(
{ component: BookmarkListItem, template: false },
{ component: BookmarkListItem },
{
props: {
type: 'seqvar',
Expand Down Expand Up @@ -35,7 +35,7 @@ describe.concurrent('BookmarkListItem.vue', () => {

it('renders information with StoreState Error', async () => {
const { wrapper } = await setupMountedComponents(
{ component: BookmarkListItem, template: false },
{ component: BookmarkListItem },
{
props: {
type: 'seqvar',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import CaseInformationCard from '../CaseInformationCard.vue'
describe.concurrent('CaseInformationCard.vue', () => {
it('renders information', async () => {
const { wrapper } = await setupMountedComponents(
{ component: CaseInformationCard, template: false },
{ component: CaseInformationCard },
{
initialStoreState: {
case: {
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/__tests__/CriterionSwitch.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe.concurrent('ClinsigCard', async () => {
const criteriaState = acmgRating.getCriteriaState(criteria)

const { wrapper } = await setupMountedComponents(
{ component: CriterionSwitch, template: false },
{ component: CriterionSwitch },
{
props: {
acmgRating: acmgRating,
Expand All @@ -40,7 +40,7 @@ describe.concurrent('ClinsigCard', async () => {
const criteriaState = acmgRating.getCriteriaState(criteria)

const { wrapper } = await setupMountedComponents(
{ component: CriterionSwitch, template: false },
{ component: CriterionSwitch },
{
props: {
acmgRating: acmgRating,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/__tests__/FooterDefault.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import FooterDefault from '../FooterDefault.vue'
describe.concurrent('FooterDefault.vue', () => {
it('renders information', async () => {
const { wrapper } = await setupMountedComponents(
{ component: FooterDefault, template: true },
{ component: FooterDefault },
{
initialStoreState: {
misc: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('AlternativeIdentifiers', async () => {
it('renders the AlternativeIdentifiers information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: AlternativeIdentifiers, template: false },
{ component: AlternativeIdentifiers },
{
props: {
hgnc: BRCA1GeneInfo['genes']['HGNC:1100']['hgnc']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('ExternalResources', async () => {
it('renders the ExternalResources information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: ExternalResources, template: false },
{ component: ExternalResources },
{
props: {
hgnc: BRCA1GeneInfo['genes']['HGNC:1100']['hgnc']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('GeneRifs', async () => {
it('renders the GeneRifs information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: GeneRifs, template: false },
{ component: GeneRifs },
{
props: {
ncbi: BRCA1GeneInfo['genes']['HGNC:1100']['ncbi']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('LocusDatabases', async () => {
it('renders the LocusDatabases information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: LocusDatabases, template: false },
{ component: LocusDatabases },
{
props: {
hgnc: BRCA1GeneInfo['genes']['HGNC:1100']['hgnc']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('SupplementaryList', async () => {
it('renders the SupplementaryList information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: SupplementaryList, template: false },
{ component: SupplementaryList },
{
props: {
acmgSf: BRCA1GeneInfo['genes']['HGNC:1100']['acmgSf']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('ClinVarFreqPlot', async () => {
it('renders the ClinVarFreqPlot info', async () => {
const { wrapper } = await setupMountedComponents(
{ component: ClinVarFreqPlot, template: false },
{ component: ClinVarFreqPlot },
{
props: {
geneSymbol: 'BRCA1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('ClinvarImpact', async () => {
it('renders the ClinvarImpact information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: ClinvarImpact, template: false },
{ component: ClinvarImpact },
{
props: {
geneClinvar: BRCA1ClinVar['genes']['HGNC:1100']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('VariationLandscape', async () => {
it('renders the VariationLandscape plot', async () => {
const { wrapper } = await setupMountedComponents(
{ component: VariationLandscape, template: false },
{ component: VariationLandscape },
{
props: {
clinvar: BRCA1Clinvar['genes']['HGNC:1100'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('ConditionsCard', async () => {
it('renders the ConditionsCard information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: ConditionsCard, template: false },
{ component: ConditionsCard },
{
props: {
geneInfo: BRCA1GeneInfo['genes']['HGNC:1100'],
Expand All @@ -24,7 +24,7 @@ describe.concurrent('ConditionsCard', async () => {

it('expands the Orphanet Disorders information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: ConditionsCard, template: false },
{ component: ConditionsCard },
{
props: {
geneInfo: BRCA1GeneInfo['genes']['HGNC:1100'],
Expand All @@ -41,7 +41,7 @@ describe.concurrent('ConditionsCard', async () => {

it.skip('shows numerical values for HPO terms.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: ConditionsCard, template: false },
{ component: ConditionsCard },
{
props: {
geneInfo: BRCA1GeneInfo['genes']['HGNC:1100'],
Expand Down Expand Up @@ -77,7 +77,7 @@ describe.concurrent('ConditionsCard', async () => {

it.skip('shows links for HPO terms.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: ConditionsCard, template: false },
{ component: ConditionsCard },
{
props: {
geneInfo: BRCA1GeneInfo['genes']['HGNC:1100'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('CadaRanking', async () => {
it('renders the CadaRanking info', async () => {
const { wrapper } = await setupMountedComponents(
{ component: CadaRanking, template: false },
{ component: CadaRanking },
{
props: {
hgncId: 'HGNC:1100'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe.concurrent('GtexGenePlotVue', async () => {
// Disable warinings, because of invalid test data
console.warn = vi.fn()
const { wrapper } = await setupMountedComponents(
{ component: GtexGenePlotVue, template: false },
{ component: GtexGenePlotVue },
{
props: {
geneSymbol: 'BRCA1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('OverviewCard', async () => {
it('renders the OverviewCard information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: OverviewCard, template: false },
{ component: OverviewCard },
{
props: {
geneInfo: BRCA1GeneInfo['genes']['HGNC:1100']
Expand All @@ -21,7 +21,7 @@ describe.concurrent('OverviewCard', async () => {

it('expands the OverviewCard information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: OverviewCard, template: false },
{ component: OverviewCard },
{
props: {
geneInfo: BRCA1GeneInfo['genes']['HGNC:1100']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { setupMountedComponents } from '@/lib/test-utils'
describe.concurrent('PathogenicityCard', async () => {
it('renders the Pathogenicity information.', async () => {
const { wrapper } = await setupMountedComponents(
{ component: PathogenicityCard, template: false },
{ component: PathogenicityCard },
{
props: {
geneInfo: BRCA1GeneInfo['genes']['HGNC:1100']
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/__tests__/GenomeBrowser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import GenomeBrowser from '../GenomeBrowser.vue'
describe.concurrent('GenomeBrowser', async () => {
it('renders the GenomeBrowser with the hg19 genome', async () => {
const { wrapper } = await setupMountedComponents(
{ component: GenomeBrowser, template: false },
{ component: GenomeBrowser },
{
props: {
genomeRelease: 'grch37',
Expand All @@ -20,7 +20,7 @@ describe.concurrent('GenomeBrowser', async () => {

it('renders the GenomeBrowser with the hg38 genome', async () => {
const { wrapper } = await setupMountedComponents(
{ component: GenomeBrowser, template: false },
{ component: GenomeBrowser },
{
props: {
genomeRelease: 'grch38',
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/__tests__/PageHeader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe.concurrent('PageHeader', async () => {

it('renders the gene symbol and nav links', async () => {
const { wrapper } = await setupMountedComponents(
{ component: PageHeader, template: true },
{ component: PageHeader },
{
initialStoreState: geneData
}
Expand All @@ -47,7 +47,7 @@ describe.concurrent('PageHeader', async () => {

it('renders the search bar', async () => {
const { wrapper } = await setupMountedComponents(
{ component: PageHeader, template: true },
{ component: PageHeader },
{
initialStoreState: geneData
}
Expand All @@ -69,7 +69,7 @@ describe.concurrent('PageHeader', async () => {
)

const { wrapper, router } = await setupMountedComponents(
{ component: PageHeader, template: true },
{ component: PageHeader },
{
initialStoreState: geneData
}
Expand Down
Loading

0 comments on commit 161da9e

Please sign in to comment.