Skip to content

Commit

Permalink
start fixing up unit tests and only show fixtures when possible
Browse files Browse the repository at this point in the history
  • Loading branch information
b-cooper committed Mar 27, 2024
1 parent 0974d69 commit c62525c
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 54 deletions.
4 changes: 2 additions & 2 deletions app/src/assets/localization/en/device_details.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"about_module": "About {{name}}",
"about_pipette_name": "About {{name}} Pipette",
"about_pipette": "About pipette",
"add_fixture_description": "Add this fixture to your deck configuration. It will be referenced during protocol analysis.",
"add_to_slot_description": "Choose a fixture below to add to your deck configuration. It will be referenced during protocol analysis.",
"add_fixture_description": "Add this item to your deck configuration. It will be referenced during protocol analysis.",
"add_to_slot_description": "Choose an item below to add to your deck configuration. It will be referenced during protocol analysis.",
"add_to_slot": "Add to slot {{slotName}}",
"add": "Add",
"an_error_occurred_while_updating_module": "An error occurred while updating your {{moduleName}}. Please try again.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react'
import { useTranslation } from 'react-i18next'
import { css } from 'styled-components'
import partition from 'lodash/partition'

import {
ALIGN_CENTER,
Expand Down Expand Up @@ -40,6 +39,7 @@ import {
THERMOCYCLER_MODULE_V2,
THERMOCYCLER_V2_FRONT_FIXTURE,
TRASH_BIN_ADAPTER_FIXTURE,
WASTE_CHUTE_CUTOUT,
WASTE_CHUTE_FIXTURES,
} from '@opentrons/shared-data'

Expand All @@ -56,7 +56,6 @@ import type {
} from '@opentrons/shared-data'
import type { ModalHeaderBaseProps } from '../../molecules/Modal/types'
import type { LegacyModalProps } from '../../molecules/LegacyModal'
import { AttachedModule } from '@opentrons/api-client'

type CutoutContents = Omit<CutoutConfig, 'cutoutId'>

Expand All @@ -67,6 +66,12 @@ interface AddFixtureModalProps {
providedFixtureOptions?: CutoutFixtureId[]
isOnDevice?: boolean
}
type OptionStage =
| 'modulesOrFixtures'
| 'fixtureOptions'
| 'moduleOptions'
| 'wasteChuteOptions'
| 'providedOptions'

export function AddFixtureModal({
cutoutId,
Expand All @@ -78,13 +83,24 @@ export function AddFixtureModal({
const { t } = useTranslation(['device_details', 'shared'])
const { updateDeckConfiguration } = useUpdateDeckConfigurationMutation()
const { data: modulesData } = useModulesQuery()
const unconfiguredMods =
modulesData?.data.filter(
attachedMod =>
!deckConfig.some(
({ opentronsModuleSerialNumber }) =>
attachedMod.serialNumber === opentronsModuleSerialNumber
)
) ?? []
const deckConfig = useDeckConfigurationQuery()?.data ?? []
const [optionStage, setOptionStage] = React.useState<
| 'modulesOrFixtures'
| 'fixtureOptions'
| 'moduleOptions'
| 'wasteChuteOptions'
>('modulesOrFixtures')

let initialStage: OptionStage = SINGLE_CENTER_CUTOUTS.includes(cutoutId) // only mag block (a module) can be configured in column 2
? 'moduleOptions'
: 'modulesOrFixtures'
if (providedFixtureOptions != null) { // only show provided options if given as props
initialStage = 'providedOptions'
}
const [optionStage, setOptionStage] = React.useState<OptionStage>(initialStage)

const [showWasteChuteOptions, setShowWasteChuteOptions] = React.useState(
false
)
Expand All @@ -107,35 +123,33 @@ export function AddFixtureModal({
width: '26.75rem',
}

const unconfiguredMods =
modulesData?.data.filter(
attachedMod =>
!deckConfig.some(
({ opentronsModuleSerialNumber }) =>
attachedMod.serialNumber === opentronsModuleSerialNumber
)
) ?? []

let availableFixtures: CutoutContents[] = []
if (optionStage === 'fixtureOptions') {
let availableOptions: CutoutContents[] = []

if (providedFixtureOptions != null) {
availableOptions = providedFixtureOptions?.map(o => ({
cutoutFixtureId: o,
opentronsModuleSerialNumber: undefined,
}))
} else if (optionStage === 'fixtureOptions') {
if (
SINGLE_RIGHT_CUTOUTS.includes(cutoutId) ||
SINGLE_LEFT_CUTOUTS.includes(cutoutId)
) {
availableFixtures = [
...availableFixtures,
availableOptions = [
...availableOptions,
{ cutoutFixtureId: TRASH_BIN_ADAPTER_FIXTURE },
]
}
if (STAGING_AREA_CUTOUTS.includes(cutoutId)) {
availableFixtures = [
...availableFixtures,
availableOptions = [
...availableOptions,
{ cutoutFixtureId: STAGING_AREA_RIGHT_SLOT_FIXTURE },
]
}
} else if (optionStage === 'moduleOptions') {
availableFixtures = [
...availableFixtures,
availableOptions = [
...availableOptions,
{ cutoutFixtureId: MAGNETIC_BLOCK_V1_FIXTURE },
]
if (unconfiguredMods.length > 0) {
Expand All @@ -146,7 +160,7 @@ export function AddFixtureModal({
cutoutFixtureId: THERMOCYCLER_V2_FRONT_FIXTURE,
opentronsModuleSerialNumber: mod.serialNumber,
}))
availableFixtures = [...availableFixtures, ...unconfiguredTCs]
availableOptions = [...availableOptions, ...unconfiguredTCs]
}
if (
HEATER_SHAKER_CUTOUTS.includes(cutoutId) &&
Expand All @@ -158,7 +172,7 @@ export function AddFixtureModal({
cutoutFixtureId: HEATERSHAKER_MODULE_V1_FIXTURE,
opentronsModuleSerialNumber: mod.serialNumber,
}))
availableFixtures = [...availableFixtures, ...unconfiguredHeaterShakers]
availableOptions = [...availableOptions, ...unconfiguredHeaterShakers]
}
if (
TEMPERATURE_MODULE_CUTOUTS.includes(cutoutId) &&
Expand All @@ -170,14 +184,14 @@ export function AddFixtureModal({
cutoutFixtureId: TEMPERATURE_MODULE_V2_FIXTURE,
opentronsModuleSerialNumber: mod.serialNumber,
}))
availableFixtures = [
...availableFixtures,
availableOptions = [
...availableOptions,
...unconfiguredTemperatureModules,
]
}
}
} else if (optionStage === 'wasteChuteOptions') {
availableFixtures = WASTE_CHUTE_FIXTURES.map(fixture => ({
availableOptions = WASTE_CHUTE_FIXTURES.map(fixture => ({
cutoutFixtureId: fixture,
}))
}
Expand All @@ -196,12 +210,6 @@ export function AddFixtureModal({
setShowAddFixtureModal(false)
}

const fixtureOptions =
providedFixtureOptions?.map(o => ({
cutoutFixtureId: o,
opentronsModuleSerialNumber: undefined,
})) ?? availableFixtures

let nextStageOptions = null
if (optionStage === 'modulesOrFixtures') {
nextStageOptions = (
Expand All @@ -228,12 +236,12 @@ export function AddFixtureModal({
/>
</>
)
} else if (optionStage === 'fixtureOptions') {
} else if (optionStage === 'fixtureOptions' && cutoutId === WASTE_CHUTE_CUTOUT) {
nextStageOptions = (
<>
<FixtureOption
key="wasteChuteStageOption"
optionName="Waste Chute"
optionName="Waste chute"
buttonText={t('select_options')}
onClickHandler={() => {
setOptionStage('wasteChuteOptions')
Expand Down Expand Up @@ -269,7 +277,7 @@ export function AddFixtureModal({
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing32}>
<StyledText as="p">{t('add_to_slot_description')}</StyledText>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing8}>
{fixtureOptions.map(cutoutContents => (
{availableOptions.map(cutoutContents => (
<FixtureOption
key={cutoutContents.cutoutFixtureId}
optionName={getFixtureDisplayName(
Expand All @@ -289,7 +297,7 @@ export function AddFixtureModal({
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing16}>
<StyledText as="p">{t('add_fixture_description')}</StyledText>
<Flex flexDirection={DIRECTION_COLUMN} gridGap={SPACING.spacing8}>
{fixtureOptions.map(cutoutContents => (
{availableOptions.map(cutoutContents => (
<FixtureOption
key={cutoutContents.cutoutFixtureId}
optionName={getFixtureDisplayName(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { describe, it, beforeEach, vi, expect, afterEach } from 'vitest'

import {
useDeckConfigurationQuery,
useModulesQuery,
useUpdateDeckConfigurationMutation,
} from '@opentrons/react-api-client'
import {
Expand All @@ -17,6 +18,7 @@ import { AddFixtureModal } from '../AddFixtureModal'

import type { UseQueryResult } from 'react-query'
import type { DeckConfiguration } from '@opentrons/shared-data'
import type { Modules } from '@opentrons/api-client'

vi.mock('@opentrons/react-api-client')
const mockSetShowAddFixtureModal = vi.fn()
Expand Down Expand Up @@ -45,24 +47,26 @@ describe('Touchscreen AddFixtureModal', () => {
vi.mocked(useDeckConfigurationQuery).mockReturnValue(({
data: [],
} as unknown) as UseQueryResult<DeckConfiguration>)
vi.mocked(useModulesQuery).mockReturnValue(({
data: { data: [] },
} as unknown) as UseQueryResult<Modules>)
})

it('should render text and buttons', () => {
render(props)
screen.getByText('Add to slot D3')
screen.getByText(
'Choose a fixture below to add to your deck configuration. It will be referenced during protocol analysis.'
'Choose an item below to add to your deck configuration. It will be referenced during protocol analysis.'
)
screen.getByText('Staging area slot')
screen.getByText('Trash bin')
screen.getByText('Waste chute')
expect(screen.getAllByText('Add').length).toBe(2)
expect(screen.getAllByText('Select options').length).toBe(1)
screen.getByText('Fixtures')
screen.getByText('Modules')
expect(screen.getAllByText('Select options').length).toBe(2)
})

it('should a mock function when tapping app button', () => {
it('should set deck config when tapping add button', () => {
render(props)
fireEvent.click(screen.getAllByText('Add')[0])
fireEvent.click(screen.getAllByText('Select options')[1])
fireEvent.click(screen.getByText('Add'))
expect(mockSetCurrentDeckConfig).toHaveBeenCalled()
})

Expand All @@ -74,7 +78,7 @@ describe('Touchscreen AddFixtureModal', () => {
render(props)
screen.getByText('Add to slot D3')
screen.getByText(
'Choose a fixture below to add to your deck configuration. It will be referenced during protocol analysis.'
'Choose an item below to add to your deck configuration. It will be referenced during protocol analysis.'
)
expect(screen.queryByText('Staging area slot')).toBeNull()
screen.getByText('Trash bin')
Expand Down Expand Up @@ -105,8 +109,12 @@ describe('Desktop AddFixtureModal', () => {
render(props)
screen.getByText('Add to slot D3')
screen.getByText(
'Add this fixture to your deck configuration. It will be referenced during protocol analysis.'
'Add this item to your deck configuration. It will be referenced during protocol analysis.'
)

screen.getByText('Fixtures')
screen.getByText('Modules')
fireEvent.click(screen.getAllByText('Select options')[0])
screen.getByText('Staging area slot')
screen.getByText('Trash bin')
screen.getByText('Waste chute')
Expand All @@ -121,8 +129,11 @@ describe('Desktop AddFixtureModal', () => {
render(props)
screen.getByText('Add to slot A1')
screen.getByText(
'Add this fixture to your deck configuration. It will be referenced during protocol analysis.'
'Add this item to your deck configuration. It will be referenced during protocol analysis.'
)
screen.getByText('Fixtures')
screen.getByText('Modules')
fireEvent.click(screen.getAllByText('Select options')[0])
screen.getByText('Trash bin')
screen.getByRole('button', { name: 'Add' })
})
Expand All @@ -132,13 +143,29 @@ describe('Desktop AddFixtureModal', () => {
render(props)
screen.getByText('Add to slot B3')
screen.getByText(
'Add this fixture to your deck configuration. It will be referenced during protocol analysis.'
'Add this item to your deck configuration. It will be referenced during protocol analysis.'
)
screen.getByText('Fixtures')
screen.getByText('Modules')
fireEvent.click(screen.getAllByText('Select options')[0])
screen.getByText('Staging area slot')
screen.getByText('Trash bin')
expect(screen.getAllByRole('button', { name: 'Add' }).length).toBe(2)
})

it('should only render module options in column 2', () => {
props = { ...props, cutoutId: 'cutoutB2' }
render(props)
screen.getByText('Add to slot B2')
screen.getByText(
'Add this item to your deck configuration. It will be referenced during protocol analysis.'
)
screen.getByText('Magnetic Block GEN1')
expect(screen.getByRole('button', { name: 'Add' })).toBeInTheDocument()
})



it('should call a mock function when clicking add button', () => {
props = { ...props, cutoutId: 'cutoutA1' }
render(props)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { describe, it, vi, beforeEach, expect, afterEach } from 'vitest'
import { BaseDeck } from '@opentrons/components'
import {
useDeckConfigurationQuery,
useModulesQuery,
useUpdateDeckConfigurationMutation,
} from '@opentrons/react-api-client'

Expand All @@ -19,6 +20,7 @@ import type {
CompletedProtocolAnalysis,
DeckConfiguration,
} from '@opentrons/shared-data'
import { Modules } from '@opentrons/api-client'

vi.mock('@opentrons/components/src/hardware-sim/BaseDeck/index')
vi.mock('@opentrons/react-api-client')
Expand Down Expand Up @@ -72,6 +74,9 @@ describe('ProtocolSetupDeckConfiguration', () => {
vi.mocked(useDeckConfigurationQuery).mockReturnValue(({
data: [],
} as unknown) as UseQueryResult<DeckConfiguration>)
vi.mocked(useModulesQuery).mockReturnValue(({
data: { data: [] },
} as unknown) as UseQueryResult<Modules>)
})

afterEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ describe('ProtocolSetup', () => {
...mockRobotSideAnalysis,
runTimeParameters: mockRunTimeParameterData,
},
flexDeckDefV4 as any
flexDeckDefV5 as any
)
.thenReturn(mockProtocolModuleInfo)
when(vi.mocked(getUnmatchedModulesForProtocol))
Expand Down

0 comments on commit c62525c

Please sign in to comment.