-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(labware-creator): Break out spacing and offset sections (#7798)
closes #7707
- Loading branch information
Showing
6 changed files
with
439 additions
and
83 deletions.
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
labware-library/src/labware-creator/components/__testUtils__/nestedTextMatcher.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type { Matcher } from '@testing-library/react' | ||
|
||
// Match things like <p>Some <strong>nested</strong> text</p> | ||
// Use with either string match: getByText(nestedTextMatcher("Some nested text")) | ||
// or regexp: getByText(nestedTextMatcher(/Some nested text/)) | ||
export const nestedTextMatcher = (textMatch: string | RegExp): Matcher => ( | ||
content, | ||
node | ||
) => { | ||
const hasText = (n: typeof node): boolean => { | ||
if (n == null || n.textContent === null) return false | ||
return typeof textMatch === 'string' | ||
? n?.textContent === textMatch | ||
: textMatch.test(n.textContent) | ||
} | ||
const nodeHasText = hasText(node) | ||
const childrenDontHaveText = | ||
node != null && Array.from(node.children).every(child => !hasText(child)) | ||
|
||
return nodeHasText && childrenDontHaveText | ||
} |
127 changes: 127 additions & 0 deletions
127
labware-library/src/labware-creator/components/__tests__/sections/GridOffset.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import React from 'react' | ||
import { FormikConfig } from 'formik' | ||
import isEqual from 'lodash/isEqual' | ||
import { when } from 'jest-when' | ||
import { render, screen } from '@testing-library/react' | ||
import { nestedTextMatcher } from '../../__testUtils__/nestedTextMatcher' | ||
import { getDefaultFormState, LabwareFields } from '../../../fields' | ||
import { isEveryFieldHidden } from '../../../utils' | ||
import { GridOffset } from '../../sections/GridOffset' | ||
import { FormAlerts } from '../../FormAlerts' | ||
import { TextField } from '../../TextField' | ||
import { wrapInFormik } from '../../utils/wrapInFormik' | ||
jest.mock('../../../utils') | ||
jest.mock('../../TextField') | ||
jest.mock('../../FormAlerts') | ||
|
||
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 formikConfig: FormikConfig<LabwareFields> = { | ||
initialValues: getDefaultFormState(), | ||
onSubmit: jest.fn(), | ||
} | ||
|
||
describe('GridOffset', () => { | ||
beforeEach(() => { | ||
textFieldMock.mockImplementation(args => { | ||
if (args.name === 'gridOffsetX') { | ||
return <div>gridOffsetX text field</div> | ||
} | ||
if (args.name === 'gridOffsetY') { | ||
return <div>gridOffsetY text field</div> | ||
} else { | ||
return <div></div> | ||
} | ||
}) | ||
|
||
FormAlertsMock.mockImplementation(args => { | ||
if ( | ||
isEqual(args, { | ||
touched: {}, | ||
errors: {}, | ||
fieldList: ['gridOffsetX', 'gridOffsetY'], | ||
}) | ||
) { | ||
return <div>mock alerts</div> | ||
} else { | ||
return <div></div> | ||
} | ||
}) | ||
}) | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks() | ||
}) | ||
|
||
it('should render when fields are visible', () => { | ||
render(wrapInFormik(<GridOffset />, formikConfig)) | ||
expect(screen.getByText('Grid Offset')) | ||
expect(screen.getByText('mock alerts')) | ||
expect( | ||
screen.getByText( | ||
"Corner offset informs the robot how far the grid of wells is from the slot's top left corner." | ||
) | ||
) | ||
expect(screen.getByText('gridOffsetX text field')) | ||
expect(screen.getByText('gridOffsetY text field')) | ||
}) | ||
|
||
it('should update instructions when reservoir is selected', () => { | ||
const { getByText } = render( | ||
wrapInFormik(<GridOffset />, { | ||
...formikConfig, | ||
initialValues: { | ||
...formikConfig.initialValues, | ||
labwareType: 'reservoir', | ||
}, | ||
}) | ||
) | ||
|
||
getByText( | ||
nestedTextMatcher( | ||
"Find the measurement from the center of the top left-most well to the edge of the labware's footprint." | ||
) | ||
) | ||
}) | ||
|
||
it('should NOT render when the labware type is aluminumBlock', () => { | ||
const { container } = render( | ||
wrapInFormik(<GridOffset />, { | ||
...formikConfig, | ||
initialValues: { | ||
...formikConfig.initialValues, | ||
labwareType: 'aluminumBlock', | ||
}, | ||
}) | ||
) | ||
expect(container.firstChild).toBe(null) | ||
}) | ||
|
||
it('should NOT render when the labware type is tubeRack', () => { | ||
const { container } = render( | ||
wrapInFormik(<GridOffset />, { | ||
...formikConfig, | ||
initialValues: { | ||
...formikConfig.initialValues, | ||
labwareType: 'tubeRack', | ||
}, | ||
}) | ||
) | ||
expect(container.firstChild).toBe(null) | ||
}) | ||
|
||
it('should not render when all fields are hidden', () => { | ||
when(isEveryFieldHiddenMock) | ||
.calledWith(['gridOffsetX', 'gridOffsetY'], formikConfig.initialValues) | ||
.mockReturnValue(true) | ||
|
||
const { container } = render(wrapInFormik(<GridOffset />, formikConfig)) | ||
expect(container.firstChild).toBe(null) | ||
}) | ||
}) |
109 changes: 109 additions & 0 deletions
109
labware-library/src/labware-creator/components/__tests__/sections/WellSpacing.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import React from 'react' | ||
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 { isEveryFieldHidden } from '../../../utils' | ||
import { WellSpacing } from '../../sections/WellSpacing' | ||
import { FormAlerts } from '../../FormAlerts' | ||
import { TextField } from '../../TextField' | ||
|
||
import { wrapInFormik } from '../../utils/wrapInFormik' | ||
|
||
jest.mock('../../../utils') | ||
jest.mock('../../TextField') | ||
jest.mock('../../FormAlerts') | ||
|
||
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 formikConfig: FormikConfig<LabwareFields> = { | ||
initialValues: getDefaultFormState(), | ||
onSubmit: jest.fn(), | ||
} | ||
|
||
describe('WellSpacing', () => { | ||
beforeEach(() => { | ||
textFieldMock.mockImplementation(args => { | ||
if (args.name === 'gridSpacingX') { | ||
return <div>gridSpacingX text field</div> | ||
} | ||
if (args.name === 'gridSpacingY') { | ||
return <div>gridSpacingY text field</div> | ||
} else { | ||
return <div></div> | ||
} | ||
}) | ||
|
||
FormAlertsMock.mockImplementation(args => { | ||
if ( | ||
isEqual(args, { | ||
touched: {}, | ||
errors: {}, | ||
fieldList: ['gridSpacingX', 'gridSpacingY'], | ||
}) | ||
) { | ||
return <div>mock alerts</div> | ||
} else { | ||
return <div></div> | ||
} | ||
}) | ||
}) | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks() | ||
}) | ||
|
||
it('should render when fields are visible', () => { | ||
render(wrapInFormik(<WellSpacing />, formikConfig)) | ||
expect(screen.getByText('Well Spacing')) | ||
expect(screen.getByText('mock alerts')) | ||
expect( | ||
screen.getByText( | ||
'Well spacing measurements inform the robot how far away rows and columns are from each other.' | ||
) | ||
) | ||
expect(screen.getByText('gridSpacingX text field')) | ||
expect(screen.getByText('gridSpacingX text field')) | ||
}) | ||
|
||
it('should NOT render when the labware type is aluminumBlock', () => { | ||
const { container } = render( | ||
wrapInFormik(<WellSpacing />, { | ||
...formikConfig, | ||
initialValues: { | ||
...formikConfig.initialValues, | ||
labwareType: 'aluminumBlock', | ||
}, | ||
}) | ||
) | ||
expect(container.firstChild).toBe(null) | ||
}) | ||
it('should NOT render when the labware type is tubeRack', () => { | ||
const { container } = render( | ||
wrapInFormik(<WellSpacing />, { | ||
...formikConfig, | ||
initialValues: { | ||
...formikConfig.initialValues, | ||
labwareType: 'tubeRack', | ||
}, | ||
}) | ||
) | ||
expect(container.firstChild).toBe(null) | ||
}) | ||
|
||
it('should not render when all fields are hidden', () => { | ||
when(isEveryFieldHiddenMock) | ||
.calledWith(['gridSpacingX', 'gridSpacingY'], formikConfig.initialValues) | ||
.mockReturnValue(true) | ||
|
||
const { container } = render(wrapInFormik(<WellSpacing />, formikConfig)) | ||
expect(container.firstChild).toBe(null) | ||
}) | ||
}) |
93 changes: 93 additions & 0 deletions
93
labware-library/src/labware-creator/components/sections/GridOffset.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import * as React from 'react' | ||
import { useFormikContext } from 'formik' | ||
import { makeMaskToDecimal } from '../../fieldMasks' | ||
import { isEveryFieldHidden } from '../../utils' | ||
import { LabwareFields } from '../../fields' | ||
import { FormAlerts } from '../FormAlerts' | ||
import { TextField } from '../TextField' | ||
import { XYOffsetImg } from '../diagrams' | ||
import { SectionBody } from './SectionBody' | ||
|
||
import styles from '../../styles.css' | ||
|
||
const maskTo2Decimal = makeMaskToDecimal(2) | ||
|
||
interface Props { | ||
values: LabwareFields | ||
} | ||
|
||
// TODO (ka 2021-5-11): Broke this out here since we will need to have more conditions for tips | ||
const Instructions = (props: Props): JSX.Element => { | ||
const { values } = props | ||
return ( | ||
<> | ||
<p> | ||
Find the measurement from the center of{' '} | ||
<strong> | ||
{values.labwareType === 'reservoir' | ||
? 'the top left-most well' | ||
: 'well A1'} | ||
</strong>{' '} | ||
to the edge of the labware{"'"}s footprint. | ||
</p> | ||
<p> | ||
Corner offset informs the robot how far the grid of wells is from the | ||
slot{"'"}s top left corner. | ||
</p> | ||
<div className={styles.help_text}> | ||
<img src={require('../../images/offset_helpText.svg')} /> | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
const Content = (props: Props): JSX.Element => { | ||
const { values } = props | ||
return ( | ||
<div className={styles.flex_row}> | ||
<div className={styles.instructions_column}> | ||
<Instructions values={values} /> | ||
</div> | ||
<div className={styles.diagram_column}> | ||
<XYOffsetImg | ||
labwareType={values.labwareType} | ||
wellShape={values.wellShape} | ||
/> | ||
</div> | ||
<div className={styles.form_fields_column}> | ||
<TextField | ||
name="gridOffsetX" | ||
inputMasks={[maskTo2Decimal]} | ||
units="mm" | ||
/> | ||
<TextField | ||
name="gridOffsetY" | ||
inputMasks={[maskTo2Decimal]} | ||
units="mm" | ||
/> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export const GridOffset = (): JSX.Element | null => { | ||
const fieldList: Array<keyof LabwareFields> = ['gridOffsetX', 'gridOffsetY'] | ||
const { values, errors, touched } = useFormikContext<LabwareFields>() | ||
if ( | ||
isEveryFieldHidden(fieldList, values) || | ||
(values.labwareType != null && | ||
['aluminumBlock', 'tubeRack'].includes(values.labwareType)) | ||
) { | ||
return null | ||
} | ||
return ( | ||
<div className={styles.new_definition_section}> | ||
<SectionBody label="Grid Offset"> | ||
<> | ||
<FormAlerts touched={touched} errors={errors} fieldList={fieldList} /> | ||
<Content values={values} /> | ||
</> | ||
</SectionBody> | ||
</div> | ||
) | ||
} |
Oops, something went wrong.