Skip to content

Commit

Permalink
NETOBSERV-1266 Netflow traffic tab crash (#377)
Browse files Browse the repository at this point in the history
* fix props infinite loop

* ensure nav always loaded

* fix testing

* add tab examples to standalone
  • Loading branch information
jpinsonneau committed Sep 4, 2023
1 parent 19a7ab9 commit 1ca3b6a
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 134 deletions.
47 changes: 43 additions & 4 deletions web/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import {
PageHeaderTools,
PageHeaderToolsGroup,
PageHeaderToolsItem,
PageSection,
PageSidebar,
Radio
} from '@patternfly/react-core';
import React from 'react';
import { BrowserRouter, Link, Route, Routes } from 'react-router-dom';
import NetflowTab from './components/netflow-tab';
import NetflowTrafficParent from './components/netflow-traffic-parent';

interface AppState {
Expand All @@ -23,8 +25,20 @@ interface AppState {

export const pages = [
{
id: '/',
id: 'netflow-traffic',
name: 'Netflow Traffic'
},
{
id: 'pod-tab',
name: 'Pod tab'
},
{
id: 'namespace-tab',
name: 'Namespace tab'
},
{
id: 'node-tab',
name: 'Node tab'
}
];

Expand All @@ -36,10 +50,12 @@ export class App extends React.Component<{}, AppState> {
};

private onNavSelect = (selectedItem: { itemId: number | string }) => {
console.debug('onNavSelect', selectedItem);
this.setState({ activeItem: selectedItem.itemId });
};

private onThemeSelect = (isDarkTheme: boolean) => {
console.debug('onThemeSelect', isDarkTheme);
this.setState({ isDarkTheme });
const htmlElement = document.getElementsByTagName('html')[0];
if (htmlElement) {
Expand All @@ -52,17 +68,41 @@ export class App extends React.Component<{}, AppState> {
};

private getPageContent = (id: string) => {
console.debug('getPageContent', id);
switch (id) {
case 'netflow-traffic-parent':
case 'pod-tab':
return <NetflowTab obj={{ kind: 'Pod', metadata: { name: 'test', namespace: 'default' } }} />;
case 'namespace-tab':
return <NetflowTab obj={{ kind: 'Namespace', metadata: { name: 'test' } }} />;
case 'node-tab':
return <NetflowTab obj={{ kind: 'Node', metadata: { name: 'test' } }} />;
default:
return <NetflowTrafficParent />;
}
};

private getPageContext = (id: string, name: string) => {
console.debug('getPageContext', id);
const content = this.getPageContent(id);
switch (id) {
case 'netflow-traffic':
return <>{content}</>;
default:
return (
<PageSection id="pageSection">
<div id="pageHeader">
<h1>{`${name} example`}</h1>
</div>
{content}
</PageSection>
);
}
};

private getPages = () => (
<Routes>
{pages.map(page => (
<Route element={this.getPageContent(page.id)} path={page.id} key={page.id} />
<Route path={page.id} key={page.id} element={this.getPageContext(page.id, page.name)} />
))}
</Routes>
);
Expand Down Expand Up @@ -124,7 +164,6 @@ export class App extends React.Component<{}, AppState> {
);

const AppSidebar = <PageSidebar isNavOpen={isNavOpen} nav={nav} />;

return (
<BrowserRouter>
<Page header={AppHeader} sidebar={AppSidebar} isManagedSidebar>
Expand Down
57 changes: 44 additions & 13 deletions web/src/components/__tests__/netflow-tab.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,55 @@
import { useResolvedExtensions } from '@openshift-console/dynamic-plugin-sdk';
import { EmptyState } from '@patternfly/react-core';
import { shallow } from 'enzyme';
import { mount } from 'enzyme';
import { waitFor } from '@testing-library/react';
import { extensionsMock } from '../__tests-data__/extensions';
import * as React from 'react';
import NetflowTab from '../netflow-tab';
import NetflowTraffic from '../netflow-traffic';
import { PodTabParam, ServiceTabParam, UnknownTabParam } from '../__tests-data__/tabs';
import { ConfigResultSample } from '../__tests-data__/config';
import { GenericMetricsResult, TopologyMetricsResult } from '../../api/loki';
import { AlertsResult, SilencedAlert } from '../../api/alert';

const useResolvedExtensionsMock = useResolvedExtensions as jest.Mock;

jest.mock('../../api/routes', () => ({
getConfig: jest.fn(() => Promise.resolve(ConfigResultSample)),
getFlows: jest.fn(() => Promise.resolve([])),
getTopologyMetrics: jest.fn(() =>
Promise.resolve({ metrics: [], stats: { numQueries: 0, limitReached: false } } as TopologyMetricsResult)
),
getGenericMetrics: jest.fn(() =>
Promise.resolve({ metrics: [], stats: { numQueries: 0, limitReached: false } } as GenericMetricsResult)
),
getAlerts: jest.fn(() => Promise.resolve({ data: { groups: [] }, status: 'success' } as AlertsResult)),
getSilencedAlerts: jest.fn(() => Promise.resolve([] as SilencedAlert[]))
}));

describe('<NetflowTab />', () => {
it('should shallow component for Pod', async () => {
const wrapper = shallow(<NetflowTab obj={PodTabParam} />);
expect(wrapper.find(NetflowTab)).toBeTruthy();
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
beforeAll(() => {
useResolvedExtensionsMock.mockReturnValue(extensionsMock);
});

it('should mount component for Pod', async () => {
const wrapper = mount(<NetflowTab obj={PodTabParam} />);
await waitFor(() => {
expect(wrapper.find(NetflowTab)).toBeTruthy();
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
});
});
it('should shallow component for Service', async () => {
const wrapper = shallow(<NetflowTab obj={ServiceTabParam} />);
expect(wrapper.find(NetflowTab)).toBeTruthy();
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
it('should mount component for Service', async () => {
const wrapper = mount(<NetflowTab obj={ServiceTabParam} />);
await waitFor(() => {
expect(wrapper.find(NetflowTab)).toBeTruthy();
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
});
});
it('should render empty state', async () => {
const wrapper = shallow(<NetflowTab obj={UnknownTabParam} />);
expect(wrapper.find(NetflowTraffic)).toHaveLength(0);
expect(wrapper.find(EmptyState)).toHaveLength(1);
it('should mount empty state', async () => {
const wrapper = mount(<NetflowTab obj={UnknownTabParam} />);
await waitFor(() => {
expect(wrapper.find(NetflowTraffic)).toHaveLength(0);
expect(wrapper.find(EmptyState)).toHaveLength(1);
});
});
});
28 changes: 18 additions & 10 deletions web/src/components/dynamic-loader/dynamic-loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,28 @@ import * as reactRouterDom from 'react-router-dom';
type NavFunc = (to: string, opts?: any) => void;
let navFunc: NavFunc | null = null;

export const loadNavFunction = () => {
const genericReactRouterDom = reactRouterDom as any;
if (genericReactRouterDom['useNavigate']) {
console.log('loading nav function from react-router useNavigate');
setNavFunction(genericReactRouterDom['useNavigate']());
} else if (genericReactRouterDom['useHistory']) {
console.log('loading nav function from react-router useHistory');
setNavFunction(genericReactRouterDom['useHistory']().push);
} else {
console.error("can't load nav function from react-router");
}
};

export const setNavFunction = (f: NavFunc) => {
navFunc = f;
};

export const navigate = (to: string, opts?: any) => {
if (!navFunc) {
loadNavFunction();
}

if (navFunc) {
navFunc(to, opts);
} else {
Expand All @@ -23,16 +40,7 @@ export const navigate = (to: string, opts?: any) => {
};

export const DynamicLoader: React.FC<{}> = ({ children }) => {
const genericReactRouterDom = reactRouterDom as any;
if (genericReactRouterDom['useNavigate']) {
console.log('loading nav function from react-router useNavigate');
setNavFunction(genericReactRouterDom['useNavigate']());
} else if (genericReactRouterDom['useHistory']) {
console.log('loading nav function from react-router useHistory');
setNavFunction(genericReactRouterDom['useHistory']().push);
} else {
console.error("can't load nav function from react-router");
}
loadNavFunction();
return <>{!!children ? children : ''}</>;
};

Expand Down
Loading

0 comments on commit 1ca3b6a

Please sign in to comment.