From 5015c929b5621256f1abdda3522d383c2d7d377c Mon Sep 17 00:00:00 2001 From: Koji Date: Wed, 22 Jun 2022 19:49:40 -0400 Subject: [PATCH] feat(app): this PR is for robot rename function This PR is for robot rename function and this PR will be used by #10723 to retrieve the new robot name partially fix #10709 --- .../Devices/hooks/useRobotAnalyticsData.ts | 56 +++++++++++++++ .../src/server/__tests__/useRobotName.test.ts | 0 .../server/__tests__/useRobotName.test.tsx | 70 +++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts delete mode 100644 react-api-client/src/server/__tests__/useRobotName.test.ts create mode 100644 react-api-client/src/server/__tests__/useRobotName.test.tsx diff --git a/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts b/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts new file mode 100644 index 00000000000..262bf699470 --- /dev/null +++ b/app/src/organisms/Devices/hooks/useRobotAnalyticsData.ts @@ -0,0 +1,56 @@ +import * as React from 'react' +import { useSelector, useDispatch } from 'react-redux' + +import { useRobot } from './' +import { getAttachedPipettes } from '../../../redux/pipettes' +import { getRobotSettings, fetchSettings } from '../../../redux/robot-settings' +import { FF_PREFIX } from '../../../redux/analytics' +import { + getRobotApiVersion, + getRobotFirmwareVersion, +} from '../../../redux/discovery' + +import type { State, Dispatch } from '../../../redux/types' +import type { RobotAnalyticsData } from '../../../redux/analytics/types' + +/** + * + * @param {string} robotName + * @returns {RobotAnalyticsData} + * for use in trackEvent + */ +export function useRobotAnalyticsData( + robotName: string +): RobotAnalyticsData | null { + const robot = useRobot(robotName) + const pipettes = useSelector((state: State) => + getAttachedPipettes(state, robotName) + ) + const settings = useSelector((state: State) => + getRobotSettings(state, robotName) + ) + const dispatch = useDispatch() + + React.useEffect(() => { + dispatch(fetchSettings(robotName)) + }, [dispatch, robotName]) + + if (robot != null) { + // @ts-expect-error RobotAnalyticsData type needs boolean values should it be boolean | string + return settings.reduce( + (result, setting) => ({ + ...result, + [`${FF_PREFIX}${setting.id}`]: !!(setting.value ?? false), + }), + // @ts-expect-error RobotAnalyticsData type needs boolean values should it be boolean | string + { + robotApiServerVersion: getRobotApiVersion(robot) || '', + robotSmoothieVersion: getRobotFirmwareVersion(robot) || '', + robotLeftPipette: pipettes.left?.model || '', + robotRightPipette: pipettes.right?.model || '', + } + ) + } + + return null +} diff --git a/react-api-client/src/server/__tests__/useRobotName.test.ts b/react-api-client/src/server/__tests__/useRobotName.test.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/react-api-client/src/server/__tests__/useRobotName.test.tsx b/react-api-client/src/server/__tests__/useRobotName.test.tsx new file mode 100644 index 00000000000..ec0f192f857 --- /dev/null +++ b/react-api-client/src/server/__tests__/useRobotName.test.tsx @@ -0,0 +1,70 @@ +import * as React from 'react' +import { when, resetAllWhenMocks } from 'jest-when' +import { QueryClient, QueryClientProvider } from 'react-query' +import { renderHook } from '@testing-library/react-hooks' +import { getRobotName } from '@opentrons/api-client' +import { useHost } from '../../api' +import { useRobotName } from '..' + +import type { + HostConfig, + Response, + CurrentRobotName, +} from '@opentrons/api-client' +import { act } from 'react-test-renderer' + +jest.mock('@opentrons/api-client') +jest.mock('../../api/useHost') + +const mockGetRobotName = getRobotName as jest.MockedFunction< + typeof getRobotName +> +const mockUseHost = useHost as jest.MockedFunction + +const HOST_CONFIG: HostConfig = { hostname: 'localhost' } + +const ROBOT_NAME = { name: 'otie' } + +describe('useRobotName hook', () => { + let wrapper: React.FunctionComponent<{}> + + beforeEach(() => { + const queryClient = new QueryClient() + const clientProvider: React.FunctionComponent<{}> = ({ children }) => ( + {children} + ) + + wrapper = clientProvider + }) + afterEach(() => { + resetAllWhenMocks() + }) + + it('should return no data if no host', () => { + when(mockUseHost).calledWith().mockReturnValue(null) + + const { result } = renderHook(useRobotName, { wrapper }) + expect(result.current.data).toBeUndefined() + }) + + it('should return no data if the getRobotName request fails', () => { + when(mockUseHost).calledWith().mockReturnValue(HOST_CONFIG) + when(mockGetRobotName).calledWith(HOST_CONFIG).mockRejectedValue('fail') + + const { result } = renderHook(useRobotName, { wrapper }) + expect(result.current.data).toBeUndefined() + }) + + it('should return robot name', async () => { + when(mockUseHost).calledWith().mockReturnValue(HOST_CONFIG) + when(mockGetRobotName) + .calledWith(HOST_CONFIG) + .mockResolvedValue({ + data: ROBOT_NAME, + } as Response) + + const { result, waitFor } = renderHook(useRobotName, { wrapper }) + await waitFor(() => result.current.data != null) + expect(result.current.data).toEqual(ROBOT_NAME) + }) +})