Skip to content

Commit

Permalink
feat(labware-creator): add dynamic footprint copy for tip racks (#7861)
Browse files Browse the repository at this point in the history
* feat(labware-creator): add dynamic footprint copy for tip racks

fix #7715

* feat(labware-creator): tests for dynamic footprint copy

fix 7715

* remove comment
  • Loading branch information
smb2268 authored Jun 1, 2021
1 parent d00cbf9 commit 5bb265f
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 103 deletions.
28 changes: 15 additions & 13 deletions labware-library/src/labware-creator/components/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,21 @@ export const TextField = (props: Props): JSX.Element => {
{({ field, form }: FieldProps) =>
getIsHidden(props.name, form.values) ? null : (
<div className={fieldStyles.field_wrapper}>
<div className={fieldStyles.field_label}>{LABELS[name]}</div>
<InputField
name={field.name}
value={field.value}
caption={caption}
placeholder={placeholder}
onChange={makeHandleChange({ field, form })}
onBlur={(e: React.FocusEvent<HTMLInputElement>) => {
reportFieldEdit({ value: field.value, name: field.name })
field.onBlur(e)
}}
units={units}
/>
<label className={fieldStyles.field_label}>
{LABELS[name]}
<InputField
name={field.name}
value={field.value}
caption={caption}
placeholder={placeholder}
onChange={makeHandleChange({ field, form })}
onBlur={(e: React.FocusEvent<HTMLInputElement>) => {
reportFieldEdit({ value: field.value, name: field.name })
field.onBlur(e)
}}
units={units}
/>
</label>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,76 +1,27 @@
import React from 'react'
import '@testing-library/jest-dom'
import { FormikConfig } from 'formik'
import isEqual from 'lodash/isEqual'
import { when } from 'jest-when'
import { render, screen } from '@testing-library/react'
import { getDefaultFormState, LabwareFields } from '../../../fields'
import { Footprint } from '../../sections/Footprint'
import { FormAlerts } from '../../alerts/FormAlerts'
import { XYDimensionAlerts } from '../../alerts/XYDimensionAlerts'
import { TextField } from '../../TextField'
import { wrapInFormik } from '../../utils/wrapInFormik'

import { isEveryFieldHidden } from '../../../utils'
import { nestedTextMatcher } from '../../__testUtils__/nestedTextMatcher'

jest.mock('../../TextField')
jest.mock('../../alerts/FormAlerts')
jest.mock('../../alerts/XYDimensionAlerts')
jest.mock('../../../utils')

const FormAlertsMock = FormAlerts as jest.MockedFunction<typeof FormAlerts>
const textFieldMock = TextField as jest.MockedFunction<typeof TextField>
const isEveryFieldHiddenMock = isEveryFieldHidden as jest.MockedFunction<
typeof isEveryFieldHidden
>

const XYDimensionAlertsMock = XYDimensionAlerts as jest.MockedFunction<
typeof XYDimensionAlerts
>

const formikConfig: FormikConfig<LabwareFields> = {
initialValues: getDefaultFormState(),
onSubmit: jest.fn(),
}

describe('Footprint', () => {
beforeEach(() => {
textFieldMock.mockImplementation(args => {
if (args.name === 'footprintXDimension') {
return <div>footprintXDimension text field</div>
}
if (args.name === 'footprintYDimension') {
return <div>footprintYDimension text field</div>
}
return <div></div>
})

FormAlertsMock.mockImplementation(args => {
if (
isEqual(args, {
touched: {},
errors: {},
fieldList: ['footprintXDimension', 'footprintYDimension'],
})
) {
return <div>mock alerts</div>
} else {
return <div></div>
}
})

XYDimensionAlertsMock.mockImplementation(args => {
if (
isEqual(args, {
values: formikConfig.initialValues,
touched: {},
})
) {
return <div>mock XYDimensionAlertsMock alerts</div>
} else {
return <div></div>
}
})

when(isEveryFieldHiddenMock)
.calledWith(
['footprintXDimension', 'footprintYDimension'],
Expand All @@ -84,17 +35,59 @@ describe('Footprint', () => {
})
it('should render alerts and text fields when fields are visible', () => {
render(wrapInFormik(<Footprint />, formikConfig))
expect(screen.getByText('Footprint'))
expect(screen.getByRole('heading')).toHaveTextContent(/total footprint/i)
screen.getByText(
`The footprint measurement helps determine if the labware (in adapter if needed) fits firmly into the slots on the OT-2 deck.`
)
const textBoxElements = screen.getAllByRole('textbox')
expect(textBoxElements).toHaveLength(2)
screen.getByRole('textbox', { name: /Length/i })
screen.getByRole('textbox', { name: /Width/i })
})

it('should render correct copy when tipRack is selected', () => {
formikConfig.initialValues.labwareType = 'tipRack'
render(wrapInFormik(<Footprint />, formikConfig))

expect(
screen.getByText(
'The footprint measurement helps determine if the labware fits firmly into the slots on the OT-2 deck.'
nestedTextMatcher(
'If your Tip Rack has an adapter, place it in the adapter.'
)
)
).toBeInTheDocument()
})

it('should not render extra copy when tipRack is not selected', () => {
formikConfig.initialValues.labwareType = 'wellPlate'
render(wrapInFormik(<Footprint />, formikConfig))
expect(
screen.queryByText(
nestedTextMatcher(
'If your Tip Rack has an adapter, place it in the adapter.'
)
)
).toBe(null)
})

it('should render form alert when error is present', () => {
const FAKE_ERROR = 'ahh'
formikConfig.initialErrors = { footprintXDimension: FAKE_ERROR }
formikConfig.initialTouched = { footprintXDimension: true }
render(wrapInFormik(<Footprint />, formikConfig))
screen.getByText(FAKE_ERROR)
})

it('should render xydimension alert when error is present', () => {
formikConfig.initialValues.footprintXDimension = '130'
formikConfig.initialTouched = { footprintXDimension: true }
const { container } = render(wrapInFormik(<Footprint />, formikConfig))
const error = container.querySelector('[class="alert info"]')
expect(error?.textContent).toBe(
'Our recommended footprint for labware is 127.76 by 85.47 +/- 1mm. If you can fit your labware snugly into a single slot on the deck continue through the form. If not please request custom labware via this form.'
)
expect(screen.getByText('mock alerts'))
expect(screen.getByText('footprintXDimension text field'))
expect(screen.getByText('footprintYDimension text field'))
expect(screen.getByText('mock XYDimensionAlertsMock alerts'))
})

it('should not render when all fields are hidden', () => {
when(isEveryFieldHiddenMock)
.calledWith(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,51 @@ import styles from '../../styles.css'

const maskTo2Decimal = makeMaskToDecimal(2)

const Content = (): JSX.Element => (
<div className={styles.flex_row}>
<div className={styles.instructions_column}>
<p>
Ensure measurement is taken from the <strong>very bottom</strong> of
plate.
</p>
<p>
The footprint measurement helps determine if the labware fits firmly
into the slots on the OT-2 deck.
</p>
</div>
<div className={styles.diagram_column}>
<img
src={require('../../images/footprint.svg')}
alt="labware footprint"
/>
</div>
<div className={styles.form_fields_column}>
<TextField
name="footprintXDimension"
inputMasks={[maskTo2Decimal]}
units="mm"
/>
<TextField
name="footprintYDimension"
inputMasks={[maskTo2Decimal]}
units="mm"
/>
interface ContentProps {
values: LabwareFields
}
const Content = (props: ContentProps): JSX.Element => {
const { values } = props

return (
<div className={styles.flex_row}>
<div className={styles.instructions_column}>
{values.labwareType === 'tipRack' && (
<p>
If your Tip Rack has an adapter,{' '}
<strong>place it in the adapter.</strong>
</p>
)}
<p>
Ensure measurement is taken from the <strong>very bottom</strong> of
labware.
</p>
<p>
The footprint measurement helps determine if the labware (in adapter
if needed) fits firmly into the slots on the OT-2 deck.
</p>
</div>
<div className={styles.diagram_column}>
<img
src={require('../../images/footprint.svg')}
alt="labware footprint"
/>
</div>
<div className={styles.form_fields_column}>
<TextField
name="footprintXDimension"
inputMasks={[maskTo2Decimal]}
units="mm"
/>
<TextField
name="footprintYDimension"
inputMasks={[maskTo2Decimal]}
units="mm"
/>
</div>
</div>
</div>
)
)
}

export const Footprint = (): JSX.Element | null => {
const fieldList: Array<keyof LabwareFields> = [
Expand All @@ -58,11 +71,11 @@ export const Footprint = (): JSX.Element | null => {

return (
<div className={styles.new_definition_section}>
<SectionBody label="Footprint" id="Footprint">
<SectionBody label="Total Footprint" id="Footprint">
<>
<FormAlerts touched={touched} errors={errors} fieldList={fieldList} />
<XYDimensionAlerts values={values} touched={touched} />
<Content />
<Content values={values} />
</>
</SectionBody>
</div>
Expand Down

0 comments on commit 5bb265f

Please sign in to comment.