test(web): drop enzyme in favor of react-testing-library (#2224)

* test(web): drop enzyme in favor of react-testing-library

Enzyme is falling behind in maintenance, it is currently maintained by one primary developer and still does [not support React 17](https://github.com/enzymejs/enzyme/pull/2430) despite it being released in October 2020.

[react-testing-library (RTL)](https://testing-library.com/docs) is [recommended by Facebook](https://reactjs.org/docs/test-utils.html#overview) and encourages writing tests that avoid testing implementation details.

* build(deps): update react monorepo to v17 (major)

* build(deps): remove @types/{enzyme,jest}
This commit is contained in:
Amir Zarrinkafsh 2021-08-03 16:25:13 +10:00 committed by GitHub
parent 942fd69776
commit 1b06e46f71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 2732 additions and 3901 deletions

View File

@ -9,27 +9,16 @@
"@fortawesome/react-fontawesome": "0.1.14", "@fortawesome/react-fontawesome": "0.1.14",
"@material-ui/core": "4.12.3", "@material-ui/core": "4.12.3",
"@material-ui/icons": "4.11.2", "@material-ui/icons": "4.11.2",
"@types/classnames": "2.3.0",
"@types/node": "15.6.0",
"@types/qrcode.react": "1.0.2",
"@types/query-string": "6.3.0",
"@types/react": "17.0.15",
"@types/react-dom": "17.0.9",
"@types/react-ga": "2.3.0",
"@types/react-router-dom": "5.1.8",
"axios": "0.21.1", "axios": "0.21.1",
"babel-preset-react-app": "10.0.0",
"classnames": "2.3.1", "classnames": "2.3.1",
"qrcode.react": "1.0.1", "qrcode.react": "1.0.1",
"query-string": "7.0.1", "query-string": "7.0.1",
"react": "16.14.0", "react": "17.0.2",
"react-dom": "16.14.0", "react-dom": "17.0.2",
"react-ga": "3.3.0", "react-ga": "3.3.0",
"react-loading": "2.0.3", "react-loading": "2.0.3",
"react-otp-input": "2.4.0", "react-otp-input": "2.4.0",
"react-router-dom": "5.2.0", "react-router-dom": "5.2.0",
"react-scripts": "4.0.3",
"typescript": "4.3.5",
"u2f-api": "1.2.1" "u2f-api": "1.2.1"
}, },
"scripts": { "scripts": {
@ -61,18 +50,25 @@
}, },
"devDependencies": { "devDependencies": {
"@craco/craco": "6.2.0", "@craco/craco": "6.2.0",
"@types/chai": "4.2.21", "@testing-library/jest-dom": "^5.14.1",
"@types/enzyme": "3.10.9", "@testing-library/react": "^12.0.0",
"@types/jest": "26.0.24", "@types/classnames": "2.3.0",
"chai": "4.3.4", "@types/node": "15.6.0",
"@types/qrcode.react": "1.0.2",
"@types/query-string": "6.3.0",
"@types/react": "17.0.15",
"@types/react-dom": "17.0.9",
"@types/react-ga": "2.3.0",
"@types/react-router-dom": "5.1.8",
"babel-preset-react-app": "10.0.0",
"craco-alias": "3.0.1", "craco-alias": "3.0.1",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.6",
"eslint-config-prettier": "8.3.0", "eslint-config-prettier": "8.3.0",
"eslint-formatter-rdjson": "1.0.5", "eslint-formatter-rdjson": "1.0.5",
"eslint-import-resolver-typescript": "2.4.0", "eslint-import-resolver-typescript": "2.4.0",
"eslint-plugin-prettier": "3.4.0", "eslint-plugin-prettier": "3.4.0",
"prettier": "2.3.2", "prettier": "2.3.2",
"react-test-renderer": "16.14.0" "react-scripts": "4.0.3",
"react-test-renderer": "17.0.2",
"typescript": "4.3.5"
} }
} }

View File

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { shallow } from "enzyme"; import { render } from "@testing-library/react";
import App from "@root/App"; import App from "@root/App";
it("renders without crashing", () => { it("renders without crashing", () => {
shallow(<App />); render(<App />);
}); });

View File

@ -1,8 +1,6 @@
import React from "react"; import React from "react";
import { SnackbarContent } from "@material-ui/core"; import { render, screen } from "@testing-library/react";
import { expect } from "chai";
import { mount, shallow } from "enzyme";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import ColoredSnackbarContent from "@components/ColoredSnackbarContent"; import ColoredSnackbarContent from "@components/ColoredSnackbarContent";
@ -14,22 +12,6 @@ it("renders without crashing", () => {
}); });
it("should contain the message", () => { it("should contain the message", () => {
const el = mount(<ColoredSnackbarContent level="success" message="this is a success" />); render(<ColoredSnackbarContent level="success" message="this is a success" />);
expect(el.text()).to.contain("this is a success"); expect(screen.getByRole("alert")).toHaveTextContent("this is a success");
}); });
/* eslint-disable @typescript-eslint/no-unused-expressions */
it("should have correct color", () => {
let el = shallow(<ColoredSnackbarContent level="success" message="this is a success" />);
expect(el.find(SnackbarContent).props().className!.indexOf("success") > -1).to.be.true;
el = shallow(<ColoredSnackbarContent level="info" message="this is an info" />);
expect(el.find(SnackbarContent).props().className!.indexOf("info") > -1).to.be.true;
el = shallow(<ColoredSnackbarContent level="error" message="this is an error" />);
expect(el.find(SnackbarContent).props().className!.indexOf("error") > -1).to.be.true;
el = shallow(<ColoredSnackbarContent level="warning" message="this is an warning" />);
expect(el.find(SnackbarContent).props().className!.indexOf("warning") > -1).to.be.true;
});
/* eslint-enable @typescript-eslint/no-unused-expressions */

View File

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import FailureIcon from "@components/FailureIcon"; import FailureIcon from "@components/FailureIcon";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<FailureIcon />); render(<FailureIcon />);
}); });

View File

@ -1,9 +1,17 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import FingerTouchIcon from "@components/FingerTouchIcon"; import FingerTouchIcon from "@components/FingerTouchIcon";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<FingerTouchIcon size={32} />); render(<FingerTouchIcon size={32} />);
});
it("renders animated without crashing", () => {
render(<FingerTouchIcon size={32} animated />);
});
it("renders animated and strong without crashing", () => {
render(<FingerTouchIcon size={32} animated strong />);
}); });

View File

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import FixedTextField from "@components/FixedTextField"; import FixedTextField from "@components/FixedTextField";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<FixedTextField />); render(<FixedTextField />);
}); });

View File

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import InformationIcon from "@components/InformationIcon"; import InformationIcon from "@components/InformationIcon";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<InformationIcon />); render(<InformationIcon />);
}); });

View File

@ -1,9 +1,13 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import LinearProgressBar from "@components/LinearProgressBar"; import LinearProgressBar from "@components/LinearProgressBar";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<LinearProgressBar value={40} />); render(<LinearProgressBar value={40} />);
});
it("renders adjusted height without crashing", () => {
render(<LinearProgressBar value={40} height={2} />);
}); });

View File

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import NotificationBar from "@components/NotificationBar"; import NotificationBar from "@components/NotificationBar";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<NotificationBar onClose={() => {}} />); render(<NotificationBar onClose={() => {}} />);
}); });

View File

@ -1,9 +1,29 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import PieChartIcon from "@components/PieChartIcon"; import PieChartIcon from "@components/PieChartIcon";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<PieChartIcon progress={40} />); render(<PieChartIcon progress={40} />);
});
it("renders maxProgress without crashing", () => {
render(<PieChartIcon progress={40} maxProgress={100} />);
});
it("renders width without crashing", () => {
render(<PieChartIcon progress={40} width={20} />);
});
it("renders height without crashing", () => {
render(<PieChartIcon progress={40} height={20} />);
});
it("renders color without crashing", () => {
render(<PieChartIcon progress={40} color="black" />);
});
it("renders backgroundColor without crashing", () => {
render(<PieChartIcon progress={40} backgroundColor="white" />);
}); });

View File

@ -1,9 +1,13 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import PushNotificationIcon from "@components/PushNotificationIcon"; import PushNotificationIcon from "@components/PushNotificationIcon";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<PushNotificationIcon width={32} height={32} />); render(<PushNotificationIcon width={32} height={32} />);
});
it("renders animated without crashing", () => {
render(<PushNotificationIcon width={32} height={32} animated />);
}); });

View File

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import SuccessIcon from "@components/SuccessIcon"; import SuccessIcon from "@components/SuccessIcon";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<SuccessIcon />); render(<SuccessIcon />);
}); });

View File

@ -1,9 +1,9 @@
import React from "react"; import React from "react";
import { mount } from "enzyme"; import { render } from "@testing-library/react";
import TimerIcon from "@components/TimerIcon"; import TimerIcon from "@components/TimerIcon";
it("renders without crashing", () => { it("renders without crashing", () => {
mount(<TimerIcon width={32} height={32} />); render(<TimerIcon width={32} height={32} period={30} />);
}); });

View File

@ -1,7 +1,6 @@
import { configure } from "enzyme"; import "@testing-library/jest-dom";
import Adapter from "enzyme-adapter-react-16";
document.body.setAttribute("data-basepath", ""); document.body.setAttribute("data-basepath", "");
document.body.setAttribute("data-rememberme", "true"); document.body.setAttribute("data-rememberme", "true");
document.body.setAttribute("data-resetpassword", "true"); document.body.setAttribute("data-resetpassword", "true");
document.body.setAttribute("data-theme", "light"); document.body.setAttribute("data-theme", "light");
configure({ adapter: new Adapter() });

View File

@ -6,7 +6,7 @@ import ReactLoading from "react-loading";
const LoadingPage = function () { const LoadingPage = function () {
const theme = useTheme(); const theme = useTheme();
return ( return (
<Grid container alignItems="center" justify="center" style={{ minHeight: "100vh" }}> <Grid container alignItems="center" justifyContent="center" style={{ minHeight: "100vh" }}>
<Grid item style={{ textAlign: "center", display: "inline-block" }}> <Grid item style={{ textAlign: "center", display: "inline-block" }}>
<ReactLoading width={64} height={64} color={theme.custom.loadingBar} type="bars" /> <ReactLoading width={64} height={64} color={theme.custom.loadingBar} type="bars" />
<Typography>Loading...</Typography> <Typography>Loading...</Typography>

File diff suppressed because it is too large Load Diff