(
head(IGNORE_OPTIONS_IN_ORDER) as IgnoreOption
)
- // It's safe to hard code the routing here, since only one route currently
- // utilizes ignoring. In the future, we may have to check the selectedRecoveryOption
- // and route appropriately.
+ // Reset client choice to ignore all errors whenever navigating back to this view. This prevents unexpected
+ // behavior after pressing "go back" and ending up on this screen.
+ useEffect(() => {
+ void ignoreErrorKindThisRun(false)
+ }, [])
+
+ // In order to keep routing linear, all extended "skip" flows should be kept as separate recovery options with
+ // go back functionality that routes to this view. Those "skip" views encapsulate the generic "skip" view.
+ // See the "manually fill well and skip" recovery option for an example.
const ignoreOnce = (): void => {
- void proceedToRouteAndStep(
- MANUAL_FILL_AND_SKIP.ROUTE,
- MANUAL_FILL_AND_SKIP.STEPS.SKIP
- )
+ switch (errorKind) {
+ case ERROR_KINDS.NO_LIQUID_DETECTED:
+ void proceedToRouteAndStep(
+ RECOVERY_MAP.MANUAL_FILL_AND_SKIP.ROUTE,
+ RECOVERY_MAP.MANUAL_FILL_AND_SKIP.STEPS.SKIP
+ )
+ break
+ default:
+ void proceedNextStep()
+ }
}
// See ignoreOnce comment.
const ignoreAlways = (): void => {
- void ignoreErrorKindThisRun().then(() =>
- proceedToRouteAndStep(
- MANUAL_FILL_AND_SKIP.ROUTE,
- MANUAL_FILL_AND_SKIP.STEPS.SKIP
- )
- )
+ void ignoreErrorKindThisRun(true).then(() => {
+ switch (errorKind) {
+ case ERROR_KINDS.NO_LIQUID_DETECTED:
+ void proceedToRouteAndStep(
+ RECOVERY_MAP.MANUAL_FILL_AND_SKIP.ROUTE,
+ RECOVERY_MAP.MANUAL_FILL_AND_SKIP.STEPS.SKIP
+ )
+ break
+ default:
+ void proceedNextStep()
+ }
+ })
}
const primaryOnClick = (): void => {
diff --git a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/IgnoreErrorSkipStep.test.tsx b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/IgnoreErrorSkipStep.test.tsx
index 0e1789aa797..547334f77c4 100644
--- a/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/IgnoreErrorSkipStep.test.tsx
+++ b/app/src/organisms/ErrorRecoveryFlows/RecoveryOptions/__tests__/IgnoreErrorSkipStep.test.tsx
@@ -10,19 +10,23 @@ import {
IgnoreErrorStepHome,
IgnoreOptions,
} from '../IgnoreErrorSkipStep'
-import { RECOVERY_MAP } from '../../constants'
+import { ERROR_KINDS, RECOVERY_MAP } from '../../constants'
import { SelectRecoveryOption } from '../SelectRecoveryOption'
import { clickButtonLabeled } from '../../__tests__/util'
+import { SkipStepInfo } from '/app/organisms/ErrorRecoveryFlows/shared'
import type { Mock } from 'vitest'
-vi.mock('../shared', async () => {
- const actual = await vi.importActual('../shared')
+vi.mock('/app/organisms/ErrorRecoveryFlows/shared', async () => {
+ const actual = await vi.importActual(
+ '/app/organisms/ErrorRecoveryFlows/shared'
+ )
return {
...actual,
RecoverySingleColumnContentWrapper: vi.fn(({ children }) => (
{children}
)),
+ SkipStepInfo: vi.fn(),
}
})
vi.mock('../SelectRecoveryOption')
@@ -47,11 +51,13 @@ describe('IgnoreErrorSkipStep', () => {
beforeEach(() => {
props = {
...mockRecoveryContentProps,
+ recoveryCommands: { ignoreErrorKindThisRun: vi.fn() } as any,
}
vi.mocked(SelectRecoveryOption).mockReturnValue(
MOCK_SELECT_RECOVERY_OPTION
)
+ vi.mocked(SkipStepInfo).mockReturnValue(MOCK_SKIP_STEP_INFO
)
})
it(`renders IgnoreErrorStepHome when step is ${RECOVERY_MAP.IGNORE_AND_SKIP.STEPS.SELECT_IGNORE_KIND}`, () => {
@@ -66,6 +72,18 @@ describe('IgnoreErrorSkipStep', () => {
screen.getByText('Ignore similar errors later in the run?')
})
+ it(`renders SkipStepInfo when step is ${RECOVERY_MAP.IGNORE_AND_SKIP.STEPS.SKIP_STEP}`, () => {
+ props = {
+ ...props,
+ recoveryMap: {
+ ...props.recoveryMap,
+ step: RECOVERY_MAP.IGNORE_AND_SKIP.STEPS.SKIP_STEP,
+ },
+ }
+ render(props)
+ screen.getByText('MOCK_SKIP_STEP_INFO')
+ })
+
it('renders SelectRecoveryOption as a fallback', () => {
props = {
...props,
@@ -84,26 +102,30 @@ describe('IgnoreErrorStepHome', () => {
let mockIgnoreErrorKindThisRun: Mock
let mockProceedToRouteAndStep: Mock
let mockGoBackPrevStep: Mock
+ let mockProceedNextStep: Mock
beforeEach(() => {
mockIgnoreErrorKindThisRun = vi.fn(() => Promise.resolve())
mockProceedToRouteAndStep = vi.fn()
mockGoBackPrevStep = vi.fn()
+ mockProceedNextStep = vi.fn()
props = {
...mockRecoveryContentProps,
isOnDevice: true,
+ errorKind: ERROR_KINDS.NO_LIQUID_DETECTED,
recoveryCommands: {
ignoreErrorKindThisRun: mockIgnoreErrorKindThisRun,
} as any,
routeUpdateActions: {
proceedToRouteAndStep: mockProceedToRouteAndStep,
goBackPrevStep: mockGoBackPrevStep,
+ proceedNextStep: mockProceedNextStep,
} as any,
}
})
- it('calls ignoreOnce when "ignore_only_this_error" is selected and primary button is clicked', async () => {
+ it(`ignoreOnce correctly routes "ignore_only_this_error" is clicked and the errorKind is ${ERROR_KINDS.NO_LIQUID_DETECTED}`, async () => {
renderIgnoreErrorStepHome(props)
fireEvent.click(screen.queryAllByText('Ignore only this error')[0])
clickButtonLabeled('Continue')
@@ -115,7 +137,19 @@ describe('IgnoreErrorStepHome', () => {
})
})
- it('calls ignoreAlways when "ignore_all_errors_of_this_type" is selected and primary button is clicked', async () => {
+ it(`ignoreOnce correctly routes "ignore_only_this_error" is clicked and the errorKind not explicitly handled`, async () => {
+ renderIgnoreErrorStepHome({
+ ...props,
+ errorKind: ERROR_KINDS.GENERAL_ERROR,
+ })
+ fireEvent.click(screen.queryAllByText('Ignore only this error')[0])
+ clickButtonLabeled('Continue')
+ await waitFor(() => {
+ expect(mockProceedNextStep).toHaveBeenCalled()
+ })
+ })
+
+ it(`ignoreAlways correctly routes when "ignore_all_errors_of_this_type" is clicked and the errorKind is ${ERROR_KINDS.NO_LIQUID_DETECTED}`, async () => {
renderIgnoreErrorStepHome(props)
fireEvent.click(screen.queryAllByText('Ignore all errors of this type')[0])
clickButtonLabeled('Continue')
@@ -130,6 +164,18 @@ describe('IgnoreErrorStepHome', () => {
})
})
+ it(`ignoreAlways correctly routes "ignore_all_errors_of_this_type" is clicked and the errorKind not explicitly handled`, async () => {
+ renderIgnoreErrorStepHome({
+ ...props,
+ errorKind: ERROR_KINDS.GENERAL_ERROR,
+ })
+ fireEvent.click(screen.queryAllByText('Ignore all errors of this type')[0])
+ clickButtonLabeled('Continue')
+ await waitFor(() => {
+ expect(mockProceedNextStep).toHaveBeenCalled()
+ })
+ })
+
it('calls goBackPrevStep when secondary button is clicked', () => {
renderIgnoreErrorStepHome(props)
clickButtonLabeled('Go back')
diff --git a/app/src/organisms/ErrorRecoveryFlows/constants.ts b/app/src/organisms/ErrorRecoveryFlows/constants.ts
index d63e69e5e22..75835fd29f3 100644
--- a/app/src/organisms/ErrorRecoveryFlows/constants.ts
+++ b/app/src/organisms/ErrorRecoveryFlows/constants.ts
@@ -120,7 +120,7 @@ export const RECOVERY_MAP = {
},
IGNORE_AND_SKIP: {
ROUTE: 'ignore-and-skip-step',
- STEPS: { SELECT_IGNORE_KIND: 'select-ignore' },
+ STEPS: { SELECT_IGNORE_KIND: 'select-ignore', SKIP_STEP: 'skip-step' },
},
MANUAL_FILL_AND_SKIP: {
ROUTE: 'manual-fill-well-and-skip',
@@ -248,7 +248,10 @@ export const STEP_ORDER: StepOrder = {
DROP_TIP_FLOWS.STEPS.CHOOSE_TIP_DROP,
],
[REFILL_AND_RESUME.ROUTE]: [],
- [IGNORE_AND_SKIP.ROUTE]: [IGNORE_AND_SKIP.STEPS.SELECT_IGNORE_KIND],
+ [IGNORE_AND_SKIP.ROUTE]: [
+ IGNORE_AND_SKIP.STEPS.SELECT_IGNORE_KIND,
+ IGNORE_AND_SKIP.STEPS.SKIP_STEP,
+ ],
[CANCEL_RUN.ROUTE]: [CANCEL_RUN.STEPS.CONFIRM_CANCEL],
[MANUAL_FILL_AND_SKIP.ROUTE]: [
MANUAL_FILL_AND_SKIP.STEPS.MANUAL_FILL,
@@ -343,6 +346,7 @@ export const RECOVERY_MAP_METADATA: RecoveryRouteStepMetadata = {
[IGNORE_AND_SKIP.STEPS.SELECT_IGNORE_KIND]: {
allowDoorOpen: false,
},
+ [IGNORE_AND_SKIP.STEPS.SKIP_STEP]: { allowDoorOpen: false },
},
[MANUAL_FILL_AND_SKIP.ROUTE]: {
[MANUAL_FILL_AND_SKIP.STEPS.MANUAL_FILL]: {
diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryCommands.test.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryCommands.test.ts
index 016e38be69d..11a15edfbfd 100644
--- a/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryCommands.test.ts
+++ b/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryCommands.test.ts
@@ -44,7 +44,7 @@ describe('useRecoveryCommands', () => {
const mockChainRunCommands = vi.fn().mockResolvedValue([])
const mockReportActionSelectedResult = vi.fn()
const mockReportRecoveredRunResult = vi.fn()
- const mockUpdateErrorRecoveryPolicy = vi.fn()
+ const mockUpdateErrorRecoveryPolicy = vi.fn(() => Promise.resolve())
const props = {
runId: mockRunId,
@@ -70,7 +70,7 @@ describe('useRecoveryCommands', () => {
chainRunCommands: mockChainRunCommands,
} as any)
vi.mocked(useUpdateErrorRecoveryPolicy).mockReturnValue({
- updateErrorRecoveryPolicy: mockUpdateErrorRecoveryPolicy,
+ mutateAsync: mockUpdateErrorRecoveryPolicy,
} as any)
})
@@ -302,12 +302,18 @@ describe('useRecoveryCommands', () => {
failedCommandByRunRecord: mockFailedCommandWithError,
}
- const { result } = renderHook(() => useRecoveryCommands(testProps))
+ const { result, rerender } = renderHook(() =>
+ useRecoveryCommands(testProps)
+ )
await act(async () => {
- await result.current.ignoreErrorKindThisRun()
+ await result.current.ignoreErrorKindThisRun(true)
})
+ rerender()
+
+ result.current.skipFailedCommand()
+
const expectedPolicyRules = buildIgnorePolicyRules(
'aspirateInPlace',
'mockErrorType'
@@ -318,16 +324,33 @@ describe('useRecoveryCommands', () => {
)
})
- it('should reject with an error when failedCommand or error is null', async () => {
+ it('should call proceedToRouteAndStep with ERROR_WHILE_RECOVERING route when updateErrorRecoveryPolicy rejects', async () => {
+ const mockFailedCommandWithError = {
+ ...mockFailedCommand,
+ commandType: 'aspirateInPlace',
+ error: {
+ errorType: 'mockErrorType',
+ },
+ }
+
const testProps = {
...props,
- failedCommand: null,
+ failedCommandByRunRecord: mockFailedCommandWithError,
}
+ mockUpdateErrorRecoveryPolicy.mockRejectedValueOnce(
+ new Error('Update policy failed')
+ )
+
const { result } = renderHook(() => useRecoveryCommands(testProps))
- await expect(result.current.ignoreErrorKindThisRun()).rejects.toThrow(
- 'Could not execute command. No failed command.'
+ await act(async () => {
+ await result.current.ignoreErrorKindThisRun(true)
+ })
+
+ expect(mockUpdateErrorRecoveryPolicy).toHaveBeenCalled()
+ expect(mockProceedToRouteAndStep).toHaveBeenCalledWith(
+ RECOVERY_MAP.ERROR_WHILE_RECOVERING.ROUTE
)
})
})
diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryOptionCopy.test.tsx b/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryOptionCopy.test.tsx
index 2c2e2b4442b..62a810cd96e 100644
--- a/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryOptionCopy.test.tsx
+++ b/app/src/organisms/ErrorRecoveryFlows/hooks/__tests__/useRecoveryOptionCopy.test.tsx
@@ -48,6 +48,15 @@ describe('useRecoveryOptionCopy', () => {
screen.getByText('Retry dropping tip')
})
+ it(`renders the correct copy for ${RECOVERY_MAP.RETRY_STEP.ROUTE} when the error kind is ${ERROR_KINDS.TIP_NOT_DETECTED}`, () => {
+ render({
+ route: RECOVERY_MAP.RETRY_STEP.ROUTE,
+ errorKind: ERROR_KINDS.TIP_NOT_DETECTED,
+ })
+
+ screen.getByText('Retry picking up tip')
+ })
+
it(`renders the correct copy for ${RECOVERY_MAP.CANCEL_RUN.ROUTE}`, () => {
render({ route: RECOVERY_MAP.CANCEL_RUN.ROUTE })
diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts
index 777294da62d..f0962b07693 100644
--- a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts
+++ b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryCommands.ts
@@ -1,4 +1,4 @@
-import { useCallback } from 'react'
+import { useCallback, useState } from 'react'
import head from 'lodash/head'
import {
@@ -50,8 +50,10 @@ export interface UseRecoveryCommandsResult {
cancelRun: () => void
/* A terminal recovery command, that causes ER to exit as the run status becomes "running" */
skipFailedCommand: () => void
- /* A non-terminal recovery command. Ignore this errorKind for the rest of this run. */
- ignoreErrorKindThisRun: () => Promise
+ /* A non-terminal recovery command. Ignore this errorKind for the rest of this run.
+ * The server is not informed of recovery policy changes until a terminal recovery command occurs that does not result
+ * in termination of the run. */
+ ignoreErrorKindThisRun: (ignoreErrors: boolean) => Promise
/* A non-terminal recovery command */
retryFailedCommand: () => Promise
/* A non-terminal recovery command */
@@ -77,6 +79,8 @@ export function useRecoveryCommands({
analytics,
selectedRecoveryOption,
}: UseRecoveryCommandsParams): UseRecoveryCommandsResult {
+ const [ignoreErrors, setIgnoreErrors] = useState(false)
+
const { proceedToRouteAndStep } = routeUpdateActions
const { chainRunCommands } = useChainRunCommands(
runId,
@@ -86,7 +90,9 @@ export function useRecoveryCommands({
mutateAsync: resumeRunFromRecovery,
} = useResumeRunFromRecoveryMutation()
const { stopRun } = useStopRunMutation()
- const { updateErrorRecoveryPolicy } = useUpdateErrorRecoveryPolicy(runId)
+ const {
+ mutateAsync: updateErrorRecoveryPolicy,
+ } = useUpdateErrorRecoveryPolicy(runId)
const { makeSuccessToast } = recoveryToastUtils
const chainRunRecoveryCommands = useCallback(
@@ -182,12 +188,59 @@ export function useRecoveryCommands({
}
}, [chainRunRecoveryCommands, failedCommandByRunRecord, failedLabwareUtils])
+ const ignoreErrorKindThisRun = (ignoreErrors: boolean): Promise => {
+ setIgnoreErrors(ignoreErrors)
+ return Promise.resolve()
+ }
+
+ // Only send the finalized error policy to the server during a terminal recovery command that does not terminate the run.
+ // If the request to update the policy fails, route to the error modal.
+ const handleIgnoringErrorKind = useCallback((): Promise => {
+ if (ignoreErrors) {
+ if (failedCommandByRunRecord?.error != null) {
+ const ignorePolicyRules = buildIgnorePolicyRules(
+ failedCommandByRunRecord.commandType,
+ failedCommandByRunRecord.error.errorType
+ )
+
+ return updateErrorRecoveryPolicy(ignorePolicyRules)
+ .then(() => Promise.resolve())
+ .catch(() =>
+ Promise.reject(new Error('Failed to update recovery policy.'))
+ )
+ } else {
+ void proceedToRouteAndStep(RECOVERY_MAP.ERROR_WHILE_RECOVERING.ROUTE)
+ return Promise.reject(
+ new Error('Could not execute command. No failed command.')
+ )
+ }
+ } else {
+ return Promise.resolve()
+ }
+ }, [
+ failedCommandByRunRecord?.error?.errorType,
+ failedCommandByRunRecord?.commandType,
+ ignoreErrors,
+ ])
+
const resumeRun = useCallback((): void => {
- void resumeRunFromRecovery(runId).then(() => {
- analytics.reportActionSelectedResult(selectedRecoveryOption, 'succeeded')
- makeSuccessToast()
- })
- }, [runId, resumeRunFromRecovery, makeSuccessToast])
+ void handleIgnoringErrorKind()
+ .then(() => resumeRunFromRecovery(runId))
+ .then(() => {
+ analytics.reportActionSelectedResult(
+ selectedRecoveryOption,
+ 'succeeded'
+ )
+ makeSuccessToast()
+ })
+ }, [
+ runId,
+ ignoreErrors,
+ resumeRunFromRecovery,
+ handleIgnoringErrorKind,
+ selectedRecoveryOption,
+ makeSuccessToast,
+ ])
const cancelRun = useCallback((): void => {
analytics.reportActionSelectedResult(selectedRecoveryOption, 'succeeded')
@@ -195,29 +248,21 @@ export function useRecoveryCommands({
}, [runId])
const skipFailedCommand = useCallback((): void => {
- void resumeRunFromRecovery(runId).then(() => {
- analytics.reportActionSelectedResult(selectedRecoveryOption, 'succeeded')
- makeSuccessToast()
- })
- }, [runId, resumeRunFromRecovery, makeSuccessToast])
-
- const ignoreErrorKindThisRun = useCallback((): Promise => {
- if (failedCommandByRunRecord?.error != null) {
- const ignorePolicyRules = buildIgnorePolicyRules(
- failedCommandByRunRecord.commandType,
- failedCommandByRunRecord.error.errorType
- )
-
- updateErrorRecoveryPolicy(ignorePolicyRules)
- return Promise.resolve()
- } else {
- return Promise.reject(
- new Error('Could not execute command. No failed command.')
- )
- }
+ void handleIgnoringErrorKind().then(() =>
+ resumeRunFromRecovery(runId).then(() => {
+ analytics.reportActionSelectedResult(
+ selectedRecoveryOption,
+ 'succeeded'
+ )
+ makeSuccessToast()
+ })
+ )
}, [
- failedCommandByRunRecord?.error?.errorType,
- failedCommandByRunRecord?.commandType,
+ runId,
+ resumeRunFromRecovery,
+ handleIgnoringErrorKind,
+ selectedRecoveryOption,
+ makeSuccessToast,
])
const releaseGripperJaws = useCallback((): Promise => {
diff --git a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryOptionCopy.tsx b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryOptionCopy.tsx
index 18a7da7a319..b364af7f9d5 100644
--- a/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryOptionCopy.tsx
+++ b/app/src/organisms/ErrorRecoveryFlows/hooks/useRecoveryOptionCopy.tsx
@@ -19,6 +19,8 @@ export function useRecoveryOptionCopy(): (
case RECOVERY_MAP.RETRY_STEP.ROUTE:
if (errorKind === ERROR_KINDS.TIP_DROP_FAILED) {
return t('retry_dropping_tip')
+ } else if (errorKind === ERROR_KINDS.TIP_NOT_DETECTED) {
+ return t('retry_picking_up_tip')
} else {
return t('retry_step')
}
diff --git a/app/src/organisms/ErrorRecoveryFlows/shared/SkipStepInfo.tsx b/app/src/organisms/ErrorRecoveryFlows/shared/SkipStepInfo.tsx
index 1caed4f583b..4cc31e4732a 100644
--- a/app/src/organisms/ErrorRecoveryFlows/shared/SkipStepInfo.tsx
+++ b/app/src/organisms/ErrorRecoveryFlows/shared/SkipStepInfo.tsx
@@ -17,6 +17,7 @@ export function SkipStepInfo(props: RecoveryContentProps): JSX.Element {
SKIP_STEP_WITH_SAME_TIPS,
SKIP_STEP_WITH_NEW_TIPS,
MANUAL_MOVE_AND_SKIP,
+ IGNORE_AND_SKIP,
} = RECOVERY_MAP
const { selectedRecoveryOption } = currentRecoveryOptionUtils
const { skipFailedCommand } = recoveryCommands
@@ -43,6 +44,7 @@ export function SkipStepInfo(props: RecoveryContentProps): JSX.Element {
return t('skip_to_next_step_same_tips')
case SKIP_STEP_WITH_NEW_TIPS.ROUTE:
return t('skip_to_next_step_new_tips')
+ case IGNORE_AND_SKIP.ROUTE:
case MANUAL_MOVE_AND_SKIP.ROUTE:
return t('skip_to_next_step')
default:
@@ -55,6 +57,8 @@ export function SkipStepInfo(props: RecoveryContentProps): JSX.Element {
const buildBodyCopyKey = (): string => {
switch (selectedRecoveryOption) {
+ case IGNORE_AND_SKIP.ROUTE:
+ return 'inspect_the_robot'
case SKIP_STEP_WITH_SAME_TIPS.ROUTE:
case SKIP_STEP_WITH_NEW_TIPS.ROUTE:
return 'failed_dispense_step_not_completed'
diff --git a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/ErrorDetailsModal.test.tsx b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/ErrorDetailsModal.test.tsx
index 11b4df62700..d759aaf3d78 100644
--- a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/ErrorDetailsModal.test.tsx
+++ b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/ErrorDetailsModal.test.tsx
@@ -171,7 +171,7 @@ describe('TipNotDetectedBanner', () => {
heading:
'Tip presence errors are usually caused by improperly placed labware or inaccurate labware offsets',
message:
- ' If the issue persists, cancel the run and initiate Labware Position Check',
+ ' If the issue persists, cancel the run and perform Labware Position Check',
}),
{}
)
diff --git a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/SkipStepInfo.test.tsx b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/SkipStepInfo.test.tsx
index 77095a45a6d..e1ac4cf1adc 100644
--- a/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/SkipStepInfo.test.tsx
+++ b/app/src/organisms/ErrorRecoveryFlows/shared/__tests__/SkipStepInfo.test.tsx
@@ -58,6 +58,18 @@ describe('SkipStepInfo', () => {
})
})
+ it(`renders correct title and body text for ${RECOVERY_MAP.IGNORE_AND_SKIP.ROUTE}`, () => {
+ props.currentRecoveryOptionUtils.selectedRecoveryOption =
+ RECOVERY_MAP.IGNORE_AND_SKIP.ROUTE
+ render(props)
+
+ screen.getByText('Skip to next step')
+ screen.getByText(
+ "First, inspect the robot to ensure it's prepared to continue the run from the next step."
+ )
+ screen.getByText('Then, close the robot door before proceeding.')
+ })
+
it(`renders correct title and body text for ${RECOVERY_MAP.SKIP_STEP_WITH_SAME_TIPS.ROUTE}`, () => {
props.currentRecoveryOptionUtils.selectedRecoveryOption =
RECOVERY_MAP.SKIP_STEP_WITH_SAME_TIPS.ROUTE
@@ -95,8 +107,7 @@ describe('SkipStepInfo', () => {
})
it('renders error message for unexpected recovery option', () => {
- props.currentRecoveryOptionUtils.selectedRecoveryOption =
- RECOVERY_MAP.IGNORE_AND_SKIP.ROUTE
+ props.currentRecoveryOptionUtils.selectedRecoveryOption = 'UNEXPECTED_ROUTE' as any
render(props)
expect(screen.getAllByText('UNEXPECTED STEP')[0]).toBeInTheDocument()