Skip to content

Commit

Permalink
ci: metadata drawer e2e (#823)
Browse files Browse the repository at this point in the history
#537

- Adds utils for metadata drawer E2E
- Adds E2E tests for single dataset, single run, and annotation metadata
drawers

## Demo

<img width="375" alt="image"
src="https://github.com/chanzuckerberg/cryoet-data-portal/assets/2176050/8a5a1cc9-5774-4891-8178-06ffcee062b3">
  • Loading branch information
codemonkey800 authored Jul 1, 2024
1 parent c039cfc commit db612e7
Show file tree
Hide file tree
Showing 8 changed files with 399 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ReactNode, useCallback, useEffect } from 'react'
import { Demo } from 'app/components/Demo'
import { Drawer } from 'app/components/Drawer'
import { TabData, Tabs } from 'app/components/Tabs'
import { TestIds } from 'app/constants/testIds'
import {
MetadataDrawerId,
MetadataTab,
Expand Down Expand Up @@ -61,7 +62,10 @@ export function MetadataDrawer({

return (
<Drawer open={isOpen} onClose={handleClose}>
<div className="flex flex-col flex-auto">
<div
className="flex flex-col flex-auto"
data-testid={TestIds.MetadataDrawer}
>
<header className="flex items-start justify-between px-sds-xl pt-sds-xl pb-sds-xxl">
<div className="flex flex-col gap-sds-s">
<p className="text-xs text-sds-gray-600 font-semibold uppercase">
Expand All @@ -79,6 +83,7 @@ export function MetadataDrawer({
sdsIconProps={{
color: 'gray',
}}
data-testid={TestIds.MetadataDrawerCloseButton}
/>
</header>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AccordionMetadataTable } from 'app/components/AccordionMetadataTable'
import { useRunById } from 'app/hooks/useRunById'
import { i18n } from 'app/i18n'
import { getTableData } from 'app/utils/table'
import { isFiducial } from 'app/utils/tomograms'

import { Matrix4x4 } from './Matrix4x4'

Expand Down Expand Up @@ -44,7 +45,7 @@ export function TomogramsTable() {
{
label: i18n.fiducialAlignmentStatus,
values: [
tomo.fiducial_alignment_status === 'FIDUCIAL' ? i18n.true : i18n.false,
isFiducial(tomo.fiducial_alignment_status) ? i18n.true : i18n.false,
],
},
{
Expand Down
2 changes: 2 additions & 0 deletions frontend/packages/data-portal/app/constants/testIds.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export enum TestIds {
EnvelopeIcon = 'envelope-icon',
MetadataDrawer = 'metadata-drawer',
MetadataDrawerCloseButton = 'metadata-drawer-close-button',
OrcIdIcon = 'orc-id-icon',
Pagination = 'pagination',
}
3 changes: 3 additions & 0 deletions frontend/packages/data-portal/app/utils/tomograms.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function isFiducial(status: string | null | undefined) {
return status === 'FIDUCIAL'
}
113 changes: 113 additions & 0 deletions frontend/packages/data-portal/e2e/metadataDrawer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { getDatasetById } from 'app/graphql/getDatasetById.server'
import { getRunById } from 'app/graphql/getRunById.server'

import {
E2E_CONFIG,
SINGLE_DATASET_URL,
SINGLE_RUN_URL,
translations,
} from './constants'
import { testMetadataDrawer } from './metadataDrawer/testMetadataDrawer'
import {
getAnnotationTestMetdata,
getDatasetTestMetadata,
getTiltSeriesTestMetadata,
getTomogramTestMetadata,
} from './metadataDrawer/utils'

testMetadataDrawer({
url: SINGLE_DATASET_URL,

async getTestData(client) {
const { data } = await getDatasetById({
client,
id: +E2E_CONFIG.datasetId,
})

const [dataset] = data.datasets
const [tiltSeries] = dataset.run_metadata[0].tiltseries

return {
title: dataset.title,
metadata: {
...getDatasetTestMetadata({
dataset,
type: 'dataset',
}),

...getTiltSeriesTestMetadata({
tiltSeries,
type: 'dataset',
}),
},
}
},

async openDrawer(page) {
await page.getByRole('button', { name: translations.viewAllInfo }).click()
},
})

testMetadataDrawer({
title: 'Run Metadata',
url: SINGLE_RUN_URL,

async getTestData(client) {
const { data } = await getRunById({
client,
id: +E2E_CONFIG.runId,
})

const [run] = data.runs
const [tiltSeries] = run.tiltseries
const [tomogram] = run.tomogram_voxel_spacings[0].tomograms

return {
title: run.name,
metadata: {
...getDatasetTestMetadata({
dataset: run.dataset,
type: 'run',
}),

...getTiltSeriesTestMetadata({
tiltSeries,
type: 'run',
}),

...getTomogramTestMetadata(tomogram),
},
}
},

async openDrawer(page) {
await page.getByRole('button', { name: translations.viewAllInfo }).click()
},
})

testMetadataDrawer({
title: 'Annotation Metadata',
url: SINGLE_RUN_URL,

async getTestData(client) {
const { data } = await getRunById({
client,
id: +E2E_CONFIG.runId,
})

const [run] = data.runs
const annotation = run.annotation_table[0].annotations[0]

return {
title: `${annotation.id} - ${annotation.object_name}`,
metadata: getAnnotationTestMetdata(annotation),
}
},

async openDrawer(page) {
await page
.getByRole('button', { name: translations.info, exact: true })
.first()
.click()
},
})
116 changes: 116 additions & 0 deletions frontend/packages/data-portal/e2e/metadataDrawer/testMetadataDrawer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/* eslint-disable playwright/no-conditional-in-test */
import { ApolloClient, NormalizedCacheObject } from '@apollo/client'
import { expect, Page, test } from '@playwright/test'
import { getApolloClient } from 'e2e/apollo'
import { E2E_CONFIG, translations } from 'e2e/constants'
import { goTo } from 'e2e/filters/utils'
import { isArray, isNumber } from 'lodash-es'

import { TestIds } from 'app/constants/testIds'

import { DrawerTestData } from './types'

function getMetadataDrawer(page: Page) {
return page.getByTestId(TestIds.MetadataDrawer)
}

function getCloseButton(page: Page) {
return page.getByTestId(TestIds.MetadataDrawerCloseButton)
}

export function testMetadataDrawer({
getTestData,
openDrawer,
title,
url,
}: {
getTestData(
client: ApolloClient<NormalizedCacheObject>,
): Promise<DrawerTestData>
openDrawer(page: Page): Promise<void>
title?: string
url: string
}) {
test.describe(
url.replace(E2E_CONFIG.url, '') + (title ? ` - ${title}` : ''),
() => {
let client = getApolloClient()

test.beforeEach(() => {
client = getApolloClient()
})

test('should open metadata drawer', async ({ page }) => {
await goTo(page, url)

const drawer = getMetadataDrawer(page)
await expect(drawer).toBeHidden()
await openDrawer(page)
await expect(drawer).toBeVisible()
})

test('should close metadata drawer on click x', async ({ page }) => {
await goTo(page, url)

await openDrawer(page)
const drawer = getMetadataDrawer(page)
await drawer.waitFor({ state: 'visible' })

await getCloseButton(page).click()
await expect(drawer).toBeHidden()
})

test('metadata should have correct data', async ({ page }) => {
await goTo(page, url)

await openDrawer(page)
const drawer = getMetadataDrawer(page)
await drawer.waitFor({ state: 'visible' })

const data = await getTestData(client)
await expect(drawer).toContainText(data.title)

const unexpanded = await drawer
.getByRole('button', { expanded: false })
.count()

// We expand the accordions one by one because clicking on all of them
// programatically will break playwright. Assume the Playwright locator
// finds two accordions and stores their locator nodes in 0 and 1. If we
// click on 0, the node is changed to have the attribute expanded=true,
// resulting in the locator updating and changing the node in 1 to 0.
//
// To get around this, we get a count of unexpanded accordions and click
// on the first accordion we find in the drawer.
for (let i = 0; i < unexpanded; i += 1) {
await drawer.getByRole('button', { expanded: false }).first().click()
}

for (const [key, value] of Object.entries(data.metadata)) {
const label = translations[key as keyof typeof translations]
const cells = drawer.locator(`tr:has-text("${label}") td`)

if (isArray(value)) {
const nodeValue = await cells.last().innerText()
expect(
value.every((v) => nodeValue.includes(v ?? '')),
`Test for ${label} with value ${nodeValue} to include ${value.join(
', ',
)}`,
).toBe(true)
} else if (isNumber(value) || value) {
await expect(
cells.last(),
`Test for ${label} to have value ${value}`,
).toContainText(`${value}`)
} else {
await expect(
cells.last(),
`Test for ${label} to be empty`,
).toContainText('--')
}
}
})
},
)
}
23 changes: 23 additions & 0 deletions frontend/packages/data-portal/e2e/metadataDrawer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { DeepPartial } from 'utility-types'

import { GetDatasetByIdQuery, GetRunByIdQuery } from 'app/__generated__/graphql'
import { I18nKeys } from 'app/types/i18n'

export type DrawerMetadataValue = number | string | null | undefined | string[]

export type DrawerTestMetadata = DeepPartial<
Record<I18nKeys, DrawerMetadataValue>
>

export interface DrawerTestData {
title: string
metadata: DrawerTestMetadata
}

export type Dataset =
| GetDatasetByIdQuery['datasets'][number]
| GetRunByIdQuery['runs'][number]['dataset']

export type TiltSeries =
GetDatasetByIdQuery['datasets'][number]['run_metadata'][number]['tiltseries'][number] &
GetRunByIdQuery['runs'][number]['tiltseries'][number]
Loading

0 comments on commit db612e7

Please sign in to comment.