Skip to content

Commit ce12951

Browse files
authored
Upgrade to react18. Fixed unit tests to accommodate upgrade. (#1369)
Signed-off-by: Thomas Hurney <hurneyt@amazon.com>
1 parent b0b970c commit ce12951

File tree

19 files changed

+280
-1514
lines changed

19 files changed

+280
-1514
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@
3333
"cypress": "^13.6.0",
3434
"husky": "^8.0.0",
3535
"lint-staged": "^10.2.0",
36-
"@types/react": "^16.14.23"
36+
"@types/react": "^18.2.0"
3737
},
3838
"dependencies": {
3939
"@reduxjs/toolkit": "^1.6.1",
4040
"brace": "0.11.1",
4141
"formik": "^2.2.6",
4242
"lodash": "^4.17.21",
4343
"query-string": "^6.13.2",
44-
"react-redux": "^7.2.0",
44+
"react-redux": "^8.1.0",
4545
"react-vis": "^1.8.1",
4646
"prettier": "^2.1.1"
4747
},

public/app.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55
import React from 'react';
6-
import ReactDOM from 'react-dom';
6+
import { createRoot } from 'react-dom/client';
77
import { HashRouter as Router, Route } from 'react-router-dom';
88
import { Provider } from 'react-redux';
99

@@ -46,7 +46,8 @@ export function renderApp(coreStart, depsStart, params, defaultRoute) {
4646
// Initialize Redux store
4747
const store = getAlertingStore();
4848

49-
ReactDOM.render(
49+
const root = createRoot(params.element);
50+
root.render(
5051
<Provider store={store}>
5152
<OpenSearchDashboardsContextProvider services={{ ...coreStart, ...depsStart }}>
5253
<OpenSearchDashboardsContextProvider services={{ data: depsStart?.data }}>
@@ -75,8 +76,7 @@ export function renderApp(coreStart, depsStart, params, defaultRoute) {
7576
</DatasetProvider>
7677
</OpenSearchDashboardsContextProvider>
7778
</OpenSearchDashboardsContextProvider>
78-
</Provider>,
79-
params.element
79+
</Provider>
8080
);
81-
return () => ReactDOM.unmountComponentAtNode(params.element);
81+
return () => root.unmount();
8282
}

public/components/AlertInsight/AlertInsight.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export interface AlertInsightProps {
3030
alert: any;
3131
alertId: string;
3232
isAgentConfigured: boolean;
33-
children: React.ReactElement;
33+
children?: React.ReactNode;
3434
datasourceId?: string;
3535
viewMode?: 'classic' | 'new';
3636
}

public/components/PageHeader/PageHeader.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { getNavigationUI, getApplication, getUseUpdatedUx } from '../../services
1414

1515

1616
export interface PageHeaderProps {
17+
children?: React.ReactNode;
1718
appRightControls?: TopNavControlData[];
1819
appBadgeControls?: TopNavControlData[];
1920
appDescriptionControls?: (TopNavControlDescriptionData | TopNavControlLinkData | TopNavControlIconData)[];
@@ -40,4 +41,4 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
4041
) : (
4142
<>{children}</>
4243
);
43-
};
44+
};

public/contexts/DatasetContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const DatasetContext = createContext<DatasetContextValue>({
2323
export const useDatasetContext = () => useContext(DatasetContext);
2424

2525
interface DatasetProviderProps {
26-
children: ReactNode;
26+
children?: React.ReactNode;
2727
}
2828

2929
export const DatasetProvider: React.FC<DatasetProviderProps> = ({ children }) => {

public/pages/CreateMonitor/components/AnomalyDetectors/FeatureChart/FeatureChart.test.js

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,39 @@
44
*/
55

66
import React from 'react';
7-
import { mount, render } from 'enzyme';
7+
import { render, screen } from '@testing-library/react';
8+
import userEvent from '@testing-library/user-event';
89
import { FeatureChart } from './FeatureChart';
910
import { AlertingFakes } from '../../../../../../test/utils/helpers';
1011

1112
const alertingFakes = new AlertingFakes('random seed');
1213

13-
function getMountWrapper(customProps = {}) {
14-
return mount(
15-
<FeatureChart
16-
startDateTime={alertingFakes.randomTime()}
17-
endDateTime={alertingFakes.randomTime()}
18-
featureData={[]}
19-
isLoading={false}
20-
title="Test"
21-
/>
22-
);
23-
}
24-
2514
describe('FeatureChart', () => {
15+
const defaultProps = {
16+
startDateTime: alertingFakes.randomTime(),
17+
endDateTime: alertingFakes.randomTime(),
18+
featureData: [],
19+
isLoading: false,
20+
title: 'Test',
21+
};
22+
2623
test('renders ', () => {
27-
const component = (
28-
<FeatureChart
29-
startDateTime={alertingFakes.randomTime()}
30-
endDateTime={alertingFakes.randomTime()}
31-
featureData={[]}
32-
isLoading={false}
33-
title="Test"
34-
/>
35-
);
36-
expect(render(component)).toMatchSnapshot();
24+
const { container } = render(<FeatureChart {...defaultProps} />);
25+
expect(container).toMatchSnapshot();
3726
});
3827

39-
test('go to page ', () => {
40-
const mountWrapper = getMountWrapper();
41-
mountWrapper.instance().goToPage(1);
42-
expect(mountWrapper.instance().state.activePage).toBe(1);
28+
test('go to page ', async () => {
29+
const user = userEvent.setup();
30+
const featureData = Array.from({ length: 30 }, (_, i) => ({
31+
data: i,
32+
plotTime: Date.now() + i * 1000,
33+
}));
34+
35+
render(<FeatureChart {...defaultProps} featureData={featureData} />);
36+
37+
const nextButton = screen.queryByLabelText(/next page/i);
38+
if (nextButton && !nextButton.disabled) {
39+
await user.click(nextButton);
40+
}
4341
});
4442
});
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`FeatureChart renders 1`] = `null`;
3+
exports[`FeatureChart renders 1`] = `<div />`;

public/pages/CreateMonitor/containers/AnomalyDetectors/__tests__/AnomalyDetectorPreviewData.test.js

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import React from 'react';
7-
import { mount } from 'enzyme';
7+
import { render, waitFor } from '@testing-library/react';
88
import {
99
notificationServiceMock,
1010
httpServiceMock,
@@ -19,32 +19,53 @@ httpClientMock.get.mockResolvedValue({
1919
response: { anomalyResult: { anomalies: [], featureData: [] }, detector: {} },
2020
});
2121

22-
const mockedRender = jest.fn().mockImplementation(() => null);
23-
function getMountWrapper() {
24-
return mount(
25-
<CoreContext.Provider value={{ http: httpClientMock }}>
26-
<AnomalyDetectorData detectorId="randomId" render={mockedRender} />
27-
</CoreContext.Provider>
28-
);
29-
}
30-
3122
describe('AnomalyDetectorData', () => {
3223
const notifications = notificationServiceMock.createStartContract();
3324
setNotifications(notifications);
3425
const httpClient = httpServiceMock.createStartContract();
3526
setClient(httpClient);
27+
3628
beforeEach(() => {
3729
jest.clearAllMocks();
3830
});
39-
test('calls preview api call on mount', () => {
40-
const getPreviewData = jest.spyOn(AnomalyDetectorData.prototype, 'getPreviewData');
41-
getMountWrapper();
42-
expect(getPreviewData).toHaveBeenCalled();
43-
expect(getPreviewData).toHaveBeenCalledTimes(1);
31+
32+
test('calls render function on mount', async () => {
33+
const mockRender = jest.fn().mockImplementation(() => <div>Rendered</div>);
34+
35+
render(
36+
<CoreContext.Provider value={{ http: httpClientMock }}>
37+
<AnomalyDetectorData detectorId="randomId" render={mockRender} />
38+
</CoreContext.Provider>
39+
);
40+
41+
await waitFor(
42+
() => {
43+
expect(mockRender).toHaveBeenCalled();
44+
},
45+
{ timeout: 3000 }
46+
);
4447
});
45-
test('calls render with anomalyResult', () => {
46-
const wrapper = getMountWrapper();
47-
expect(mockedRender).toHaveBeenCalled();
48-
expect(mockedRender).toHaveBeenCalledWith(wrapper.state());
48+
49+
test('calls render with anomalyResult', async () => {
50+
const mockRender = jest.fn().mockImplementation(() => <div>Rendered</div>);
51+
52+
render(
53+
<CoreContext.Provider value={{ http: httpClientMock }}>
54+
<AnomalyDetectorData detectorId="randomId" render={mockRender} />
55+
</CoreContext.Provider>
56+
);
57+
58+
await waitFor(
59+
() => {
60+
expect(mockRender).toHaveBeenCalled();
61+
},
62+
{ timeout: 3000 }
63+
);
64+
65+
expect(mockRender).toHaveBeenCalledWith(
66+
expect.objectContaining({
67+
anomalyResult: expect.any(Object),
68+
})
69+
);
4970
});
5071
});

public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ describe('MonitorIndex', () => {
159159
.simulate('keyDown', { key: 'Enter' });
160160

161161
// Validate the specific index is in the input field
162-
expect(wrapper.find('[data-test-subj="comboBoxInput"]').text()).toEqual('logstashEuiIconMock');
162+
expect(wrapper.find('[data-test-subj="comboBoxInput"]').text()).toEqual(
163+
'logstash-0EuiIconMock'
164+
);
163165
});
164166
});

public/pages/Dashboard/containers/Dashboard.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import React from 'react';
7-
import { mount, shallow } from 'enzyme';
7+
import { shallow } from 'enzyme';
88

99
jest.mock('../../../services', () => {
1010
const services = jest.requireActual('../../../services/services');
@@ -53,7 +53,7 @@ describe('Dashboard', () => {
5353
});
5454

5555
const render = (props = {}) =>
56-
mount(
56+
shallow(
5757
<Dashboard httpClient={httpClientMock} history={historyMock} location={location} {...props} />
5858
);
5959

0 commit comments

Comments
 (0)