From d283b936570e5401de3a5c1105ed2cee4225b0e1 Mon Sep 17 00:00:00 2001 From: Sakib Hossain Date: Tue, 29 Mar 2022 20:55:55 -0400 Subject: [PATCH 1/5] wire up test shake page --- .../Devices/HeaterShakerWizard/TestShake.tsx | 131 ++++++++++++++++-- 1 file changed, 117 insertions(+), 14 deletions(-) diff --git a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx index fc382e43946..f9b0efb71fc 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx @@ -1,5 +1,6 @@ import React from 'react' import { useTranslation } from 'react-i18next' +import { useCreateLiveCommandMutation } from '@opentrons/react-api-client' import { ALIGN_CENTER, ALIGN_FLEX_START, @@ -8,19 +9,27 @@ import { DIRECTION_ROW, Flex, Icon, - InputField, SIZE_AUTO, SPACING, Text, TYPOGRAPHY, + Tooltip, + useHoverTooltip, } from '@opentrons/components' -import { RPM } from '@opentrons/shared-data' +import { RPM, HS_RPM_MAX, HS_RPM_MIN } from '@opentrons/shared-data' import { HeaterShakerModuleCard } from './HeaterShakerModuleCard' import { TertiaryButton } from '../../../atoms/Buttons' import { CollapsibleStep } from '../../ProtocolSetup/RunSetupCard/CollapsibleStep' import { Divider } from '../../../atoms/structure' +import { InputField } from '../../../atoms/InputField' import type { HeaterShakerModule } from '../../../redux/modules/types' +import type { + HeaterShakerSetTargetShakeSpeedCreateCommand, + HeaterShakerStopShakeCreateCommand, + HeaterShakerOpenLatchCreateCommand, + HeaterShakerCloseLatchCreateCommand, +} from '@opentrons/shared-data/protocol/types/schemaV6/command/module' interface TestShakeProps { module: HeaterShakerModule @@ -29,9 +38,73 @@ interface TestShakeProps { export function TestShake(props: TestShakeProps): JSX.Element { const { module, setCurrentPage } = props - const { t } = useTranslation('heater_shaker') - + const { t } = useTranslation(['heater_shaker', 'device_details']) + const { createLiveCommand } = useCreateLiveCommandMutation() const [isExpanded, setExpanded] = React.useState(false) + const [shakeValue, setShakeValue] = React.useState(null) + const [targetProps, tooltipProps] = useHoverTooltip() + + const isShaking = module.data.speedStatus !== 'idle' + const isLatchOpen = + module.data.labwareLatchStatus === 'idle_open' || + module.data.labwareLatchStatus === 'opening' + + const setLatchCommand: + | HeaterShakerOpenLatchCreateCommand + | HeaterShakerCloseLatchCreateCommand = { + commandType: isLatchOpen + ? 'heaterShakerModule/closeLatch' + : 'heaterShakerModule/openLatch', + params: { + moduleId: module.id, + }, + } + + const setShakeCommand: HeaterShakerSetTargetShakeSpeedCreateCommand = { + commandType: 'heaterShakerModule/setTargetShakeSpeed', + params: { + moduleId: module.id, + rpm: shakeValue !== null ? parseInt(shakeValue) : 0, + }, + } + + const stopShakeCommand: HeaterShakerStopShakeCreateCommand = { + commandType: 'heaterShakerModule/stopShake', + params: { + moduleId: module.id, + }, + } + + const handleLatchCommand = (): void => { + createLiveCommand({ + command: setLatchCommand, + }).catch((e: Error) => { + console.error( + `error setting module status with command type ${setLatchCommand.commandType}: ${e.message}` + ) + }) + } + + const handleShakeCommand = (): void => { + if (shakeValue !== null) { + createLiveCommand({ + command: isShaking ? stopShakeCommand : setShakeCommand, + }).catch((e: Error) => { + console.error( + `error setting module status with command type ${ + stopShakeCommand.commandType ?? setShakeCommand.commandType + }: ${e.message}` + ) + }) + } + setShakeValue(null) + } + + const errorMessage = + shakeValue != null && + (parseInt(shakeValue) < HS_RPM_MIN || parseInt(shakeValue) > HS_RPM_MAX) + ? t('input_out_of_range') + : null return ( @@ -76,31 +149,61 @@ export function TestShake(props: TestShakeProps): JSX.Element { fontSize={TYPOGRAPHY.fontSizeCaption} > - - {t('open_labware_latch')} + + {isLatchOpen ? t('close_labware_latch') : t('open_labware_latch')} + {isShaking ? ( + + {t('cannot_open_latch', { ns: 'heater_shaker' })} + + ) : null} - + {t('set_shake_speed')} - {/* TODO(sh, 2022-02-22): Wire up input when end points are updated */} - - - {t('min_max_rpm', { min: '200', max: '1800' })} - + setShakeValue(e.target.value)} + type="number" + caption={t('min_max_rpm', { + ns: 'heater_shaker', + min: HS_RPM_MIN, + max: HS_RPM_MAX, + })} + error={errorMessage} + /> - {t('start_shaking')} + {isShaking ? t('stop_shaking') : t('start_shaking')} + {isLatchOpen ? ( + + {t('cannot_shake', { ns: 'heater_shaker' })} + + ) : null} From c5e9055a720ee693ff1b696cfe1ba5c98a8c6d40 Mon Sep 17 00:00:00 2001 From: Sakib Hossain Date: Wed, 30 Mar 2022 13:06:40 -0400 Subject: [PATCH 2/5] refactor(app): wire up heater shaker wizard TestShake page This PR wires up the buttons and input for the testshake page of the heater shaker wizard. closes #9613 --- .../assets/localization/en/heater_shaker.json | 4 +- .../Devices/HeaterShakerWizard/TestShake.tsx | 2 +- .../__tests__/TestShake.test.tsx | 132 +++++++++++++++++- .../ModuleCard/HeaterShakerModuleData.tsx | 46 +++++- .../Devices/ModuleCard/TestShakeSlideout.tsx | 2 +- 5 files changed, 175 insertions(+), 11 deletions(-) diff --git a/app/src/assets/localization/en/heater_shaker.json b/app/src/assets/localization/en/heater_shaker.json index 540e0def792..209d7349b7f 100644 --- a/app/src/assets/localization/en/heater_shaker.json +++ b/app/src/assets/localization/en/heater_shaker.json @@ -79,5 +79,7 @@ "test_shake_slideout_banner_info": "If you want to add labware to the module before doing a test shake, you can use the labware latch controls to hold the latches open.", "shake_speed": "Shake speed", "test_shake_troubleshooting_slideout_description": "Revisit instructions for attaching the module to the deck as well as attaching the thermal adapter.", - "go_to_attachment_instructions": "Go to attachment instructions" + "go_to_attachment_instructions": "Go to attachment instructions", + "closed": "Closed", + "closed_and_locked": "Closed and Locked" } diff --git a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx index f9b0efb71fc..120f7878795 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx @@ -103,7 +103,7 @@ export function TestShake(props: TestShakeProps): JSX.Element { const errorMessage = shakeValue != null && (parseInt(shakeValue) < HS_RPM_MIN || parseInt(shakeValue) > HS_RPM_MAX) - ? t('input_out_of_range') + ? t('input_out_of_range', { ns: 'device_details' }) : null return ( diff --git a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx index 720eb245c0b..c09d3a9fb9a 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx @@ -1,13 +1,19 @@ import * as React from 'react' import { renderWithProviders } from '@opentrons/components' import { fireEvent } from '@testing-library/react' +import { useCreateLiveCommandMutation } from '@opentrons/react-api-client' import { i18n } from '../../../../i18n' import { TestShake } from '../TestShake' import { HeaterShakerModuleCard } from '../HeaterShakerModuleCard' import { mockHeaterShaker } from '../../../../redux/modules/__fixtures__' +jest.mock('@opentrons/react-api-client') jest.mock('../HeaterShakerModuleCard') +const mockUseLiveCommandMutation = useCreateLiveCommandMutation as jest.MockedFunction< + typeof useCreateLiveCommandMutation +> + const mockHeaterShakerModuleCard = HeaterShakerModuleCard as jest.MockedFunction< typeof HeaterShakerModuleCard > @@ -18,13 +24,63 @@ const render = (props: React.ComponentProps) => { })[0] } +const mockOpenLatchHeaterShaker = { + model: 'heaterShakerModuleV1', + type: 'heaterShakerModuleType', + port: '/dev/ot_module_heatershaker0', + serial: 'jkl123', + revision: 'heatershaker_v4.0', + fwVersion: 'v2.0.0', + status: 'idle', + hasAvailableUpdate: true, + data: { + labwareLatchStatus: 'idle_open', + speedStatus: 'idle', + temperatureStatus: 'idle', + currentSpeed: null, + currentTemp: null, + targetSpeed: null, + targetTemp: null, + errorDetails: null, + }, + usbPort: { hub: 1, port: 1 }, +} as any + +const mockCloseLatchHeaterShaker = { + model: 'heaterShakerModuleV1', + type: 'heaterShakerModuleType', + port: '/dev/ot_module_heatershaker0', + serial: 'jkl123', + revision: 'heatershaker_v4.0', + fwVersion: 'v2.0.0', + status: 'idle', + hasAvailableUpdate: true, + data: { + labwareLatchStatus: 'idle_closed', + speedStatus: 'idle', + temperatureStatus: 'idle', + currentSpeed: null, + currentTemp: null, + targetSpeed: null, + targetTemp: null, + errorDetails: null, + }, + usbPort: { hub: 1, port: 1 }, +} as any + describe('TestShake', () => { let props: React.ComponentProps + let mockCreateLiveCommand = jest.fn() beforeEach(() => { props = { setCurrentPage: jest.fn(), module: mockHeaterShaker, } + mockCreateLiveCommand = jest.fn() + mockCreateLiveCommand.mockResolvedValue(null) + mockUseLiveCommandMutation.mockReturnValue({ + createLiveCommand: mockCreateLiveCommand, + } as any) mockHeaterShakerModuleCard.mockReturnValue(
Mock Heater Shaker Module Card
) @@ -64,7 +120,7 @@ describe('TestShake', () => { const { getByText, getByRole } = render(props) getByText('Set shake speed') - getByRole('textbox') + getByRole('spinbutton') }) it('renders troubleshooting accordion and contents', () => { @@ -85,4 +141,78 @@ describe('TestShake', () => { const buttonStep2 = getByRole('button', { name: /Go to Step 2/i }) expect(buttonStep2).toBeEnabled() }) + + it('start shake button should be disabled if the labware latch is open', () => { + props = { + module: mockOpenLatchHeaterShaker, + setCurrentPage: jest.fn(), + } + + const { getByRole } = render(props) + const button = getByRole('button', { name: /Start/i }) + expect(button).toBeDisabled() + }) + + it('clicking the open latch button should open the heater shaker latch', () => { + props = { + module: mockCloseLatchHeaterShaker, + setCurrentPage: jest.fn(), + } + + const { getByRole } = render(props) + const button = getByRole('button', { name: /Open Labware Latch/i }) + fireEvent.click(button) + + expect(mockCreateLiveCommand).toHaveBeenCalledWith({ + command: { + commandType: 'heaterShakerModule/openLatch', + params: { + moduleId: mockCloseLatchHeaterShaker.id, + }, + }, + }) + }) + + it('clicking the close latch button should close the heater shaker latch', () => { + props = { + module: mockOpenLatchHeaterShaker, + setCurrentPage: jest.fn(), + } + + const { getByRole } = render(props) + const button = getByRole('button', { name: /Close Labware Latch/i }) + fireEvent.click(button) + + expect(mockCreateLiveCommand).toHaveBeenCalledWith({ + command: { + commandType: 'heaterShakerModule/closeLatch', + params: { + moduleId: mockOpenLatchHeaterShaker.id, + }, + }, + }) + }) + + it('entering an input for shake speed and clicking start should begin shaking', () => { + props = { + module: mockHeaterShaker, + setCurrentPage: jest.fn(), + } + + const { getByRole } = render(props) + const button = getByRole('button', { name: /Start/i }) + const input = getByRole('spinbutton') + fireEvent.change(input, { target: { value: '300' } }) + fireEvent.click(button) + + expect(mockCreateLiveCommand).toHaveBeenCalledWith({ + command: { + commandType: 'heaterShakerModule/setTargetShakeSpeed', + params: { + moduleId: 'heatershaker_id', + rpm: 300, + }, + }, + }) + }) }) diff --git a/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx b/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx index 52e876fa41a..521f86e661a 100644 --- a/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx +++ b/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx @@ -15,10 +15,16 @@ import { } from '@opentrons/components' import { StatusLabel } from '../../../atoms/StatusLabel' +import type { + LatchStatus, + SpeedStatus, + TemperatureStatus, +} from '../../../redux/modules/api-types' + interface HeaterShakerModuleDataProps { - heaterStatus: string - shakerStatus: string - latchStatus: string + heaterStatus: TemperatureStatus + shakerStatus: SpeedStatus + latchStatus: LatchStatus targetTemp: number | null currentTemp: number | null targetSpeed: number | null @@ -39,7 +45,8 @@ export const HeaterShakerModuleData = ( currentSpeed, showTemperatureData, } = props - const { t } = useTranslation(['device_details', 'heater_shaker']) + const { t } = useTranslation(['device_details', 'heater_shaker', 'shared']) + const isShaking = shakerStatus !== 'idle' const getStatusLabelProps = ( status: string | null @@ -68,6 +75,26 @@ export const HeaterShakerModuleData = ( return StatusLabelProps } + const getLatchStatus = (latchStatus: LatchStatus): string => { + switch (latchStatus) { + case 'opening': + case 'idle_open': { + return t('open', { ns: 'shared' }) + } + case 'closing': + case 'idle_closed': { + if (isShaking) { + return t('closed_and_locked', { ns: 'heater_shaker' }) + } else { + return t('closed', { ns: 'heater_shaker' }) + } + } + // TODO(sh, 2022-03-30): potentially add cases for idle_unknown and unknown + default: + return latchStatus + } + } + return ( <> @@ -155,9 +182,14 @@ export const HeaterShakerModuleData = ( alignItems={ALIGN_FLEX_START} > - {/* {TODO(sh, 2022-02-22): Conditionally render icon based on latch status} */} - - {latchStatus} + {isShaking && ( + + )} + {getLatchStatus(latchStatus)} diff --git a/app/src/organisms/Devices/ModuleCard/TestShakeSlideout.tsx b/app/src/organisms/Devices/ModuleCard/TestShakeSlideout.tsx index b3a82d560ff..13ff2204364 100644 --- a/app/src/organisms/Devices/ModuleCard/TestShakeSlideout.tsx +++ b/app/src/organisms/Devices/ModuleCard/TestShakeSlideout.tsx @@ -92,7 +92,7 @@ export const TestShakeSlideout = ( const errorMessage = shakeValue != null && (parseInt(shakeValue) < HS_RPM_MIN || parseInt(shakeValue) > HS_RPM_MAX) - ? t('input_out_of_range') + ? t('input_out_of_range', { ns: 'device_details' }) : null return ( From ef6bc31a91187077b9eb56fc698a5e6f85cc1e2b Mon Sep 17 00:00:00 2001 From: Sakib Hossain Date: Tue, 5 Apr 2022 12:42:35 -0400 Subject: [PATCH 3/5] address PR comments --- .../Devices/HeaterShakerWizard/TestShake.tsx | 36 ++--------- .../__tests__/HeaterShakerWizard.test.tsx | 52 ++++++++++------ .../__tests__/TestShake.test.tsx | 61 ++++++++++++++++++- .../Devices/HeaterShakerWizard/index.tsx | 17 ++---- .../ModuleCard/HeaterShakerModuleData.tsx | 25 ++++++-- 5 files changed, 124 insertions(+), 67 deletions(-) diff --git a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx index 120f7878795..b641271c4e5 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx @@ -17,6 +17,7 @@ import { useHoverTooltip, } from '@opentrons/components' import { RPM, HS_RPM_MAX, HS_RPM_MIN } from '@opentrons/shared-data' +import { useLatchCommand } from '../ModuleCard/hooks' import { HeaterShakerModuleCard } from './HeaterShakerModuleCard' import { TertiaryButton } from '../../../atoms/Buttons' import { CollapsibleStep } from '../../ProtocolSetup/RunSetupCard/CollapsibleStep' @@ -27,8 +28,6 @@ import type { HeaterShakerModule } from '../../../redux/modules/types' import type { HeaterShakerSetTargetShakeSpeedCreateCommand, HeaterShakerStopShakeCreateCommand, - HeaterShakerOpenLatchCreateCommand, - HeaterShakerCloseLatchCreateCommand, } from '@opentrons/shared-data/protocol/types/schemaV6/command/module' interface TestShakeProps { @@ -43,22 +42,9 @@ export function TestShake(props: TestShakeProps): JSX.Element { const [isExpanded, setExpanded] = React.useState(false) const [shakeValue, setShakeValue] = React.useState(null) const [targetProps, tooltipProps] = useHoverTooltip() + const { toggleLatch, isLatchClosed } = useLatchCommand(module) const isShaking = module.data.speedStatus !== 'idle' - const isLatchOpen = - module.data.labwareLatchStatus === 'idle_open' || - module.data.labwareLatchStatus === 'opening' - - const setLatchCommand: - | HeaterShakerOpenLatchCreateCommand - | HeaterShakerCloseLatchCreateCommand = { - commandType: isLatchOpen - ? 'heaterShakerModule/closeLatch' - : 'heaterShakerModule/openLatch', - params: { - moduleId: module.id, - }, - } const setShakeCommand: HeaterShakerSetTargetShakeSpeedCreateCommand = { commandType: 'heaterShakerModule/setTargetShakeSpeed', @@ -75,16 +61,6 @@ export function TestShake(props: TestShakeProps): JSX.Element { }, } - const handleLatchCommand = (): void => { - createLiveCommand({ - command: setLatchCommand, - }).catch((e: Error) => { - console.error( - `error setting module status with command type ${setLatchCommand.commandType}: ${e.message}` - ) - }) - } - const handleShakeCommand = (): void => { if (shakeValue !== null) { createLiveCommand({ @@ -152,11 +128,11 @@ export function TestShake(props: TestShakeProps): JSX.Element { - {isLatchOpen ? t('close_labware_latch') : t('open_labware_latch')} + {isLatchClosed ? t('open_labware_latch') : t('close_labware_latch')} {isShaking ? ( @@ -194,12 +170,12 @@ export function TestShake(props: TestShakeProps): JSX.Element { marginLeft={SIZE_AUTO} marginTop={SPACING.spacing4} onClick={handleShakeCommand} - disabled={isLatchOpen} + disabled={!isLatchClosed} {...targetProps} > {isShaking ? t('stop_shaking') : t('start_shaking')} - {isLatchOpen ? ( + {!isLatchClosed ? ( {t('cannot_shake', { ns: 'heater_shaker' })} diff --git a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx index bc1b6fa64ee..f56bc27b0d8 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx @@ -1,9 +1,11 @@ import * as React from 'react' +import { MemoryRouter } from 'react-router-dom' import { fireEvent } from '@testing-library/react' import { renderWithProviders } from '@opentrons/components' import { i18n } from '../../../../i18n' -import { getAttachedModules } from '../../../../redux/modules' -import { getConnectedRobotName } from '../../../../redux/robot/selectors' +// import { getAttachedModules } from '../../../../redux/modules' +// import { getConnectedRobotName } from '../../../../redux/robot/selectors' +import { useAttachedModules } from '../../hooks' import { mockHeaterShaker } from '../../../../redux/modules/__fixtures__' import { HeaterShakerWizard } from '..' import { Introduction } from '../Introduction' @@ -13,17 +15,22 @@ import { AttachAdapter } from '../AttachAdapter' import { PowerOn } from '../PowerOn' import { TestShake } from '../TestShake' -jest.mock('../../../../redux/robot/selectors') +// jest.mock('../../../../redux/robot/selectors') +jest.mock('../../hooks') jest.mock('../Introduction') jest.mock('../KeyParts') jest.mock('../AttachModule') jest.mock('../AttachAdapter') jest.mock('../PowerOn') jest.mock('../TestShake') -jest.mock('../../../../redux/modules') +// jest.mock('../../../../redux/modules') -const mockGetConnectedRobotName = getConnectedRobotName as jest.MockedFunction< - typeof getConnectedRobotName +// const mockGetConnectedRobotName = getConnectedRobotName as jest.MockedFunction< +// typeof getConnectedRobotName +// > + +const mockUseAttachedModules = useAttachedModules as jest.MockedFunction< + typeof useAttachedModules > const mockIntroduction = Introduction as jest.MockedFunction< typeof Introduction @@ -37,14 +44,22 @@ const mockAttachAdapter = AttachAdapter as jest.MockedFunction< > const mockPowerOn = PowerOn as jest.MockedFunction const mockTestShake = TestShake as jest.MockedFunction -const mockGetAttachedModules = getAttachedModules as jest.MockedFunction< - typeof getAttachedModules -> - -const render = (props: React.ComponentProps) => { - return renderWithProviders(, { - i18nInstance: i18n, - })[0] +// const mockGetAttachedModules = getAttachedModules as jest.MockedFunction< +// typeof getAttachedModules +// > + +const render = ( + props: React.ComponentProps, + path = '/' +) => { + return renderWithProviders( + + + , + { + i18nInstance: i18n, + } + )[0] } describe('HeaterShakerWizard', () => { @@ -52,19 +67,20 @@ describe('HeaterShakerWizard', () => { onCloseClick: jest.fn(), } beforeEach(() => { - mockGetConnectedRobotName.mockReturnValue('Mock Robot') + // mockGetConnectedRobotName.mockReturnValue('Mock Robot') + mockUseAttachedModules.mockReturnValue([mockHeaterShaker]) mockIntroduction.mockReturnValue(
Mock Introduction
) mockKeyParts.mockReturnValue(
Mock Key Parts
) mockAttachModule.mockReturnValue(
Mock Attach Module
) mockAttachAdapter.mockReturnValue(
Mock Attach Adapter
) mockPowerOn.mockReturnValue(
Mock Power On
) mockTestShake.mockReturnValue(
Mock Test Shake
) - mockGetAttachedModules.mockReturnValue([mockHeaterShaker]) + // mockGetAttachedModules.mockReturnValue([mockHeaterShaker]) }) it('renders the main modal component of the wizard', () => { const { getByText } = render(props) - getByText('Mock Robot - Attach Heater Shaker Module') + getByText(/Attach Heater Shaker Module/s) getByText('Mock Introduction') }) @@ -95,7 +111,7 @@ describe('HeaterShakerWizard', () => { }) it('renders power on component and the test shake button is not disabled', () => { - mockGetAttachedModules.mockReturnValue([]) + mockUseAttachedModules.mockReturnValue([]) const { getByText, getByRole } = render(props) diff --git a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx index c09d3a9fb9a..a413cb88d53 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx @@ -25,6 +25,7 @@ const render = (props: React.ComponentProps) => { } const mockOpenLatchHeaterShaker = { + id: 'heatershaker_id', model: 'heaterShakerModuleV1', type: 'heaterShakerModuleType', port: '/dev/ot_module_heatershaker0', @@ -47,6 +48,7 @@ const mockOpenLatchHeaterShaker = { } as any const mockCloseLatchHeaterShaker = { + id: 'heatershaker_id', model: 'heaterShakerModuleV1', type: 'heaterShakerModuleType', port: '/dev/ot_module_heatershaker0', @@ -68,6 +70,29 @@ const mockCloseLatchHeaterShaker = { usbPort: { hub: 1, port: 1 }, } as any +const mockMovingHeaterShaker = { + id: 'heatershaker_id', + model: 'heaterShakerModuleV1', + type: 'heaterShakerModuleType', + port: '/dev/ot_module_thermocycler0', + serial: 'jkl123', + revision: 'heatershaker_v4.0', + fwVersion: 'v2.0.0', + status: 'idle', + hasAvailableUpdate: true, + data: { + labwareLatchStatus: 'idle_closed', + speedStatus: 'speeding up', + temperatureStatus: 'idle', + currentSpeed: null, + currentTemp: null, + targetSpeed: null, + targetTemp: null, + errorDetails: null, + }, + usbPort: { hub: 1, port: 1 }, +} as any + describe('TestShake', () => { let props: React.ComponentProps let mockCreateLiveCommand = jest.fn() @@ -105,12 +130,22 @@ describe('TestShake', () => { }) it('renders the open labware latch button and is enabled', () => { + props = { + module: mockCloseLatchHeaterShaker, + setCurrentPage: jest.fn(), + } + const { getByRole } = render(props) const button = getByRole('button', { name: /Open Labware Latch/i }) expect(button).toBeEnabled() }) it('renders the start shaking button and is enabled', () => { + props = { + module: mockCloseLatchHeaterShaker, + setCurrentPage: jest.fn(), + } + const { getByRole } = render(props) const button = getByRole('button', { name: /Start Shaking/i }) expect(button).toBeEnabled() @@ -195,12 +230,12 @@ describe('TestShake', () => { it('entering an input for shake speed and clicking start should begin shaking', () => { props = { - module: mockHeaterShaker, + module: mockCloseLatchHeaterShaker, setCurrentPage: jest.fn(), } const { getByRole } = render(props) - const button = getByRole('button', { name: /Start/i }) + const button = getByRole('button', { name: /Start Shaking/i }) const input = getByRole('spinbutton') fireEvent.change(input, { target: { value: '300' } }) fireEvent.click(button) @@ -215,4 +250,26 @@ describe('TestShake', () => { }, }) }) + + it('when the heater shaker is shaking clicking stop should deactivate the shaking', () => { + props = { + module: mockMovingHeaterShaker, + setCurrentPage: jest.fn(), + } + + const { getByRole } = render(props) + const button = getByRole('button', { name: /Stop Shaking/i }) + const input = getByRole('spinbutton') + fireEvent.change(input, { target: { value: '0' } }) + fireEvent.click(button) + + expect(mockCreateLiveCommand).toHaveBeenCalledWith({ + command: { + commandType: 'heaterShakerModule/stopShake', + params: { + moduleId: mockHeaterShaker.id, + }, + }, + }) + }) }) diff --git a/app/src/organisms/Devices/HeaterShakerWizard/index.tsx b/app/src/organisms/Devices/HeaterShakerWizard/index.tsx index 7240d449ac2..1075f00879a 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/index.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/index.tsx @@ -1,13 +1,9 @@ import * as React from 'react' +import { useParams } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { Portal } from '../../../App/portal' -import { useSelector } from 'react-redux' -import { getConnectedRobotName } from '../../../redux/robot/selectors' import { Interstitial } from '../../../atoms/Interstitial/Interstitial' -import { - getAttachedModules, - HEATERSHAKER_MODULE_TYPE, -} from '../../../redux/modules' +import { HEATERSHAKER_MODULE_TYPE } from '../../../redux/modules' import { PrimaryButton, SecondaryButton } from '../../../atoms/Buttons' import { Introduction } from './Introduction' import { KeyParts } from './KeyParts' @@ -24,8 +20,9 @@ import { useHoverTooltip, } from '@opentrons/components' -import type { State } from '../../../redux/types' +import type { NextGenRouteParams } from '../../../App/NextGenApp' import type { HeaterShakerModule } from '../../../redux/modules/types' +import { useAttachedModules } from '../hooks' interface HeaterShakerWizardProps { onCloseClick: () => unknown @@ -37,10 +34,8 @@ export const HeaterShakerWizard = ( const { onCloseClick } = props const { t } = useTranslation(['heater_shaker', 'shared']) const [currentPage, setCurrentPage] = React.useState(0) - const robotName = useSelector((state: State) => getConnectedRobotName(state)) - const attachedModules = useSelector((state: State) => - getAttachedModules(state, robotName === null ? null : robotName) - ) + const { robotName } = useParams() + const attachedModules = useAttachedModules(robotName) const [targetProps, tooltipProps] = useHoverTooltip() const heaterShaker = (attachedModules.find( diff --git a/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx b/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx index 521f86e661a..793e3f12ff9 100644 --- a/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx +++ b/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx @@ -12,6 +12,7 @@ import { Icon, DIRECTION_ROW, TYPOGRAPHY, + TEXT_TRANSFORM_CAPITALIZE, } from '@opentrons/components' import { StatusLabel } from '../../../atoms/StatusLabel' @@ -75,21 +76,33 @@ export const HeaterShakerModuleData = ( return StatusLabelProps } - const getLatchStatus = (latchStatus: LatchStatus): string => { + const getLatchStatus = (latchStatus: LatchStatus): JSX.Element | string => { switch (latchStatus) { case 'opening': - case 'idle_open': { - return t('open', { ns: 'shared' }) + case 'idle_open': + case 'idle_unknown': { + return ( + + {t('open', { ns: 'shared' })} + + ) } case 'closing': case 'idle_closed': { if (isShaking) { - return t('closed_and_locked', { ns: 'heater_shaker' }) + return ( + + {t('closed_and_locked', { ns: 'heater_shaker' })} + + ) } else { - return t('closed', { ns: 'heater_shaker' }) + return ( + + {t('closed', { ns: 'heater_shaker' })} + + ) } } - // TODO(sh, 2022-03-30): potentially add cases for idle_unknown and unknown default: return latchStatus } From 97d77e5633b64b44f67134ec1b582940e63454eb Mon Sep 17 00:00:00 2001 From: Sakib Hossain Date: Tue, 5 Apr 2022 15:05:39 -0400 Subject: [PATCH 4/5] update tests and inputfield component --- .../assets/localization/en/heater_shaker.json | 2 +- app/src/atoms/InputField/index.tsx | 5 + .../Devices/HeaterShakerWizard/TestShake.tsx | 34 +++++- .../__tests__/HeaterShakerWizard.test.tsx | 15 +-- .../__tests__/TestShake.test.tsx | 105 ++++++++++++++---- .../Devices/HeaterShakerWizard/index.tsx | 9 +- .../__tests__/ConfirmAttachmentModal.test.tsx | 2 +- .../__tests__/HeaterShakerModuleData.test.tsx | 6 +- .../HeaterShakerBanner.tsx | 5 +- 9 files changed, 132 insertions(+), 51 deletions(-) diff --git a/app/src/assets/localization/en/heater_shaker.json b/app/src/assets/localization/en/heater_shaker.json index 76c74478bde..7d8b250838a 100644 --- a/app/src/assets/localization/en/heater_shaker.json +++ b/app/src/assets/localization/en/heater_shaker.json @@ -29,7 +29,6 @@ "check_alignment": "Check alignment.", "a_properly_attached_adapter": "A properly attached adapter will sit evenly on the module.", "check_alignment_instructions": "Check attachment by rocking the adapter back and forth.", - "modal_title": "{{name}} - Attach Heater Shaker Module", "intro_title": "Use this guide to attach the Heater Shaker Module to your robot’s deck for secure shaking.", "intro_subtitle": "You will need:", "intro_heater_shaker_mod": "Heater Shaker Module", @@ -58,6 +57,7 @@ "heater_shaker_anchor_description": "The 2 Anchors keep the module attached to the deck while it is shaking. The screw above each anchor is used to extend and retract them. See animation below. Extending the bolts slightly increases the module’s footprint, which allows it to be more firmly attached to the edges of a slot.", "step_4_of_4": "Step 4 of 4: Test shake", "test_shake_banner_information": "If you want to add labware to the module before doing a test shake, you can use the labware latch controls to hold the latches open.", + "test_shake_banner_labware_information": "If you want to add the {{labware}} to the module before doing a test shake, you can use the labware latch controls.", "open_labware_latch": "Open Labware Latch", "close_labware_latch": "Close Labware Latch", "labware_latch": "Labware Latch", diff --git a/app/src/atoms/InputField/index.tsx b/app/src/atoms/InputField/index.tsx index 8fe2d80c8db..39d62bd2881 100644 --- a/app/src/atoms/InputField/index.tsx +++ b/app/src/atoms/InputField/index.tsx @@ -113,6 +113,11 @@ function Input(props: InputFieldProps): JSX.Element { &:disabled { border: ${SPACING.spacingXXS} ${BORDERS.styleSolid} ${COLORS.greyDisabled}; } + input[type='number']::-webkit-inner-spin-button, + input[type='number']::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } ` return ( diff --git a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx index b641271c4e5..f932c859fa9 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/TestShake.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { useTranslation } from 'react-i18next' +import { Trans, useTranslation } from 'react-i18next' import { useCreateLiveCommandMutation } from '@opentrons/react-api-client' import { ALIGN_CENTER, @@ -17,7 +17,10 @@ import { useHoverTooltip, } from '@opentrons/components' import { RPM, HS_RPM_MAX, HS_RPM_MIN } from '@opentrons/shared-data' -import { useLatchCommand } from '../ModuleCard/hooks' +import { + useHeaterShakerFromProtocol, + useLatchCommand, +} from '../ModuleCard/hooks' import { HeaterShakerModuleCard } from './HeaterShakerModuleCard' import { TertiaryButton } from '../../../atoms/Buttons' import { CollapsibleStep } from '../../ProtocolSetup/RunSetupCard/CollapsibleStep' @@ -33,17 +36,18 @@ import type { interface TestShakeProps { module: HeaterShakerModule setCurrentPage: React.Dispatch> + hasProtocol: boolean | undefined } export function TestShake(props: TestShakeProps): JSX.Element { - const { module, setCurrentPage } = props + const { module, setCurrentPage, hasProtocol } = props const { t } = useTranslation(['heater_shaker', 'device_details']) const { createLiveCommand } = useCreateLiveCommandMutation() + const heaterShakerFromProtocol = useHeaterShakerFromProtocol() const [isExpanded, setExpanded] = React.useState(false) const [shakeValue, setShakeValue] = React.useState(null) const [targetProps, tooltipProps] = useHoverTooltip() const { toggleLatch, isLatchClosed } = useLatchCommand(module) - const isShaking = module.data.speedStatus !== 'idle' const setShakeCommand: HeaterShakerSetTargetShakeSpeedCreateCommand = { @@ -114,8 +118,26 @@ export function TestShake(props: TestShakeProps): JSX.Element { paddingBottom={SPACING.spacing4} > - {/* TODO(sh, 2022-02-22): Dynamically render this text if a labware/protocol exists */} - {t('test_shake_banner_information')} + , + block: ( + + ), + }} + /> diff --git a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx index f56bc27b0d8..2014f93fe4a 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/HeaterShakerWizard.test.tsx @@ -3,8 +3,6 @@ import { MemoryRouter } from 'react-router-dom' import { fireEvent } from '@testing-library/react' import { renderWithProviders } from '@opentrons/components' import { i18n } from '../../../../i18n' -// import { getAttachedModules } from '../../../../redux/modules' -// import { getConnectedRobotName } from '../../../../redux/robot/selectors' import { useAttachedModules } from '../../hooks' import { mockHeaterShaker } from '../../../../redux/modules/__fixtures__' import { HeaterShakerWizard } from '..' @@ -15,7 +13,6 @@ import { AttachAdapter } from '../AttachAdapter' import { PowerOn } from '../PowerOn' import { TestShake } from '../TestShake' -// jest.mock('../../../../redux/robot/selectors') jest.mock('../../hooks') jest.mock('../Introduction') jest.mock('../KeyParts') @@ -23,11 +20,6 @@ jest.mock('../AttachModule') jest.mock('../AttachAdapter') jest.mock('../PowerOn') jest.mock('../TestShake') -// jest.mock('../../../../redux/modules') - -// const mockGetConnectedRobotName = getConnectedRobotName as jest.MockedFunction< -// typeof getConnectedRobotName -// > const mockUseAttachedModules = useAttachedModules as jest.MockedFunction< typeof useAttachedModules @@ -44,9 +36,6 @@ const mockAttachAdapter = AttachAdapter as jest.MockedFunction< > const mockPowerOn = PowerOn as jest.MockedFunction const mockTestShake = TestShake as jest.MockedFunction -// const mockGetAttachedModules = getAttachedModules as jest.MockedFunction< -// typeof getAttachedModules -// > const render = ( props: React.ComponentProps, @@ -67,7 +56,6 @@ describe('HeaterShakerWizard', () => { onCloseClick: jest.fn(), } beforeEach(() => { - // mockGetConnectedRobotName.mockReturnValue('Mock Robot') mockUseAttachedModules.mockReturnValue([mockHeaterShaker]) mockIntroduction.mockReturnValue(
Mock Introduction
) mockKeyParts.mockReturnValue(
Mock Key Parts
) @@ -75,12 +63,11 @@ describe('HeaterShakerWizard', () => { mockAttachAdapter.mockReturnValue(
Mock Attach Adapter
) mockPowerOn.mockReturnValue(
Mock Power On
) mockTestShake.mockReturnValue(
Mock Test Shake
) - // mockGetAttachedModules.mockReturnValue([mockHeaterShaker]) }) it('renders the main modal component of the wizard', () => { const { getByText } = render(props) - getByText(/Attach Heater Shaker Module/s) + getByText(/Attach Heater Shaker Module/i) getByText('Mock Introduction') }) diff --git a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx index a413cb88d53..038b6e18f59 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/__tests__/TestShake.test.tsx @@ -1,19 +1,32 @@ import * as React from 'react' -import { renderWithProviders } from '@opentrons/components' +import { nestedTextMatcher, renderWithProviders } from '@opentrons/components' import { fireEvent } from '@testing-library/react' import { useCreateLiveCommandMutation } from '@opentrons/react-api-client' +import { + useHeaterShakerFromProtocol, + useLatchCommand, +} from '../../ModuleCard/hooks' import { i18n } from '../../../../i18n' import { TestShake } from '../TestShake' import { HeaterShakerModuleCard } from '../HeaterShakerModuleCard' +import heaterShakerCommands from '@opentrons/shared-data/protocol/fixtures/6/heaterShakerCommands.json' import { mockHeaterShaker } from '../../../../redux/modules/__fixtures__' +import type { ProtocolModuleInfo } from '../../../ProtocolSetup/utils/getProtocolModulesInfo' + jest.mock('@opentrons/react-api-client') jest.mock('../HeaterShakerModuleCard') +jest.mock('../../ModuleCard/hooks') const mockUseLiveCommandMutation = useCreateLiveCommandMutation as jest.MockedFunction< typeof useCreateLiveCommandMutation > - +const mockUseLatchCommand = useLatchCommand as jest.MockedFunction< + typeof useLatchCommand +> +const mockUseHeaterShakerFromProtocol = useHeaterShakerFromProtocol as jest.MockedFunction< + typeof useHeaterShakerFromProtocol +> const mockHeaterShakerModuleCard = HeaterShakerModuleCard as jest.MockedFunction< typeof HeaterShakerModuleCard > @@ -24,6 +37,19 @@ const render = (props: React.ComponentProps) => { })[0] } +const HEATER_SHAKER_PROTOCOL_MODULE_INFO = { + moduleId: 'heater_shaker_id', + x: 0, + y: 0, + z: 0, + moduleDef: mockHeaterShaker as any, + nestedLabwareDef: heaterShakerCommands.labwareDefinitions['example/plate/1'], + nestedLabwareDisplayName: 'Source Plate', + nestedLabwareId: null, + protocolLoadOrder: 1, + slotName: '1', +} as ProtocolModuleInfo + const mockOpenLatchHeaterShaker = { id: 'heatershaker_id', model: 'heaterShakerModuleV1', @@ -100,6 +126,7 @@ describe('TestShake', () => { props = { setCurrentPage: jest.fn(), module: mockHeaterShaker, + hasProtocol: false, } mockCreateLiveCommand = jest.fn() mockCreateLiveCommand.mockResolvedValue(null) @@ -109,6 +136,13 @@ describe('TestShake', () => { mockHeaterShakerModuleCard.mockReturnValue(
Mock Heater Shaker Module Card
) + mockUseLatchCommand.mockReturnValue({ + handleLatch: jest.fn(), + isLatchClosed: true, + } as any) + mockUseHeaterShakerFromProtocol.mockReturnValue( + HEATER_SHAKER_PROTOCOL_MODULE_INFO + ) }) it('renders the correct title', () => { const { getByText } = render(props) @@ -123,20 +157,40 @@ describe('TestShake', () => { ) }) + it('renders labware name in the banner description when there is a protocol', () => { + props = { + setCurrentPage: jest.fn(), + module: mockHeaterShaker, + hasProtocol: true, + } + const { getByText } = render(props) + getByText( + nestedTextMatcher( + 'If you want to add the Source Plate to the module before doing a test shake, you can use the labware latch controls.' + ) + ) + }) + it('renders a heater shaker module card', () => { const { getByText } = render(props) getByText('Mock Heater Shaker Module Card') }) - it('renders the open labware latch button and is enabled', () => { + it('renders the close labware latch button and is enabled when latch status is open', () => { props = { - module: mockCloseLatchHeaterShaker, + module: mockHeaterShaker, setCurrentPage: jest.fn(), + hasProtocol: false, } + mockUseLatchCommand.mockReturnValue({ + toggleLatch: jest.fn(), + isLatchClosed: false, + }) + const { getByRole } = render(props) - const button = getByRole('button', { name: /Open Labware Latch/i }) + const button = getByRole('button', { name: /Close Labware Latch/i }) expect(button).toBeEnabled() }) @@ -144,6 +198,7 @@ describe('TestShake', () => { props = { module: mockCloseLatchHeaterShaker, setCurrentPage: jest.fn(), + hasProtocol: false, } const { getByRole } = render(props) @@ -181,8 +236,14 @@ describe('TestShake', () => { props = { module: mockOpenLatchHeaterShaker, setCurrentPage: jest.fn(), + hasProtocol: false, } + mockUseLatchCommand.mockReturnValue({ + toggleLatch: jest.fn(), + isLatchClosed: false, + }) + const { getByRole } = render(props) const button = getByRole('button', { name: /Start/i }) expect(button).toBeDisabled() @@ -192,46 +253,43 @@ describe('TestShake', () => { props = { module: mockCloseLatchHeaterShaker, setCurrentPage: jest.fn(), + hasProtocol: false, } + mockUseLatchCommand.mockReturnValue({ + toggleLatch: jest.fn(), + isLatchClosed: true, + }) + const { getByRole } = render(props) const button = getByRole('button', { name: /Open Labware Latch/i }) fireEvent.click(button) - - expect(mockCreateLiveCommand).toHaveBeenCalledWith({ - command: { - commandType: 'heaterShakerModule/openLatch', - params: { - moduleId: mockCloseLatchHeaterShaker.id, - }, - }, - }) + expect(mockUseLatchCommand).toHaveBeenCalled() }) it('clicking the close latch button should close the heater shaker latch', () => { props = { module: mockOpenLatchHeaterShaker, setCurrentPage: jest.fn(), + hasProtocol: false, } + mockUseLatchCommand.mockReturnValue({ + toggleLatch: jest.fn(), + isLatchClosed: false, + }) + const { getByRole } = render(props) const button = getByRole('button', { name: /Close Labware Latch/i }) fireEvent.click(button) - - expect(mockCreateLiveCommand).toHaveBeenCalledWith({ - command: { - commandType: 'heaterShakerModule/closeLatch', - params: { - moduleId: mockOpenLatchHeaterShaker.id, - }, - }, - }) + expect(mockUseLatchCommand).toHaveBeenCalled() }) it('entering an input for shake speed and clicking start should begin shaking', () => { props = { module: mockCloseLatchHeaterShaker, setCurrentPage: jest.fn(), + hasProtocol: false, } const { getByRole } = render(props) @@ -255,6 +313,7 @@ describe('TestShake', () => { props = { module: mockMovingHeaterShaker, setCurrentPage: jest.fn(), + hasProtocol: false, } const { getByRole } = render(props) diff --git a/app/src/organisms/Devices/HeaterShakerWizard/index.tsx b/app/src/organisms/Devices/HeaterShakerWizard/index.tsx index 1075f00879a..b1076613b05 100644 --- a/app/src/organisms/Devices/HeaterShakerWizard/index.tsx +++ b/app/src/organisms/Devices/HeaterShakerWizard/index.tsx @@ -26,12 +26,13 @@ import { useAttachedModules } from '../hooks' interface HeaterShakerWizardProps { onCloseClick: () => unknown + hasProtocol?: boolean } export const HeaterShakerWizard = ( props: HeaterShakerWizardProps ): JSX.Element | null => { - const { onCloseClick } = props + const { onCloseClick, hasProtocol } = props const { t } = useTranslation(['heater_shaker', 'shared']) const [currentPage, setCurrentPage] = React.useState(0) const { robotName } = useParams() @@ -73,7 +74,11 @@ export const HeaterShakerWizard = ( case 5: buttonContent = t('complete') return ( - + ) default: return null diff --git a/app/src/organisms/Devices/ModuleCard/__tests__/ConfirmAttachmentModal.test.tsx b/app/src/organisms/Devices/ModuleCard/__tests__/ConfirmAttachmentModal.test.tsx index 998f8bb2427..a1dc8cfacf9 100644 --- a/app/src/organisms/Devices/ModuleCard/__tests__/ConfirmAttachmentModal.test.tsx +++ b/app/src/organisms/Devices/ModuleCard/__tests__/ConfirmAttachmentModal.test.tsx @@ -70,7 +70,7 @@ describe('ConfirmAttachmentBanner', () => { expect(props.onCloseClick).toHaveBeenCalled() }) - it('renders the correct modal info when accessed through proceed to run CTA and clicks proceed to run button ', () => { + it('renders the correct modal info when accessed through proceed to run CTA and clicks proceed to run button', () => { props = { onCloseClick: jest.fn(), isProceedToRunModal: true, diff --git a/app/src/organisms/Devices/ModuleCard/__tests__/HeaterShakerModuleData.test.tsx b/app/src/organisms/Devices/ModuleCard/__tests__/HeaterShakerModuleData.test.tsx index 289c11b8454..46fb26c464a 100644 --- a/app/src/organisms/Devices/ModuleCard/__tests__/HeaterShakerModuleData.test.tsx +++ b/app/src/organisms/Devices/ModuleCard/__tests__/HeaterShakerModuleData.test.tsx @@ -73,8 +73,8 @@ describe('HeaterShakerModuleData', () => { it('renders a shaking status', () => { props = { - heaterStatus: 'shaking', - shakerStatus: 'idle', + heaterStatus: 'idle', + shakerStatus: 'speeding up', latchStatus: 'idle_unknown', targetTemp: null, currentTemp: null, @@ -93,6 +93,6 @@ describe('HeaterShakerModuleData', () => { const { getByText } = render(props) getByText('Target: N/A RPM') getByText('Labware Latch') - getByText('idle_unknown') + getByText(/Open/i) }) }) diff --git a/app/src/organisms/ProtocolSetup/RunSetupCard/ModuleSetup/HeaterShakerSetupWizard/HeaterShakerBanner.tsx b/app/src/organisms/ProtocolSetup/RunSetupCard/ModuleSetup/HeaterShakerSetupWizard/HeaterShakerBanner.tsx index c007965c4fc..3cc04454c6c 100644 --- a/app/src/organisms/ProtocolSetup/RunSetupCard/ModuleSetup/HeaterShakerSetupWizard/HeaterShakerBanner.tsx +++ b/app/src/organisms/ProtocolSetup/RunSetupCard/ModuleSetup/HeaterShakerSetupWizard/HeaterShakerBanner.tsx @@ -17,7 +17,10 @@ export function HeaterShakerBanner( return ( <> {showWizard && ( - setShowWizard(false)} /> + setShowWizard(false)} + hasProtocol={true} + /> )} Date: Tue, 5 Apr 2022 15:09:40 -0400 Subject: [PATCH 5/5] add size constant --- .../organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx b/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx index 74f50f65486..6226f0631d8 100644 --- a/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx +++ b/app/src/organisms/Devices/ModuleCard/HeaterShakerModuleData.tsx @@ -14,6 +14,7 @@ import { TYPOGRAPHY, C_SKY_BLUE, TEXT_TRANSFORM_CAPITALIZE, + SIZE_1, } from '@opentrons/components' import { StatusLabel } from '../../../atoms/StatusLabel' @@ -206,7 +207,7 @@ export const HeaterShakerModuleData = ( )} {getLatchStatus(latchStatus)}