Upgrade to React 18 (#1955)
* Upgrade deps * migration * Fix specs * exclude index.tsx from sonar metrics * Update deps
This commit is contained in:
parent
1e3561ea28
commit
eb47ec012d
76 changed files with 6635 additions and 5786 deletions
11106
kafka-ui-react-app/package-lock.json
generated
11106
kafka-ui-react-app/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "kafka-ui",
|
"name": "kafka-ui",
|
||||||
"version": "0.1.0",
|
"version": "0.4.0",
|
||||||
"homepage": "./",
|
"homepage": "./",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||||
"@hookform/error-message": "^2.0.0",
|
"@hookform/error-message": "^2.0.0",
|
||||||
"@hookform/resolvers": "^2.7.1",
|
"@hookform/resolvers": "^2.7.1",
|
||||||
"@reduxjs/toolkit": "^1.7.1",
|
"@reduxjs/toolkit": "^1.8.1",
|
||||||
"@rooks/use-outside-click-ref": "^4.10.1",
|
"@rooks/use-outside-click-ref": "^4.10.1",
|
||||||
"@testing-library/react": "^12.0.0",
|
"@testing-library/react": "^13.2.0",
|
||||||
"@types/eventsource": "^1.1.6",
|
"@types/eventsource": "^1.1.6",
|
||||||
"@types/yup": "^0.29.13",
|
"@types/yup": "^0.29.13",
|
||||||
"ace-builds": "^1.4.12",
|
"ace-builds": "^1.4.12",
|
||||||
|
@ -17,22 +17,22 @@
|
||||||
"bulma": "^0.9.3",
|
"bulma": "^0.9.3",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"dayjs": "^1.10.6",
|
"dayjs": "^1.10.6",
|
||||||
"eslint-import-resolver-node": "^0.3.5",
|
"eslint-import-resolver-node": "^0.3.6",
|
||||||
"eslint-import-resolver-typescript": "^2.4.0",
|
"eslint-import-resolver-typescript": "^2.7.1",
|
||||||
"fetch-mock": "^9.11.0",
|
"fetch-mock": "^9.11.0",
|
||||||
"json-schema-faker": "^0.5.0-rcv.39",
|
"json-schema-faker": "^0.5.0-rcv.39",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"pretty-ms": "^7.0.1",
|
"pretty-ms": "^7.0.1",
|
||||||
"react": "^17.0.1",
|
"react": "^18.1.0",
|
||||||
"react-ace": "^9.4.3",
|
"react-ace": "^9.4.3",
|
||||||
"react-datepicker": "^4.2.0",
|
"react-datepicker": "^4.2.0",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^18.1.0",
|
||||||
"react-hook-form": "7.6.9",
|
"react-hook-form": "7.6.9",
|
||||||
"react-multi-select-component": "^4.0.6",
|
"react-multi-select-component": "^4.0.6",
|
||||||
"react-redux": "^7.2.6",
|
"react-redux": "^7.2.6",
|
||||||
"react-router": "^5.2.0",
|
"react-router": "^5.2.0",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.3.1",
|
||||||
"redux": "^4.1.1",
|
"redux": "^4.1.1",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"sass": "^1.43.4",
|
"sass": "^1.43.4",
|
||||||
|
@ -79,39 +79,36 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest/types": "^27.0.6",
|
"@jest/types": "^27.0.6",
|
||||||
"@openapitools/openapi-generator-cli": "^2.4.15",
|
"@openapitools/openapi-generator-cli": "^2.5.1",
|
||||||
"@testing-library/dom": "^8.11.1",
|
"@testing-library/dom": "^8.11.1",
|
||||||
"@testing-library/jest-dom": "^5.14.1",
|
"@testing-library/jest-dom": "^5.14.1",
|
||||||
"@testing-library/react-hooks": "^7.0.2",
|
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"@types/classnames": "^2.2.11",
|
"@types/classnames": "^2.2.11",
|
||||||
"@types/jest": "^27.0.2",
|
"@types/jest": "^27.0.2",
|
||||||
"@types/lodash": "^4.14.172",
|
"@types/lodash": "^4.14.172",
|
||||||
"@types/node": "^16.4.13",
|
"@types/node": "^16.4.13",
|
||||||
"@types/node-fetch": "^3.0.3",
|
"@types/node-fetch": "^3.0.3",
|
||||||
"@types/react": "^17.0.16",
|
"@types/react": "^18.0.9",
|
||||||
"@types/react-datepicker": "^4.1.4",
|
"@types/react-datepicker": "^4.1.4",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^18.0.3",
|
||||||
"@types/react-redux": "^7.1.18",
|
"@types/react-redux": "^7.1.18",
|
||||||
"@types/react-router-dom": "^5.1.8",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"@types/react-test-renderer": "^17.0.1",
|
|
||||||
"@types/redux-mock-store": "^1.0.3",
|
"@types/redux-mock-store": "^1.0.3",
|
||||||
"@types/styled-components": "^5.1.13",
|
"@types/styled-components": "^5.1.13",
|
||||||
"@types/uuid": "^8.3.1",
|
"@types/uuid": "^8.3.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||||
"@typescript-eslint/parser": "^5.10.0",
|
"@typescript-eslint/parser": "^5.10.0",
|
||||||
"dotenv": "^15.0.0",
|
"dotenv": "^16.0.1",
|
||||||
"eslint": "^8.7.0",
|
"eslint": "^8.15.0",
|
||||||
"eslint-config-airbnb": "^19.0.0",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-airbnb-typescript": "^16.1.0",
|
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"eslint-plugin-jest-dom": "^4.0.1",
|
"eslint-plugin-jest-dom": "^4.0.1",
|
||||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-react": "^7.28.0",
|
"eslint-plugin-react": "^7.29.4",
|
||||||
"eslint-plugin-react-hooks": "^4.3.0",
|
"eslint-plugin-react-hooks": "^4.5.0",
|
||||||
"esprint": "^3.1.0",
|
|
||||||
"fetch-mock-jest": "^1.5.1",
|
"fetch-mock-jest": "^1.5.1",
|
||||||
"history": "^5.0.0",
|
"history": "^5.0.0",
|
||||||
"http-proxy-middleware": "^2.0.1",
|
"http-proxy-middleware": "^2.0.1",
|
||||||
|
@ -120,8 +117,7 @@
|
||||||
"jest-styled-components": "^7.0.6",
|
"jest-styled-components": "^7.0.6",
|
||||||
"lint-staged": "^12.1.2",
|
"lint-staged": "^12.1.2",
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.1",
|
||||||
"react-test-renderer": "^17.0.2",
|
|
||||||
"redux-mock-store": "^1.5.4",
|
"redux-mock-store": "^1.5.4",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"ts-jest": "^26.5.4",
|
"ts-jest": "^26.5.4",
|
||||||
|
|
|
@ -2,7 +2,7 @@ sonar.projectKey=com.provectus:kafka-ui_frontend
|
||||||
sonar.organization=provectus
|
sonar.organization=provectus
|
||||||
|
|
||||||
sonar.sources=.
|
sonar.sources=.
|
||||||
sonar.exclusions=**/__tests__/**,**/__test__/**,src/serviceWorker.ts,src/setupTests.ts,src/setupProxy.js,**/fixtures.ts,src/lib/testHelpers.tsx
|
sonar.exclusions=**/__tests__/**,**/__test__/**,src/serviceWorker.ts,src/setupTests.ts,src/setupProxy.js,**/fixtures.ts,src/lib/testHelpers.tsx,src/index.tsx
|
||||||
|
|
||||||
sonar.typescript.lcov.reportPaths=./coverage/lcov.info
|
sonar.typescript.lcov.reportPaths=./coverage/lcov.info
|
||||||
sonar.testExecutionReportPaths=./test-report.xml
|
sonar.testExecutionReportPaths=./test-report.xml
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Action, FailurePayload, ServerResponse } from 'redux/interfaces';
|
import { Action, FailurePayload, ServerResponse } from 'redux/interfaces';
|
||||||
import { screen } from '@testing-library/react';
|
import { act, screen } from '@testing-library/react';
|
||||||
import Alerts from 'components/Alerts/Alerts';
|
import Alerts from 'components/Alerts/Alerts';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { store } from 'redux/store';
|
import { store } from 'redux/store';
|
||||||
import { UnknownAsyncThunkRejectedWithValueAction } from '@reduxjs/toolkit/dist/matchers';
|
import { UnknownAsyncThunkRejectedWithValueAction } from '@reduxjs/toolkit/dist/matchers';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
describe('Alerts', () => {
|
|
||||||
beforeEach(() => render(<Alerts />, { store }));
|
|
||||||
|
|
||||||
it('renders alerts', async () => {
|
|
||||||
const payload: ServerResponse = {
|
const payload: ServerResponse = {
|
||||||
status: 422,
|
status: 422,
|
||||||
statusText: 'Unprocessable Entity',
|
statusText: 'Unprocessable Entity',
|
||||||
|
@ -30,8 +26,6 @@ describe('Alerts', () => {
|
||||||
},
|
},
|
||||||
error: { message: 'Rejected' },
|
error: { message: 'Rejected' },
|
||||||
};
|
};
|
||||||
store.dispatch(action);
|
|
||||||
|
|
||||||
const alert: FailurePayload = {
|
const alert: FailurePayload = {
|
||||||
title: '404 - Not Found',
|
title: '404 - Not Found',
|
||||||
message: 'Item is not found',
|
message: 'Item is not found',
|
||||||
|
@ -41,8 +35,16 @@ describe('Alerts', () => {
|
||||||
type: 'CLEAR_TOPIC_MESSAGES__FAILURE',
|
type: 'CLEAR_TOPIC_MESSAGES__FAILURE',
|
||||||
payload: { alert },
|
payload: { alert },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
describe('Alerts', () => {
|
||||||
|
it('renders alerts', async () => {
|
||||||
|
store.dispatch(action);
|
||||||
store.dispatch(legacyAction);
|
store.dispatch(legacyAction);
|
||||||
|
|
||||||
|
await act(() => {
|
||||||
|
render(<Alerts />, { store });
|
||||||
|
});
|
||||||
|
|
||||||
expect(screen.getAllByRole('alert').length).toEqual(2);
|
expect(screen.getAllByRole('alert').length).toEqual(2);
|
||||||
|
|
||||||
const dissmissAlertButtons = screen.getAllByRole('button');
|
const dissmissAlertButtons = screen.getAllByRole('button');
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { ClusterName } from 'redux/interfaces';
|
import { ClusterName } from 'redux/interfaces';
|
||||||
import useInterval from 'lib/hooks/useInterval';
|
import useInterval from 'lib/hooks/useInterval';
|
||||||
import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
|
import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router-dom';
|
||||||
import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
|
import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
|
||||||
import { Table } from 'components/common/table/Table/Table.styled';
|
import { Table } from 'components/common/table/Table/Table.styled';
|
||||||
import PageHeading from 'components/common/PageHeading/PageHeading';
|
import PageHeading from 'components/common/PageHeading/PageHeading';
|
||||||
|
|
|
@ -2,10 +2,11 @@ import React from 'react';
|
||||||
import Brokers from 'components/Brokers/Brokers';
|
import Brokers from 'components/Brokers/Brokers';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen, waitFor } from '@testing-library/dom';
|
import { screen, waitFor } from '@testing-library/dom';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { clusterBrokersPath } from 'lib/paths';
|
import { clusterBrokersPath } from 'lib/paths';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import { clusterStatsPayload } from 'redux/reducers/brokers/__test__/fixtures';
|
import { clusterStatsPayload } from 'redux/reducers/brokers/__test__/fixtures';
|
||||||
|
import { act } from '@testing-library/react';
|
||||||
|
|
||||||
describe('Brokers Component', () => {
|
describe('Brokers Component', () => {
|
||||||
afterEach(() => fetchMock.reset());
|
afterEach(() => fetchMock.reset());
|
||||||
|
@ -41,23 +42,26 @@ describe('Brokers Component', () => {
|
||||||
fetchStatsUrl,
|
fetchStatsUrl,
|
||||||
clusterStatsPayload
|
clusterStatsPayload
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
await waitFor(() => {
|
|
||||||
expect(fetchStatsMock.called()).toBeTruthy();
|
|
||||||
});
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(fetchBrokersMock.called()).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await waitFor(() => expect(fetchStatsMock.called()).toBeTruthy());
|
||||||
|
await waitFor(() => expect(fetchBrokersMock.called()).toBeTruthy());
|
||||||
|
|
||||||
expect(screen.getByRole('table')).toBeInTheDocument();
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
||||||
const rows = screen.getAllByRole('row');
|
const rows = screen.getAllByRole('row');
|
||||||
expect(rows.length).toEqual(3);
|
expect(rows.length).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows warning when offlinePartitionCount > 0', async () => {
|
it('shows warning when offlinePartitionCount > 0', async () => {
|
||||||
const fetchStatsMock = fetchMock.getOnce(fetchStatsUrl, {
|
const fetchStatsMock = fetchMock.getOnce(fetchStatsUrl, {
|
||||||
...clusterStatsPayload,
|
...clusterStatsPayload,
|
||||||
offlinePartitionCount: 1345,
|
offlinePartitionCount: 1345,
|
||||||
});
|
});
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(fetchStatsMock.called()).toBeTruthy();
|
expect(fetchStatsMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -76,7 +80,9 @@ describe('Brokers Component', () => {
|
||||||
inSyncReplicasCount: testInSyncReplicasCount,
|
inSyncReplicasCount: testInSyncReplicasCount,
|
||||||
outOfSyncReplicasCount: testOutOfSyncReplicasCount,
|
outOfSyncReplicasCount: testOutOfSyncReplicasCount,
|
||||||
});
|
});
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(fetchStatsMock.called()).toBeTruthy();
|
expect(fetchStatsMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -94,7 +100,9 @@ describe('Brokers Component', () => {
|
||||||
inSyncReplicasCount: undefined,
|
inSyncReplicasCount: undefined,
|
||||||
outOfSyncReplicasCount: testOutOfSyncReplicasCount,
|
outOfSyncReplicasCount: testOutOfSyncReplicasCount,
|
||||||
});
|
});
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(fetchStatsMock.called()).toBeTruthy();
|
expect(fetchStatsMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -108,7 +116,9 @@ describe('Brokers Component', () => {
|
||||||
inSyncReplicasCount: testInSyncReplicasCount,
|
inSyncReplicasCount: testInSyncReplicasCount,
|
||||||
outOfSyncReplicasCount: undefined,
|
outOfSyncReplicasCount: undefined,
|
||||||
});
|
});
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(fetchStatsMock.called()).toBeTruthy();
|
expect(fetchStatsMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
|
@ -85,7 +85,7 @@ const Actions: React.FC<ActionsProps> = ({
|
||||||
}, [restartConnector, clusterName, connectName, connectorName]);
|
}, [restartConnector, clusterName, connectName, connectorName]);
|
||||||
|
|
||||||
const restartTasksHandler = React.useCallback(
|
const restartTasksHandler = React.useCallback(
|
||||||
(actionType) => {
|
(actionType: ConnectorAction) => {
|
||||||
restartTasks({
|
restartTasks({
|
||||||
clusterName,
|
clusterName,
|
||||||
connectName,
|
connectName,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
ClusterName,
|
ClusterName,
|
||||||
ConnectName,
|
ConnectName,
|
||||||
|
|
|
@ -6,9 +6,9 @@ import {
|
||||||
} from 'lib/paths';
|
} from 'lib/paths';
|
||||||
import Edit, { EditProps } from 'components/Connect/Edit/Edit';
|
import Edit, { EditProps } from 'components/Connect/Edit/Edit';
|
||||||
import { connector } from 'redux/reducers/connect/__test__/fixtures';
|
import { connector } from 'redux/reducers/connect/__test__/fixtures';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { waitFor } from '@testing-library/dom';
|
import { waitFor } from '@testing-library/dom';
|
||||||
import { fireEvent, screen } from '@testing-library/react';
|
import { act, fireEvent, screen } from '@testing-library/react';
|
||||||
|
|
||||||
jest.mock('components/common/PageLoader/PageLoader', () => 'mock-PageLoader');
|
jest.mock('components/common/PageLoader/PageLoader', () => 'mock-PageLoader');
|
||||||
|
|
||||||
|
@ -52,9 +52,9 @@ describe('Edit', () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
it('fetches config on mount', () => {
|
it('fetches config on mount', async () => {
|
||||||
const fetchConfig = jest.fn();
|
const fetchConfig = jest.fn();
|
||||||
renderComponent({ fetchConfig });
|
await waitFor(() => renderComponent({ fetchConfig }));
|
||||||
expect(fetchConfig).toHaveBeenCalledTimes(1);
|
expect(fetchConfig).toHaveBeenCalledTimes(1);
|
||||||
expect(fetchConfig).toHaveBeenCalledWith({
|
expect(fetchConfig).toHaveBeenCalledWith({
|
||||||
clusterName,
|
clusterName,
|
||||||
|
@ -65,9 +65,9 @@ describe('Edit', () => {
|
||||||
|
|
||||||
it('calls updateConfig on form submit', async () => {
|
it('calls updateConfig on form submit', async () => {
|
||||||
const updateConfig = jest.fn();
|
const updateConfig = jest.fn();
|
||||||
renderComponent({ updateConfig });
|
await waitFor(() => renderComponent({ updateConfig }));
|
||||||
await waitFor(() => fireEvent.submit(screen.getByRole('form')));
|
fireEvent.submit(screen.getByRole('form'));
|
||||||
expect(updateConfig).toHaveBeenCalledTimes(1);
|
await waitFor(() => expect(updateConfig).toHaveBeenCalledTimes(1));
|
||||||
expect(updateConfig).toHaveBeenCalledWith({
|
expect(updateConfig).toHaveBeenCalledWith({
|
||||||
clusterName,
|
clusterName,
|
||||||
connectName,
|
connectName,
|
||||||
|
@ -78,9 +78,10 @@ describe('Edit', () => {
|
||||||
|
|
||||||
it('redirects to connector config view on successful submit', async () => {
|
it('redirects to connector config view on successful submit', async () => {
|
||||||
const updateConfig = jest.fn().mockResolvedValueOnce(connector);
|
const updateConfig = jest.fn().mockResolvedValueOnce(connector);
|
||||||
renderComponent({ updateConfig });
|
await waitFor(() => renderComponent({ updateConfig }));
|
||||||
await waitFor(() => fireEvent.submit(screen.getByRole('form')));
|
fireEvent.submit(screen.getByRole('form'));
|
||||||
expect(mockHistoryPush).toHaveBeenCalledTimes(1);
|
|
||||||
|
await waitFor(() => expect(mockHistoryPush).toHaveBeenCalledTimes(1));
|
||||||
expect(mockHistoryPush).toHaveBeenCalledWith(
|
expect(mockHistoryPush).toHaveBeenCalledWith(
|
||||||
clusterConnectConnectorConfigPath(clusterName, connectName, connectorName)
|
clusterConnectConnectorConfigPath(clusterName, connectName, connectorName)
|
||||||
);
|
);
|
||||||
|
@ -88,8 +89,10 @@ describe('Edit', () => {
|
||||||
|
|
||||||
it('does not redirect to connector config view on unsuccessful submit', async () => {
|
it('does not redirect to connector config view on unsuccessful submit', async () => {
|
||||||
const updateConfig = jest.fn().mockResolvedValueOnce(undefined);
|
const updateConfig = jest.fn().mockResolvedValueOnce(undefined);
|
||||||
renderComponent({ updateConfig });
|
await waitFor(() => renderComponent({ updateConfig }));
|
||||||
await waitFor(() => fireEvent.submit(screen.getByRole('form')));
|
await act(() => {
|
||||||
|
fireEvent.submit(screen.getByRole('form'));
|
||||||
|
});
|
||||||
expect(mockHistoryPush).not.toHaveBeenCalled();
|
expect(mockHistoryPush).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,13 +6,15 @@ import ClusterContext, {
|
||||||
} from 'components/contexts/ClusterContext';
|
} from 'components/contexts/ClusterContext';
|
||||||
import ListContainer from 'components/Connect/List/ListContainer';
|
import ListContainer from 'components/Connect/List/ListContainer';
|
||||||
import List, { ListProps } from 'components/Connect/List/List';
|
import List, { ListProps } from 'components/Connect/List/List';
|
||||||
import { screen } from '@testing-library/react';
|
import { act, screen } from '@testing-library/react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
|
|
||||||
describe('Connectors List', () => {
|
describe('Connectors List', () => {
|
||||||
describe('Container', () => {
|
describe('Container', () => {
|
||||||
it('renders view with initial state of storage', () => {
|
it('renders view with initial state of storage', async () => {
|
||||||
|
await act(() => {
|
||||||
render(<ListContainer />);
|
render(<ListContainer />);
|
||||||
|
});
|
||||||
expect(screen.getByRole('heading')).toHaveTextContent('Connectors');
|
expect(screen.getByRole('heading')).toHaveTextContent('Connectors');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -21,10 +23,11 @@ describe('Connectors List', () => {
|
||||||
const fetchConnects = jest.fn();
|
const fetchConnects = jest.fn();
|
||||||
const fetchConnectors = jest.fn();
|
const fetchConnectors = jest.fn();
|
||||||
const setConnectorSearch = jest.fn();
|
const setConnectorSearch = jest.fn();
|
||||||
const setupComponent = (
|
const renderComponent = (
|
||||||
props: Partial<ListProps> = {},
|
props: Partial<ListProps> = {},
|
||||||
contextValue: ContextProps = initialValue
|
contextValue: ContextProps = initialValue
|
||||||
) => (
|
) => {
|
||||||
|
render(
|
||||||
<ClusterContext.Provider value={contextValue}>
|
<ClusterContext.Provider value={contextValue}>
|
||||||
<List
|
<List
|
||||||
areConnectorsFetching
|
areConnectorsFetching
|
||||||
|
@ -39,45 +42,44 @@ describe('Connectors List', () => {
|
||||||
/>
|
/>
|
||||||
</ClusterContext.Provider>
|
</ClusterContext.Provider>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
it('renders PageLoader', () => {
|
it('renders PageLoader', async () => {
|
||||||
render(setupComponent({ areConnectorsFetching: true }));
|
await act(() => renderComponent({ areConnectorsFetching: true }));
|
||||||
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('row')).not.toBeInTheDocument();
|
expect(screen.queryByRole('row')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders table', () => {
|
it('renders table', () => {
|
||||||
render(setupComponent({ areConnectorsFetching: false }));
|
renderComponent({ areConnectorsFetching: false });
|
||||||
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
||||||
expect(screen.getByRole('table')).toBeInTheDocument();
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders connectors list', () => {
|
it('renders connectors list', () => {
|
||||||
render(
|
renderComponent({
|
||||||
setupComponent({
|
|
||||||
areConnectorsFetching: false,
|
areConnectorsFetching: false,
|
||||||
connectors,
|
connectors,
|
||||||
})
|
});
|
||||||
);
|
|
||||||
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
||||||
expect(screen.getByRole('table')).toBeInTheDocument();
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
||||||
expect(screen.getAllByRole('row').length).toEqual(3);
|
expect(screen.getAllByRole('row').length).toEqual(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles fetchConnects and fetchConnectors', () => {
|
it('handles fetchConnects and fetchConnectors', () => {
|
||||||
render(setupComponent());
|
renderComponent();
|
||||||
expect(fetchConnects).toHaveBeenCalledTimes(1);
|
expect(fetchConnects).toHaveBeenCalledTimes(1);
|
||||||
expect(fetchConnectors).toHaveBeenCalledTimes(1);
|
expect(fetchConnectors).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders actions if cluster is not readonly', () => {
|
it('renders actions if cluster is not readonly', () => {
|
||||||
render(setupComponent({}, { ...initialValue, isReadOnly: false }));
|
renderComponent({}, { ...initialValue, isReadOnly: false });
|
||||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('readonly cluster', () => {
|
describe('readonly cluster', () => {
|
||||||
it('does not render actions if cluster is readonly', () => {
|
it('does not render actions if cluster is readonly', () => {
|
||||||
render(setupComponent({}, { ...initialValue, isReadOnly: true }));
|
renderComponent({}, { ...initialValue, isReadOnly: true });
|
||||||
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,8 +6,8 @@ import {
|
||||||
} from 'lib/paths';
|
} from 'lib/paths';
|
||||||
import New, { NewProps } from 'components/Connect/New/New';
|
import New, { NewProps } from 'components/Connect/New/New';
|
||||||
import { connects, connector } from 'redux/reducers/connect/__test__/fixtures';
|
import { connects, connector } from 'redux/reducers/connect/__test__/fixtures';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { waitFor, fireEvent, screen } from '@testing-library/react';
|
import { fireEvent, screen, act } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { ControllerRenderProps } from 'react-hook-form';
|
import { ControllerRenderProps } from 'react-hook-form';
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ jest.mock('react-router-dom', () => ({
|
||||||
describe('New', () => {
|
describe('New', () => {
|
||||||
const clusterName = 'my-cluster';
|
const clusterName = 'my-cluster';
|
||||||
const simulateFormSubmit = async () => {
|
const simulateFormSubmit = async () => {
|
||||||
|
await act(() => {
|
||||||
userEvent.type(
|
userEvent.type(
|
||||||
screen.getByPlaceholderText('Connector Name'),
|
screen.getByPlaceholderText('Connector Name'),
|
||||||
'my-connector'
|
'my-connector'
|
||||||
|
@ -38,10 +39,12 @@ describe('New', () => {
|
||||||
screen.getByPlaceholderText('json'),
|
screen.getByPlaceholderText('json'),
|
||||||
'{"class":"MyClass"}'.replace(/[{[]/g, '$&$&')
|
'{"class":"MyClass"}'.replace(/[{[]/g, '$&$&')
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
expect(screen.getByPlaceholderText('json')).toHaveValue(
|
expect(screen.getByPlaceholderText('json')).toHaveValue(
|
||||||
'{"class":"MyClass"}'
|
'{"class":"MyClass"}'
|
||||||
);
|
);
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
fireEvent.submit(screen.getByRole('form'));
|
fireEvent.submit(screen.getByRole('form'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -62,7 +65,9 @@ describe('New', () => {
|
||||||
|
|
||||||
it('fetches connects on mount', async () => {
|
it('fetches connects on mount', async () => {
|
||||||
const fetchConnects = jest.fn();
|
const fetchConnects = jest.fn();
|
||||||
await waitFor(() => renderComponent({ fetchConnects }));
|
await act(() => {
|
||||||
|
renderComponent({ fetchConnects });
|
||||||
|
});
|
||||||
expect(fetchConnects).toHaveBeenCalledTimes(1);
|
expect(fetchConnects).toHaveBeenCalledTimes(1);
|
||||||
expect(fetchConnects).toHaveBeenCalledWith(clusterName);
|
expect(fetchConnects).toHaveBeenCalledWith(clusterName);
|
||||||
});
|
});
|
||||||
|
@ -71,6 +76,7 @@ describe('New', () => {
|
||||||
const createConnector = jest.fn();
|
const createConnector = jest.fn();
|
||||||
renderComponent({ createConnector });
|
renderComponent({ createConnector });
|
||||||
await simulateFormSubmit();
|
await simulateFormSubmit();
|
||||||
|
|
||||||
expect(createConnector).toHaveBeenCalledTimes(1);
|
expect(createConnector).toHaveBeenCalledTimes(1);
|
||||||
expect(createConnector).toHaveBeenCalledWith({
|
expect(createConnector).toHaveBeenCalledWith({
|
||||||
clusterName,
|
clusterName,
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
import { ConsumerGroupID } from 'redux/interfaces/consumerGroup';
|
import { ConsumerGroupID } from 'redux/interfaces/consumerGroup';
|
||||||
import PageLoader from 'components/common/PageLoader/PageLoader';
|
import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||||
import ConfirmationModal from 'components/common/ConfirmationModal/ConfirmationModal';
|
import ConfirmationModal from 'components/common/ConfirmationModal/ConfirmationModal';
|
||||||
import { useHistory, useParams } from 'react-router';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import ClusterContext from 'components/contexts/ClusterContext';
|
import ClusterContext from 'components/contexts/ClusterContext';
|
||||||
import PageHeading from 'components/common/PageHeading/PageHeading';
|
import PageHeading from 'components/common/PageHeading/PageHeading';
|
||||||
import VerticalElipsisIcon from 'components/common/Icons/VerticalElipsisIcon';
|
import VerticalElipsisIcon from 'components/common/Icons/VerticalElipsisIcon';
|
||||||
|
|
|
@ -15,7 +15,7 @@ import 'react-datepicker/dist/react-datepicker.css';
|
||||||
import { groupBy } from 'lodash';
|
import { groupBy } from 'lodash';
|
||||||
import PageLoader from 'components/common/PageLoader/PageLoader';
|
import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||||
import { ErrorMessage } from '@hookform/error-message';
|
import { ErrorMessage } from '@hookform/error-message';
|
||||||
import { useHistory, useParams } from 'react-router';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import Select from 'components/common/Select/Select';
|
import Select from 'components/common/Select/Select';
|
||||||
import { InputLabel } from 'components/common/Input/InputLabel.styled';
|
import { InputLabel } from 'components/common/Input/InputLabel.styled';
|
||||||
import { Button } from 'components/common/Button/Button';
|
import { Button } from 'components/common/Button/Button';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { screen, waitFor } from '@testing-library/react';
|
import { act, screen, waitFor } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { clusterConsumerGroupResetOffsetsPath } from 'lib/paths';
|
import { clusterConsumerGroupResetOffsetsPath } from 'lib/paths';
|
||||||
|
@ -77,12 +77,12 @@ describe('ResetOffsets', () => {
|
||||||
fetchMock.reset();
|
fetchMock.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders progress bar for initial state', () => {
|
it('renders progress bar for initial state', async () => {
|
||||||
fetchMock.getOnce(
|
fetchMock.getOnce(
|
||||||
`/api/clusters/${clusterName}/consumer-groups/${groupId}`,
|
`/api/clusters/${clusterName}/consumer-groups/${groupId}`,
|
||||||
404
|
404
|
||||||
);
|
);
|
||||||
renderComponent();
|
await waitFor(() => renderComponent());
|
||||||
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -93,11 +93,10 @@ describe('ResetOffsets', () => {
|
||||||
`/api/clusters/${clusterName}/consumer-groups/${groupId}`,
|
`/api/clusters/${clusterName}/consumer-groups/${groupId}`,
|
||||||
consumerGroupPayload
|
consumerGroupPayload
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
await waitFor(() =>
|
});
|
||||||
expect(fetchConsumerGroupMock.called()).toBeTruthy()
|
expect(fetchConsumerGroupMock.called()).toBeTruthy();
|
||||||
);
|
|
||||||
await waitFor(() => screen.queryByRole('form'));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls resetConsumerGroupOffsets with EARLIEST', async () => {
|
it('calls resetConsumerGroupOffsets with EARLIEST', async () => {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { screen } from '@testing-library/react';
|
||||||
import TopicContents from 'components/ConsumerGroups/Details/TopicContents/TopicContents';
|
import TopicContents from 'components/ConsumerGroups/Details/TopicContents/TopicContents';
|
||||||
import { consumerGroupPayload } from 'redux/reducers/consumerGroups/__test__/fixtures';
|
import { consumerGroupPayload } from 'redux/reducers/consumerGroups/__test__/fixtures';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { ConsumerGroupTopicPartition } from 'generated-sources';
|
import { ConsumerGroupTopicPartition } from 'generated-sources';
|
||||||
|
|
||||||
const clusterName = 'cluster1';
|
const clusterName = 'cluster1';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { Route, Router } from 'react-router';
|
import { Route, Router } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
clusterConsumerGroupDetailsPath,
|
clusterConsumerGroupDetailsPath,
|
||||||
clusterConsumerGroupResetOffsetsPath,
|
clusterConsumerGroupResetOffsetsPath,
|
||||||
|
@ -16,6 +16,7 @@ import {
|
||||||
waitForElementToBeRemoved,
|
waitForElementToBeRemoved,
|
||||||
} from '@testing-library/dom';
|
} from '@testing-library/dom';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { act } from '@testing-library/react';
|
||||||
|
|
||||||
const clusterName = 'cluster1';
|
const clusterName = 'cluster1';
|
||||||
const { groupId } = consumerGroupPayload;
|
const { groupId } = consumerGroupPayload;
|
||||||
|
@ -92,20 +93,18 @@ describe('Details component', () => {
|
||||||
|
|
||||||
it('handles [Delete consumer group] click', async () => {
|
it('handles [Delete consumer group] click', async () => {
|
||||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||||
|
await act(() => {
|
||||||
userEvent.click(screen.getByText('Delete consumer group'));
|
userEvent.click(screen.getByText('Delete consumer group'));
|
||||||
|
});
|
||||||
await waitFor(() =>
|
expect(screen.queryByRole('dialog')).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('dialog')).toBeInTheDocument()
|
|
||||||
);
|
|
||||||
|
|
||||||
const deleteConsumerGroupMock = fetchMock.deleteOnce(
|
const deleteConsumerGroupMock = fetchMock.deleteOnce(
|
||||||
`/api/clusters/${clusterName}/consumer-groups/${groupId}`,
|
`/api/clusters/${clusterName}/consumer-groups/${groupId}`,
|
||||||
200
|
200
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
userEvent.click(screen.getByText('Submit'));
|
userEvent.click(screen.getByText('Submit'));
|
||||||
await waitFor(() =>
|
});
|
||||||
expect(deleteConsumerGroupMock.called()).toBeTruthy()
|
expect(deleteConsumerGroupMock.called()).toBeTruthy();
|
||||||
);
|
|
||||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
||||||
expect(history.location.pathname).toEqual(
|
expect(history.location.pathname).toEqual(
|
||||||
clusterConsumerGroupsPath(clusterName)
|
clusterConsumerGroupsPath(clusterName)
|
||||||
|
|
|
@ -5,7 +5,7 @@ import userEvent from '@testing-library/user-event';
|
||||||
import ListItem from 'components/ConsumerGroups/Details/ListItem';
|
import ListItem from 'components/ConsumerGroups/Details/ListItem';
|
||||||
import { consumerGroupPayload } from 'redux/reducers/consumerGroups/__test__/fixtures';
|
import { consumerGroupPayload } from 'redux/reducers/consumerGroups/__test__/fixtures';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { ConsumerGroupTopicPartition } from 'generated-sources';
|
import { ConsumerGroupTopicPartition } from 'generated-sources';
|
||||||
|
|
||||||
const clusterName = 'cluster1';
|
const clusterName = 'cluster1';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { clusterConsumerGroupsPath } from 'lib/paths';
|
import { clusterConsumerGroupsPath } from 'lib/paths';
|
||||||
import {
|
import {
|
||||||
|
act,
|
||||||
screen,
|
screen,
|
||||||
waitFor,
|
waitFor,
|
||||||
waitForElementToBeRemoved,
|
waitForElementToBeRemoved,
|
||||||
|
@ -12,7 +13,7 @@ import {
|
||||||
} from 'redux/reducers/consumerGroups/__test__/fixtures';
|
} from 'redux/reducers/consumerGroups/__test__/fixtures';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import { Route, Router } from 'react-router';
|
import { Route, Router } from 'react-router-dom';
|
||||||
import { ConsumerGroupOrdering, SortOrder } from 'generated-sources';
|
import { ConsumerGroupOrdering, SortOrder } from 'generated-sources';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
|
|
||||||
|
@ -37,7 +38,6 @@ const renderComponent = (history = historyMock) =>
|
||||||
describe('ConsumerGroups', () => {
|
describe('ConsumerGroups', () => {
|
||||||
it('renders with initial state', async () => {
|
it('renders with initial state', async () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -54,10 +54,10 @@ describe('ConsumerGroups', () => {
|
||||||
sortOrder: SortOrder.ASC,
|
sortOrder: SortOrder.ASC,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
await waitFor(() => expect(fetchMock.calls().length).toBe(1));
|
});
|
||||||
|
expect(fetchMock.calls().length).toBe(1);
|
||||||
expect(screen.getByRole('table')).toBeInTheDocument();
|
expect(screen.getByRole('table')).toBeInTheDocument();
|
||||||
expect(screen.getByText('No active consumer groups')).toBeInTheDocument();
|
expect(screen.getByText('No active consumer groups')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||||
import ListItem from 'components/KsqlDb/List/ListItem';
|
import ListItem from 'components/KsqlDb/List/ListItem';
|
||||||
import React, { FC, useEffect } from 'react';
|
import React, { FC, useEffect } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router-dom';
|
||||||
import { fetchKsqlDbTables } from 'redux/reducers/ksqlDb/ksqlDbSlice';
|
import { fetchKsqlDbTables } from 'redux/reducers/ksqlDb/ksqlDbSlice';
|
||||||
import { getKsqlDbTables } from 'redux/reducers/ksqlDb/selectors';
|
import { getKsqlDbTables } from 'redux/reducers/ksqlDb/selectors';
|
||||||
import { clusterKsqlDbQueryPath } from 'lib/paths';
|
import { clusterKsqlDbQueryPath } from 'lib/paths';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import List from 'components/KsqlDb/List/List';
|
import List from 'components/KsqlDb/List/List';
|
||||||
import { Route, Router } from 'react-router';
|
import { Route, Router } from 'react-router-dom';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import { clusterKsqlDbPath } from 'lib/paths';
|
import { clusterKsqlDbPath } from 'lib/paths';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useCallback, useEffect, FC, useState } from 'react';
|
import React, { useCallback, useEffect, FC, useState } from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useParams } from 'react-router-dom';
|
||||||
import TableRenderer from 'components/KsqlDb/Query/renderer/TableRenderer/TableRenderer';
|
import TableRenderer from 'components/KsqlDb/Query/renderer/TableRenderer/TableRenderer';
|
||||||
import {
|
import {
|
||||||
executeKsql,
|
executeKsql,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import QueryForm, { Props } from 'components/KsqlDb/Query/QueryForm/QueryForm';
|
import QueryForm, { Props } from 'components/KsqlDb/Query/QueryForm/QueryForm';
|
||||||
import { screen, waitFor, within } from '@testing-library/dom';
|
import { screen, within } from '@testing-library/dom';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { act } from '@testing-library/react';
|
||||||
|
|
||||||
const renderComponent = (props: Props) => render(<QueryForm {...props} />);
|
const renderComponent = (props: Props) => render(<QueryForm {...props} />);
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ describe('QueryForm', () => {
|
||||||
submitHandler: submitFn,
|
submitHandler: submitFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
||||||
);
|
);
|
||||||
expect(screen.getByText('ksql is a required field')).toBeInTheDocument();
|
expect(screen.getByText('ksql is a required field')).toBeInTheDocument();
|
||||||
|
@ -81,7 +82,7 @@ describe('QueryForm', () => {
|
||||||
submitHandler: jest.fn(),
|
submitHandler: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
// the use of `paste` is a hack that i found somewhere,
|
// the use of `paste` is a hack that i found somewhere,
|
||||||
// `type` won't work
|
// `type` won't work
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
|
@ -89,12 +90,10 @@ describe('QueryForm', () => {
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'not-a-JSON-string'
|
'not-a-JSON-string'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
userEvent.click(screen.getByRole('button', { name: 'Execute' }));
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
});
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByText('streamsProperties is not JSON object')
|
screen.getByText('streamsProperties is not JSON object')
|
||||||
|
@ -110,19 +109,15 @@ describe('QueryForm', () => {
|
||||||
submitHandler: jest.fn(),
|
submitHandler: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'{"totallyJSON": "string"}'
|
'{"totallyJSON": "string"}'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
userEvent.click(screen.getByRole('button', { name: 'Execute' }));
|
||||||
await waitFor(() =>
|
});
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.queryByText('streamsProperties is not JSON object')
|
screen.queryByText('streamsProperties is not JSON object')
|
||||||
).not.toBeInTheDocument();
|
).not.toBeInTheDocument();
|
||||||
|
@ -138,25 +133,21 @@ describe('QueryForm', () => {
|
||||||
submitHandler: submitFn,
|
submitHandler: submitFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'show tables;'
|
'show tables;'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'{"totallyJSON": "string"}'
|
'{"totallyJSON": "string"}'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
userEvent.click(screen.getByRole('button', { name: 'Execute' }));
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
});
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen.queryByText('ksql is a required field')
|
screen.queryByText('ksql is a required field')
|
||||||
|
@ -181,7 +172,7 @@ describe('QueryForm', () => {
|
||||||
|
|
||||||
expect(screen.getByRole('button', { name: 'Clear results' })).toBeEnabled();
|
expect(screen.getByRole('button', { name: 'Clear results' })).toBeEnabled();
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Clear results' }))
|
userEvent.click(screen.getByRole('button', { name: 'Clear results' }))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -200,7 +191,7 @@ describe('QueryForm', () => {
|
||||||
|
|
||||||
expect(screen.getByRole('button', { name: 'Stop query' })).toBeEnabled();
|
expect(screen.getByRole('button', { name: 'Stop query' })).toBeEnabled();
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Stop query' }))
|
userEvent.click(screen.getByRole('button', { name: 'Stop query' }))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -217,19 +208,17 @@ describe('QueryForm', () => {
|
||||||
submitHandler: submitFn,
|
submitHandler: submitFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'show tables;'
|
'show tables;'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.type(
|
userEvent.type(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'{ctrl}{enter}'
|
'{ctrl}{enter}'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
expect(submitFn.mock.calls.length).toBe(1);
|
expect(submitFn.mock.calls.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
@ -244,30 +233,26 @@ describe('QueryForm', () => {
|
||||||
submitHandler: submitFn,
|
submitHandler: submitFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'show tables;'
|
'show tables;'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'{"some":"json"}'
|
'{"some":"json"}'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.type(
|
userEvent.type(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'{ctrl}{enter}'
|
'{ctrl}{enter}'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
expect(submitFn.mock.calls.length).toBe(1);
|
expect(submitFn.mock.calls.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
@ -281,20 +266,17 @@ describe('QueryForm', () => {
|
||||||
submitHandler: jest.fn(),
|
submitHandler: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'show tables;'
|
'show tables;'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('button', {
|
within(screen.getByLabelText('KSQL')).getByRole('button', {
|
||||||
name: 'Clear',
|
name: 'Clear',
|
||||||
})
|
})
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
expect(screen.queryByText('show tables;')).not.toBeInTheDocument();
|
expect(screen.queryByText('show tables;')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
@ -308,25 +290,21 @@ describe('QueryForm', () => {
|
||||||
submitHandler: jest.fn(),
|
submitHandler: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'{"some":"json"}'
|
'{"some":"json"}'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('button', {
|
).getByRole('button', {
|
||||||
name: 'Clear',
|
name: 'Clear',
|
||||||
})
|
})
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
expect(screen.queryByText('{"some":"json"}')).not.toBeInTheDocument();
|
expect(screen.queryByText('{"some":"json"}')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,11 +3,12 @@ import React from 'react';
|
||||||
import Query, {
|
import Query, {
|
||||||
getFormattedErrorFromTableData,
|
getFormattedErrorFromTableData,
|
||||||
} from 'components/KsqlDb/Query/Query';
|
} from 'components/KsqlDb/Query/Query';
|
||||||
import { screen, waitFor, within } from '@testing-library/dom';
|
import { screen, within } from '@testing-library/dom';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { Route } from 'react-router-dom';
|
import { Route } from 'react-router-dom';
|
||||||
import { clusterKsqlDbQueryPath } from 'lib/paths';
|
import { clusterKsqlDbQueryPath } from 'lib/paths';
|
||||||
|
import { act } from '@testing-library/react';
|
||||||
|
|
||||||
const clusterName = 'testLocal';
|
const clusterName = 'testLocal';
|
||||||
const renderComponent = () =>
|
const renderComponent = () =>
|
||||||
|
@ -42,16 +43,14 @@ describe('Query', () => {
|
||||||
value: EventSourceMock,
|
value: EventSourceMock,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'show tables;'
|
'show tables;'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
userEvent.click(screen.getByRole('button', { name: 'Execute' }));
|
||||||
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
|
||||||
);
|
|
||||||
expect(mock.calls().length).toBe(1);
|
expect(mock.calls().length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -66,25 +65,19 @@ describe('Query', () => {
|
||||||
value: EventSourceMock,
|
value: EventSourceMock,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'show tables;'
|
'show tables;'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'{"some":"json"}'
|
'{"some":"json"}'
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
|
||||||
);
|
);
|
||||||
|
userEvent.click(screen.getByRole('button', { name: 'Execute' }));
|
||||||
|
});
|
||||||
expect(mock.calls().length).toBe(1);
|
expect(mock.calls().length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -99,25 +92,19 @@ describe('Query', () => {
|
||||||
value: EventSourceMock,
|
value: EventSourceMock,
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
within(screen.getByLabelText('KSQL')).getByRole('textbox'),
|
||||||
'show tables;'
|
'show tables;'
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
within(
|
within(
|
||||||
screen.getByLabelText('Stream properties (JSON format)')
|
screen.getByLabelText('Stream properties (JSON format)')
|
||||||
).getByRole('textbox'),
|
).getByRole('textbox'),
|
||||||
'{"some":"json"}'
|
'{"some":"json"}'
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
await waitFor(() =>
|
|
||||||
userEvent.click(screen.getByRole('button', { name: 'Execute' }))
|
|
||||||
);
|
);
|
||||||
|
userEvent.click(screen.getByRole('button', { name: 'Execute' }));
|
||||||
|
});
|
||||||
expect(mock.calls().length).toBe(1);
|
expect(mock.calls().length).toBe(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,7 +24,7 @@ const ClusterMenu: React.FC<Props> = ({
|
||||||
singleMode,
|
singleMode,
|
||||||
}) => {
|
}) => {
|
||||||
const hasFeatureConfigured = React.useCallback(
|
const hasFeatureConfigured = React.useCallback(
|
||||||
(key) => features?.includes(key),
|
(key: ClusterFeaturesEnum) => features?.includes(key),
|
||||||
[features]
|
[features]
|
||||||
);
|
);
|
||||||
const [isOpen, setIsOpen] = React.useState(!!singleMode);
|
const [isOpen, setIsOpen] = React.useState(!!singleMode);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { NavLinkProps } from 'react-router-dom';
|
import { NavLinkProps } from 'react-router-dom';
|
||||||
|
|
||||||
import * as S from './Nav.styled';
|
import * as S from './Nav.styled';
|
||||||
|
@ -11,7 +11,9 @@ export interface ClusterMenuItemProps {
|
||||||
isActive?: NavLinkProps['isActive'];
|
isActive?: NavLinkProps['isActive'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClusterMenuItem: React.FC<ClusterMenuItemProps> = (props) => {
|
const ClusterMenuItem: React.FC<PropsWithChildren<ClusterMenuItemProps>> = (
|
||||||
|
props
|
||||||
|
) => {
|
||||||
const { to, title, children, exact, isTopLevel, isActive } = props;
|
const { to, title, children, exact, isTopLevel, isActive } = props;
|
||||||
|
|
||||||
if (to) {
|
if (to) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useHistory, useParams } from 'react-router';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
clusterSchemasPath,
|
clusterSchemasPath,
|
||||||
clusterSchemaSchemaDiffPath,
|
clusterSchemaSchemaDiffPath,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Details from 'components/Schemas/Details/Details';
|
import Details from 'components/Schemas/Details/Details';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { clusterSchemaPath } from 'lib/paths';
|
import { clusterSchemaPath } from 'lib/paths';
|
||||||
import { screen, waitFor } from '@testing-library/dom';
|
import { screen, waitFor } from '@testing-library/dom';
|
||||||
import {
|
import {
|
||||||
|
@ -14,6 +14,7 @@ import ClusterContext, {
|
||||||
initialValue as contextInitialValue,
|
initialValue as contextInitialValue,
|
||||||
} from 'components/contexts/ClusterContext';
|
} from 'components/contexts/ClusterContext';
|
||||||
import { RootState } from 'redux/interfaces';
|
import { RootState } from 'redux/interfaces';
|
||||||
|
import { act } from '@testing-library/react';
|
||||||
|
|
||||||
import { versionPayload, versionEmptyPayload } from './fixtures';
|
import { versionPayload, versionEmptyPayload } from './fixtures';
|
||||||
|
|
||||||
|
@ -24,8 +25,8 @@ const schemasAPIVersionsUrl = `/api/clusters/${clusterName}/schemas/${schemaVers
|
||||||
const renderComponent = (
|
const renderComponent = (
|
||||||
initialState: RootState['schemas'] = schemasInitialState,
|
initialState: RootState['schemas'] = schemasInitialState,
|
||||||
context: ContextProps = contextInitialValue
|
context: ContextProps = contextInitialValue
|
||||||
) => {
|
) =>
|
||||||
return render(
|
render(
|
||||||
<Route path={clusterSchemaPath(':clusterName', ':subject')}>
|
<Route path={clusterSchemaPath(':clusterName', ':subject')}>
|
||||||
<ClusterContext.Provider value={context}>
|
<ClusterContext.Provider value={context}>
|
||||||
<Details />
|
<Details />
|
||||||
|
@ -38,7 +39,6 @@ const renderComponent = (
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
describe('Details', () => {
|
describe('Details', () => {
|
||||||
afterEach(() => fetchMock.reset());
|
afterEach(() => fetchMock.reset());
|
||||||
|
@ -50,7 +50,10 @@ describe('Details', () => {
|
||||||
schemasAPIVersionsUrl,
|
schemasAPIVersionsUrl,
|
||||||
404
|
404
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(schemasAPILatestMock.called()).toBeTruthy();
|
expect(schemasAPILatestMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -78,7 +81,9 @@ describe('Details', () => {
|
||||||
schemasAPIVersionsUrl,
|
schemasAPIVersionsUrl,
|
||||||
versionPayload
|
versionPayload
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(schemasAPILatestMock.called()).toBeTruthy();
|
expect(schemasAPILatestMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
@ -104,7 +109,9 @@ describe('Details', () => {
|
||||||
schemasAPIVersionsUrl,
|
schemasAPIVersionsUrl,
|
||||||
versionEmptyPayload
|
versionEmptyPayload
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(schemasAPILatestMock.called()).toBeTruthy();
|
expect(schemasAPILatestMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { SchemaSubject } from 'generated-sources';
|
||||||
import { clusterSchemaSchemaDiffPath } from 'lib/paths';
|
import { clusterSchemaSchemaDiffPath } from 'lib/paths';
|
||||||
import PageLoader from 'components/common/PageLoader/PageLoader';
|
import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||||
import DiffViewer from 'components/common/DiffViewer/DiffViewer';
|
import DiffViewer from 'components/common/DiffViewer/DiffViewer';
|
||||||
import { useHistory, useParams, useLocation } from 'react-router';
|
import { useHistory, useParams, useLocation } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
fetchSchemaVersions,
|
fetchSchemaVersions,
|
||||||
SCHEMAS_VERSIONS_FETCH_ACTION,
|
SCHEMAS_VERSIONS_FETCH_ACTION,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useHistory, useParams } from 'react-router';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
||||||
import {
|
import {
|
||||||
CompatibilityLevelCompatibilityEnum,
|
CompatibilityLevelCompatibilityEnum,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
schemasInitialState,
|
schemasInitialState,
|
||||||
schemaVersion,
|
schemaVersion,
|
||||||
} from 'redux/reducers/schemas/__test__/fixtures';
|
} from 'redux/reducers/schemas/__test__/fixtures';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { screen, waitFor } from '@testing-library/dom';
|
import { screen, waitFor } from '@testing-library/dom';
|
||||||
import ClusterContext, {
|
import ClusterContext, {
|
||||||
ContextProps,
|
ContextProps,
|
||||||
|
@ -14,6 +14,7 @@ import ClusterContext, {
|
||||||
} from 'components/contexts/ClusterContext';
|
} from 'components/contexts/ClusterContext';
|
||||||
import { RootState } from 'redux/interfaces';
|
import { RootState } from 'redux/interfaces';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
|
import { act } from '@testing-library/react';
|
||||||
|
|
||||||
const clusterName = 'testClusterName';
|
const clusterName = 'testClusterName';
|
||||||
const schemasAPILatestUrl = `/api/clusters/${clusterName}/schemas/${schemaVersion.subject}/latest`;
|
const schemasAPILatestUrl = `/api/clusters/${clusterName}/schemas/${schemaVersion.subject}/latest`;
|
||||||
|
@ -21,8 +22,8 @@ const schemasAPILatestUrl = `/api/clusters/${clusterName}/schemas/${schemaVersio
|
||||||
const renderComponent = (
|
const renderComponent = (
|
||||||
initialState: RootState['schemas'] = schemasInitialState,
|
initialState: RootState['schemas'] = schemasInitialState,
|
||||||
context: ContextProps = contextInitialValue
|
context: ContextProps = contextInitialValue
|
||||||
) => {
|
) =>
|
||||||
return render(
|
render(
|
||||||
<Route path={clusterSchemaEditPath(':clusterName', ':subject')}>
|
<Route path={clusterSchemaEditPath(':clusterName', ':subject')}>
|
||||||
<ClusterContext.Provider value={context}>
|
<ClusterContext.Provider value={context}>
|
||||||
<Edit />
|
<Edit />
|
||||||
|
@ -35,21 +36,17 @@ const renderComponent = (
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
describe('Edit', () => {
|
describe('Edit', () => {
|
||||||
afterEach(() => fetchMock.reset());
|
afterEach(() => fetchMock.reset());
|
||||||
|
|
||||||
describe('fetch failed', () => {
|
describe('fetch failed', () => {
|
||||||
beforeEach(async () => {
|
it('renders pageloader', async () => {
|
||||||
const schemasAPILatestMock = fetchMock.getOnce(schemasAPILatestUrl, 404);
|
const schemasAPILatestMock = fetchMock.getOnce(schemasAPILatestUrl, 404);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
await waitFor(() => {
|
|
||||||
expect(schemasAPILatestMock.called()).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
});
|
await waitFor(() => expect(schemasAPILatestMock.called()).toBeTruthy());
|
||||||
|
|
||||||
it('renders pageloader', () => {
|
|
||||||
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
||||||
expect(screen.queryByText(schemaVersion.subject)).not.toBeInTheDocument();
|
expect(screen.queryByText(schemaVersion.subject)).not.toBeInTheDocument();
|
||||||
expect(screen.queryByText('Submit')).not.toBeInTheDocument();
|
expect(screen.queryByText('Submit')).not.toBeInTheDocument();
|
||||||
|
@ -58,19 +55,15 @@ describe('Edit', () => {
|
||||||
|
|
||||||
describe('fetch success', () => {
|
describe('fetch success', () => {
|
||||||
describe('has schema versions', () => {
|
describe('has schema versions', () => {
|
||||||
beforeEach(async () => {
|
it('renders component with schema info', async () => {
|
||||||
const schemasAPILatestMock = fetchMock.getOnce(
|
const schemasAPILatestMock = fetchMock.getOnce(
|
||||||
schemasAPILatestUrl,
|
schemasAPILatestUrl,
|
||||||
schemaVersion
|
schemaVersion
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
await waitFor(() => {
|
|
||||||
expect(schemasAPILatestMock.called()).toBeTruthy();
|
|
||||||
});
|
});
|
||||||
});
|
await waitFor(() => expect(schemasAPILatestMock.called()).toBeTruthy());
|
||||||
|
|
||||||
it('renders component with schema info', () => {
|
|
||||||
expect(screen.getByText('Submit')).toBeInTheDocument();
|
expect(screen.getByText('Submit')).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { screen, waitFor, within } from '@testing-library/react';
|
import { act, screen, waitFor, within } from '@testing-library/react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { CompatibilityLevelCompatibilityEnum } from 'generated-sources';
|
import { CompatibilityLevelCompatibilityEnum } from 'generated-sources';
|
||||||
import GlobalSchemaSelector from 'components/Schemas/List/GlobalSchemaSelector/GlobalSchemaSelector';
|
import GlobalSchemaSelector from 'components/Schemas/List/GlobalSchemaSelector/GlobalSchemaSelector';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { clusterSchemasPath } from 'lib/paths';
|
import { clusterSchemasPath } from 'lib/paths';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
|
|
||||||
const clusterName = 'testClusterName';
|
const clusterName = 'testClusterName';
|
||||||
|
@ -42,7 +42,9 @@ describe('GlobalSchemaSelector', () => {
|
||||||
`api/clusters/${clusterName}/schemas/compatibility`,
|
`api/clusters/${clusterName}/schemas/compatibility`,
|
||||||
{ compatibility: CompatibilityLevelCompatibilityEnum.FULL }
|
{ compatibility: CompatibilityLevelCompatibilityEnum.FULL }
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(fetchGlobalCompatibilityLevelMock.called()).toBeTruthy()
|
expect(fetchGlobalCompatibilityLevelMock.called()).toBeTruthy()
|
||||||
);
|
);
|
||||||
|
@ -89,7 +91,10 @@ describe('GlobalSchemaSelector', () => {
|
||||||
});
|
});
|
||||||
await waitFor(() => expect(putNewCompatibilityMock.called()).toBeTruthy());
|
await waitFor(() => expect(putNewCompatibilityMock.called()).toBeTruthy());
|
||||||
await waitFor(() => expect(getSchemasMock.called()).toBeTruthy());
|
await waitFor(() => expect(getSchemasMock.called()).toBeTruthy());
|
||||||
expect(screen.queryByText('Confirm the action')).not.toBeInTheDocument();
|
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(screen.queryByText('Confirm the action')).not.toBeInTheDocument()
|
||||||
|
);
|
||||||
expectOptionIsSelected(CompatibilityLevelCompatibilityEnum.FORWARD);
|
expectOptionIsSelected(CompatibilityLevelCompatibilityEnum.FORWARD);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import List from 'components/Schemas/List/List';
|
import List from 'components/Schemas/List/List';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { clusterSchemasPath } from 'lib/paths';
|
import { clusterSchemasPath } from 'lib/paths';
|
||||||
import { screen, waitFor } from '@testing-library/dom';
|
import { act, screen } from '@testing-library/react';
|
||||||
import {
|
import {
|
||||||
schemasFulfilledState,
|
schemasFulfilledState,
|
||||||
schemasInitialState,
|
schemasInitialState,
|
||||||
|
@ -52,9 +52,11 @@ describe('List', () => {
|
||||||
schemasAPICompabilityUrl,
|
schemasAPICompabilityUrl,
|
||||||
404
|
404
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
await waitFor(() => expect(fetchSchemasMock.called()).toBeTruthy());
|
});
|
||||||
await waitFor(() => expect(fetchCompabilityMock.called()).toBeTruthy());
|
expect(fetchSchemasMock.called()).toBeTruthy();
|
||||||
|
expect(fetchCompabilityMock.called()).toBeTruthy();
|
||||||
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
expect(screen.getByRole('progressbar')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -70,9 +72,11 @@ describe('List', () => {
|
||||||
schemasAPICompabilityUrl,
|
schemasAPICompabilityUrl,
|
||||||
200
|
200
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
await waitFor(() => expect(fetchSchemasMock.called()).toBeTruthy());
|
});
|
||||||
await waitFor(() => expect(fetchCompabilityMock.called()).toBeTruthy());
|
expect(fetchSchemasMock.called()).toBeTruthy();
|
||||||
|
expect(fetchCompabilityMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
it('renders empty table', () => {
|
it('renders empty table', () => {
|
||||||
expect(screen.getByText('No schemas found')).toBeInTheDocument();
|
expect(screen.getByText('No schemas found')).toBeInTheDocument();
|
||||||
|
@ -88,9 +92,11 @@ describe('List', () => {
|
||||||
schemasAPICompabilityUrl,
|
schemasAPICompabilityUrl,
|
||||||
200
|
200
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent(schemasFulfilledState);
|
renderComponent(schemasFulfilledState);
|
||||||
await waitFor(() => expect(fetchSchemasMock.called()).toBeTruthy());
|
});
|
||||||
await waitFor(() => expect(fetchCompabilityMock.called()).toBeTruthy());
|
expect(fetchSchemasMock.called()).toBeTruthy();
|
||||||
|
expect(fetchCompabilityMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
it('renders list', () => {
|
it('renders list', () => {
|
||||||
expect(screen.getByText(schemaVersion1.subject)).toBeInTheDocument();
|
expect(screen.getByText(schemaVersion1.subject)).toBeInTheDocument();
|
||||||
|
@ -104,12 +110,13 @@ describe('List', () => {
|
||||||
schemasAPIUrl,
|
schemasAPIUrl,
|
||||||
schemasPayload
|
schemasPayload
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent(schemasFulfilledState, {
|
renderComponent(schemasFulfilledState, {
|
||||||
...contextInitialValue,
|
...contextInitialValue,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
});
|
});
|
||||||
await waitFor(() => expect(fetchSchemasMock.called()).toBeTruthy());
|
});
|
||||||
|
expect(fetchSchemasMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
it('does not render Create Schema button', () => {
|
it('does not render Create Schema button', () => {
|
||||||
expect(screen.queryByText('Create Schema')).not.toBeInTheDocument();
|
expect(screen.queryByText('Create Schema')).not.toBeInTheDocument();
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { ErrorMessage } from '@hookform/error-message';
|
||||||
import { clusterSchemaPath } from 'lib/paths';
|
import { clusterSchemaPath } from 'lib/paths';
|
||||||
import { SchemaType } from 'generated-sources';
|
import { SchemaType } from 'generated-sources';
|
||||||
import { SCHEMA_NAME_VALIDATION_PATTERN } from 'lib/constants';
|
import { SCHEMA_NAME_VALIDATION_PATTERN } from 'lib/constants';
|
||||||
import { useHistory, useParams } from 'react-router';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { InputLabel } from 'components/common/Input/InputLabel.styled';
|
import { InputLabel } from 'components/common/Input/InputLabel.styled';
|
||||||
import Input from 'components/common/Input/Input';
|
import Input from 'components/common/Input/Input';
|
||||||
import { FormError } from 'components/common/Input/Input.styled';
|
import { FormError } from 'components/common/Input/Input.styled';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import New from 'components/Schemas/New/New';
|
import New from 'components/Schemas/New/New';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { clusterSchemaNewPath } from 'lib/paths';
|
import { clusterSchemaNewPath } from 'lib/paths';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import { screen } from '@testing-library/dom';
|
import { screen } from '@testing-library/dom';
|
||||||
|
|
||||||
const clusterName = 'local';
|
const clusterName = 'local';
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
clusterSchemasPath,
|
clusterSchemasPath,
|
||||||
} from 'lib/paths';
|
} from 'lib/paths';
|
||||||
import { screen, waitFor } from '@testing-library/dom';
|
import { screen, waitFor } from '@testing-library/dom';
|
||||||
import { Route } from 'react-router';
|
import { Route } from 'react-router-dom';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import { schemaVersion } from 'redux/reducers/schemas/__test__/fixtures';
|
import { schemaVersion } from 'redux/reducers/schemas/__test__/fixtures';
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
TopicWithDetailedInfo,
|
TopicWithDetailedInfo,
|
||||||
ClusterName,
|
ClusterName,
|
||||||
TopicName,
|
TopicName,
|
||||||
} from 'redux/interfaces';
|
} from 'redux/interfaces';
|
||||||
import { useParams } from 'react-router-dom';
|
|
||||||
import { clusterTopicCopyPath, clusterTopicNewPath } from 'lib/paths';
|
import { clusterTopicCopyPath, clusterTopicNewPath } from 'lib/paths';
|
||||||
import usePagination from 'lib/hooks/usePagination';
|
import usePagination from 'lib/hooks/usePagination';
|
||||||
import useModal from 'lib/hooks/useModal';
|
import useModal from 'lib/hooks/useModal';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen, waitFor, within } from '@testing-library/react';
|
import { screen, waitFor, within } from '@testing-library/react';
|
||||||
import { Route, Router, StaticRouter } from 'react-router';
|
import { Route, Router, StaticRouter } from 'react-router-dom';
|
||||||
import ClusterContext, {
|
import ClusterContext, {
|
||||||
ContextProps,
|
ContextProps,
|
||||||
} from 'components/contexts/ClusterContext';
|
} from 'components/contexts/ClusterContext';
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from 'redux/actions';
|
} from 'redux/actions';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { getResponse } from 'lib/errorHandling';
|
import { getResponse } from 'lib/errorHandling';
|
||||||
import { useHistory, useLocation, useParams } from 'react-router';
|
import { useHistory, useLocation, useParams } from 'react-router-dom';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { topicFormValidationSchema } from 'lib/yupExtended';
|
import { topicFormValidationSchema } from 'lib/yupExtended';
|
||||||
import PageHeading from 'components/common/PageHeading/PageHeading';
|
import PageHeading from 'components/common/PageHeading/PageHeading';
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import New from 'components/Topics/New/New';
|
import New from 'components/Topics/New/New';
|
||||||
import { Route, Router } from 'react-router';
|
import { Route, Router } from 'react-router-dom';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import { RootState } from 'redux/interfaces';
|
import { RootState } from 'redux/interfaces';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { screen, waitFor } from '@testing-library/react';
|
import { act, screen, waitFor } from '@testing-library/react';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import fetchMock from 'fetch-mock-jest';
|
import fetchMock from 'fetch-mock-jest';
|
||||||
import {
|
import {
|
||||||
|
@ -139,7 +139,7 @@ describe('New', () => {
|
||||||
jest.spyOn(mocked, 'push');
|
jest.spyOn(mocked, 'push');
|
||||||
renderComponent(mocked);
|
renderComponent(mocked);
|
||||||
|
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.type(screen.getByPlaceholderText('Topic Name'), topicName);
|
userEvent.type(screen.getByPlaceholderText('Topic Name'), topicName);
|
||||||
userEvent.click(screen.getByText(/submit/i));
|
userEvent.click(screen.getByText(/submit/i));
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {
|
||||||
} from 'generated-sources';
|
} from 'generated-sources';
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { omitBy } from 'lodash';
|
import { omitBy } from 'lodash';
|
||||||
import { useHistory, useLocation } from 'react-router';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
import DatePicker from 'react-datepicker';
|
import DatePicker from 'react-datepicker';
|
||||||
import MultiSelect from 'components/common/MultiSelect/MultiSelect.styled';
|
import MultiSelect from 'components/common/MultiSelect/MultiSelect.styled';
|
||||||
import { Option } from 'react-multi-select-component/dist/lib/interfaces';
|
import { Option } from 'react-multi-select-component/dist/lib/interfaces';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import AddEditFilterContainer, {
|
||||||
AddEditFilterContainerProps,
|
AddEditFilterContainerProps,
|
||||||
} from 'components/Topics/Topic/Details/Messages/Filters/AddEditFilterContainer';
|
} from 'components/Topics/Topic/Details/Messages/Filters/AddEditFilterContainer';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen, waitFor } from '@testing-library/react';
|
import { act, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { MessageFilters } from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
import { MessageFilters } from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
||||||
|
|
||||||
|
@ -15,7 +15,9 @@ describe('AddEditFilterContainer component', () => {
|
||||||
code: 'mockCode',
|
code: 'mockCode',
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupComponent = (props: Partial<AddEditFilterContainerProps> = {}) =>
|
const renderComponent = (
|
||||||
|
props: Partial<AddEditFilterContainerProps> = {}
|
||||||
|
) => {
|
||||||
render(
|
render(
|
||||||
<AddEditFilterContainer
|
<AddEditFilterContainer
|
||||||
cancelBtnHandler={jest.fn()}
|
cancelBtnHandler={jest.fn()}
|
||||||
|
@ -23,10 +25,11 @@ describe('AddEditFilterContainer component', () => {
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
describe('default Component Parameters', () => {
|
describe('default Component Parameters', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await waitFor(() => setupComponent());
|
await act(() => renderComponent());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check the default Button text', () => {
|
it('should check the default Button text', () => {
|
||||||
|
@ -40,39 +43,43 @@ describe('AddEditFilterContainer component', () => {
|
||||||
const inputs = screen.getAllByRole('textbox');
|
const inputs = screen.getAllByRole('textbox');
|
||||||
|
|
||||||
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
||||||
userEvent.paste(textAreaElement, 'Hello World With TextArea');
|
await act(() =>
|
||||||
|
userEvent.paste(textAreaElement, 'Hello World With TextArea')
|
||||||
|
);
|
||||||
|
|
||||||
const inputNameElement = inputs[1];
|
const inputNameElement = inputs[1];
|
||||||
userEvent.type(inputNameElement, 'Hello World!');
|
await act(() => userEvent.type(inputNameElement, 'Hello World!'));
|
||||||
|
|
||||||
await waitFor(() => expect(submitButtonElem).toBeEnabled());
|
expect(submitButtonElem).toBeEnabled();
|
||||||
|
|
||||||
userEvent.clear(inputNameElement);
|
await act(() => userEvent.clear(inputNameElement));
|
||||||
|
|
||||||
await waitFor(() => expect(submitButtonElem).toBeDisabled());
|
expect(submitButtonElem).toBeDisabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should view the error message after typing and clearing the input', async () => {
|
it('should view the error message after typing and clearing the input', async () => {
|
||||||
const inputs = screen.getAllByRole('textbox');
|
const inputs = screen.getAllByRole('textbox');
|
||||||
|
|
||||||
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
||||||
userEvent.paste(textAreaElement, 'Hello World With TextArea');
|
await act(() =>
|
||||||
|
userEvent.paste(textAreaElement, 'Hello World With TextArea')
|
||||||
|
);
|
||||||
|
|
||||||
const inputNameElement = inputs[1];
|
const inputNameElement = inputs[1];
|
||||||
|
await act(() => {
|
||||||
userEvent.type(inputNameElement, 'Hello World!');
|
userEvent.type(inputNameElement, 'Hello World!');
|
||||||
|
|
||||||
userEvent.clear(inputNameElement);
|
userEvent.clear(inputNameElement);
|
||||||
userEvent.clear(textAreaElement);
|
userEvent.clear(textAreaElement);
|
||||||
|
});
|
||||||
|
|
||||||
await waitFor(() =>
|
expect(screen.getByText(/required field/i)).toBeInTheDocument();
|
||||||
expect(screen.getByText(/required field/i)).toBeInTheDocument()
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Custom setup for the component', () => {
|
describe('Custom setup for the component', () => {
|
||||||
it('should render the input with default data if they are passed', async () => {
|
it('should render the input with default data if they are passed', async () => {
|
||||||
setupComponent({
|
renderComponent({
|
||||||
inputDisplayNameDefaultValue: mockData.name,
|
inputDisplayNameDefaultValue: mockData.name,
|
||||||
inputCodeDefaultValue: mockData.code,
|
inputCodeDefaultValue: mockData.code,
|
||||||
});
|
});
|
||||||
|
@ -80,23 +87,24 @@ describe('AddEditFilterContainer component', () => {
|
||||||
const inputs = screen.getAllByRole('textbox');
|
const inputs = screen.getAllByRole('textbox');
|
||||||
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
||||||
const inputNameElement = inputs[1];
|
const inputNameElement = inputs[1];
|
||||||
await waitFor(() => expect(inputNameElement).toHaveValue(mockData.name));
|
expect(inputNameElement).toHaveValue(mockData.name);
|
||||||
expect(textAreaElement.value).toEqual('');
|
expect(textAreaElement.value).toEqual('');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should test whether the cancel callback is being called', async () => {
|
it('should test whether the cancel callback is being called', async () => {
|
||||||
const cancelCallback = jest.fn();
|
const cancelCallback = jest.fn();
|
||||||
setupComponent({
|
renderComponent({
|
||||||
cancelBtnHandler: cancelCallback,
|
cancelBtnHandler: cancelCallback,
|
||||||
});
|
});
|
||||||
const cancelBtnElement = screen.getByText(/cancel/i);
|
const cancelBtnElement = screen.getByText(/cancel/i);
|
||||||
userEvent.click(cancelBtnElement);
|
|
||||||
await waitFor(() => expect(cancelCallback).toBeCalled());
|
await act(() => userEvent.click(cancelBtnElement));
|
||||||
|
expect(cancelCallback).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should test whether the submit Callback is being called', async () => {
|
it('should test whether the submit Callback is being called', async () => {
|
||||||
const submitCallback = jest.fn();
|
const submitCallback = jest.fn();
|
||||||
setupComponent({
|
renderComponent({
|
||||||
submitCallback,
|
submitCallback,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -106,30 +114,30 @@ describe('AddEditFilterContainer component', () => {
|
||||||
userEvent.paste(textAreaElement, 'Hello World With TextArea');
|
userEvent.paste(textAreaElement, 'Hello World With TextArea');
|
||||||
|
|
||||||
const inputNameElement = inputs[1];
|
const inputNameElement = inputs[1];
|
||||||
userEvent.type(inputNameElement, 'Hello World!');
|
await act(() => userEvent.type(inputNameElement, 'Hello World!'));
|
||||||
|
|
||||||
const submitBtnElement = screen.getByText(defaultSubmitBtn);
|
const submitBtnElement = screen.getByText(defaultSubmitBtn);
|
||||||
|
|
||||||
await waitFor(() => expect(submitBtnElement).toBeEnabled());
|
expect(submitBtnElement).toBeEnabled();
|
||||||
|
|
||||||
userEvent.click(submitBtnElement);
|
await act(() => userEvent.click(submitBtnElement));
|
||||||
|
|
||||||
await waitFor(() => expect(submitCallback).toBeCalled());
|
expect(submitCallback).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should display the checkbox if the props is passed and initially check state', async () => {
|
it('should display the checkbox if the props is passed and initially check state', async () => {
|
||||||
setupComponent({ isAdd: true });
|
renderComponent({ isAdd: true });
|
||||||
const checkbox = screen.getByRole('checkbox');
|
const checkbox = screen.getByRole('checkbox');
|
||||||
expect(checkbox).toBeInTheDocument();
|
expect(checkbox).toBeInTheDocument();
|
||||||
expect(checkbox).not.toBeChecked();
|
expect(checkbox).not.toBeChecked();
|
||||||
await waitFor(() => userEvent.click(checkbox));
|
await act(() => userEvent.click(checkbox));
|
||||||
expect(checkbox).toBeChecked();
|
expect(checkbox).toBeChecked();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass and render the correct button text', async () => {
|
it('should pass and render the correct button text', async () => {
|
||||||
const submitBtnText = 'submitBtnTextTest';
|
const submitBtnText = 'submitBtnTextTest';
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
setupComponent({
|
renderComponent({
|
||||||
submitBtnText,
|
submitBtnText,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,7 @@ import AddFilter, {
|
||||||
} from 'components/Topics/Topic/Details/Messages/Filters/AddFilter';
|
} from 'components/Topics/Topic/Details/Messages/Filters/AddFilter';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { MessageFilters } from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
import { MessageFilters } from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
||||||
import { screen, waitFor } from '@testing-library/react';
|
import { act, screen } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
const filters: MessageFilters[] = [
|
const filters: MessageFilters[] = [
|
||||||
|
@ -14,7 +14,7 @@ const filters: MessageFilters[] = [
|
||||||
|
|
||||||
const editFilterMock = jest.fn();
|
const editFilterMock = jest.fn();
|
||||||
|
|
||||||
const setupComponent = (props: Partial<FilterModalProps> = {}) =>
|
const renderComponent = (props: Partial<FilterModalProps> = {}) =>
|
||||||
render(
|
render(
|
||||||
<AddFilter
|
<AddFilter
|
||||||
toggleIsOpen={jest.fn()}
|
toggleIsOpen={jest.fn()}
|
||||||
|
@ -30,20 +30,21 @@ const setupComponent = (props: Partial<FilterModalProps> = {}) =>
|
||||||
|
|
||||||
describe('AddFilter component', () => {
|
describe('AddFilter component', () => {
|
||||||
it('should test click on Saved Filters redirects to Saved components', () => {
|
it('should test click on Saved Filters redirects to Saved components', () => {
|
||||||
setupComponent();
|
renderComponent();
|
||||||
userEvent.click(screen.getByRole('savedFilterText'));
|
userEvent.click(screen.getByRole('savedFilterText'));
|
||||||
expect(screen.getByText('Saved filters')).toBeInTheDocument();
|
expect(screen.getByText('Saved filters')).toBeInTheDocument();
|
||||||
expect(screen.getAllByRole('savedFilter')).toHaveLength(2);
|
expect(screen.getAllByRole('savedFilter')).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should test click on return to custom filter redirects to Add filters', async () => {
|
it('should test click on return to custom filter redirects to Add filters', async () => {
|
||||||
setupComponent();
|
renderComponent();
|
||||||
userEvent.click(screen.getByRole('savedFilterText'));
|
userEvent.click(screen.getByRole('savedFilterText'));
|
||||||
|
|
||||||
expect(screen.getByText('Saved filters')).toBeInTheDocument();
|
expect(screen.getByText('Saved filters')).toBeInTheDocument();
|
||||||
expect(screen.queryByRole('savedFilterText')).not.toBeInTheDocument();
|
expect(screen.queryByRole('savedFilterText')).not.toBeInTheDocument();
|
||||||
expect(screen.getAllByRole('savedFilter')).toHaveLength(2);
|
expect(screen.getAllByRole('savedFilter')).toHaveLength(2);
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
userEvent.click(screen.getByText(/back to custom filters/i))
|
userEvent.click(screen.getByText(/back to custom filters/i))
|
||||||
);
|
);
|
||||||
expect(screen.queryByText('Saved filters')).not.toBeInTheDocument();
|
expect(screen.queryByText('Saved filters')).not.toBeInTheDocument();
|
||||||
|
@ -52,7 +53,9 @@ describe('AddFilter component', () => {
|
||||||
|
|
||||||
describe('Add new filter', () => {
|
describe('Add new filter', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await waitFor(() => setupComponent());
|
await act(() => {
|
||||||
|
renderComponent();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adding new filter', async () => {
|
it('adding new filter', async () => {
|
||||||
|
@ -66,8 +69,12 @@ describe('AddFilter component', () => {
|
||||||
const addFilterBtn = screen.getByRole('button', { name: /Add filter/i });
|
const addFilterBtn = screen.getByRole('button', { name: /Add filter/i });
|
||||||
expect(addFilterBtn).toBeDisabled();
|
expect(addFilterBtn).toBeDisabled();
|
||||||
expect(screen.getByPlaceholderText('Enter Name')).toBeInTheDocument();
|
expect(screen.getByPlaceholderText('Enter Name')).toBeInTheDocument();
|
||||||
await waitFor(() => userEvent.paste(codeTextBox, codeValue));
|
|
||||||
await waitFor(() => userEvent.type(nameTextBox, nameValue));
|
await act(() => {
|
||||||
|
userEvent.paste(codeTextBox, codeValue);
|
||||||
|
userEvent.type(nameTextBox, nameValue);
|
||||||
|
});
|
||||||
|
|
||||||
expect(addFilterBtn).toBeEnabled();
|
expect(addFilterBtn).toBeEnabled();
|
||||||
expect(codeTextBox.value).toEqual(`${codeValue}\n\n`);
|
expect(codeTextBox.value).toEqual(`${codeValue}\n\n`);
|
||||||
expect(nameTextBox).toHaveValue(nameValue);
|
expect(nameTextBox).toHaveValue(nameValue);
|
||||||
|
@ -81,7 +88,7 @@ describe('AddFilter component', () => {
|
||||||
const addFilterBtn = screen.getByRole('button', { name: /Add filter/i });
|
const addFilterBtn = screen.getByRole('button', { name: /Add filter/i });
|
||||||
expect(addFilterBtn).toBeDisabled();
|
expect(addFilterBtn).toBeDisabled();
|
||||||
expect(screen.getByPlaceholderText('Enter Name')).toBeInTheDocument();
|
expect(screen.getByPlaceholderText('Enter Name')).toBeInTheDocument();
|
||||||
await waitFor(() => userEvent.paste(codeTextBox, code));
|
await act(() => userEvent.paste(codeTextBox, code));
|
||||||
expect(addFilterBtn).toBeEnabled();
|
expect(addFilterBtn).toBeEnabled();
|
||||||
expect(codeTextBox).toHaveValue(`${code}\n\n`);
|
expect(codeTextBox).toHaveValue(`${code}\n\n`);
|
||||||
});
|
});
|
||||||
|
@ -110,13 +117,13 @@ describe('AddFilter component', () => {
|
||||||
const nameValue = 'filter name';
|
const nameValue = 'filter name';
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await waitFor(() =>
|
await act(() => {
|
||||||
setupComponent({
|
renderComponent({
|
||||||
addFilter: addFilterMock,
|
addFilter: addFilterMock,
|
||||||
activeFilterHandler: activeFilterHandlerMock,
|
activeFilterHandler: activeFilterHandlerMock,
|
||||||
toggleIsOpen: toggleModelMock,
|
toggleIsOpen: toggleModelMock,
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -127,7 +134,7 @@ describe('AddFilter component', () => {
|
||||||
|
|
||||||
describe('OnSubmit conditions with codeValue and nameValue in fields', () => {
|
describe('OnSubmit conditions with codeValue and nameValue in fields', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.paste(
|
userEvent.paste(
|
||||||
screen.getAllByRole('textbox')[0] as HTMLTextAreaElement,
|
screen.getAllByRole('textbox')[0] as HTMLTextAreaElement,
|
||||||
codeValue
|
codeValue
|
||||||
|
@ -142,19 +149,20 @@ describe('AddFilter component', () => {
|
||||||
name: /Add filter/i,
|
name: /Add filter/i,
|
||||||
});
|
});
|
||||||
expect(addFilterBtn).toBeEnabled();
|
expect(addFilterBtn).toBeEnabled();
|
||||||
userEvent.click(addFilterBtn);
|
|
||||||
|
|
||||||
await waitFor(() => expect(activeFilterHandlerMock).toHaveBeenCalled());
|
await act(() => userEvent.click(addFilterBtn));
|
||||||
|
|
||||||
|
expect(activeFilterHandlerMock).toHaveBeenCalled();
|
||||||
expect(addFilterMock).not.toHaveBeenCalled();
|
expect(addFilterMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('OnSubmit condition with checkbox on functionality', async () => {
|
it('OnSubmit condition with checkbox on functionality', async () => {
|
||||||
|
await act(() => {
|
||||||
userEvent.click(screen.getByRole('checkbox'));
|
userEvent.click(screen.getByRole('checkbox'));
|
||||||
|
|
||||||
userEvent.click(screen.getAllByRole('button')[1]);
|
userEvent.click(screen.getAllByRole('button')[1]);
|
||||||
await waitFor(() =>
|
});
|
||||||
expect(activeFilterHandlerMock).not.toHaveBeenCalled()
|
|
||||||
);
|
expect(activeFilterHandlerMock).not.toHaveBeenCalled();
|
||||||
expect(addFilterMock).toHaveBeenCalled();
|
expect(addFilterMock).toHaveBeenCalled();
|
||||||
expect(toggleModelMock).not.toHaveBeenCalled();
|
expect(toggleModelMock).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
@ -169,13 +177,12 @@ describe('AddFilter component', () => {
|
||||||
name: /Add filter/i,
|
name: /Add filter/i,
|
||||||
});
|
});
|
||||||
|
|
||||||
userEvent.clear(nameTextBox);
|
await act(() => userEvent.clear(nameTextBox));
|
||||||
|
|
||||||
expect(nameTextBox).toHaveValue('');
|
expect(nameTextBox).toHaveValue('');
|
||||||
|
|
||||||
userEvent.click(addFilterBtn);
|
await act(() => userEvent.click(addFilterBtn));
|
||||||
await waitFor(() =>
|
expect(activeFilterHandlerMock).toHaveBeenCalledTimes(1);
|
||||||
expect(activeFilterHandlerMock).toHaveBeenCalledTimes(1)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(activeFilterHandlerMock).toHaveBeenCalledWith(
|
expect(activeFilterHandlerMock).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
|
@ -189,20 +196,18 @@ describe('AddFilter component', () => {
|
||||||
expect(codeTextBox).toHaveValue(``);
|
expect(codeTextBox).toHaveValue(``);
|
||||||
expect(toggleModelMock).toHaveBeenCalled();
|
expect(toggleModelMock).toHaveBeenCalled();
|
||||||
|
|
||||||
userEvent.paste(codeTextBox, codeValue);
|
await act(() => userEvent.paste(codeTextBox, codeValue));
|
||||||
expect(codeTextBox).toHaveValue(`${codeValue}\n\n`);
|
expect(codeTextBox).toHaveValue(`${codeValue}\n\n`);
|
||||||
|
|
||||||
userEvent.click(checkbox);
|
await act(() => userEvent.click(checkbox));
|
||||||
expect(addFilterBtn).toBeDisabled();
|
expect(addFilterBtn).toBeDisabled();
|
||||||
|
|
||||||
userEvent.type(nameTextBox, nameValue);
|
await act(() => userEvent.type(nameTextBox, nameValue));
|
||||||
expect(nameTextBox).toHaveValue(nameValue);
|
expect(nameTextBox).toHaveValue(nameValue);
|
||||||
await waitFor(() => expect(addFilterBtn).toBeEnabled());
|
expect(addFilterBtn).toBeEnabled();
|
||||||
userEvent.click(addFilterBtn);
|
await act(() => userEvent.click(addFilterBtn));
|
||||||
|
|
||||||
await waitFor(() =>
|
expect(activeFilterHandlerMock).toHaveBeenCalledTimes(1);
|
||||||
expect(activeFilterHandlerMock).toHaveBeenCalledTimes(1)
|
|
||||||
);
|
|
||||||
expect(addFilterMock).toHaveBeenCalledWith({
|
expect(addFilterMock).toHaveBeenCalledWith({
|
||||||
name: nameValue,
|
name: nameValue,
|
||||||
code: codeValue,
|
code: codeValue,
|
||||||
|
@ -217,22 +222,19 @@ describe('AddFilter component', () => {
|
||||||
)[0] as HTMLTextAreaElement;
|
)[0] as HTMLTextAreaElement;
|
||||||
const nameTextBox = screen.getAllByRole('textbox')[1];
|
const nameTextBox = screen.getAllByRole('textbox')[1];
|
||||||
const addFilterBtn = screen.getByRole('button', { name: /Add filter/i });
|
const addFilterBtn = screen.getByRole('button', { name: /Add filter/i });
|
||||||
|
await act(() => {
|
||||||
userEvent.clear(nameTextBox);
|
userEvent.clear(nameTextBox);
|
||||||
userEvent.clear(codeTextBox);
|
userEvent.clear(codeTextBox);
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.paste(codeTextBox, longCodeValue);
|
userEvent.paste(codeTextBox, longCodeValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(nameTextBox).toHaveValue('');
|
expect(nameTextBox).toHaveValue('');
|
||||||
expect(codeTextBox).toHaveValue(`${longCodeValue}\n\n`);
|
expect(codeTextBox).toHaveValue(`${longCodeValue}\n\n`);
|
||||||
|
|
||||||
userEvent.click(addFilterBtn);
|
await act(() => userEvent.click(addFilterBtn));
|
||||||
|
|
||||||
const filterName = `${longCodeValue.slice(0, 16)}...`;
|
const filterName = `${longCodeValue.slice(0, 16)}...`;
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(activeFilterHandlerMock).toHaveBeenCalledTimes(1);
|
expect(activeFilterHandlerMock).toHaveBeenCalledTimes(1);
|
||||||
expect(activeFilterHandlerMock).toHaveBeenCalledWith(
|
expect(activeFilterHandlerMock).toHaveBeenCalledWith(
|
||||||
{
|
{
|
||||||
|
@ -242,9 +244,8 @@ describe('AddFilter component', () => {
|
||||||
},
|
},
|
||||||
-1
|
-1
|
||||||
);
|
);
|
||||||
expect(codeTextBox.value).toEqual('');
|
expect(codeTextBox).toHaveValue('');
|
||||||
expect(toggleModelMock).toHaveBeenCalled();
|
expect(toggleModelMock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import EditFilter, {
|
||||||
EditFilterProps,
|
EditFilterProps,
|
||||||
} from 'components/Topics/Topic/Details/Messages/Filters/EditFilter';
|
} from 'components/Topics/Topic/Details/Messages/Filters/EditFilter';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen, waitFor, fireEvent, within } from '@testing-library/react';
|
import { screen, fireEvent, within, act } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { FilterEdit } from 'components/Topics/Topic/Details/Messages/Filters/FilterModal';
|
import { FilterEdit } from 'components/Topics/Topic/Details/Messages/Filters/FilterModal';
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const editFilter: FilterEdit = {
|
||||||
filter: { name: 'name', code: '' },
|
filter: { name: 'name', code: '' },
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupComponent = (props?: Partial<EditFilterProps>) =>
|
const renderComponent = (props?: Partial<EditFilterProps>) =>
|
||||||
render(
|
render(
|
||||||
<EditFilter
|
<EditFilter
|
||||||
toggleEditModal={jest.fn()}
|
toggleEditModal={jest.fn()}
|
||||||
|
@ -24,13 +24,17 @@ const setupComponent = (props?: Partial<EditFilterProps>) =>
|
||||||
|
|
||||||
describe('EditFilter component', () => {
|
describe('EditFilter component', () => {
|
||||||
it('renders component', async () => {
|
it('renders component', async () => {
|
||||||
await waitFor(() => setupComponent());
|
await act(() => {
|
||||||
|
renderComponent();
|
||||||
|
});
|
||||||
expect(screen.getByText(/edit saved filter/i)).toBeInTheDocument();
|
expect(screen.getByText(/edit saved filter/i)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('closes editFilter modal', async () => {
|
it('closes editFilter modal', async () => {
|
||||||
const toggleEditModal = jest.fn();
|
const toggleEditModal = jest.fn();
|
||||||
await waitFor(() => setupComponent({ toggleEditModal }));
|
await act(() => {
|
||||||
|
renderComponent({ toggleEditModal });
|
||||||
|
});
|
||||||
userEvent.click(screen.getByRole('button', { name: /Cancel/i }));
|
userEvent.click(screen.getByRole('button', { name: /Cancel/i }));
|
||||||
expect(toggleEditModal).toHaveBeenCalledTimes(1);
|
expect(toggleEditModal).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
@ -38,19 +42,27 @@ describe('EditFilter component', () => {
|
||||||
it('save edited fields and close modal', async () => {
|
it('save edited fields and close modal', async () => {
|
||||||
const toggleEditModal = jest.fn();
|
const toggleEditModal = jest.fn();
|
||||||
const editSavedFilter = jest.fn();
|
const editSavedFilter = jest.fn();
|
||||||
await waitFor(() => setupComponent({ toggleEditModal, editSavedFilter }));
|
|
||||||
|
await act(() => {
|
||||||
|
renderComponent({ toggleEditModal, editSavedFilter });
|
||||||
|
});
|
||||||
|
|
||||||
const inputs = screen.getAllByRole('textbox');
|
const inputs = screen.getAllByRole('textbox');
|
||||||
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
||||||
const inputNameElement = inputs[1];
|
const inputNameElement = inputs[1];
|
||||||
|
await act(() => {
|
||||||
userEvent.paste(textAreaElement, 'edited code');
|
userEvent.paste(textAreaElement, 'edited code');
|
||||||
userEvent.type(inputNameElement, 'edited name');
|
userEvent.type(inputNameElement, 'edited name');
|
||||||
await waitFor(() => fireEvent.submit(screen.getByRole('form')));
|
fireEvent.submit(screen.getByRole('form'));
|
||||||
|
});
|
||||||
expect(toggleEditModal).toHaveBeenCalledTimes(1);
|
expect(toggleEditModal).toHaveBeenCalledTimes(1);
|
||||||
expect(editSavedFilter).toHaveBeenCalledTimes(1);
|
expect(editSavedFilter).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('checks input values to match', async () => {
|
it('checks input values to match', async () => {
|
||||||
await waitFor(() => setupComponent());
|
await act(() => {
|
||||||
|
renderComponent();
|
||||||
|
});
|
||||||
const inputs = screen.getAllByRole('textbox');
|
const inputs = screen.getAllByRole('textbox');
|
||||||
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
const textAreaElement = inputs[0] as HTMLTextAreaElement;
|
||||||
const inputNameElement = inputs[1];
|
const inputNameElement = inputs[1];
|
||||||
|
|
|
@ -4,12 +4,12 @@ import FilterModal, {
|
||||||
} from 'components/Topics/Topic/Details/Messages/Filters/FilterModal';
|
} from 'components/Topics/Topic/Details/Messages/Filters/FilterModal';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { MessageFilters } from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
import { MessageFilters } from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
||||||
import { screen, waitFor } from '@testing-library/react';
|
import { screen, act } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
const filters: MessageFilters[] = [{ name: 'name', code: 'code' }];
|
const filters: MessageFilters[] = [{ name: 'name', code: 'code' }];
|
||||||
|
|
||||||
const setupWrapper = (props?: Partial<FilterModalProps>) =>
|
const renderComponent = (props?: Partial<FilterModalProps>) =>
|
||||||
render(
|
render(
|
||||||
<FilterModal
|
<FilterModal
|
||||||
toggleIsOpen={jest.fn()}
|
toggleIsOpen={jest.fn()}
|
||||||
|
@ -23,7 +23,9 @@ const setupWrapper = (props?: Partial<FilterModalProps>) =>
|
||||||
);
|
);
|
||||||
describe('FilterModal component', () => {
|
describe('FilterModal component', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await waitFor(() => setupWrapper());
|
await act(() => {
|
||||||
|
renderComponent();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('renders component with add filter modal', () => {
|
it('renders component with add filter modal', () => {
|
||||||
expect(
|
expect(
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Filters, {
|
||||||
SeekTypeOptions,
|
SeekTypeOptions,
|
||||||
} from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
} from 'components/Topics/Topic/Details/Messages/Filters/Filters';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen, waitFor, within } from '@testing-library/react';
|
import { act, screen, within, waitFor } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import TopicMessagesContext, {
|
import TopicMessagesContext, {
|
||||||
ContextProps,
|
ContextProps,
|
||||||
|
@ -19,7 +19,7 @@ const defaultContextValue: ContextProps = {
|
||||||
changeSeekDirection: jest.fn(),
|
changeSeekDirection: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupWrapper = (
|
const renderComponent = (
|
||||||
props: Partial<FiltersProps> = {},
|
props: Partial<FiltersProps> = {},
|
||||||
ctx: ContextProps = defaultContextValue
|
ctx: ContextProps = defaultContextValue
|
||||||
) => {
|
) => {
|
||||||
|
@ -41,52 +41,58 @@ const setupWrapper = (
|
||||||
</TopicMessagesContext.Provider>
|
</TopicMessagesContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const getSubmit = () => screen.getByText('Submit');
|
|
||||||
|
|
||||||
describe('Filters component', () => {
|
describe('Filters component', () => {
|
||||||
it('shows cancel button while fetching', () => {
|
it('shows cancel button while fetching', () => {
|
||||||
setupWrapper({ isFetching: true });
|
renderComponent({ isFetching: true });
|
||||||
expect(screen.getByText('Cancel')).toBeInTheDocument();
|
expect(screen.getByText('Cancel')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows submit button while fetching is over', () => {
|
it('shows submit button while fetching is over', () => {
|
||||||
setupWrapper();
|
renderComponent();
|
||||||
expect(getSubmit()).toBeInTheDocument();
|
expect(screen.getByText('Submit')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Input elements', () => {
|
describe('Input elements', () => {
|
||||||
const inputValue = 'Hello World!';
|
const inputValue = 'Hello World!';
|
||||||
|
|
||||||
beforeEach(() => setupWrapper());
|
beforeEach(async () => {
|
||||||
|
await act(() => {
|
||||||
|
renderComponent();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('search input', () => {
|
it('search input', () => {
|
||||||
const SearchInput = screen.getByPlaceholderText('Search');
|
const searchInput = screen.getByPlaceholderText('Search');
|
||||||
expect(SearchInput).toBeInTheDocument();
|
expect(searchInput).toHaveValue('');
|
||||||
expect(SearchInput).toHaveValue('');
|
userEvent.type(searchInput, inputValue);
|
||||||
userEvent.type(SearchInput, inputValue);
|
expect(searchInput).toHaveValue(inputValue);
|
||||||
expect(SearchInput).toHaveValue(inputValue);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('offset input', () => {
|
it('offset input', () => {
|
||||||
const OffsetInput = screen.getByPlaceholderText('Offset');
|
const offsetInput = screen.getByPlaceholderText('Offset');
|
||||||
expect(OffsetInput).toBeInTheDocument();
|
expect(offsetInput).toHaveValue('');
|
||||||
expect(OffsetInput).toHaveValue('');
|
userEvent.type(offsetInput, inputValue);
|
||||||
userEvent.type(OffsetInput, inputValue);
|
expect(offsetInput).toHaveValue(inputValue);
|
||||||
expect(OffsetInput).toHaveValue(inputValue);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('timestamp input', async () => {
|
it('timestamp input', async () => {
|
||||||
const seekTypeSelect = screen.getAllByRole('listbox');
|
const seekTypeSelect = screen.getAllByRole('listbox');
|
||||||
const option = screen.getAllByRole('option');
|
const option = screen.getAllByRole('option');
|
||||||
|
|
||||||
userEvent.click(seekTypeSelect[0]);
|
await act(() => userEvent.click(seekTypeSelect[0]));
|
||||||
|
|
||||||
|
await act(() => {
|
||||||
userEvent.selectOptions(seekTypeSelect[0], ['Timestamp']);
|
userEvent.selectOptions(seekTypeSelect[0], ['Timestamp']);
|
||||||
|
});
|
||||||
|
|
||||||
expect(option[0]).toHaveTextContent('Timestamp');
|
expect(option[0]).toHaveTextContent('Timestamp');
|
||||||
const timestampInput = screen.getByPlaceholderText('Select timestamp');
|
const timestampInput = screen.getByPlaceholderText('Select timestamp');
|
||||||
expect(timestampInput).toBeInTheDocument();
|
|
||||||
expect(timestampInput).toHaveValue('');
|
expect(timestampInput).toHaveValue('');
|
||||||
userEvent.type(timestampInput, inputValue);
|
|
||||||
await waitFor(() => expect(timestampInput).toHaveValue(inputValue));
|
await waitFor(() => userEvent.type(timestampInput, inputValue));
|
||||||
|
|
||||||
|
expect(timestampInput).toHaveValue(inputValue);
|
||||||
expect(screen.getByText('Submit')).toBeInTheDocument();
|
expect(screen.getByText('Submit')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -101,7 +107,7 @@ describe('Filters component', () => {
|
||||||
const mockTypeOptionSelectLabel = selectTypeOptionValue.label;
|
const mockTypeOptionSelectLabel = selectTypeOptionValue.label;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
setupWrapper();
|
renderComponent();
|
||||||
seekTypeSelects = screen.getAllByRole('listbox');
|
seekTypeSelects = screen.getAllByRole('listbox');
|
||||||
options = screen.getAllByRole('option');
|
options = screen.getAllByRole('option');
|
||||||
});
|
});
|
||||||
|
@ -124,16 +130,16 @@ describe('Filters component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('stop loading when live mode is active', () => {
|
it('stop loading when live mode is active', () => {
|
||||||
setupWrapper();
|
renderComponent();
|
||||||
userEvent.click(screen.getByText('Stop loading'));
|
userEvent.click(screen.getByText('Stop loading'));
|
||||||
const option = screen.getAllByRole('option');
|
const option = screen.getAllByRole('option');
|
||||||
expect(option[1]).toHaveTextContent('Oldest First');
|
expect(option[1]).toHaveTextContent('Oldest First');
|
||||||
expect(getSubmit()).toBeInTheDocument();
|
expect(screen.getByText('Submit')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders addFilter modal', async () => {
|
it('renders addFilter modal', async () => {
|
||||||
setupWrapper();
|
renderComponent();
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
screen.getByRole('button', {
|
screen.getByRole('button', {
|
||||||
name: /add filters/i,
|
name: /add filters/i,
|
||||||
|
@ -145,9 +151,9 @@ describe('Filters component', () => {
|
||||||
|
|
||||||
describe('when there is active smart filter', () => {
|
describe('when there is active smart filter', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
setupWrapper();
|
renderComponent();
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
screen.getByRole('button', {
|
screen.getByRole('button', {
|
||||||
name: /add filters/i,
|
name: /add filters/i,
|
||||||
|
@ -165,7 +171,7 @@ describe('Filters component', () => {
|
||||||
|
|
||||||
const textAreaElement = textBoxElements[0] as HTMLTextAreaElement;
|
const textAreaElement = textBoxElements[0] as HTMLTextAreaElement;
|
||||||
const inputNameElement = textBoxElements[1];
|
const inputNameElement = textBoxElements[1];
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.paste(textAreaElement, filterName);
|
userEvent.paste(textAreaElement, filterName);
|
||||||
userEvent.type(inputNameElement, filterCode);
|
userEvent.type(inputNameElement, filterCode);
|
||||||
});
|
});
|
||||||
|
@ -173,7 +179,7 @@ describe('Filters component', () => {
|
||||||
expect(textAreaElement.value).toEqual(`${filterName}\n\n`);
|
expect(textAreaElement.value).toEqual(`${filterName}\n\n`);
|
||||||
expect(inputNameElement).toHaveValue(filterCode);
|
expect(inputNameElement).toHaveValue(filterCode);
|
||||||
|
|
||||||
await waitFor(() =>
|
await act(() =>
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
within(messageFilterModal).getByRole('button', {
|
within(messageFilterModal).getByRole('button', {
|
||||||
name: /add filter/i,
|
name: /add filter/i,
|
||||||
|
@ -191,7 +197,7 @@ describe('Filters component', () => {
|
||||||
const deleteIcon = within(smartFilterElement).getByTestId(
|
const deleteIcon = within(smartFilterElement).getByTestId(
|
||||||
'activeSmartFilterCloseIcon'
|
'activeSmartFilterCloseIcon'
|
||||||
);
|
);
|
||||||
await waitFor(() => userEvent.click(deleteIcon));
|
await act(() => userEvent.click(deleteIcon));
|
||||||
|
|
||||||
const anotherSmartFilterElement =
|
const anotherSmartFilterElement =
|
||||||
screen.queryByTestId('activeSmartFilter');
|
screen.queryByTestId('activeSmartFilter');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useMemo, useState } from 'react';
|
||||||
import TopicMessagesContext from 'components/contexts/TopicMessagesContext';
|
import TopicMessagesContext from 'components/contexts/TopicMessagesContext';
|
||||||
import { SeekDirection } from 'generated-sources';
|
import { SeekDirection } from 'generated-sources';
|
||||||
import { useLocation } from 'react-router';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import FiltersContainer from './Filters/FiltersContainer';
|
import FiltersContainer from './Filters/FiltersContainer';
|
||||||
import MessagesTable from './MessagesTable';
|
import MessagesTable from './MessagesTable';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import styled from 'styled-components';
|
||||||
import { compact, concat, groupBy, map, maxBy, minBy } from 'lodash';
|
import { compact, concat, groupBy, map, maxBy, minBy } from 'lodash';
|
||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
getTopicMessges,
|
getTopicMessges,
|
||||||
getIsTopicMessagesFetching,
|
getIsTopicMessagesFetching,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import MessagesTable from 'components/Topics/Topic/Details/Messages/MessagesTable';
|
import MessagesTable from 'components/Topics/Topic/Details/Messages/MessagesTable';
|
||||||
import { Router } from 'react-router';
|
import { Router } from 'react-router-dom';
|
||||||
import { createMemoryHistory, MemoryHistory } from 'history';
|
import { createMemoryHistory, MemoryHistory } from 'history';
|
||||||
import { SeekDirection, SeekType, TopicMessage } from 'generated-sources';
|
import { SeekDirection, SeekType, TopicMessage } from 'generated-sources';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import DangerZone, {
|
import DangerZone, {
|
||||||
Props,
|
Props,
|
||||||
} from 'components/Topics/Topic/Edit/DangerZone/DangerZone';
|
} from 'components/Topics/Topic/Edit/DangerZone/DangerZone';
|
||||||
import { screen, waitFor, within } from '@testing-library/react';
|
import { act, screen, waitFor, within } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import {
|
import {
|
||||||
|
@ -13,8 +13,8 @@ import {
|
||||||
const defaultPartitions = 3;
|
const defaultPartitions = 3;
|
||||||
const defaultReplicationFactor = 3;
|
const defaultReplicationFactor = 3;
|
||||||
|
|
||||||
const renderComponent = (props?: Partial<Props>) => {
|
const renderComponent = (props?: Partial<Props>) =>
|
||||||
return render(
|
render(
|
||||||
<DangerZone
|
<DangerZone
|
||||||
clusterName={clusterName}
|
clusterName={clusterName}
|
||||||
topicName={topicName}
|
topicName={topicName}
|
||||||
|
@ -27,7 +27,6 @@ const renderComponent = (props?: Partial<Props>) => {
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
const clickOnDialogSubmitButton = () => {
|
const clickOnDialogSubmitButton = () => {
|
||||||
userEvent.click(
|
userEvent.click(
|
||||||
|
@ -40,18 +39,14 @@ const clickOnDialogSubmitButton = () => {
|
||||||
const checkDialogThenPressCancel = async () => {
|
const checkDialogThenPressCancel = async () => {
|
||||||
const dialog = screen.getByRole('dialog');
|
const dialog = screen.getByRole('dialog');
|
||||||
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.click(within(dialog).getByText(/cancel/i));
|
userEvent.click(within(dialog).getByText(/cancel/i));
|
||||||
});
|
|
||||||
|
|
||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('DangerZone', () => {
|
describe('DangerZone', () => {
|
||||||
it('renders the component', () => {
|
it('renders the component', async () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const numberOfPartitionsEditForm = screen.getByRole('form', {
|
const numberOfPartitionsEditForm = screen.getByRole('form', {
|
||||||
|
@ -139,27 +134,23 @@ describe('DangerZone', () => {
|
||||||
const partitionInput = screen.getByPlaceholderText('Number of partitions');
|
const partitionInput = screen.getByPlaceholderText('Number of partitions');
|
||||||
const partitionInputSubmitBtn = screen.getAllByText(/submit/i)[0];
|
const partitionInputSubmitBtn = screen.getAllByText(/submit/i)[0];
|
||||||
const value = (defaultPartitions - 4).toString();
|
const value = (defaultPartitions - 4).toString();
|
||||||
|
|
||||||
expect(partitionInputSubmitBtn).toBeDisabled();
|
expect(partitionInputSubmitBtn).toBeDisabled();
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.clear(partitionInput);
|
userEvent.clear(partitionInput);
|
||||||
userEvent.type(partitionInput, value);
|
userEvent.type(partitionInput, value);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(partitionInput).toHaveValue(+value);
|
expect(partitionInput).toHaveValue(+value);
|
||||||
expect(partitionInputSubmitBtn).toBeEnabled();
|
expect(partitionInputSubmitBtn).toBeEnabled();
|
||||||
|
await act(() => {
|
||||||
userEvent.click(partitionInputSubmitBtn);
|
userEvent.click(partitionInputSubmitBtn);
|
||||||
|
});
|
||||||
await waitFor(() => {
|
|
||||||
expect(
|
expect(
|
||||||
screen.getByText(/You can only increase the number of partitions!/i)
|
screen.getByText(/You can only increase the number of partitions!/i)
|
||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
});
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.clear(partitionInput);
|
userEvent.clear(partitionInput);
|
||||||
});
|
await waitFor(() =>
|
||||||
expect(screen.getByText(/are required/i)).toBeInTheDocument();
|
expect(screen.getByText(/are required/i)).toBeInTheDocument()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should view the validation error when Replication Facto value is lower than the default passed or empty', async () => {
|
it('should view the validation error when Replication Facto value is lower than the default passed or empty', async () => {
|
||||||
|
@ -168,31 +159,31 @@ describe('DangerZone', () => {
|
||||||
screen.getByPlaceholderText('Replication Factor');
|
screen.getByPlaceholderText('Replication Factor');
|
||||||
const replicatorFactorInputSubmitBtn = screen.getAllByText(/submit/i)[1];
|
const replicatorFactorInputSubmitBtn = screen.getAllByText(/submit/i)[1];
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => userEvent.clear(replicatorFactorInput));
|
||||||
userEvent.clear(replicatorFactorInput);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(replicatorFactorInputSubmitBtn).toBeEnabled();
|
expect(replicatorFactorInputSubmitBtn).toBeEnabled();
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.click(replicatorFactorInputSubmitBtn);
|
userEvent.click(replicatorFactorInputSubmitBtn);
|
||||||
});
|
await waitFor(() =>
|
||||||
|
expect(screen.getByText(/are required/i)).toBeInTheDocument()
|
||||||
expect(screen.getByText(/are required/i)).toBeInTheDocument();
|
);
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.type(replicatorFactorInput, '1');
|
userEvent.type(replicatorFactorInput, '1');
|
||||||
});
|
await waitFor(() =>
|
||||||
expect(screen.queryByText(/are required/i)).not.toBeInTheDocument();
|
expect(screen.queryByText(/are required/i)).not.toBeInTheDocument()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should close any popup if the partitionsCount is Increased ', () => {
|
it('should close any popup if the partitionsCount is Increased ', async () => {
|
||||||
renderComponent({ partitionsCountIncreased: true });
|
renderComponent({ partitionsCountIncreased: true });
|
||||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
await waitFor(() =>
|
||||||
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should close any popup if the replicationFactor is Updated', () => {
|
it('should close any popup if the replicationFactor is Updated', async () => {
|
||||||
renderComponent({ replicationFactorUpdated: true });
|
renderComponent({ replicationFactorUpdated: true });
|
||||||
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
await waitFor(() =>
|
||||||
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should already opened Confirmation popup if partitionsCount is Increased', async () => {
|
it('should already opened Confirmation popup if partitionsCount is Increased', async () => {
|
||||||
|
@ -254,14 +245,12 @@ describe('DangerZone', () => {
|
||||||
|
|
||||||
it('should close the partitions dialog if he cancel button is pressed', async () => {
|
it('should close the partitions dialog if he cancel button is pressed', async () => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
|
||||||
const partitionInput = screen.getByPlaceholderText('Number of partitions');
|
const partitionInput = screen.getByPlaceholderText('Number of partitions');
|
||||||
const partitionInputSubmitBtn = screen.getAllByText(/submit/i)[0];
|
const partitionInputSubmitBtn = screen.getAllByText(/submit/i)[0];
|
||||||
|
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.type(partitionInput, '5');
|
userEvent.type(partitionInput, '5');
|
||||||
});
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.click(partitionInputSubmitBtn);
|
userEvent.click(partitionInputSubmitBtn);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -274,11 +263,8 @@ describe('DangerZone', () => {
|
||||||
screen.getByPlaceholderText('Replication Factor');
|
screen.getByPlaceholderText('Replication Factor');
|
||||||
const replicatorFactorInputSubmitBtn = screen.getAllByText(/submit/i)[1];
|
const replicatorFactorInputSubmitBtn = screen.getAllByText(/submit/i)[1];
|
||||||
|
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.type(replicatorFactorInput, '5');
|
userEvent.type(replicatorFactorInput, '5');
|
||||||
});
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
userEvent.click(replicatorFactorInputSubmitBtn);
|
userEvent.click(replicatorFactorInputSubmitBtn);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
import { useForm, FormProvider } from 'react-hook-form';
|
import { useForm, FormProvider } from 'react-hook-form';
|
||||||
import TopicForm from 'components/Topics/shared/Form/TopicForm';
|
import TopicForm from 'components/Topics/shared/Form/TopicForm';
|
||||||
import { clusterTopicPath } from 'lib/paths';
|
import { clusterTopicPath } from 'lib/paths';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { yupResolver } from '@hookform/resolvers/yup';
|
import { yupResolver } from '@hookform/resolvers/yup';
|
||||||
import { topicFormValidationSchema } from 'lib/yupExtended';
|
import { topicFormValidationSchema } from 'lib/yupExtended';
|
||||||
import { TOPIC_CUSTOM_PARAMS_PREFIX, TOPIC_CUSTOM_PARAMS } from 'lib/constants';
|
import { TOPIC_CUSTOM_PARAMS_PREFIX, TOPIC_CUSTOM_PARAMS } from 'lib/constants';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Edit, { DEFAULTS, Props } from 'components/Topics/Topic/Edit/Edit';
|
import Edit, { DEFAULTS, Props } from 'components/Topics/Topic/Edit/Edit';
|
||||||
import { screen, waitFor } from '@testing-library/react';
|
import { act, screen } from '@testing-library/react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { Router } from 'react-router-dom';
|
import { Router } from 'react-router-dom';
|
||||||
|
@ -109,7 +109,7 @@ describe('Edit Component', () => {
|
||||||
const btn = screen.getAllByText(/submit/i)[0];
|
const btn = screen.getAllByText(/submit/i)[0];
|
||||||
expect(btn).toBeEnabled();
|
expect(btn).toBeEnabled();
|
||||||
|
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.type(
|
userEvent.type(
|
||||||
screen.getByPlaceholderText('Min In Sync Replicas'),
|
screen.getByPlaceholderText('Min In Sync Replicas'),
|
||||||
'1'
|
'1'
|
||||||
|
@ -117,10 +117,8 @@ describe('Edit Component', () => {
|
||||||
userEvent.click(btn);
|
userEvent.click(btn);
|
||||||
});
|
});
|
||||||
expect(updateTopicMock).toHaveBeenCalledTimes(1);
|
expect(updateTopicMock).toHaveBeenCalledTimes(1);
|
||||||
await waitFor(() => {
|
|
||||||
expect(mocked.push).not.toHaveBeenCalled();
|
expect(mocked.push).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the submit functionality when topic updated is true', async () => {
|
it('should check the submit functionality when topic updated is true', async () => {
|
||||||
const updateTopicMock = jest.fn();
|
const updateTopicMock = jest.fn();
|
||||||
|
@ -135,7 +133,7 @@ describe('Edit Component', () => {
|
||||||
|
|
||||||
const btn = screen.getAllByText(/submit/i)[0];
|
const btn = screen.getAllByText(/submit/i)[0];
|
||||||
|
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.type(
|
userEvent.type(
|
||||||
screen.getByPlaceholderText('Min In Sync Replicas'),
|
screen.getByPlaceholderText('Min In Sync Replicas'),
|
||||||
'1'
|
'1'
|
||||||
|
@ -143,7 +141,6 @@ describe('Edit Component', () => {
|
||||||
userEvent.click(btn);
|
userEvent.click(btn);
|
||||||
});
|
});
|
||||||
expect(updateTopicMock).toHaveBeenCalledTimes(1);
|
expect(updateTopicMock).toHaveBeenCalledTimes(1);
|
||||||
await waitFor(() => {
|
|
||||||
expect(mocked.push).toHaveBeenCalled();
|
expect(mocked.push).toHaveBeenCalled();
|
||||||
expect(mocked.location.pathname).toBe(
|
expect(mocked.location.pathname).toBe(
|
||||||
clusterTopicPath(clusterName, topicName)
|
clusterTopicPath(clusterName, topicName)
|
||||||
|
@ -151,4 +148,3 @@ describe('Edit Component', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Editor from 'components/common/Editor/Editor';
|
||||||
import PageLoader from 'components/common/PageLoader/PageLoader';
|
import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useForm, Controller } from 'react-hook-form';
|
import { useForm, Controller } from 'react-hook-form';
|
||||||
import { useHistory, useParams } from 'react-router';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { clusterTopicMessagesPath } from 'lib/paths';
|
import { clusterTopicMessagesPath } from 'lib/paths';
|
||||||
import jsf from 'json-schema-faker';
|
import jsf from 'json-schema-faker';
|
||||||
import { fetchTopicMessageSchema, messagesApiClient } from 'redux/actions';
|
import { fetchTopicMessageSchema, messagesApiClient } from 'redux/actions';
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SendMessage from 'components/Topics/Topic/SendMessage/SendMessage';
|
import SendMessage from 'components/Topics/Topic/SendMessage/SendMessage';
|
||||||
import {
|
import { act, screen } from '@testing-library/react';
|
||||||
screen,
|
|
||||||
waitFor,
|
|
||||||
waitForElementToBeRemoved,
|
|
||||||
} from '@testing-library/react';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { Route, Router } from 'react-router';
|
import { Route, Router } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
clusterTopicMessagesPath,
|
clusterTopicMessagesPath,
|
||||||
clusterTopicSendMessagePath,
|
clusterTopicSendMessagePath,
|
||||||
|
@ -43,12 +39,15 @@ const clusterName = 'testCluster';
|
||||||
const topicName = externalTopicPayload.name;
|
const topicName = externalTopicPayload.name;
|
||||||
const history = createMemoryHistory();
|
const history = createMemoryHistory();
|
||||||
|
|
||||||
const renderComponent = () => {
|
const renderComponent = async () => {
|
||||||
history.push(clusterTopicSendMessagePath(clusterName, topicName));
|
history.push(clusterTopicSendMessagePath(clusterName, topicName));
|
||||||
|
await act(() => {
|
||||||
render(
|
render(
|
||||||
<>
|
<>
|
||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
<Route path={clusterTopicSendMessagePath(':clusterName', ':topicName')}>
|
<Route
|
||||||
|
path={clusterTopicSendMessagePath(':clusterName', ':topicName')}
|
||||||
|
>
|
||||||
<SendMessage />
|
<SendMessage />
|
||||||
</Route>
|
</Route>
|
||||||
</Router>
|
</Router>
|
||||||
|
@ -58,16 +57,17 @@ const renderComponent = () => {
|
||||||
</>,
|
</>,
|
||||||
{ store }
|
{ store }
|
||||||
);
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderAndSubmitData = async (error: string[] = []) => {
|
const renderAndSubmitData = async (error: string[] = []) => {
|
||||||
renderComponent();
|
await renderComponent();
|
||||||
await waitForElementToBeRemoved(() => screen.getByRole('progressbar'));
|
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument();
|
||||||
|
await act(() => {
|
||||||
userEvent.selectOptions(screen.getByLabelText('Partition'), '0');
|
userEvent.selectOptions(screen.getByLabelText('Partition'), '0');
|
||||||
const sendBtn = await screen.findByText('Send');
|
|
||||||
(validateMessage as Mock).mockImplementation(() => error);
|
(validateMessage as Mock).mockImplementation(() => error);
|
||||||
userEvent.click(sendBtn);
|
userEvent.click(screen.getByText('Send'));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('SendMessage', () => {
|
describe('SendMessage', () => {
|
||||||
|
@ -85,12 +85,14 @@ describe('SendMessage', () => {
|
||||||
fetchMock.reset();
|
fetchMock.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('fetches schema on first render', () => {
|
it('fetches schema on first render', async () => {
|
||||||
const fetchTopicMessageSchemaMock = fetchMock.getOnce(
|
const fetchTopicMessageSchemaMock = fetchMock.getOnce(
|
||||||
`/api/clusters/${clusterName}/topics/${topicName}/messages/schema`,
|
`/api/clusters/${clusterName}/topics/${topicName}/messages/schema`,
|
||||||
testSchema
|
testSchema
|
||||||
);
|
);
|
||||||
|
await act(() => {
|
||||||
renderComponent();
|
renderComponent();
|
||||||
|
});
|
||||||
expect(fetchTopicMessageSchemaMock.called()).toBeTruthy();
|
expect(fetchTopicMessageSchemaMock.called()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -107,9 +109,7 @@ describe('SendMessage', () => {
|
||||||
it('calls sendTopicMessage on submit', async () => {
|
it('calls sendTopicMessage on submit', async () => {
|
||||||
const sendTopicMessageMock = fetchMock.postOnce(url, 200);
|
const sendTopicMessageMock = fetchMock.postOnce(url, 200);
|
||||||
await renderAndSubmitData();
|
await renderAndSubmitData();
|
||||||
await waitFor(() =>
|
expect(sendTopicMessageMock.called(url)).toBeTruthy();
|
||||||
expect(sendTopicMessageMock.called(url)).toBeTruthy()
|
|
||||||
);
|
|
||||||
expect(history.location.pathname).toEqual(
|
expect(history.location.pathname).toEqual(
|
||||||
clusterTopicMessagesPath(clusterName, topicName)
|
clusterTopicMessagesPath(clusterName, topicName)
|
||||||
);
|
);
|
||||||
|
@ -120,12 +120,8 @@ describe('SendMessage', () => {
|
||||||
throws: 'Error',
|
throws: 'Error',
|
||||||
});
|
});
|
||||||
await renderAndSubmitData();
|
await renderAndSubmitData();
|
||||||
await waitFor(() => {
|
|
||||||
expect(sendTopicMessageMock.called(url)).toBeTruthy();
|
expect(sendTopicMessageMock.called(url)).toBeTruthy();
|
||||||
});
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(screen.getByRole('alert')).toBeInTheDocument();
|
expect(screen.getByRole('alert')).toBeInTheDocument();
|
||||||
});
|
|
||||||
expect(history.location.pathname).toEqual(
|
expect(history.location.pathname).toEqual(
|
||||||
clusterTopicMessagesPath(clusterName, topicName)
|
clusterTopicMessagesPath(clusterName, topicName)
|
||||||
);
|
);
|
||||||
|
@ -134,7 +130,7 @@ describe('SendMessage', () => {
|
||||||
it('should check and view validation error message when is not valid', async () => {
|
it('should check and view validation error message when is not valid', async () => {
|
||||||
const sendTopicMessageMock = fetchMock.postOnce(url, 200);
|
const sendTopicMessageMock = fetchMock.postOnce(url, 200);
|
||||||
await renderAndSubmitData(['error']);
|
await renderAndSubmitData(['error']);
|
||||||
await waitFor(() => expect(sendTopicMessageMock.called(url)).toBeFalsy());
|
expect(sendTopicMessageMock.called(url)).toBeFalsy();
|
||||||
expect(history.location.pathname).not.toEqual(
|
expect(history.location.pathname).not.toEqual(
|
||||||
clusterTopicMessagesPath(clusterName, topicName)
|
clusterTopicMessagesPath(clusterName, topicName)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { screen, waitFor, within } from '@testing-library/react';
|
import { act, screen, within } from '@testing-library/react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import CustomParamsField, {
|
import CustomParamsField, {
|
||||||
Props,
|
Props,
|
||||||
|
@ -16,8 +16,8 @@ const field = { name: 'name', value: 'value', id: 'id' };
|
||||||
const SPACE_KEY = ' ';
|
const SPACE_KEY = ' ';
|
||||||
|
|
||||||
const selectOption = async (listbox: HTMLElement, option: string) => {
|
const selectOption = async (listbox: HTMLElement, option: string) => {
|
||||||
await waitFor(() => userEvent.click(listbox));
|
await act(() => userEvent.click(listbox));
|
||||||
await waitFor(() => userEvent.click(screen.getByText(option)));
|
await act(() => userEvent.click(screen.getByText(option)));
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('CustomParamsField', () => {
|
describe('CustomParamsField', () => {
|
||||||
|
@ -25,7 +25,7 @@ describe('CustomParamsField', () => {
|
||||||
const setExistingFields = jest.fn();
|
const setExistingFields = jest.fn();
|
||||||
|
|
||||||
const setupComponent = (props: Props) => {
|
const setupComponent = (props: Props) => {
|
||||||
const Wrapper: React.FC = ({ children }) => {
|
const Wrapper: React.FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const methods = useForm();
|
const methods = useForm();
|
||||||
return <FormProvider {...methods}>{children}</FormProvider>;
|
return <FormProvider {...methods}>{children}</FormProvider>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { screen, waitFor, within } from '@testing-library/react';
|
import { act, screen, within } from '@testing-library/react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import CustomParams, {
|
import CustomParams, {
|
||||||
CustomParamsProps,
|
CustomParamsProps,
|
||||||
|
@ -11,10 +11,10 @@ import { TOPIC_CUSTOM_PARAMS } from 'lib/constants';
|
||||||
import { defaultValues } from './fixtures';
|
import { defaultValues } from './fixtures';
|
||||||
|
|
||||||
const selectOption = async (listbox: HTMLElement, option: string) => {
|
const selectOption = async (listbox: HTMLElement, option: string) => {
|
||||||
await waitFor(() => {
|
await act(() => {
|
||||||
userEvent.click(listbox);
|
userEvent.click(listbox);
|
||||||
userEvent.click(screen.getByText(option));
|
|
||||||
});
|
});
|
||||||
|
userEvent.click(screen.getByText(option));
|
||||||
};
|
};
|
||||||
|
|
||||||
const expectOptionIsSelected = (listbox: HTMLElement, option: string) => {
|
const expectOptionIsSelected = (listbox: HTMLElement, option: string) => {
|
||||||
|
@ -28,7 +28,7 @@ const expectOptionAvailability = async (
|
||||||
option: string,
|
option: string,
|
||||||
disabled: boolean
|
disabled: boolean
|
||||||
) => {
|
) => {
|
||||||
await waitFor(() => userEvent.click(listbox));
|
await act(() => userEvent.click(listbox));
|
||||||
const selectedOptions = within(listbox).getAllByText(option).reverse();
|
const selectedOptions = within(listbox).getAllByText(option).reverse();
|
||||||
// its either two or one nodes, we only need last one
|
// its either two or one nodes, we only need last one
|
||||||
const selectedOption = selectedOptions[0];
|
const selectedOption = selectedOptions[0];
|
||||||
|
@ -43,11 +43,11 @@ const expectOptionAvailability = async (
|
||||||
'cursor',
|
'cursor',
|
||||||
disabled ? 'not-allowed' : 'pointer'
|
disabled ? 'not-allowed' : 'pointer'
|
||||||
);
|
);
|
||||||
await waitFor(() => userEvent.click(listbox));
|
await act(() => userEvent.click(listbox));
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderComponent = (props: CustomParamsProps, defaults = {}) => {
|
const renderComponent = (props: CustomParamsProps, defaults = {}) => {
|
||||||
const Wrapper: React.FC = ({ children }) => {
|
const Wrapper: React.FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const methods = useForm({ defaultValues: defaults });
|
const methods = useForm({ defaultValues: defaults });
|
||||||
return <FormProvider {...methods}>{children}</FormProvider>;
|
return <FormProvider {...methods}>{children}</FormProvider>;
|
||||||
};
|
};
|
||||||
|
@ -81,10 +81,11 @@ describe('CustomParams', () => {
|
||||||
|
|
||||||
describe('works with user inputs correctly', () => {
|
describe('works with user inputs correctly', () => {
|
||||||
let button: HTMLButtonElement;
|
let button: HTMLButtonElement;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
renderComponent({ isSubmitting: false });
|
renderComponent({ isSubmitting: false });
|
||||||
button = screen.getByRole('button');
|
button = screen.getByRole('button');
|
||||||
await waitFor(() => userEvent.click(button));
|
await act(() => userEvent.click(button));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('button click creates custom param fieldset', async () => {
|
it('button click creates custom param fieldset', async () => {
|
||||||
|
@ -119,8 +120,8 @@ describe('CustomParams', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('multiple button clicks create multiple fieldsets', async () => {
|
it('multiple button clicks create multiple fieldsets', async () => {
|
||||||
await waitFor(() => userEvent.click(button));
|
await act(() => userEvent.click(button));
|
||||||
await waitFor(() => userEvent.click(button));
|
await act(() => userEvent.click(button));
|
||||||
|
|
||||||
const listboxes = screen.getAllByRole('listbox');
|
const listboxes = screen.getAllByRole('listbox');
|
||||||
expect(listboxes.length).toBe(3);
|
expect(listboxes.length).toBe(3);
|
||||||
|
@ -130,7 +131,7 @@ describe('CustomParams', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can't select already selected option", async () => {
|
it("can't select already selected option", async () => {
|
||||||
await waitFor(() => userEvent.click(button));
|
await act(() => userEvent.click(button));
|
||||||
|
|
||||||
const listboxes = screen.getAllByRole('listbox');
|
const listboxes = screen.getAllByRole('listbox');
|
||||||
|
|
||||||
|
@ -143,8 +144,8 @@ describe('CustomParams', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('when fieldset with selected custom property type is deleted disabled options update correctly', async () => {
|
it('when fieldset with selected custom property type is deleted disabled options update correctly', async () => {
|
||||||
await waitFor(() => userEvent.click(button));
|
await act(() => userEvent.click(button));
|
||||||
await waitFor(() => userEvent.click(button));
|
await act(() => userEvent.click(button));
|
||||||
|
|
||||||
const listboxes = screen.getAllByRole('listbox');
|
const listboxes = screen.getAllByRole('listbox');
|
||||||
|
|
||||||
|
@ -171,7 +172,7 @@ describe('CustomParams', () => {
|
||||||
const deleteSecondFieldsetButton = screen.getByTitle(
|
const deleteSecondFieldsetButton = screen.getByTitle(
|
||||||
'Delete customParam field 1'
|
'Delete customParam field 1'
|
||||||
);
|
);
|
||||||
await waitFor(() => userEvent.click(deleteSecondFieldsetButton));
|
await act(() => userEvent.click(deleteSecondFieldsetButton));
|
||||||
expect(secondListbox).not.toBeInTheDocument();
|
expect(secondListbox).not.toBeInTheDocument();
|
||||||
|
|
||||||
await expectOptionAvailability(
|
await expectOptionAvailability(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
import TimeToRetainBtn, {
|
import TimeToRetainBtn, {
|
||||||
|
@ -14,7 +14,7 @@ describe('TimeToRetainBtn', () => {
|
||||||
text: 'defaultPropsText',
|
text: 'defaultPropsText',
|
||||||
value: 0,
|
value: 0,
|
||||||
};
|
};
|
||||||
const Wrapper: React.FC = ({ children }) => {
|
const Wrapper: React.FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const methods = useForm();
|
const methods = useForm();
|
||||||
return <FormProvider {...methods}>{children}</FormProvider>;
|
return <FormProvider {...methods}>{children}</FormProvider>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
import TimeToRetainBtns, {
|
import TimeToRetainBtns, {
|
||||||
|
@ -11,7 +11,7 @@ describe('TimeToRetainBtns', () => {
|
||||||
name: 'defaultPropsTestingName',
|
name: 'defaultPropsTestingName',
|
||||||
value: 'defaultPropsValue',
|
value: 'defaultPropsValue',
|
||||||
};
|
};
|
||||||
const Wrapper: React.FC = ({ children }) => {
|
const Wrapper: React.FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const methods = useForm();
|
const methods = useForm();
|
||||||
return <FormProvider {...methods}>{children}</FormProvider>;
|
return <FormProvider {...methods}>{children}</FormProvider>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { screen } from '@testing-library/dom';
|
import { screen } from '@testing-library/dom';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
|
@ -9,7 +9,7 @@ const isSubmitting = false;
|
||||||
const onSubmit = jest.fn();
|
const onSubmit = jest.fn();
|
||||||
|
|
||||||
const renderComponent = (props: Props = { isSubmitting, onSubmit }) => {
|
const renderComponent = (props: Props = { isSubmitting, onSubmit }) => {
|
||||||
const Wrapper: React.FC = ({ children }) => {
|
const Wrapper: React.FC<PropsWithChildren<unknown>> = ({ children }) => {
|
||||||
const methods = useForm();
|
const methods = useForm();
|
||||||
return <FormProvider {...methods}>{children}</FormProvider>;
|
return <FormProvider {...methods}>{children}</FormProvider>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { screen, within, waitFor } from '@testing-library/react';
|
import { screen, within, act } from '@testing-library/react';
|
||||||
import App from 'components/App';
|
import App from 'components/App';
|
||||||
import { render } from 'lib/testHelpers';
|
import { render } from 'lib/testHelpers';
|
||||||
import { clustersPayload } from 'redux/reducers/clusters/__test__/fixtures';
|
import { clustersPayload } from 'redux/reducers/clusters/__test__/fixtures';
|
||||||
|
@ -43,10 +43,14 @@ describe('App', () => {
|
||||||
describe('with clusters list fetched', () => {
|
describe('with clusters list fetched', () => {
|
||||||
it('shows Cluster list', async () => {
|
it('shows Cluster list', async () => {
|
||||||
const mock = fetchMock.getOnce('/api/clusters', clustersPayload);
|
const mock = fetchMock.getOnce('/api/clusters', clustersPayload);
|
||||||
|
await act(() => {
|
||||||
render(<App />, {
|
render(<App />, {
|
||||||
pathname: '/',
|
pathname: '/',
|
||||||
});
|
});
|
||||||
await waitFor(() => expect(mock.called()).toBeTruthy());
|
});
|
||||||
|
|
||||||
|
expect(mock.called()).toBeTruthy();
|
||||||
|
|
||||||
const menuContainer = screen.getByLabelText('Sidebar Menu');
|
const menuContainer = screen.getByLabelText('Sidebar Menu');
|
||||||
expect(menuContainer).toBeInTheDocument();
|
expect(menuContainer).toBeInTheDocument();
|
||||||
expect(within(menuContainer).getByText('Dashboard')).toBeInTheDocument();
|
expect(within(menuContainer).getByText('Dashboard')).toBeInTheDocument();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from 'react';
|
import React, { PropsWithChildren, useState } from 'react';
|
||||||
import capitalize from 'lodash/capitalize';
|
import capitalize from 'lodash/capitalize';
|
||||||
|
|
||||||
import { BreadcrumbContext, BreadcrumbEntry } from './Breadcrumb.context';
|
import { BreadcrumbContext, BreadcrumbEntry } from './Breadcrumb.context';
|
||||||
|
@ -13,7 +13,9 @@ const mapLocationToPath = (
|
||||||
: item
|
: item
|
||||||
);
|
);
|
||||||
|
|
||||||
export const BreadcrumbProvider: React.FC = ({ children }) => {
|
export const BreadcrumbProvider: React.FC<PropsWithChildren<unknown>> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
const [state, setState] = useState<BreadcrumbEntry>({
|
const [state, setState] = useState<BreadcrumbEntry>({
|
||||||
link: '',
|
link: '',
|
||||||
path: [],
|
path: [],
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { Button } from 'components/common/Button/Button';
|
import { Button } from 'components/common/Button/Button';
|
||||||
|
|
||||||
import { ConfirmationModalWrapper } from './ConfirmationModal.styled';
|
import { ConfirmationModalWrapper } from './ConfirmationModal.styled';
|
||||||
|
@ -12,7 +12,9 @@ export interface ConfirmationModalProps {
|
||||||
submitBtnText?: string;
|
submitBtnText?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConfirmationModal: React.FC<ConfirmationModalProps> = ({
|
const ConfirmationModal: React.FC<
|
||||||
|
PropsWithChildren<ConfirmationModalProps>
|
||||||
|
> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
children,
|
children,
|
||||||
title = 'Confirm the action',
|
title = 'Confirm the action',
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import useOutsideClickRef from '@rooks/use-outside-click-ref';
|
import useOutsideClickRef from '@rooks/use-outside-click-ref';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, {
|
||||||
|
PropsWithChildren,
|
||||||
|
useCallback,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
|
||||||
import * as S from './Dropdown.styled';
|
import * as S from './Dropdown.styled';
|
||||||
|
|
||||||
|
@ -10,7 +15,12 @@ export interface DropdownProps {
|
||||||
up?: boolean;
|
up?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Dropdown: React.FC<DropdownProps> = ({ label, right, up, children }) => {
|
const Dropdown: React.FC<PropsWithChildren<DropdownProps>> = ({
|
||||||
|
label,
|
||||||
|
right,
|
||||||
|
up,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
const [active, setActive] = useState<boolean>(false);
|
const [active, setActive] = useState<boolean>(false);
|
||||||
const [wrapperRef] = useOutsideClickRef(() => setActive(false));
|
const [wrapperRef] = useOutsideClickRef(() => setActive(false));
|
||||||
const onClick = useCallback(() => setActive(!active), [active]);
|
const onClick = useCallback(() => setActive(!active), [active]);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
import * as S from './Dropdown.styled';
|
import * as S from './Dropdown.styled';
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ export interface DropdownItemProps {
|
||||||
danger?: boolean;
|
danger?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DropdownItem: React.FC<DropdownItemProps> = ({
|
const DropdownItem: React.FC<PropsWithChildren<DropdownItemProps>> = ({
|
||||||
onClick,
|
onClick,
|
||||||
danger,
|
danger,
|
||||||
children,
|
children,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { AlertType } from 'redux/interfaces';
|
import { AlertType } from 'redux/interfaces';
|
||||||
|
|
||||||
import * as S from './Metrics.styled';
|
import * as S from './Metrics.styled';
|
||||||
|
@ -11,15 +11,14 @@ export interface Props {
|
||||||
alertType?: AlertType;
|
alertType?: AlertType;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Indicator: React.FC<Props> = ({
|
const Indicator: React.FC<PropsWithChildren<Props>> = ({
|
||||||
label,
|
label,
|
||||||
title,
|
title,
|
||||||
fetching,
|
fetching,
|
||||||
isAlert,
|
isAlert,
|
||||||
alertType = 'error',
|
alertType = 'error',
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => (
|
||||||
return (
|
|
||||||
<S.IndicatorWrapper>
|
<S.IndicatorWrapper>
|
||||||
<div title={title}>
|
<div title={title}>
|
||||||
<S.IndicatorTitle>
|
<S.IndicatorTitle>
|
||||||
|
@ -36,6 +35,5 @@ const Indicator: React.FC<Props> = ({
|
||||||
</div>
|
</div>
|
||||||
</S.IndicatorWrapper>
|
</S.IndicatorWrapper>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export default Indicator;
|
export default Indicator;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
|
|
||||||
import * as S from './Metrics.styled';
|
import * as S from './Metrics.styled';
|
||||||
|
|
||||||
|
@ -6,13 +6,11 @@ interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Section: React.FC<Props> = ({ title, children }) => {
|
const Section: React.FC<PropsWithChildren<Props>> = ({ title, children }) => (
|
||||||
return (
|
|
||||||
<div>
|
<div>
|
||||||
{title && <S.SectionTitle>{title}</S.SectionTitle>}
|
{title && <S.SectionTitle>{title}</S.SectionTitle>}
|
||||||
<S.IndicatorsWrapper>{children}</S.IndicatorsWrapper>
|
<S.IndicatorsWrapper>{children}</S.IndicatorsWrapper>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
export default Section;
|
export default Section;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import Heading from 'components/common/heading/Heading.styled';
|
import Heading from 'components/common/heading/Heading.styled';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -7,7 +7,11 @@ interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PageHeading: React.FC<Props> = ({ text, className, children }) => {
|
const PageHeading: React.FC<PropsWithChildren<Props>> = ({
|
||||||
|
text,
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<Heading>{text}</Heading>
|
<Heading>{text}</Heading>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StaticRouter } from 'react-router';
|
import { StaticRouter } from 'react-router-dom';
|
||||||
import Pagination, {
|
import Pagination, {
|
||||||
PaginationProps,
|
PaginationProps,
|
||||||
} from 'components/common/Pagination/Pagination';
|
} from 'components/common/Pagination/Pagination';
|
||||||
|
|
|
@ -67,9 +67,7 @@ export const TableRow = <T, TId extends IdType, OT = never>({
|
||||||
const Cell = cell as React.FC<TableCellProps<T, TId, OT>> | undefined;
|
const Cell = cell as React.FC<TableCellProps<T, TId, OT>> | undefined;
|
||||||
const TdComponent = customTd || Td;
|
const TdComponent = customTd || Td;
|
||||||
|
|
||||||
return (
|
const content = Cell ? (
|
||||||
<TdComponent maxWidth={maxWidth}>
|
|
||||||
{Cell ? (
|
|
||||||
<Cell
|
<Cell
|
||||||
tableState={tableState}
|
tableState={tableState}
|
||||||
hovered={hovered}
|
hovered={hovered}
|
||||||
|
@ -78,7 +76,11 @@ export const TableRow = <T, TId extends IdType, OT = never>({
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
field && propertyLookup(field, dataItem)
|
field && propertyLookup(field, dataItem)
|
||||||
)}
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TdComponent maxWidth={maxWidth}>
|
||||||
|
{content as React.ReactNode}
|
||||||
</TdComponent>
|
</TdComponent>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* eslint-disable jsx-a11y/anchor-is-valid */
|
/* eslint-disable jsx-a11y/anchor-is-valid */
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
interface TabsProps {
|
interface TabsProps {
|
||||||
|
@ -8,7 +8,7 @@ interface TabsProps {
|
||||||
onChange?(index: number): void;
|
onChange?(index: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tabs: React.FC<TabsProps> = ({
|
const Tabs: React.FC<PropsWithChildren<TabsProps>> = ({
|
||||||
tabs,
|
tabs,
|
||||||
defaultSelectedIndex = 0,
|
defaultSelectedIndex = 0,
|
||||||
onChange,
|
onChange,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
||||||
|
@ -13,7 +13,10 @@ const HeadingBase = styled.h1<HeadingBaseProps>`
|
||||||
export interface Props {
|
export interface Props {
|
||||||
level?: HeadingLevel;
|
level?: HeadingLevel;
|
||||||
}
|
}
|
||||||
const Heading: React.FC<Props> = ({ level = 1, ...rest }) => {
|
const Heading: React.FC<PropsWithChildren<Props>> = ({
|
||||||
|
level = 1,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
return <HeadingBase as={`h${level}`} $level={level} {...rest} />;
|
return <HeadingBase as={`h${level}`} $level={level} {...rest} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { SortOrder, TopicColumnsToSort } from 'generated-sources';
|
import { SortOrder, TopicColumnsToSort } from 'generated-sources';
|
||||||
import * as S from 'components/common/table/TableHeaderCell/TableHeaderCell.styled';
|
import * as S from 'components/common/table/TableHeaderCell/TableHeaderCell.styled';
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@ export interface TableHeaderCellProps {
|
||||||
handleOrderBy?: (orderBy: TopicColumnsToSort | null) => void;
|
handleOrderBy?: (orderBy: TopicColumnsToSort | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TableHeaderCell: React.FC<TableHeaderCellProps> = (props) => {
|
const TableHeaderCell: React.FC<PropsWithChildren<TableHeaderCellProps>> = (
|
||||||
|
props
|
||||||
|
) => {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
previewText,
|
previewText,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import * as serviceWorker from 'serviceWorker';
|
import * as serviceWorker from 'serviceWorker';
|
||||||
|
@ -8,13 +8,16 @@ import { store } from 'redux/store';
|
||||||
import 'theme/index.scss';
|
import 'theme/index.scss';
|
||||||
import 'lib/constants';
|
import 'lib/constants';
|
||||||
|
|
||||||
ReactDOM.render(
|
const container =
|
||||||
|
document.getElementById('root') || document.createElement('div');
|
||||||
|
const root = createRoot(container);
|
||||||
|
|
||||||
|
root.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<BrowserRouter basename={window.basePath || '/'}>
|
<BrowserRouter basename={window.basePath || '/'}>
|
||||||
<App />
|
<App />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</Provider>,
|
</Provider>
|
||||||
document.getElementById('root')
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want your app to work offline and load faster, you can change
|
// If you want your app to work offline and load faster, you can change
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { renderHook, act } from '@testing-library/react-hooks';
|
import { renderHook, act } from '@testing-library/react';
|
||||||
import useModal from 'lib/hooks/useModal';
|
import useModal from 'lib/hooks/useModal';
|
||||||
|
|
||||||
describe('useModal CustomHook', () => {
|
describe('useModal CustomHook', () => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useLocation } from 'react-router';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
const usePagination = () => {
|
const usePagination = () => {
|
||||||
const { search, pathname } = useLocation();
|
const { search, pathname } = useLocation();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useCallback, useEffect, useMemo } from 'react';
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { useHistory, useLocation } from 'react-router';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
const SEARCH_QUERY_ARG = 'q';
|
const SEARCH_QUERY_ARG = 'q';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { ReactElement } from 'react';
|
import React, { PropsWithChildren, ReactElement } from 'react';
|
||||||
import { StaticRouter } from 'react-router-dom';
|
import { StaticRouter } from 'react-router-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { ThemeProvider } from 'styled-components';
|
import { ThemeProvider } from 'styled-components';
|
||||||
|
@ -40,7 +40,9 @@ const customRender = (
|
||||||
}: CustomRenderOptions = {}
|
}: CustomRenderOptions = {}
|
||||||
) => {
|
) => {
|
||||||
// overrides @testing-library/react render.
|
// overrides @testing-library/react render.
|
||||||
const AllTheProviders: React.FC = ({ children }) => {
|
const AllTheProviders: React.FC<PropsWithChildren<unknown>> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
|
Loading…
Add table
Reference in a new issue