From e15cbe2388c3ffdce0470da80b4efd697634e5bd Mon Sep 17 00:00:00 2001 From: Jamey Huffnagle Date: Thu, 17 Oct 2024 17:30:46 -0400 Subject: [PATCH] feat(app): Add Error Recovery support for in-place commands (#16515) Closes EXEC-777 #16510 appears to have fixed most of the inPlace issues we had seen back in 8.0, and it has (hopefully) greatly simplified the additional support the app needs to provide to get inPlace variations of aspirate/dispense working. This commit just wires up those commands to the appropriate flows. --- .../ErrorRecoveryFlows/hooks/index.ts | 1 - .../hooks/useErrorMessage.ts | 13 -- .../utils/__tests__/getErrorKind.test.ts | 147 ++++++++---------- .../ErrorRecoveryFlows/utils/getErrorKind.ts | 4 +- 4 files changed, 66 insertions(+), 99 deletions(-) delete mode 100644 app/src/organisms/ErrorRecoveryFlows/hooks/useErrorMessage.ts diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts index da85e8b770e..baa685c0dcc 100644 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts +++ b/app/src/organisms/ErrorRecoveryFlows/hooks/index.ts @@ -1,5 +1,4 @@ export { useCurrentlyRecoveringFrom } from './useCurrentlyRecoveringFrom' -export { useErrorMessage } from './useErrorMessage' export { useErrorName } from './useErrorName' export { useRecoveryCommands } from './useRecoveryCommands' export { useRouteUpdateActions } from './useRouteUpdateActions' diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useErrorMessage.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/useErrorMessage.ts deleted file mode 100644 index d8efb33d4eb..00000000000 --- a/app/src/organisms/ErrorRecoveryFlows/hooks/useErrorMessage.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useTranslation } from 'react-i18next' - -import type { ErrorKind } from '../types' - -// The generalized error message shown to the user in select locations. -export function useErrorMessage(errorKind: ErrorKind): string { - const { t } = useTranslation('error_recovery') - - switch (errorKind) { - default: - return t('general_error_message') - } -} diff --git a/app/src/organisms/ErrorRecoveryFlows/utils/__tests__/getErrorKind.test.ts b/app/src/organisms/ErrorRecoveryFlows/utils/__tests__/getErrorKind.test.ts index 55399fa1d22..1aa7080a52a 100644 --- a/app/src/organisms/ErrorRecoveryFlows/utils/__tests__/getErrorKind.test.ts +++ b/app/src/organisms/ErrorRecoveryFlows/utils/__tests__/getErrorKind.test.ts @@ -6,93 +6,74 @@ import { getErrorKind } from '../getErrorKind' import type { RunCommandError, RunTimeCommand } from '@opentrons/shared-data' describe('getErrorKind', () => { - it(`returns ${ERROR_KINDS.NO_LIQUID_DETECTED} for ${DEFINED_ERROR_TYPES.LIQUID_NOT_FOUND} errorType`, () => { - const result = getErrorKind({ - commandType: 'liquidProbe', - error: { - isDefined: true, - errorType: DEFINED_ERROR_TYPES.LIQUID_NOT_FOUND, - } as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.NO_LIQUID_DETECTED) - }) - - it(`returns ${ERROR_KINDS.OVERPRESSURE_WHILE_ASPIRATING} for ${DEFINED_ERROR_TYPES.OVERPRESSURE} errorType`, () => { - const result = getErrorKind({ + it.each([ + { commandType: 'aspirate', - error: { - isDefined: true, - errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, - } as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.OVERPRESSURE_WHILE_ASPIRATING) - }) - - it(`returns ${ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING} for ${DEFINED_ERROR_TYPES.OVERPRESSURE} errorType`, () => { - const result = getErrorKind({ + errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, + expectedError: ERROR_KINDS.OVERPRESSURE_WHILE_ASPIRATING, + }, + { + commandType: 'aspirateInPlace', + errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, + expectedError: ERROR_KINDS.OVERPRESSURE_WHILE_ASPIRATING, + }, + { commandType: 'dispense', - error: { - isDefined: true, - errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, - } as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING) - }) - - it(`returns ${ERROR_KINDS.TIP_NOT_DETECTED} for ${DEFINED_ERROR_TYPES.TIP_PHYSICALLY_MISSING} errorType`, () => { - const result = getErrorKind({ - commandType: 'pickUpTip', - error: { - isDefined: true, - errorType: DEFINED_ERROR_TYPES.TIP_PHYSICALLY_MISSING, - } as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.TIP_NOT_DETECTED) - }) - - it(`returns ${ERROR_KINDS.TIP_DROP_FAILED} for ${DEFINED_ERROR_TYPES.TIP_PHYSICALLY_ATTACHED} errorType`, () => { - const result = getErrorKind({ + errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, + expectedError: ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING, + }, + { + commandType: 'dispenseInPlace', + errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, + expectedError: ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING, + }, + { commandType: 'dropTip', - error: { - isDefined: true, - errorType: DEFINED_ERROR_TYPES.TIP_PHYSICALLY_ATTACHED, - } as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.TIP_DROP_FAILED) - }) - - it(`returns ${ERROR_KINDS.GRIPPER_ERROR} for ${DEFINED_ERROR_TYPES.GRIPPER_MOVEMENT} errorType`, () => { - const result = getErrorKind({ + errorType: DEFINED_ERROR_TYPES.TIP_PHYSICALLY_ATTACHED, + expectedError: ERROR_KINDS.TIP_DROP_FAILED, + }, + { + commandType: 'dropTipInPlace', + errorType: DEFINED_ERROR_TYPES.TIP_PHYSICALLY_ATTACHED, + expectedError: ERROR_KINDS.TIP_DROP_FAILED, + }, + { + commandType: 'liquidProbe', + errorType: DEFINED_ERROR_TYPES.LIQUID_NOT_FOUND, + expectedError: ERROR_KINDS.NO_LIQUID_DETECTED, + }, + { + commandType: 'pickUpTip', + errorType: DEFINED_ERROR_TYPES.TIP_PHYSICALLY_MISSING, + expectedError: ERROR_KINDS.TIP_NOT_DETECTED, + }, + { commandType: 'moveLabware', - error: { - isDefined: true, - errorType: DEFINED_ERROR_TYPES.GRIPPER_MOVEMENT, - } as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.GRIPPER_ERROR) - }) - - it(`returns ${ERROR_KINDS.GENERAL_ERROR} for undefined errors`, () => { - const result = getErrorKind({ + errorType: DEFINED_ERROR_TYPES.GRIPPER_MOVEMENT, + expectedError: ERROR_KINDS.GRIPPER_ERROR, + }, + { commandType: 'aspirate', - error: { - isDefined: false, - // It should treat this error as undefined because isDefined===false, - // even though the errorType happens to match a defined error. - errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, - } as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.GENERAL_ERROR) - }) - - it(`returns ${ERROR_KINDS.GENERAL_ERROR} for defined errors not handled explicitly`, () => { - const result = getErrorKind({ + errorType: DEFINED_ERROR_TYPES.OVERPRESSURE, + isDefined: false, + expectedError: ERROR_KINDS.GENERAL_ERROR, + }, + { commandType: 'aspirate', - error: ({ - isDefined: true, - errorType: 'someHithertoUnknownDefinedErrorType', - } as unknown) as RunCommandError, - } as RunTimeCommand) - expect(result).toEqual(ERROR_KINDS.GENERAL_ERROR) - }) + errorType: 'someHithertoUnknownDefinedErrorType', + expectedError: ERROR_KINDS.GENERAL_ERROR, + }, + ])( + 'returns $expectedError for $commandType with errorType $errorType', + ({ commandType, errorType, expectedError, isDefined = true }) => { + const result = getErrorKind({ + commandType, + error: { + isDefined, + errorType, + } as RunCommandError, + } as RunTimeCommand) + expect(result).toEqual(expectedError) + } + ) }) diff --git a/app/src/organisms/ErrorRecoveryFlows/utils/getErrorKind.ts b/app/src/organisms/ErrorRecoveryFlows/utils/getErrorKind.ts index 9c96230836b..a537c3cf295 100644 --- a/app/src/organisms/ErrorRecoveryFlows/utils/getErrorKind.ts +++ b/app/src/organisms/ErrorRecoveryFlows/utils/getErrorKind.ts @@ -16,12 +16,12 @@ export function getErrorKind(failedCommand: RunTimeCommand | null): ErrorKind { // todo(mm, 2024-07-02): Also handle aspirateInPlace and dispenseInPlace. // https://opentrons.atlassian.net/browse/EXEC-593 if ( - commandType === 'aspirate' && + (commandType === 'aspirate' || commandType === 'aspirateInPlace') && errorType === DEFINED_ERROR_TYPES.OVERPRESSURE ) { return ERROR_KINDS.OVERPRESSURE_WHILE_ASPIRATING } else if ( - commandType === 'dispense' && + (commandType === 'dispense' || commandType === 'dispenseInPlace') && errorType === DEFINED_ERROR_TYPES.OVERPRESSURE ) { return ERROR_KINDS.OVERPRESSURE_WHILE_DISPENSING