-
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): revert run a protocol from devices pages (#11909)
adds back the previously-removed ability to run a protocol from the robot card overflow menu, and adds a similar menu item to the overflow menu on the device details page. closes RCORE-327
- Loading branch information
1 parent
c50e145
commit a9e3123
Showing
9 changed files
with
1,135 additions
and
55 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
176 changes: 176 additions & 0 deletions
176
app/src/organisms/ChooseProtocolSlideout/__tests__/ChooseProtocolSlideout.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,176 @@ | ||
import * as React from 'react' | ||
import { when } from 'jest-when' | ||
import { renderWithProviders } from '@opentrons/components' | ||
import { StaticRouter } from 'react-router-dom' | ||
import { fireEvent } from '@testing-library/react' | ||
import { i18n } from '../../../i18n' | ||
import { getStoredProtocols } from '../../../redux/protocol-storage' | ||
import { mockConnectableRobot } from '../../../redux/discovery/__fixtures__' | ||
import { useFeatureFlag } from '../../../redux/config' | ||
import { storedProtocolData as storedProtocolDataFixture } from '../../../redux/protocol-storage/__fixtures__' | ||
import { DeckThumbnail } from '../../../molecules/DeckThumbnail' | ||
import { useTrackCreateProtocolRunEvent } from '../../../organisms/Devices/hooks' | ||
import { useCreateRunFromProtocol } from '../../ChooseRobotToRunProtocolSlideout/useCreateRunFromProtocol' | ||
import { ChooseProtocolSlideout } from '../' | ||
|
||
jest.mock('../../ChooseRobotToRunProtocolSlideout/useCreateRunFromProtocol') | ||
jest.mock('../../../redux/protocol-storage') | ||
jest.mock('../../../molecules/DeckThumbnail') | ||
jest.mock('../../../organisms/Devices/hooks') | ||
jest.mock('../../../redux/config') | ||
|
||
const mockUseFeatureFlag = useFeatureFlag as jest.MockedFunction< | ||
typeof useFeatureFlag | ||
> | ||
const mockGetStoredProtocols = getStoredProtocols as jest.MockedFunction< | ||
typeof getStoredProtocols | ||
> | ||
const mockUseCreateRunFromProtocol = useCreateRunFromProtocol as jest.MockedFunction< | ||
typeof useCreateRunFromProtocol | ||
> | ||
const mockDeckThumbnail = DeckThumbnail as jest.MockedFunction< | ||
typeof DeckThumbnail | ||
> | ||
const mockUseTrackCreateProtocolRunEvent = useTrackCreateProtocolRunEvent as jest.MockedFunction< | ||
typeof useTrackCreateProtocolRunEvent | ||
> | ||
|
||
const render = (props: React.ComponentProps<typeof ChooseProtocolSlideout>) => { | ||
return renderWithProviders( | ||
<StaticRouter> | ||
<ChooseProtocolSlideout {...props} /> | ||
</StaticRouter>, | ||
{ | ||
i18nInstance: i18n, | ||
} | ||
) | ||
} | ||
|
||
describe('ChooseProtocolSlideout', () => { | ||
let mockCreateRunFromProtocol: jest.Mock | ||
let mockTrackCreateProtocolRunEvent: jest.Mock | ||
beforeEach(() => { | ||
mockCreateRunFromProtocol = jest.fn() | ||
mockTrackCreateProtocolRunEvent = jest.fn( | ||
() => new Promise(resolve => resolve({})) | ||
) | ||
mockGetStoredProtocols.mockReturnValue([storedProtocolDataFixture]) | ||
mockDeckThumbnail.mockReturnValue(<div>mock Deck Thumbnail</div>) | ||
mockUseCreateRunFromProtocol.mockReturnValue({ | ||
createRunFromProtocolSource: mockCreateRunFromProtocol, | ||
} as any) | ||
mockUseTrackCreateProtocolRunEvent.mockReturnValue({ | ||
trackCreateProtocolRunEvent: mockTrackCreateProtocolRunEvent, | ||
}) | ||
when(mockUseFeatureFlag) | ||
.calledWith('enableManualDeckStateModification') | ||
.mockReturnValue(true) | ||
}) | ||
afterEach(() => { | ||
jest.resetAllMocks() | ||
}) | ||
|
||
it('renders slideout if showSlideout true', () => { | ||
const [{ queryAllByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
expect(queryAllByText('Choose Protocol to Run')).not.toBeFalsy() | ||
expect(queryAllByText(mockConnectableRobot.name)).not.toBeFalsy() | ||
}) | ||
it('does not render slideout if showSlideout false', () => { | ||
const [{ queryAllByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
expect(queryAllByText('Choose Protocol to Run').length).toEqual(0) | ||
expect(queryAllByText(mockConnectableRobot.name).length).toEqual(0) | ||
}) | ||
it('renders an available protocol option for every stored protocol if any', () => { | ||
const [{ getByText, queryByRole }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
getByText('mock Deck Thumbnail') | ||
getByText('fakeSrcFileName') | ||
expect(queryByRole('heading', { name: 'No protocols found' })).toBeNull() | ||
}) | ||
it('renders an empty state if no protocol options', () => { | ||
mockGetStoredProtocols.mockReturnValue([]) | ||
const [{ getByRole, queryByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
expect(queryByText('mock Deck Thumbnail')).toBeNull() | ||
expect(queryByText('fakeSrcFileName')).toBeNull() | ||
expect( | ||
getByRole('heading', { name: 'No protocols found' }) | ||
).toBeInTheDocument() | ||
}) | ||
it('calls createRunFromProtocolSource if CTA clicked', () => { | ||
const [{ getByRole }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
const proceedButton = getByRole('button', { name: 'Proceed to setup' }) | ||
fireEvent.click(proceedButton) | ||
expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ | ||
files: [expect.any(File)], | ||
protocolKey: storedProtocolDataFixture.protocolKey, | ||
}) | ||
expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() | ||
}) | ||
it('renders error state when there is a run creation error', () => { | ||
mockUseCreateRunFromProtocol.mockReturnValue({ | ||
runCreationError: 'run creation error', | ||
createRunFromProtocolSource: mockCreateRunFromProtocol, | ||
isCreatingRun: false, | ||
reset: jest.fn(), | ||
runCreationErrorCode: 500, | ||
}) | ||
const [{ getByRole, getByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
const proceedButton = getByRole('button', { name: 'Proceed to setup' }) | ||
proceedButton.click() | ||
expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ | ||
files: [expect.any(File)], | ||
protocolKey: storedProtocolDataFixture.protocolKey, | ||
}) | ||
expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() | ||
expect(getByText('run creation error')).toBeInTheDocument() | ||
}) | ||
|
||
it('renders error state when run creation error code is 409', () => { | ||
mockUseCreateRunFromProtocol.mockReturnValue({ | ||
runCreationError: 'Current run is not idle or stopped.', | ||
createRunFromProtocolSource: mockCreateRunFromProtocol, | ||
isCreatingRun: false, | ||
reset: jest.fn(), | ||
runCreationErrorCode: 409, | ||
}) | ||
const [{ getByRole, getByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
const proceedButton = getByRole('button', { name: 'Proceed to setup' }) | ||
proceedButton.click() | ||
expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ | ||
files: [expect.any(File)], | ||
protocolKey: storedProtocolDataFixture.protocolKey, | ||
}) | ||
expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() | ||
getByText('This robot is busy and can’t run this protocol right now.') | ||
const link = getByRole('link', { name: 'Go to Robot' }) | ||
fireEvent.click(link) | ||
expect(link.getAttribute('href')).toEqual('/devices/opentrons-robot-name') | ||
}) | ||
}) |
182 changes: 182 additions & 0 deletions
182
app/src/organisms/ChooseProtocolSlideout/__tests__/DeprecatedChooseProtocolSlideout.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,182 @@ | ||
/** | ||
* This component test can be removed along with the | ||
* enableManualDeckStateMod feature flag. It's coverage will be | ||
* replaced by the ChooseProtocolSlideout.text.tsx file | ||
*/ | ||
|
||
import * as React from 'react' | ||
import { when } from 'jest-when' | ||
import { renderWithProviders } from '@opentrons/components' | ||
import { StaticRouter } from 'react-router-dom' | ||
import { fireEvent } from '@testing-library/react' | ||
import { i18n } from '../../../i18n' | ||
import { getStoredProtocols } from '../../../redux/protocol-storage' | ||
import { mockConnectableRobot } from '../../../redux/discovery/__fixtures__' | ||
import { useFeatureFlag } from '../../../redux/config' | ||
import { storedProtocolData as storedProtocolDataFixture } from '../../../redux/protocol-storage/__fixtures__' | ||
import { DeckThumbnail } from '../../../molecules/DeckThumbnail' | ||
import { useTrackCreateProtocolRunEvent } from '../../../organisms/Devices/hooks' | ||
import { useCreateRunFromProtocol } from '../../ChooseRobotToRunProtocolSlideout/useCreateRunFromProtocol' | ||
import { ChooseProtocolSlideout } from '../' | ||
|
||
jest.mock('../../ChooseRobotToRunProtocolSlideout/useCreateRunFromProtocol') | ||
jest.mock('../../../redux/protocol-storage') | ||
jest.mock('../../../molecules/DeckThumbnail') | ||
jest.mock('../../../organisms/Devices/hooks') | ||
jest.mock('../../../redux/config') | ||
|
||
const mockUseFeatureFlag = useFeatureFlag as jest.MockedFunction< | ||
typeof useFeatureFlag | ||
> | ||
const mockGetStoredProtocols = getStoredProtocols as jest.MockedFunction< | ||
typeof getStoredProtocols | ||
> | ||
const mockUseCreateRunFromProtocol = useCreateRunFromProtocol as jest.MockedFunction< | ||
typeof useCreateRunFromProtocol | ||
> | ||
const mockDeckThumbnail = DeckThumbnail as jest.MockedFunction< | ||
typeof DeckThumbnail | ||
> | ||
const mockUseTrackCreateProtocolRunEvent = useTrackCreateProtocolRunEvent as jest.MockedFunction< | ||
typeof useTrackCreateProtocolRunEvent | ||
> | ||
|
||
const render = (props: React.ComponentProps<typeof ChooseProtocolSlideout>) => { | ||
return renderWithProviders( | ||
<StaticRouter> | ||
<ChooseProtocolSlideout {...props} /> | ||
</StaticRouter>, | ||
{ | ||
i18nInstance: i18n, | ||
} | ||
) | ||
} | ||
|
||
describe('ChooseProtocolSlideout', () => { | ||
let mockCreateRunFromProtocol: jest.Mock | ||
let mockTrackCreateProtocolRunEvent: jest.Mock | ||
beforeEach(() => { | ||
mockCreateRunFromProtocol = jest.fn() | ||
mockTrackCreateProtocolRunEvent = jest.fn( | ||
() => new Promise(resolve => resolve({})) | ||
) | ||
mockGetStoredProtocols.mockReturnValue([storedProtocolDataFixture]) | ||
mockDeckThumbnail.mockReturnValue(<div>mock Deck Thumbnail</div>) | ||
mockUseCreateRunFromProtocol.mockReturnValue({ | ||
createRunFromProtocolSource: mockCreateRunFromProtocol, | ||
} as any) | ||
mockUseTrackCreateProtocolRunEvent.mockReturnValue({ | ||
trackCreateProtocolRunEvent: mockTrackCreateProtocolRunEvent, | ||
}) | ||
when(mockUseFeatureFlag) | ||
.calledWith('enableManualDeckStateModification') | ||
.mockReturnValue(false) | ||
}) | ||
afterEach(() => { | ||
jest.resetAllMocks() | ||
}) | ||
|
||
it('renders slideout if showSlideout true', () => { | ||
const [{ queryAllByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
expect(queryAllByText('Choose Protocol to Run')).not.toBeFalsy() | ||
expect(queryAllByText(mockConnectableRobot.name)).not.toBeFalsy() | ||
}) | ||
it('does not render slideout if showSlideout false', () => { | ||
const [{ queryAllByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
expect(queryAllByText('Choose Protocol to Run').length).toEqual(0) | ||
expect(queryAllByText(mockConnectableRobot.name).length).toEqual(0) | ||
}) | ||
it('renders an available protocol option for every stored protocol if any', () => { | ||
const [{ getByText, queryByRole }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
getByText('mock Deck Thumbnail') | ||
getByText('fakeSrcFileName') | ||
expect(queryByRole('heading', { name: 'No protocols found' })).toBeNull() | ||
}) | ||
it('renders an empty state if no protocol options', () => { | ||
mockGetStoredProtocols.mockReturnValue([]) | ||
const [{ getByRole, queryByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
expect(queryByText('mock Deck Thumbnail')).toBeNull() | ||
expect(queryByText('fakeSrcFileName')).toBeNull() | ||
expect( | ||
getByRole('heading', { name: 'No protocols found' }) | ||
).toBeInTheDocument() | ||
}) | ||
it('calls createRunFromProtocolSource if CTA clicked', () => { | ||
const [{ getByRole }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
const proceedButton = getByRole('button', { name: 'Proceed to setup' }) | ||
fireEvent.click(proceedButton) | ||
expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ | ||
files: [expect.any(File)], | ||
protocolKey: storedProtocolDataFixture.protocolKey, | ||
}) | ||
expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() | ||
}) | ||
it('renders error state when there is a run creation error', () => { | ||
mockUseCreateRunFromProtocol.mockReturnValue({ | ||
runCreationError: 'run creation error', | ||
createRunFromProtocolSource: mockCreateRunFromProtocol, | ||
isCreatingRun: false, | ||
reset: jest.fn(), | ||
runCreationErrorCode: 500, | ||
}) | ||
const [{ getByRole, getByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
const proceedButton = getByRole('button', { name: 'Proceed to setup' }) | ||
proceedButton.click() | ||
expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ | ||
files: [expect.any(File)], | ||
protocolKey: storedProtocolDataFixture.protocolKey, | ||
}) | ||
expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() | ||
expect(getByText('run creation error')).toBeInTheDocument() | ||
}) | ||
|
||
it('renders error state when run creation error code is 409', () => { | ||
mockUseCreateRunFromProtocol.mockReturnValue({ | ||
runCreationError: 'Current run is not idle or stopped.', | ||
createRunFromProtocolSource: mockCreateRunFromProtocol, | ||
isCreatingRun: false, | ||
reset: jest.fn(), | ||
runCreationErrorCode: 409, | ||
}) | ||
const [{ getByRole, getByText }] = render({ | ||
robot: mockConnectableRobot, | ||
onCloseClick: jest.fn(), | ||
showSlideout: true, | ||
}) | ||
const proceedButton = getByRole('button', { name: 'Proceed to setup' }) | ||
proceedButton.click() | ||
expect(mockCreateRunFromProtocol).toHaveBeenCalledWith({ | ||
files: [expect.any(File)], | ||
protocolKey: storedProtocolDataFixture.protocolKey, | ||
}) | ||
expect(mockTrackCreateProtocolRunEvent).toHaveBeenCalled() | ||
getByText('This robot is busy and can’t run this protocol right now.') | ||
const link = getByRole('link', { name: 'Go to Robot' }) | ||
fireEvent.click(link) | ||
expect(link.getAttribute('href')).toEqual('/devices/opentrons-robot-name') | ||
}) | ||
}) |
Oops, something went wrong.