-
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(app): consolidate header onClicks into their own hook
- Loading branch information
Showing
11 changed files
with
286 additions
and
117 deletions.
There are no files selected for viewing
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
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 |
---|---|---|
|
@@ -28,24 +28,13 @@ const SUPPORT_EMAIL = '[email protected]' | |
|
||
export function LPCErrorModal(props: LPCWizardContentProps): JSX.Element { | ||
const { t } = useTranslation(['labware_position_check', 'shared', 'branded']) | ||
const { | ||
errorMessage, | ||
toggleRobotMoving, | ||
handleCleanUpAndClose, | ||
} = props.commandUtils | ||
|
||
// If the maintenance run fails, we cannot move the gantry, so just clean up LPC. | ||
const handleClose = (): void => { | ||
void toggleRobotMoving(true).then(() => { | ||
void handleCleanUpAndClose() | ||
}) | ||
} | ||
const { errorMessage, headerCommands } = props.commandUtils | ||
|
||
return ( | ||
<LPCContentContainer | ||
{...props} | ||
header={t('labware_position_check_title')} | ||
onClickButton={handleClose} | ||
onClickButton={headerCommands.handleClose} | ||
buttonText={t('exit')} | ||
> | ||
<ModalContainer | ||
|
@@ -82,7 +71,7 @@ export function LPCErrorModal(props: LPCWizardContentProps): JSX.Element { | |
<PrimaryButton | ||
textTransform={TEXT_TRANSFORM_CAPITALIZE} | ||
alignSelf={ALIGN_FLEX_END} | ||
onClick={handleClose} | ||
onClick={headerCommands.handleClose} | ||
> | ||
{t('shared:exit')} | ||
</PrimaryButton> | ||
|
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
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
181 changes: 181 additions & 0 deletions
181
...ganisms/LabwarePositionCheck/hooks/useLPCCommands/__tests__/useLPCHeaderCommands.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,181 @@ | ||
import { describe, beforeEach, afterEach, it, vi, expect } from 'vitest' | ||
import { renderHook, act, waitFor } from '@testing-library/react' | ||
import { useSelector, Provider } from 'react-redux' | ||
import { createStore } from 'redux' | ||
import { I18nextProvider } from 'react-i18next' | ||
|
||
import { i18n } from '/app/i18n' | ||
import { LPC_STEP } from '/app/redux/protocol-runs' | ||
import { useLPCHeaderCommands } from '../useLPCHeaderCommands' | ||
|
||
import type { FunctionComponent, ReactNode } from 'react' | ||
import type { UseLPCCommandsResult } from '/app/organisms/LabwarePositionCheck/hooks' | ||
import type { UseLPCHeaderCommandsProps } from '../useLPCHeaderCommands' | ||
import type { State } from '/app/redux/types' | ||
import type { Store } from 'redux' | ||
|
||
vi.mock('react-redux', async importOriginal => { | ||
const actual = await importOriginal<typeof Provider>() | ||
return { | ||
...actual, | ||
useSelector: vi.fn(), | ||
} | ||
}) | ||
|
||
let props: UseLPCHeaderCommandsProps | ||
let mockLPCHandlerUtils: UseLPCCommandsResult | ||
let wrapper: FunctionComponent<{ children: ReactNode }> | ||
let store: Store<State> | ||
let toggleRobotMovingPromise: Promise<void> | ||
let handleStartLPCPromise: Promise<void> | ||
let handleProbeAttachmentPromise: Promise<void> | ||
let handleValidMoveToMaintenancePositionPromise: Promise<void> | ||
let handleCleanUpAndClosePromise: Promise<void> | ||
|
||
describe('useLPCHeaderCommands', () => { | ||
const mockPipette = { id: 'mock-pipette' } | ||
const mockRunId = 'mock-run-id' | ||
const mockProceedStep = vi.fn() | ||
|
||
beforeEach(() => { | ||
toggleRobotMovingPromise = Promise.resolve() | ||
handleStartLPCPromise = Promise.resolve() | ||
handleProbeAttachmentPromise = Promise.resolve() | ||
handleValidMoveToMaintenancePositionPromise = Promise.resolve() | ||
handleCleanUpAndClosePromise = Promise.resolve() | ||
|
||
mockLPCHandlerUtils = { | ||
toggleRobotMoving: vi.fn(() => toggleRobotMovingPromise), | ||
handleStartLPC: vi.fn(() => handleStartLPCPromise), | ||
handleProbeAttachment: vi.fn(() => handleProbeAttachmentPromise), | ||
handleValidMoveToMaintenancePosition: vi.fn( | ||
() => handleValidMoveToMaintenancePositionPromise | ||
), | ||
handleCleanUpAndClose: vi.fn(() => handleCleanUpAndClosePromise), | ||
} as any | ||
|
||
props = { | ||
LPCHandlerUtils: mockLPCHandlerUtils, | ||
proceedStep: mockProceedStep, | ||
goBackLastStep: vi.fn(), | ||
runId: mockRunId, | ||
} | ||
|
||
store = createStore(vi.fn(), {}) | ||
store.dispatch = vi.fn() | ||
|
||
wrapper = ({ children }) => ( | ||
<I18nextProvider i18n={i18n}> | ||
<Provider store={store}>{children}</Provider> | ||
</I18nextProvider> | ||
) | ||
|
||
vi.mocked(useSelector).mockImplementation(() => { | ||
return mockPipette | ||
}) | ||
}) | ||
|
||
afterEach(() => { | ||
vi.clearAllMocks() | ||
}) | ||
|
||
it('should execute handleProceed commands in correct sequence', async () => { | ||
const { result } = renderHook(() => useLPCHeaderCommands(props), { | ||
wrapper, | ||
}) | ||
|
||
await act(async () => { | ||
result.current.handleProceed() | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.toggleRobotMoving).toHaveBeenCalledWith(true) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.handleStartLPC).toHaveBeenCalledWith( | ||
mockPipette, | ||
mockProceedStep | ||
) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.toggleRobotMoving).toHaveBeenCalledWith(false) | ||
}) | ||
}) | ||
|
||
it('should execute handleAttachProbeCheck commands in correct sequence', async () => { | ||
const { result } = renderHook(() => useLPCHeaderCommands(props), { | ||
wrapper, | ||
}) | ||
|
||
await act(async () => { | ||
result.current.handleAttachProbeCheck() | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.toggleRobotMoving).toHaveBeenCalledWith(true) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.handleProbeAttachment).toHaveBeenCalledWith( | ||
mockPipette, | ||
mockProceedStep | ||
) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockProceedStep).toHaveBeenCalled() | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.toggleRobotMoving).toHaveBeenCalledWith(false) | ||
}) | ||
}) | ||
|
||
it('should execute handleNavToDetachProbe commands in correct sequence', async () => { | ||
const { result } = renderHook(() => useLPCHeaderCommands(props), { | ||
wrapper, | ||
}) | ||
|
||
await act(async () => { | ||
result.current.handleNavToDetachProbe() | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.toggleRobotMoving).toHaveBeenCalledWith(true) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect( | ||
mockLPCHandlerUtils.handleValidMoveToMaintenancePosition | ||
).toHaveBeenCalledWith(mockPipette) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockProceedStep).toHaveBeenCalledWith(LPC_STEP.DETACH_PROBE) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.toggleRobotMoving).toHaveBeenCalledWith(false) | ||
}) | ||
}) | ||
|
||
it('should execute handleClose commands in correct sequence', async () => { | ||
const { result } = renderHook(() => useLPCHeaderCommands(props), { | ||
wrapper, | ||
}) | ||
|
||
await act(async () => { | ||
result.current.handleClose() | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.toggleRobotMoving).toHaveBeenCalledWith(true) | ||
}) | ||
|
||
await waitFor(() => { | ||
expect(mockLPCHandlerUtils.handleCleanUpAndClose).toHaveBeenCalled() | ||
}) | ||
}) | ||
}) |
76 changes: 76 additions & 0 deletions
76
app/src/organisms/LabwarePositionCheck/hooks/useLPCCommands/useLPCHeaderCommands.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,76 @@ | ||
import { useSelector } from 'react-redux' | ||
|
||
import { LPC_STEP, selectActivePipette } from '/app/redux/protocol-runs' | ||
|
||
import type { LPCWizardContentProps } from '/app/organisms/LabwarePositionCheck/types' | ||
import type { UseLPCCommandsResult } from '/app/organisms/LabwarePositionCheck/hooks' | ||
|
||
export type UseLPCHeaderCommandsProps = Omit< | ||
LPCWizardContentProps, | ||
'commandUtils' | ||
> & { | ||
LPCHandlerUtils: UseLPCCommandsResult | ||
} | ||
|
||
export interface UseLPCHeaderCommandsResult { | ||
handleProceed: () => void | ||
handleAttachProbeCheck: () => void | ||
handleNavToDetachProbe: () => void | ||
handleClose: () => void | ||
} | ||
|
||
// Wraps core LPC command functionality, since the header component reuses many of the same commands. | ||
export function useLPCHeaderCommands({ | ||
LPCHandlerUtils, | ||
proceedStep, | ||
runId, | ||
}: UseLPCHeaderCommandsProps): UseLPCHeaderCommandsResult { | ||
const activePipette = useSelector(selectActivePipette(runId)) | ||
const pipette = useSelector(selectActivePipette(runId)) | ||
|
||
const { | ||
handleStartLPC, | ||
toggleRobotMoving, | ||
handleValidMoveToMaintenancePosition, | ||
handleCleanUpAndClose, | ||
handleProbeAttachment, | ||
} = LPCHandlerUtils | ||
|
||
const handleProceed = (): void => { | ||
void toggleRobotMoving(true) | ||
.then(() => handleStartLPC(activePipette, proceedStep)) | ||
.finally(() => toggleRobotMoving(false)) | ||
} | ||
|
||
// If the maintenance run fails, we cannot move the gantry, so just clean up LPC. | ||
const handleClose = (): void => { | ||
void toggleRobotMoving(true).then(() => { | ||
void handleCleanUpAndClose() | ||
}) | ||
} | ||
|
||
const handleAttachProbeCheck = (): void => { | ||
void toggleRobotMoving(true) | ||
.then(() => handleProbeAttachment(pipette, proceedStep)) | ||
.then(() => { | ||
proceedStep() | ||
}) | ||
.finally(() => toggleRobotMoving(false)) | ||
} | ||
|
||
const handleNavToDetachProbe = (): void => { | ||
void toggleRobotMoving(true) | ||
.then(() => handleValidMoveToMaintenancePosition(pipette)) | ||
.then(() => { | ||
proceedStep(LPC_STEP.DETACH_PROBE) | ||
}) | ||
.finally(() => toggleRobotMoving(false)) | ||
} | ||
|
||
return { | ||
handleProceed, | ||
handleAttachProbeCheck, | ||
handleNavToDetachProbe, | ||
handleClose, | ||
} | ||
} |
Oops, something went wrong.