From 8bd134873a6548e9febe037f6218e6c3d1c87538 Mon Sep 17 00:00:00 2001 From: Andrew Azores Date: Wed, 8 Feb 2023 13:48:05 -0500 Subject: [PATCH] add more tests Signed-off-by: Andrew Azores --- src/app/Dashboard/Charts/ChartCard.tsx | 4 +- src/test/Dashboard/Charts/ChartCard.test.tsx | 139 +++++++++++++++++- .../__snapshots__/ChartCard.test.tsx.snap | 126 +++++++++++++++- 3 files changed, 258 insertions(+), 11 deletions(-) diff --git a/src/app/Dashboard/Charts/ChartCard.tsx b/src/app/Dashboard/Charts/ChartCard.tsx index f53e505829..cfae406f72 100644 --- a/src/app/Dashboard/Charts/ChartCard.tsx +++ b/src/app/Dashboard/Charts/ChartCard.tsx @@ -69,7 +69,7 @@ export interface ChartCardProps extends DashboardCardProps { } // TODO these need to be localized -enum ChartKind { +export enum ChartKind { 'Core Count' = 1, 'Thread Count' = 2, 'CPU Load' = 3, @@ -96,7 +96,7 @@ enum ChartKind { 'Object Allocation Sample' = 38, } -function kindToId(kind: string): number { +export function kindToId(kind: string): number { return ChartKind[kind]; } diff --git a/src/test/Dashboard/Charts/ChartCard.test.tsx b/src/test/Dashboard/Charts/ChartCard.test.tsx index 92287044b5..b303930cb5 100644 --- a/src/test/Dashboard/Charts/ChartCard.test.tsx +++ b/src/test/Dashboard/Charts/ChartCard.test.tsx @@ -37,19 +37,30 @@ */ jest.mock('@app/Dashboard/Charts/ChartController'); -import { ChartCard } from '@app/Dashboard/Charts/ChartCard'; + +import { createMemoryHistory } from 'history'; +const history = createMemoryHistory({ initialEntries: ['/'] }); +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useRouteMatch: () => ({ url: history.location.pathname }), + useHistory: () => history, +})); +import { ChartCard, ChartKind, kindToId } from '@app/Dashboard/Charts/ChartCard'; import { ChartContext } from '@app/Dashboard/Charts/ChartContext'; import { ChartController } from '@app/Dashboard/Charts/ChartController'; import { NotificationsContext, NotificationsInstance } from '@app/Notifications/Notifications'; -import { store } from '@app/Shared/Redux/ReduxStore'; +import { setupStore, store } from '@app/Shared/Redux/ReduxStore'; import { defaultServices, ServiceContext } from '@app/Shared/Services/Services'; -import React from 'react'; +import { render } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React, { PropsWithChildren } from 'react'; import { Provider } from 'react-redux'; import renderer, { act } from 'react-test-renderer'; -import { of } from 'rxjs'; +import { Observable, of } from 'rxjs'; +import { cleanup, screen, waitFor } from '@testing-library/react'; -const mockGrafanaDashboardUrlResponse = 'http://localhost:3000'; -jest.spyOn(defaultServices.api, 'grafanaDashboardUrl').mockReturnValueOnce(of(mockGrafanaDashboardUrlResponse)); +const mockDashboardUrl = 'http://localhost:3000'; +jest.spyOn(defaultServices.api, 'grafanaDashboardUrl').mockReturnValue(of(mockDashboardUrl)); const mockTarget = { connectUrl: 'service:jmx:rmi://someUrl', alias: 'fooTarget' }; jest.spyOn(defaultServices.target, 'target').mockReturnValue(of(mockTarget)); @@ -64,10 +75,11 @@ const mockChartContext = { controller: mockController, }; +jest.spyOn(mockController, 'attach').mockReturnValue(of(0)); + describe('', () => { it('renders correctly', async () => { jest.spyOn(mockController, 'hasActiveRecording').mockReturnValue(of(true)); - jest.spyOn(mockController, 'attach').mockReturnValue(of(0)); let tree; await act(async () => { @@ -83,6 +95,117 @@ describe('', () => { ); }); - expect(tree.toJSON()).toMatchSnapshot(); + expect(tree.toJSON()).toMatchSnapshot('with-content'); + }); + + it('renders empty state correctly', async () => { + jest.spyOn(mockController, 'hasActiveRecording').mockReturnValue(of(false)); + + let tree; + await act(async () => { + tree = renderer.create( + + + + + + + + + + ); + }); + expect(tree.toJSON()).toMatchSnapshot('empty-state'); + }); + + it('renders empty state with information and action button', async () => { + jest.spyOn(mockController, 'hasActiveRecording').mockReturnValue(of(false)); + + renderChartCard( + + ); + + expect(screen.getByText('CPU Load')).toBeInTheDocument(); + expect(screen.getByText('No source recording')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: /create/i })).toBeInTheDocument(); + }); + + it('navigates to recording creation with prefilled state when empty state button clicked', async () => { + jest.spyOn(mockController, 'hasActiveRecording').mockReturnValue(of(false)); + + const { user } = renderChartCard( + + ); + + expect(history.location.pathname).toBe('/'); + await user.click(screen.getByRole('button', { name: /create/i })); + expect(history.location.pathname).toBe('/recordings/create'); + expect(history.location.state).toEqual({ + duration: -1, + labels: [ + { + key: 'origin', + value: 'dashboard_metrics', + }, + ], + maxAge: 120, + maxSize: 100 * 1024 * 1024, + name: 'dashboard_metrics', + restartExisting: true, + templateName: 'Profiling', + templateType: 'TARGET', + }); + }); + + it.each([ + ['CPU Load', 120, 5], + ['Heap Usage', 90, 10], + ['Network Utilization', 60, 15], + ['File I/O', 30, 20], + ])('renders iframe', async (chartKind: string, duration: number, period: number) => { + jest.spyOn(mockController, 'hasActiveRecording').mockReturnValue(of(true)); + + const { container } = renderChartCard( + + ); + + const iframe = container.querySelector('iframe'); + expect(iframe).toBeTruthy(); + const u = new URL(iframe?.src || ''); + expect(u.host).toBe('localhost:3000'); + expect(u.protocol).toBe('http:'); + const params = new URLSearchParams(); + params.set('theme', 'light'); + params.set('panelId', String(kindToId(chartKind))); + params.set('to', 'now'); + params.set('from', `now-${duration}s`); + params.set('refresh', `${period}s`); + expect(u.searchParams.toString()).toEqual(params.toString()); }); }); + +const renderChartCard = ( + ui: React.ReactElement, + { + services = defaultServices, + notifications = NotificationsInstance, + chartContext = mockChartContext, + preloadState = {}, + store = setupStore(preloadState), + user = userEvent.setup(), + ...renderOptions + } = {} +) => { + const Wrapper = ({ children }: PropsWithChildren) => { + return ( + + + + {children} + + + + ); + }; + return { store, user, ...render(ui, { wrapper: Wrapper, ...renderOptions }) }; +}; diff --git a/src/test/Dashboard/Charts/__snapshots__/ChartCard.test.tsx.snap b/src/test/Dashboard/Charts/__snapshots__/ChartCard.test.tsx.snap index f38722b309..182fbc04d6 100644 --- a/src/test/Dashboard/Charts/__snapshots__/ChartCard.test.tsx.snap +++ b/src/test/Dashboard/Charts/__snapshots__/ChartCard.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` renders correctly 1`] = ` +exports[` renders correctly: with-content 1`] = `
renders correctly 1`] = `
`; + +exports[` renders empty state correctly: empty-state 1`] = ` +
+
+
+
+
+
+ CPU Load +
+
+
+
+
+
+
+
+ +

+ No source recording +

+
+ Metrics cards display data taken from running flight recordings with the label + + + origin= + dashboard_metrics + + . No such recordings are currently available. +
+ +
+
+
+
+
+
+
+
+`;