Skip to content

Commit

Permalink
feat(app): Ignore error this run (#15854)
Browse files Browse the repository at this point in the history
Closes EXEC-560 and EXEC-446

Adds support for "ignoring all errors of this type this run".
  • Loading branch information
mjhuff authored Jul 31, 2024
1 parent 1c059f9 commit 0869f43
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { renderHook, act } from '@testing-library/react'
import {
useResumeRunFromRecoveryMutation,
useStopRunMutation,
useUpdateErrorRecoveryPolicy,
} from '@opentrons/react-api-client'

import { useChainRunCommands } from '../../../../resources/runs'
import {
useRecoveryCommands,
HOME_PIPETTE_Z_AXES,
buildPickUpTips,
buildIgnorePolicyRules,
} from '../useRecoveryCommands'
import { RECOVERY_MAP } from '../../constants'

Expand Down Expand Up @@ -40,6 +42,7 @@ describe('useRecoveryCommands', () => {
const mockChainRunCommands = vi.fn().mockResolvedValue([])
const mockReportActionSelectedResult = vi.fn()
const mockReportRecoveredRunResult = vi.fn()
const mockUpdateErrorRecoveryPolicy = vi.fn()

const props = {
runId: mockRunId,
Expand All @@ -64,6 +67,9 @@ describe('useRecoveryCommands', () => {
vi.mocked(useChainRunCommands).mockReturnValue({
chainRunCommands: mockChainRunCommands,
} as any)
vi.mocked(useUpdateErrorRecoveryPolicy).mockReturnValue({
updateErrorRecoveryPolicy: mockUpdateErrorRecoveryPolicy,
} as any)
})

it('should call chainRunRecoveryCommands with continuePastCommandFailure set to false', async () => {
Expand Down Expand Up @@ -254,18 +260,46 @@ describe('useRecoveryCommands', () => {
expect(mockMakeSuccessToast).toHaveBeenCalled()
})

it('should call ignoreErrorKindThisRun and resolve immediately', async () => {
const { result } = renderHook(() => useRecoveryCommands(props))
it('should call updateErrorRecoveryPolicy with correct policy rules when failedCommand has an error', async () => {
const mockFailedCommandWithError = {
...mockFailedCommand,
commandType: 'aspirateInPlace',
error: {
errorType: 'mockErrorType',
},
}

const consoleSpy = vi.spyOn(console, 'log')
const testProps = {
...props,
failedCommand: mockFailedCommandWithError,
}

const { result } = renderHook(() => useRecoveryCommands(testProps))

await act(async () => {
await result.current.ignoreErrorKindThisRun()
})

expect(consoleSpy).toHaveBeenCalledWith(
'IGNORING ALL ERRORS OF THIS KIND THIS RUN'
const expectedPolicyRules = buildIgnorePolicyRules(
'aspirateInPlace',
'mockErrorType'
)

expect(mockUpdateErrorRecoveryPolicy).toHaveBeenCalledWith(
expectedPolicyRules
)
})

it('should reject with an error when failedCommand or error is null', async () => {
const testProps = {
...props,
failedCommand: null,
}

const { result } = renderHook(() => useRecoveryCommands(testProps))

await expect(result.current.ignoreErrorKindThisRun()).rejects.toThrow(
'Could not execute command. No failed command.'
)
expect(result.current.ignoreErrorKindThisRun()).resolves.toBeUndefined()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function useFailedLabwareUtils({
}: UseFailedLabwareUtilsProps): UseFailedLabwareUtilsResult {
const recentRelevantFailedLabwareCmd = React.useMemo(
() => getRelevantFailedLabwareCmdFrom({ failedCommand, runCommands }),
[failedCommand?.key, runCommands]
[failedCommand?.error?.errorType, runCommands]
)

const tipSelectionUtils = useTipSelectionUtils(recentRelevantFailedLabwareCmd)
Expand Down
37 changes: 33 additions & 4 deletions app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import head from 'lodash/head'
import {
useResumeRunFromRecoveryMutation,
useStopRunMutation,
useUpdateErrorRecoveryPolicy,
} from '@opentrons/react-api-client'

import { useChainRunCommands } from '../../../resources/runs'
Expand All @@ -19,7 +20,10 @@ import type {
DropTipInPlaceRunTimeCommand,
PrepareToAspirateRunTimeCommand,
} from '@opentrons/shared-data'
import type { CommandData } from '@opentrons/api-client'
import type {
CommandData,
RecoveryPolicyRulesParams,
} from '@opentrons/api-client'
import type { WellGroup } from '@opentrons/components'
import type { FailedCommand } from '../types'
import type { UseFailedLabwareUtilsResult } from './useFailedLabwareUtils'
Expand Down Expand Up @@ -71,6 +75,7 @@ export function useRecoveryCommands({
mutateAsync: resumeRunFromRecovery,
} = useResumeRunFromRecoveryMutation()
const { stopRun } = useStopRunMutation()
const { updateErrorRecoveryPolicy } = useUpdateErrorRecoveryPolicy(runId)
const { makeSuccessToast } = recoveryToastUtils

const buildRetryPrepMove = (): MoveToCoordinatesCreateCommand | null => {
Expand Down Expand Up @@ -184,9 +189,20 @@ export function useRecoveryCommands({
}, [runId, resumeRunFromRecovery, makeSuccessToast])

const ignoreErrorKindThisRun = React.useCallback((): Promise<void> => {
console.log('IGNORING ALL ERRORS OF THIS KIND THIS RUN')
return Promise.resolve()
}, [])
if (failedCommand?.error != null) {
const ignorePolicyRules = buildIgnorePolicyRules(
failedCommand.commandType,
failedCommand.error.errorType
)

updateErrorRecoveryPolicy(ignorePolicyRules)
return Promise.resolve()
} else {
return Promise.reject(
new Error('Could not execute command. No failed command.')
)
}
}, [failedCommand?.error?.errorType, failedCommand?.commandType])

return {
resumeRun,
Expand Down Expand Up @@ -230,3 +246,16 @@ export const buildPickUpTips = (
}
}
}

export const buildIgnorePolicyRules = (
commandType: FailedCommand['commandType'],
errorType: string
): RecoveryPolicyRulesParams => {
return [
{
commandType,
errorType,
ifMatch: 'ignoreAndContinue',
},
]
}
2 changes: 1 addition & 1 deletion app/src/organisms/ErrorRecoveryFlows/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export function ErrorRecoveryFlows(
const analytics = useRecoveryAnalytics()
React.useEffect(() => {
analytics.reportErrorEvent(failedCommand)
}, [failedCommand?.key])
}, [failedCommand?.error?.detail])

const { hasLaunchedRecovery, toggleERWizard, showERWizard } = useERWizard()
const isOnDevice = useSelector(getIsOnDevice)
Expand Down

0 comments on commit 0869f43

Please sign in to comment.