From fc6944921c42843cf720ed80ede48f3fa65b0e18 Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Tue, 7 Jan 2025 12:41:33 -0500 Subject: [PATCH] fix(app): fix gantry not homing when no labware in gripper jaws during Error Recovery --- .../shared/GripperIsHoldingLabware.tsx | 44 +++++++++++-------- .../GripperIsHoldingLabware.test.tsx | 18 ++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/app/src/organisms/ErrorRecoveryFlows/shared/GripperIsHoldingLabware.tsx b/app/src/organisms/ErrorRecoveryFlows/shared/GripperIsHoldingLabware.tsx index 036f1aff3d0..6f4157bc909 100644 --- a/app/src/organisms/ErrorRecoveryFlows/shared/GripperIsHoldingLabware.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/shared/GripperIsHoldingLabware.tsx @@ -29,12 +29,15 @@ export const HOLDING_LABWARE_OPTIONS: HoldingLabwareOption[] = [ export function GripperIsHoldingLabware({ routeUpdateActions, currentRecoveryOptionUtils, + recoveryCommands, }: RecoveryContentProps): JSX.Element { const { proceedNextStep, proceedToRouteAndStep, goBackPrevStep, + handleMotionRouting, } = routeUpdateActions + const { homeExceptPlungers } = recoveryCommands const { selectedRecoveryOption } = currentRecoveryOptionUtils const { MANUAL_MOVE_AND_SKIP, @@ -48,24 +51,29 @@ export function GripperIsHoldingLabware({ const { t } = useTranslation(['error_recovery', 'shared']) const handleNoOption = (): void => { - switch (selectedRecoveryOption) { - case MANUAL_MOVE_AND_SKIP.ROUTE: - void proceedToRouteAndStep( - MANUAL_MOVE_AND_SKIP.ROUTE, - MANUAL_MOVE_AND_SKIP.STEPS.MANUAL_MOVE - ) - break - case MANUAL_REPLACE_AND_RETRY.ROUTE: - void proceedToRouteAndStep( - MANUAL_REPLACE_AND_RETRY.ROUTE, - MANUAL_REPLACE_AND_RETRY.STEPS.MANUAL_REPLACE - ) - break - default: { - console.error('Unexpected recovery option for gripper routing.') - void proceedToRouteAndStep(OPTION_SELECTION.ROUTE) - } - } + // The "yes" option also contains a home, but it occurs later in the control flow, + // after the user has extricated the labware from the gripper jaws. + void handleMotionRouting(true) + .then(() => homeExceptPlungers()) + .then(() => { + switch (selectedRecoveryOption) { + case MANUAL_MOVE_AND_SKIP.ROUTE: + return proceedToRouteAndStep( + MANUAL_MOVE_AND_SKIP.ROUTE, + MANUAL_MOVE_AND_SKIP.STEPS.MANUAL_MOVE + ) + case MANUAL_REPLACE_AND_RETRY.ROUTE: + return proceedToRouteAndStep( + MANUAL_REPLACE_AND_RETRY.ROUTE, + MANUAL_REPLACE_AND_RETRY.STEPS.MANUAL_REPLACE + ) + default: { + console.error('Unexpected recovery option for gripper routing.') + return proceedToRouteAndStep(OPTION_SELECTION.ROUTE) + } + } + }) + .finally(() => handleMotionRouting(false)) } const primaryOnClick = (): void => { diff --git a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/GripperIsHoldingLabware.test.tsx b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/GripperIsHoldingLabware.test.tsx index adedca04009..3279bdfea7c 100644 --- a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/GripperIsHoldingLabware.test.tsx +++ b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/GripperIsHoldingLabware.test.tsx @@ -23,19 +23,25 @@ const render = (props: ComponentProps) => { let mockProceedToRouteAndStep: Mock let mockProceedNextStep: Mock +let mockHandleMotionRouting: Mock +let mockHomeExceptPlungers: Mock describe('GripperIsHoldingLabware', () => { let props: ComponentProps beforeEach(() => { mockProceedToRouteAndStep = vi.fn(() => Promise.resolve()) mockProceedNextStep = vi.fn(() => Promise.resolve()) + mockHandleMotionRouting = vi.fn(() => Promise.resolve()) + mockHomeExceptPlungers = vi.fn(() => Promise.resolve()) props = { ...mockRecoveryContentProps, routeUpdateActions: { proceedToRouteAndStep: mockProceedToRouteAndStep, proceedNextStep: mockProceedNextStep, + handleMotionRouting: mockHandleMotionRouting, } as any, + recoveryCommands: { homeExceptPlungers: mockHomeExceptPlungers } as any, } }) @@ -82,12 +88,24 @@ describe('GripperIsHoldingLabware', () => { fireEvent.click(screen.getAllByLabelText('No')[0]) clickButtonLabeled('Continue') + await waitFor(() => { + expect(mockHandleMotionRouting).toHaveBeenCalledWith(true) + }) + + await waitFor(() => { + expect(mockHomeExceptPlungers).toHaveBeenCalled() + }) + await waitFor(() => { expect(mockProceedToRouteAndStep).toHaveBeenCalledWith( RECOVERY_MAP.MANUAL_MOVE_AND_SKIP.ROUTE, RECOVERY_MAP.MANUAL_MOVE_AND_SKIP.STEPS.MANUAL_MOVE ) }) + + await waitFor(() => { + expect(mockHandleMotionRouting).toHaveBeenCalledWith(false) + }) }) it(`proceeds to the correct step when the no option is clicked for ${RECOVERY_MAP.MANUAL_REPLACE_AND_RETRY.ROUTE}`, async () => {