From 8b497d67f7342e323e5f4d698e06aaaf4dd6e1a0 Mon Sep 17 00:00:00 2001 From: Thomas Dillard Date: Sat, 21 Sep 2019 23:14:15 -0400 Subject: [PATCH] Added ErrorBoundry reconfigured Jest Testing - Setup an error boundry component based on [React Documentation](https://reactjs.org/docs/error-boundaries.html) - Renamed `.babelrc` to `.babel.config.js` based on [GitHub issues](https://github.com/facebook/jest/issues/6053#issuecomment-383632515) - Added `babel-plugin-dynamic-import-node` because of Jest errors regarding `import` syntax - Added `react-dom` to devDependencies as it's used in `@testing-library/jest-dom` --- .babelrc | 4 ---- .eslintrc | 1 + .lintstagedrc | 4 ++-- babel.config.js | 15 +++++++++++++++ config/jest.config.js | 5 ++--- package.json | 14 ++++++++++---- src/__tests__/_helpers.test.js | 24 ++++++++++++++++++++++++ src/_helpers/Error.js | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 88 insertions(+), 13 deletions(-) delete mode 100644 .babelrc create mode 100644 babel.config.js create mode 100644 src/__tests__/_helpers.test.js create mode 100644 src/_helpers/Error.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 87f1fd2..0000000 --- a/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["@babel/preset-env", "@babel/preset-react"], - "plugins": ["react-hot-loader/babel", "@babel/plugin-proposal-class-properties"] -} diff --git a/.eslintrc b/.eslintrc index 6d5726d..e9b2dec 100644 --- a/.eslintrc +++ b/.eslintrc @@ -48,6 +48,7 @@ "react-hooks/rules-of-hooks": 2, "react/jsx-filename-extension": 0, "react/jsx-one-expression-per-line": 0, + "react/state-in-constructor": [1, "never"], "react/prefer-stateless-function": [2, { "ignorePureComponents": true }], diff --git a/.lintstagedrc b/.lintstagedrc index 5781d0c..748e32e 100644 --- a/.lintstagedrc +++ b/.lintstagedrc @@ -1,6 +1,6 @@ { - "*.js": ["eslint"], - "*.+(js|json|yml|yaml|css|less|md|graphql|mdx)": [ + "*.js": ["eslint", "jest --findRelatedTests --config ./config/jest.config.js"], + "*.+(jsx?|json|yml|yaml|css|less|md|graphql|mdx)": [ "prettier --write", "git add" ] diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..7c77e7e --- /dev/null +++ b/babel.config.js @@ -0,0 +1,15 @@ +// The babel file needs to be babel.config.js +// https://github.com/facebook/jest/issues/6053#issuecomment-383632515 +module.exports = { + presets: ['@babel/preset-env', '@babel/preset-react'], + env: { + test: { + presets: ['@babel/preset-env', '@babel/preset-react'], + plugins: [ + '@babel/plugin-proposal-class-properties', + 'transform-es2015-modules-commonjs', + 'babel-plugin-dynamic-import-node', + ], + }, + }, +}; diff --git a/config/jest.config.js b/config/jest.config.js index af852ec..721a5d8 100644 --- a/config/jest.config.js +++ b/config/jest.config.js @@ -5,7 +5,6 @@ const ROOT_DIR = path.resolve(__dirname, '../'); module.exports = { rootDir: ROOT_DIR, moduleFileExtensions: ['js', 'json'], - moduleNameMapper: { - App: '/src/App.js', - }, + moduleDirectories: ['node_modules', 'src'], + transformIgnorePatterns: ['/node_modules/'], }; diff --git a/package.json b/package.json index 84eadc2..c7f8b12 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "A React.js dashboard", "main": "src/index.js", "scripts": { - "test": "jest --config ./config/jest.config.js", + "test": "cross-env BABEL_ENV=test jest --config ./config/jest.config.js", "start": "webpack-dev-server --config ./config/webpack.development.js --open", "lint": "eslint ./", "prettier": "prettier --config ./.prettierrc --ignore-path ./.prettierignore \"*.+(js|jsonc?|yml|yaml|css|less|md|graphql|mdx)\"" @@ -14,8 +14,10 @@ "license": "MIT", "dependencies": { "@hot-loader/react-dom": "^16.9.0", - "react-hot-loader": "^4.12.13", - "react": "^16.9.0" + "cross-env": "^6.0.0", + "prop-types": "^15.7.2", + "react": "^16.9.0", + "react-hot-loader": "^4.12.13" }, "devDependencies": { "@babel/core": "^7.5.5", @@ -23,10 +25,14 @@ "@babel/preset-env": "^7.5.5", "@babel/preset-react": "^7.0.0", "@babel/register": "^7.5.5", + "@testing-library/jest-dom": "^4.1.0", + "@testing-library/react": "^9.1.4", "@types/jest": "^24.0.18", + "babel-cli": "^6.26.0", "babel-eslint": "^10.0.3", "babel-jest": "^24.9.0", "babel-loader": "^8.0.6", + "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "clean-webpack-plugin": "^3.0.0", "eslint": "^6.4.0", "eslint-config-airbnb": "^18.0.1", @@ -43,7 +49,7 @@ "jest": "^24.9.0", "lint-staged": "^9.2.5", "prettier": "^1.18.2", - "react-testing-library": "^8.0.1", + "react-dom": "^16.9.0", "webpack": "^4.38.0", "webpack-cli": "^3.3.6", "webpack-dev-server": "^3.7.2", diff --git a/src/__tests__/_helpers.test.js b/src/__tests__/_helpers.test.js new file mode 100644 index 0000000..6bb6e13 --- /dev/null +++ b/src/__tests__/_helpers.test.js @@ -0,0 +1,24 @@ +import React from 'react'; +import '@testing-library/jest-dom/extend-expect'; +import { render } from '@testing-library/react'; +import ErrorBoundry from '../_helpers/Error'; + +const TestComponent = () => { + return this.methodDoesntExist.value; +}; + +describe('Error', () => { + beforeEach(() => { + jest.spyOn(console, 'error'); + console.error.mockImplementation(() => {}); + }); + it('renders that there was a problem', () => { + const { container } = render( + + + , + ); + + expect(container).toHaveTextContent('Something went wrong.'); + }); +}); diff --git a/src/_helpers/Error.js b/src/_helpers/Error.js new file mode 100644 index 0000000..c6655df --- /dev/null +++ b/src/_helpers/Error.js @@ -0,0 +1,34 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +class ErrorBoundry extends Component { + state = { hasError: false }; + + static getDerivedStateFromError() { + return { hasError: true }; + } + + componentDidCatch(error, errorInfo) { + // TODO: hookup to error service + console.error(error, errorInfo); + } + + render() { + const { children } = this.props; + const { hasError } = this.state; + if (hasError) { + return

Something went wrong.

; + } + + return children; + } +} + +export default ErrorBoundry; + +ErrorBoundry.propTypes = { + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node, + ]), +};