Skip to content

Commit 1ca3b6a

Browse files
authored
NETOBSERV-1266 Netflow traffic tab crash (#377)
* fix props infinite loop * ensure nav always loaded * fix testing * add tab examples to standalone
1 parent 19a7ab9 commit 1ca3b6a

File tree

6 files changed

+223
-134
lines changed

6 files changed

+223
-134
lines changed

web/src/app.tsx

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ import {
88
PageHeaderTools,
99
PageHeaderToolsGroup,
1010
PageHeaderToolsItem,
11+
PageSection,
1112
PageSidebar,
1213
Radio
1314
} from '@patternfly/react-core';
1415
import React from 'react';
1516
import { BrowserRouter, Link, Route, Routes } from 'react-router-dom';
17+
import NetflowTab from './components/netflow-tab';
1618
import NetflowTrafficParent from './components/netflow-traffic-parent';
1719

1820
interface AppState {
@@ -23,8 +25,20 @@ interface AppState {
2325

2426
export const pages = [
2527
{
26-
id: '/',
28+
id: 'netflow-traffic',
2729
name: 'Netflow Traffic'
30+
},
31+
{
32+
id: 'pod-tab',
33+
name: 'Pod tab'
34+
},
35+
{
36+
id: 'namespace-tab',
37+
name: 'Namespace tab'
38+
},
39+
{
40+
id: 'node-tab',
41+
name: 'Node tab'
2842
}
2943
];
3044

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

3852
private onNavSelect = (selectedItem: { itemId: number | string }) => {
53+
console.debug('onNavSelect', selectedItem);
3954
this.setState({ activeItem: selectedItem.itemId });
4055
};
4156

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

5470
private getPageContent = (id: string) => {
71+
console.debug('getPageContent', id);
5572
switch (id) {
56-
case 'netflow-traffic-parent':
73+
case 'pod-tab':
74+
return <NetflowTab obj={{ kind: 'Pod', metadata: { name: 'test', namespace: 'default' } }} />;
75+
case 'namespace-tab':
76+
return <NetflowTab obj={{ kind: 'Namespace', metadata: { name: 'test' } }} />;
77+
case 'node-tab':
78+
return <NetflowTab obj={{ kind: 'Node', metadata: { name: 'test' } }} />;
5779
default:
5880
return <NetflowTrafficParent />;
5981
}
6082
};
6183

84+
private getPageContext = (id: string, name: string) => {
85+
console.debug('getPageContext', id);
86+
const content = this.getPageContent(id);
87+
switch (id) {
88+
case 'netflow-traffic':
89+
return <>{content}</>;
90+
default:
91+
return (
92+
<PageSection id="pageSection">
93+
<div id="pageHeader">
94+
<h1>{`${name} example`}</h1>
95+
</div>
96+
{content}
97+
</PageSection>
98+
);
99+
}
100+
};
101+
62102
private getPages = () => (
63103
<Routes>
64104
{pages.map(page => (
65-
<Route element={this.getPageContent(page.id)} path={page.id} key={page.id} />
105+
<Route path={page.id} key={page.id} element={this.getPageContext(page.id, page.name)} />
66106
))}
67107
</Routes>
68108
);
@@ -124,7 +164,6 @@ export class App extends React.Component<{}, AppState> {
124164
);
125165

126166
const AppSidebar = <PageSidebar isNavOpen={isNavOpen} nav={nav} />;
127-
128167
return (
129168
<BrowserRouter>
130169
<Page header={AppHeader} sidebar={AppSidebar} isManagedSidebar>
Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,55 @@
1+
import { useResolvedExtensions } from '@openshift-console/dynamic-plugin-sdk';
12
import { EmptyState } from '@patternfly/react-core';
2-
import { shallow } from 'enzyme';
3+
import { mount } from 'enzyme';
4+
import { waitFor } from '@testing-library/react';
5+
import { extensionsMock } from '../__tests-data__/extensions';
36
import * as React from 'react';
47
import NetflowTab from '../netflow-tab';
58
import NetflowTraffic from '../netflow-traffic';
69
import { PodTabParam, ServiceTabParam, UnknownTabParam } from '../__tests-data__/tabs';
10+
import { ConfigResultSample } from '../__tests-data__/config';
11+
import { GenericMetricsResult, TopologyMetricsResult } from '../../api/loki';
12+
import { AlertsResult, SilencedAlert } from '../../api/alert';
13+
14+
const useResolvedExtensionsMock = useResolvedExtensions as jest.Mock;
15+
16+
jest.mock('../../api/routes', () => ({
17+
getConfig: jest.fn(() => Promise.resolve(ConfigResultSample)),
18+
getFlows: jest.fn(() => Promise.resolve([])),
19+
getTopologyMetrics: jest.fn(() =>
20+
Promise.resolve({ metrics: [], stats: { numQueries: 0, limitReached: false } } as TopologyMetricsResult)
21+
),
22+
getGenericMetrics: jest.fn(() =>
23+
Promise.resolve({ metrics: [], stats: { numQueries: 0, limitReached: false } } as GenericMetricsResult)
24+
),
25+
getAlerts: jest.fn(() => Promise.resolve({ data: { groups: [] }, status: 'success' } as AlertsResult)),
26+
getSilencedAlerts: jest.fn(() => Promise.resolve([] as SilencedAlert[]))
27+
}));
728

829
describe('<NetflowTab />', () => {
9-
it('should shallow component for Pod', async () => {
10-
const wrapper = shallow(<NetflowTab obj={PodTabParam} />);
11-
expect(wrapper.find(NetflowTab)).toBeTruthy();
12-
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
30+
beforeAll(() => {
31+
useResolvedExtensionsMock.mockReturnValue(extensionsMock);
32+
});
33+
34+
it('should mount component for Pod', async () => {
35+
const wrapper = mount(<NetflowTab obj={PodTabParam} />);
36+
await waitFor(() => {
37+
expect(wrapper.find(NetflowTab)).toBeTruthy();
38+
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
39+
});
1340
});
14-
it('should shallow component for Service', async () => {
15-
const wrapper = shallow(<NetflowTab obj={ServiceTabParam} />);
16-
expect(wrapper.find(NetflowTab)).toBeTruthy();
17-
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
41+
it('should mount component for Service', async () => {
42+
const wrapper = mount(<NetflowTab obj={ServiceTabParam} />);
43+
await waitFor(() => {
44+
expect(wrapper.find(NetflowTab)).toBeTruthy();
45+
expect(wrapper.find(NetflowTraffic)).toHaveLength(1);
46+
});
1847
});
19-
it('should render empty state', async () => {
20-
const wrapper = shallow(<NetflowTab obj={UnknownTabParam} />);
21-
expect(wrapper.find(NetflowTraffic)).toHaveLength(0);
22-
expect(wrapper.find(EmptyState)).toHaveLength(1);
48+
it('should mount empty state', async () => {
49+
const wrapper = mount(<NetflowTab obj={UnknownTabParam} />);
50+
await waitFor(() => {
51+
expect(wrapper.find(NetflowTraffic)).toHaveLength(0);
52+
expect(wrapper.find(EmptyState)).toHaveLength(1);
53+
});
2354
});
2455
});

web/src/components/dynamic-loader/dynamic-loader.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,28 @@ import * as reactRouterDom from 'react-router-dom';
1010
type NavFunc = (to: string, opts?: any) => void;
1111
let navFunc: NavFunc | null = null;
1212

13+
export const loadNavFunction = () => {
14+
const genericReactRouterDom = reactRouterDom as any;
15+
if (genericReactRouterDom['useNavigate']) {
16+
console.log('loading nav function from react-router useNavigate');
17+
setNavFunction(genericReactRouterDom['useNavigate']());
18+
} else if (genericReactRouterDom['useHistory']) {
19+
console.log('loading nav function from react-router useHistory');
20+
setNavFunction(genericReactRouterDom['useHistory']().push);
21+
} else {
22+
console.error("can't load nav function from react-router");
23+
}
24+
};
25+
1326
export const setNavFunction = (f: NavFunc) => {
1427
navFunc = f;
1528
};
1629

1730
export const navigate = (to: string, opts?: any) => {
31+
if (!navFunc) {
32+
loadNavFunction();
33+
}
34+
1835
if (navFunc) {
1936
navFunc(to, opts);
2037
} else {
@@ -23,16 +40,7 @@ export const navigate = (to: string, opts?: any) => {
2340
};
2441

2542
export const DynamicLoader: React.FC<{}> = ({ children }) => {
26-
const genericReactRouterDom = reactRouterDom as any;
27-
if (genericReactRouterDom['useNavigate']) {
28-
console.log('loading nav function from react-router useNavigate');
29-
setNavFunction(genericReactRouterDom['useNavigate']());
30-
} else if (genericReactRouterDom['useHistory']) {
31-
console.log('loading nav function from react-router useHistory');
32-
setNavFunction(genericReactRouterDom['useHistory']().push);
33-
} else {
34-
console.error("can't load nav function from react-router");
35-
}
43+
loadNavFunction();
3644
return <>{!!children ? children : ''}</>;
3745
};
3846

0 commit comments

Comments
 (0)