From fd626f1dfdb792388ad41032ac028e1d48ef961a Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 11:16:33 +0900 Subject: [PATCH 01/55] =?UTF-8?q?npm=20install=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 203 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 4 +- 2 files changed, 193 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47281602d..029905387 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,9 @@ "license": "ISC", "dependencies": { "react": "^17.0.2", - "react-dom": "^17.0.2" + "react-dom": "^17.0.2", + "react-redux": "^7.2.4", + "redux": "^4.1.0" }, "devDependencies": { "@babel/core": "^7.14.2", @@ -1377,7 +1379,6 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" } @@ -2527,6 +2528,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -2597,6 +2607,37 @@ "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", "dev": true }, + "node_modules/@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + }, + "node_modules/@types/react": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.6.tgz", + "integrity": "sha512-u/TtPoF/hrvb63LdukET6ncaplYsvCvmkceasx8oG84/ZCsoLxz9Z/raPBP4lTAiWW1Jb889Y9svHmv8R26dWw==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz", + "integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", + "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" + }, "node_modules/@types/stack-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", @@ -4711,6 +4752,11 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, + "node_modules/csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + }, "node_modules/cucumber-expressions": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-6.6.2.tgz", @@ -7361,6 +7407,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -12640,7 +12699,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -12650,8 +12708,7 @@ "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/proto-list": { "version": "1.2.4", @@ -12887,6 +12944,35 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/react-redux": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz", + "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/react-redux": "^7.1.16", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -13032,6 +13118,14 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", + "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -13053,8 +13147,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "node_modules/regenerator-transform": { "version": "0.14.5", @@ -18448,7 +18541,6 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz", "integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==", - "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } @@ -19371,6 +19463,15 @@ "@types/node": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -19441,6 +19542,37 @@ "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", "dev": true }, + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + }, + "@types/react": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.6.tgz", + "integrity": "sha512-u/TtPoF/hrvb63LdukET6ncaplYsvCvmkceasx8oG84/ZCsoLxz9Z/raPBP4lTAiWW1Jb889Y9svHmv8R26dWw==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-redux": { + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz", + "integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "@types/scheduler": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", + "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" + }, "@types/stack-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", @@ -21155,6 +21287,11 @@ } } }, + "csstype": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" + }, "cucumber-expressions": { "version": "6.6.2", "resolved": "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-6.6.2.tgz", @@ -23220,6 +23357,21 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, "hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -27259,7 +27411,6 @@ "version": "15.7.2", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, "requires": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -27269,8 +27420,7 @@ "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" } } }, @@ -27468,6 +27618,26 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "react-redux": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz", + "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/react-redux": "^7.1.16", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + } + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -27579,6 +27749,14 @@ "strip-indent": "^3.0.0" } }, + "redux": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", + "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -27597,8 +27775,7 @@ "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "regenerator-transform": { "version": "0.14.5", diff --git a/package.json b/package.json index 19b40b504..cf023a429 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,8 @@ }, "dependencies": { "react": "^17.0.2", - "react-dom": "^17.0.2" + "react-dom": "^17.0.2", + "react-redux": "^7.2.4", + "redux": "^4.1.0" } } From 220fe982ed9795bd44402c1168f3c31d12c8bd30 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 11:17:13 +0900 Subject: [PATCH 02/55] =?UTF-8?q?=EC=83=81=ED=83=9C=EB=B3=80=ED=99=94?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=EC=9D=84=20App=EC=97=90=EC=84=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 58 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 7630c320f..5492fea60 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,36 +2,54 @@ import { useState } from 'react'; import Page from './Page'; -export default function App() { - const [state, setState] = useState({ - newId: 100, +const initialState = { + newId: 100, + taskTitle: '', + tasks: [], +}; + +function updateTitle(oldState, newTitle) { + return { + ...oldState, + taskTitle: newTitle, + }; +} + +function addTask(oldState) { + const { newId, taskTitle, tasks } = oldState; + + return { + ...oldState, + newId: newId + 1, taskTitle: '', - tasks: [], - }); + tasks: [...tasks, { id: newId, title: taskTitle }], + }; +} + +function deleteTask(oldState, id) { + const { tasks } = oldState; + + return { + ...oldState, + tasks: tasks.filter((task) => task.id !== id), + }; +} + +export default function App() { + const [state, setState] = useState(initialState); - const { newId, taskTitle, tasks } = state; + const { taskTitle, tasks } = state; function handleChangeTitle(event) { - setState({ - ...state, - taskTitle: event.target.value, - }); + setState(updateTitle(state, event.target.value)); } function handleClickAddTask() { - setState({ - ...state, - newId: newId + 1, - taskTitle: '', - tasks: [...tasks, { id: newId, title: taskTitle }], - }); + setState(addTask(state)); } function handleClickDeleteTask(id) { - setState({ - ...state, - tasks: tasks.filter((task) => task.id !== id), - }); + setState(deleteTask(state, id)); } return ( From ee3938593824f4aa44f7ed255e66b121664f775e Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 11:17:35 +0900 Subject: [PATCH 03/55] =?UTF-8?q?redux=EB=A5=BC=20=EB=8F=84=EC=9E=85?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/index.jsx | 8 +++++++- src/store.js | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/store.js diff --git a/src/index.jsx b/src/index.jsx index 5752f9375..7dc6b2529 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,8 +1,14 @@ import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; import App from './App'; +import store from './store'; ReactDOM.render( - , + ( + + + + ), document.getElementById('app'), ); diff --git a/src/store.js b/src/store.js new file mode 100644 index 000000000..491b0375c --- /dev/null +++ b/src/store.js @@ -0,0 +1,7 @@ +import { createStore } from 'redux'; + +const reducer = (state = initialState, action) => ({}); + +const store = createStore(reducer); + +export default store; From 0afb159aa39a39d6278b822076a487bf97bf6d63 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 11:25:50 +0900 Subject: [PATCH 04/55] =?UTF-8?q?reducer=EC=9D=84=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC=ED=95=98=EA=B3=A0=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=ED=8C=8C=EC=9D=BC=EC=9D=84=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 2 ++ src/reducer.test.js | 13 +++++++++++++ src/store.js | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/reducer.js create mode 100644 src/reducer.test.js diff --git a/src/reducer.js b/src/reducer.js new file mode 100644 index 000000000..ed8a2c40a --- /dev/null +++ b/src/reducer.js @@ -0,0 +1,2 @@ +const reducer = (state = initialState, action) => ({}); +export default reducer; diff --git a/src/reducer.test.js b/src/reducer.test.js new file mode 100644 index 000000000..41b37c7f8 --- /dev/null +++ b/src/reducer.test.js @@ -0,0 +1,13 @@ +import reducer from './reducer'; + +describe('reducer', () => { + describe('updateTitle', () => { + + }); + describe('addTask', () => { + + }); + describe('deleteTask', () => { + + }); +}); diff --git a/src/store.js b/src/store.js index 491b0375c..f33af8ed0 100644 --- a/src/store.js +++ b/src/store.js @@ -1,6 +1,6 @@ import { createStore } from 'redux'; -const reducer = (state = initialState, action) => ({}); +import reducer from './reducer'; const store = createStore(reducer); From 79bf6445fd8d51adba09e7379d0c54f4e79dc8c3 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 11:26:35 +0900 Subject: [PATCH 05/55] =?UTF-8?q?updateTitle=EC=9D=84=20updateTaskTitle?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 4 ++-- src/reducer.test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 5492fea60..40962448e 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -8,7 +8,7 @@ const initialState = { tasks: [], }; -function updateTitle(oldState, newTitle) { +function updateTaskTitle(oldState, newTitle) { return { ...oldState, taskTitle: newTitle, @@ -41,7 +41,7 @@ export default function App() { const { taskTitle, tasks } = state; function handleChangeTitle(event) { - setState(updateTitle(state, event.target.value)); + setState(updateTaskTitle(state, event.target.value)); } function handleClickAddTask() { diff --git a/src/reducer.test.js b/src/reducer.test.js index 41b37c7f8..9044204ea 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -1,7 +1,7 @@ import reducer from './reducer'; describe('reducer', () => { - describe('updateTitle', () => { + describe('updateTaskTitle', () => { }); describe('addTask', () => { From c493676ff598552f90e259d297fd07dba909fc52 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 11:32:16 +0900 Subject: [PATCH 06/55] =?UTF-8?q?updateTaskTitle=20=EB=A6=AC=EB=93=80?= =?UTF-8?q?=EC=84=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/reducer.test.js b/src/reducer.test.js index 9044204ea..bcb4722b1 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -2,7 +2,22 @@ import reducer from './reducer'; describe('reducer', () => { describe('updateTaskTitle', () => { + it('updates title of task', () => { + const state = { + taskTitle: '', + }; + const action = { + type: 'UpdateTaskTitle', + payload: { + taskTitle: 'newTitle', + }, + }; + + const newState = reducer(state, action); + + expect(newState.taskTitle).toBe('newTitle'); + }); }); describe('addTask', () => { From 7c0cb26d9291dae9b1c556924ca74c8cf5ff0670 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:24:07 +0900 Subject: [PATCH 07/55] =?UTF-8?q?updateTaskTitle=20=EB=A6=AC=EB=93=80?= =?UTF-8?q?=EC=84=9C=EB=A5=BC=20=EC=9E=91=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/reducer.js b/src/reducer.js index ed8a2c40a..e4b56eff4 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -1,2 +1,15 @@ -const reducer = (state = initialState, action) => ({}); +const initialState = { + newId: 100, + taskTitle: '', + tasks: [], +}; + +const reducer = (state = initialState, action) => { + if (action.type === 'UpdateTaskTitle') { + return { + ...state, + taskTitle: action.payload.taskTitle, + }; + } +}; export default reducer; From 384e1420a9062901a3505efeaecefa38268c7e50 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:31:00 +0900 Subject: [PATCH 08/55] =?UTF-8?q?AddTask=20=EB=A6=AC=EB=93=80=EC=84=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/reducer.test.js b/src/reducer.test.js index bcb4722b1..df162414f 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -20,7 +20,23 @@ describe('reducer', () => { }); }); describe('addTask', () => { + it('adds new task to tasks', () => { + const state = { + taskTitle: 'new Title', + newId: 100, + tasks: [], + }; + + const action = { + type: 'AddTask', + }; + + const newState = reducer(state, action); + const { tasks } = newState; + expect(tasks).toHaveLength(1); + expect(tasks[0]).toEqual({ id: 100, title: 'new Title' }); + }); }); describe('deleteTask', () => { From 4d9637fc7963b5d2bd2125c1c39a6fee1b134fa3 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:31:07 +0900 Subject: [PATCH 09/55] =?UTF-8?q?AddTask=20=EB=A6=AC=EB=93=80=EC=84=9C?= =?UTF-8?q?=EB=A5=BC=20=EC=9E=91=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/reducer.js b/src/reducer.js index e4b56eff4..4c4c92edd 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -11,5 +11,15 @@ const reducer = (state = initialState, action) => { taskTitle: action.payload.taskTitle, }; } + if (action.type === 'AddTask') { + const { newId, tasks, taskTitle } = state; + + return { + ...state, + newId: newId + 1, + taskTitle: '', + tasks: [...tasks, { id: newId, title: taskTitle }], + }; + } }; export default reducer; From 28d414e3cbf1bda1c71d1a7924d4dc37d9a6e30d Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:35:15 +0900 Subject: [PATCH 10/55] =?UTF-8?q?DeleteTask=20=EB=A6=AC=EB=93=80=EC=84=9C?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/reducer.test.js b/src/reducer.test.js index df162414f..d717cac83 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -39,6 +39,24 @@ describe('reducer', () => { }); }); describe('deleteTask', () => { + it('delete task from tasks', () => { + const state = { + taskTitle: 'new Title', + newId: 100, + tasks: [{ id: 1, title: 'codeSoom' }], + }; + const action = { + type: 'DeleteTask', + payload: { + id: 1, + }, + }; + + const newState = reducer(state, action); + + const { tasks } = newState; + expect(tasks).toHaveLength(0); + }); }); }); From 33aac4d0dc565538fec4d41792597d37cbd55f16 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:35:25 +0900 Subject: [PATCH 11/55] =?UTF-8?q?DeleteTask=20=EB=A6=AC=EB=93=80=EC=84=9C?= =?UTF-8?q?=EB=A5=BC=20=EC=9E=91=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/reducer.js b/src/reducer.js index 4c4c92edd..edc52b5d3 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -21,5 +21,13 @@ const reducer = (state = initialState, action) => { tasks: [...tasks, { id: newId, title: taskTitle }], }; } + if (action.type === 'DeleteTask') { + const { tasks } = state; + + return { + ...state, + tasks: tasks.filter((task) => task.id !== action.payload.id), + }; + } }; export default reducer; From e809245ef34d46283b212b5385d78e03b277aef1 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:38:43 +0900 Subject: [PATCH 12/55] =?UTF-8?q?=EB=A6=AC=EB=93=80=EC=84=9C=EC=9D=98=20?= =?UTF-8?q?=EB=B0=98=EB=B3=B5=EB=90=9C=20if=EB=AC=B8=EC=9D=84=20switch?= =?UTF-8?q?=EB=AC=B8=EC=9C=BC=EB=A1=9C=20=EB=8C=80=EC=B2=B4=ED=95=98?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/reducer.js b/src/reducer.js index edc52b5d3..e64f9a62c 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -5,29 +5,31 @@ const initialState = { }; const reducer = (state = initialState, action) => { - if (action.type === 'UpdateTaskTitle') { + const { newId, tasks, taskTitle } = state; + + switch (action.type) { + case ('UpdateTaskTitle'): return { ...state, taskTitle: action.payload.taskTitle, }; - } - if (action.type === 'AddTask') { - const { newId, tasks, taskTitle } = state; + case ('AddTask'): return { ...state, newId: newId + 1, taskTitle: '', tasks: [...tasks, { id: newId, title: taskTitle }], }; - } - if (action.type === 'DeleteTask') { - const { tasks } = state; + case ('DeleteTask'): return { ...state, tasks: tasks.filter((task) => task.id !== action.payload.id), }; + + default: + return state; } }; export default reducer; From 3faf51a74eecd49b3b5997a9684014861c207ba1 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:42:02 +0900 Subject: [PATCH 13/55] =?UTF-8?q?=EB=A6=AC=EB=93=80=EC=84=9C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=97=90=20context=EB=A5=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 66 ++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/src/reducer.test.js b/src/reducer.test.js index d717cac83..fa8f2bb9f 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -20,43 +20,53 @@ describe('reducer', () => { }); }); describe('addTask', () => { - it('adds new task to tasks', () => { - const state = { - taskTitle: 'new Title', - newId: 100, - tasks: [], - }; + context('with title', () => { + it('adds new task to tasks', () => { + const state = { + taskTitle: 'new Title', + newId: 100, + tasks: [], + }; - const action = { - type: 'AddTask', - }; + const action = { + type: 'AddTask', + }; - const newState = reducer(state, action); + const newState = reducer(state, action); + + const { tasks } = newState; + expect(tasks).toHaveLength(1); + expect(tasks[0]).toEqual({ id: 100, title: 'new Title' }); + }); + }); - const { tasks } = newState; - expect(tasks).toHaveLength(1); - expect(tasks[0]).toEqual({ id: 100, title: 'new Title' }); + context('without title', () => { }); }); describe('deleteTask', () => { - it('delete task from tasks', () => { - const state = { - taskTitle: 'new Title', - newId: 100, - tasks: [{ id: 1, title: 'codeSoom' }], - }; + context('with existing id', () => { + it('delete task from tasks', () => { + const state = { + taskTitle: 'new Title', + newId: 100, + tasks: [{ id: 1, title: 'codeSoom' }], + }; - const action = { - type: 'DeleteTask', - payload: { - id: 1, - }, - }; + const action = { + type: 'DeleteTask', + payload: { + id: 1, + }, + }; - const newState = reducer(state, action); + const newState = reducer(state, action); + + const { tasks } = newState; + expect(tasks).toHaveLength(0); + }); + }); - const { tasks } = newState; - expect(tasks).toHaveLength(0); + context('with non-existing id', () => { }); }); }); From 527b42eba67cb843589f4c841ccb2fe94210effe Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:47:00 +0900 Subject: [PATCH 14/55] =?UTF-8?q?add=20task=20without=20title=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=95=98?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/reducer.test.js b/src/reducer.test.js index fa8f2bb9f..5c4964110 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -41,8 +41,24 @@ describe('reducer', () => { }); context('without title', () => { + const state = { + taskTitle: '', + newId: 100, + tasks: [], + }; + + const action = { + type: 'AddTask', + }; + + const newState = reducer(state, action); + + const { tasks } = newState; + expect(tasks).toHaveLength(0); + expect(tasks).toEqual([]); }); }); + describe('deleteTask', () => { context('with existing id', () => { it('delete task from tasks', () => { From dd2b9457b597b3ba537d9b458e56c43cabe63459 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:48:46 +0900 Subject: [PATCH 15/55] =?UTF-8?q?add=20task=20without=20title=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=ED=86=B5=EA=B3=BC=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/reducer.js b/src/reducer.js index e64f9a62c..51fc4eeaa 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -15,6 +15,9 @@ const reducer = (state = initialState, action) => { }; case ('AddTask'): + if (taskTitle === '') { + return state; + } return { ...state, newId: newId + 1, From d7a535040b510ebe4837f7c8214f749ae1687a75 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 12:50:25 +0900 Subject: [PATCH 16/55] =?UTF-8?q?delete=20task=20with=20non-existing=20id?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/reducer.test.js b/src/reducer.test.js index 5c4964110..1042512e9 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -83,6 +83,23 @@ describe('reducer', () => { }); context('with non-existing id', () => { + const state = { + taskTitle: 'new Title', + newId: 100, + tasks: [{ id: 1, title: 'codeSoom' }], + }; + + const action = { + type: 'DeleteTask', + payload: { + id: 2, + }, + }; + + const newState = reducer(state, action); + + const { tasks } = newState; + expect(tasks).toHaveLength(1); }); }); }); From 05da2a76a79907582ac77aa5f9547ad500579636 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 13:08:25 +0900 Subject: [PATCH 17/55] =?UTF-8?q?=EC=95=A1=EC=85=98=EC=83=9D=EC=84=B1?= =?UTF-8?q?=ED=95=A8=EC=88=98=EB=A5=BC=20=EB=8F=84=EC=9E=85=ED=95=98?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions.js | 17 +++++++++++++++++ src/reducer.test.js | 38 +++++++++----------------------------- 2 files changed, 26 insertions(+), 29 deletions(-) create mode 100644 src/actions.js diff --git a/src/actions.js b/src/actions.js new file mode 100644 index 000000000..7d021b843 --- /dev/null +++ b/src/actions.js @@ -0,0 +1,17 @@ +export const updateTaskTitle = (newTitle) => ({ + type: 'UpdateTaskTitle', + payload: { + taskTitle: newTitle, + }, +}); + +export const addTask = () => ({ + type: 'AddTask', +}); + +export const deleteTask = (id) => ({ + type: 'DeleteTask', + payload: { + id, + }, +}); diff --git a/src/reducer.test.js b/src/reducer.test.js index 1042512e9..7d9f5d1f9 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -1,4 +1,9 @@ import reducer from './reducer'; +import { + updateTaskTitle, + addTask, + deleteTask, +} from './actions'; describe('reducer', () => { describe('updateTaskTitle', () => { @@ -7,14 +12,7 @@ describe('reducer', () => { taskTitle: '', }; - const action = { - type: 'UpdateTaskTitle', - payload: { - taskTitle: 'newTitle', - }, - }; - - const newState = reducer(state, action); + const newState = reducer(state, updateTaskTitle('newTitle')); expect(newState.taskTitle).toBe('newTitle'); }); @@ -28,11 +26,7 @@ describe('reducer', () => { tasks: [], }; - const action = { - type: 'AddTask', - }; - - const newState = reducer(state, action); + const newState = reducer(state, addTask()); const { tasks } = newState; expect(tasks).toHaveLength(1); @@ -68,14 +62,7 @@ describe('reducer', () => { tasks: [{ id: 1, title: 'codeSoom' }], }; - const action = { - type: 'DeleteTask', - payload: { - id: 1, - }, - }; - - const newState = reducer(state, action); + const newState = reducer(state, deleteTask(1)); const { tasks } = newState; expect(tasks).toHaveLength(0); @@ -89,14 +76,7 @@ describe('reducer', () => { tasks: [{ id: 1, title: 'codeSoom' }], }; - const action = { - type: 'DeleteTask', - payload: { - id: 2, - }, - }; - - const newState = reducer(state, action); + const newState = reducer(state, deleteTask(2)); const { tasks } = newState; expect(tasks).toHaveLength(1); From f5db30d83e61a7a346f846dd432bb7c543c135b8 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 13:26:32 +0900 Subject: [PATCH 18/55] =?UTF-8?q?reducer.js=EC=97=90=EC=84=9C=20=ED=99=94?= =?UTF-8?q?=EC=82=B4=ED=91=9C=ED=95=A8=EC=88=98=EB=A5=BC=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/reducer.js b/src/reducer.js index 51fc4eeaa..209ecffb1 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -4,7 +4,7 @@ const initialState = { tasks: [], }; -const reducer = (state = initialState, action) => { +export default function reducer(state = initialState, action) { const { newId, tasks, taskTitle } = state; switch (action.type) { @@ -34,5 +34,4 @@ const reducer = (state = initialState, action) => { default: return state; } -}; -export default reducer; +} From 91685e541bdfd30c52151b19e327abd2325d854e Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 13:27:15 +0900 Subject: [PATCH 19/55] =?UTF-8?q?useSelector,=20useDispatch=EB=A5=BC=20moc?= =?UTF-8?q?k=ED=95=98=EC=97=AC=20App=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=A4=80=EB=B9=84?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 9 ++------- src/__mock__/react-redux.js | 2 ++ 2 files changed, 4 insertions(+), 7 deletions(-) create mode 100644 src/__mock__/react-redux.js diff --git a/src/App.test.jsx b/src/App.test.jsx index 3b7c1a886..ab53e0747 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -2,13 +2,8 @@ import { render } from '@testing-library/react'; import App from './App'; -test('App', () => { - const { getByText } = render(( - - )); +jest.mock('react-redux'); - expect(getByText(/추가/)).not.toBeNull(); +test('App', () => { - // TODO: 통합 테스트 코드 작성 - // CodeceptJS => 실제 브라우저에서 사용자 테스트 실행 가능. }); diff --git a/src/__mock__/react-redux.js b/src/__mock__/react-redux.js new file mode 100644 index 000000000..f0fc07560 --- /dev/null +++ b/src/__mock__/react-redux.js @@ -0,0 +1,2 @@ +export const useSelector = jest.fn(); +export const useDispatch = jest.fn(); From 0560273b676a87d01919e448e672f337bb5e6edf Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 14:40:54 +0900 Subject: [PATCH 20/55] =?UTF-8?q?App=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9E=91=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 75 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index ab53e0747..3fe4ee6cd 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -1,9 +1,80 @@ -import { render } from '@testing-library/react'; +import { render, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { useDispatch, useSelector } from 'react-redux'; import App from './App'; jest.mock('react-redux'); -test('App', () => { +it('renders tasks', () => { + useSelector.mockImplementation((selector) => selector({ + taskTitle: 'new Title', + tasks: [{ id: 1, title: 'codesoom' }], + })); + const { getByText } = render(); + expect(getByText('codesoom')).toBeInTheDocument(); +}); + +it('adds task to tasks with 추가 button', () => { + useSelector.mockImplementation((selector) => selector({ + taskTitle: 'new Title', + tasks: [{ id: 1, title: 'codesoom' }], + })); + + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + + const { getByRole } = render(); + userEvent.click(getByRole('button', { name: '추가' })); + + expect(dispatch).toBeCalledWith({ type: 'AddTask' }); +}); + +it('deletes task from tasks with 완료 button', () => { + useSelector.mockImplementation((selector) => selector({ + taskTitle: 'new Title', + tasks: [{ id: 1, title: 'codesoom' }], + })); + + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + + const { getByRole, getByText } = render(); + userEvent.click(getByRole('button', { name: '완료' })); + + userEvent.click( + within(getByText('codesoom')) + .getByRole('button', { name: '완료' }), + ); + + expect(dispatch).toBeCalledWith({ + type: 'DeleteTask', + payload: { + id: 1, + }, + }); +}); + +it('updates taskTitle', () => { + useSelector.mockImplementation((selector) => selector({ + taskTitle: '', + tasks: [], + })); + + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + const { getByRole } = render(); + + userEvent.type( + getByRole('textbox', { name: '할 일' }), + 'codesoom', + ); + + expect(dispatch).toHaveBeenLastCalledWith({ + type: 'UpdateTaskTitle', + payload: { + taskTitle: 'm', + }, + }); }); From 70f2a6335e39fa35b1755b5bf424340a8f8ddf31 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 14:41:20 +0900 Subject: [PATCH 21/55] =?UTF-8?q?App=EC=97=90=EC=84=9C=20useState=EB=A5=BC?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20redux=EB=A5=BC=20?= =?UTF-8?q?=EB=8F=84=EC=9E=85=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 56 ++++++++++++++--------------------------------------- 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 40962448e..477ed08f9 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,61 +1,33 @@ -import { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; -import Page from './Page'; - -const initialState = { - newId: 100, - taskTitle: '', - tasks: [], -}; - -function updateTaskTitle(oldState, newTitle) { - return { - ...oldState, - taskTitle: newTitle, - }; -} - -function addTask(oldState) { - const { newId, taskTitle, tasks } = oldState; +import { + updateTaskTitle, + addTask, + deleteTask, +} from './actions'; - return { - ...oldState, - newId: newId + 1, - taskTitle: '', - tasks: [...tasks, { id: newId, title: taskTitle }], - }; -} - -function deleteTask(oldState, id) { - const { tasks } = oldState; - - return { - ...oldState, - tasks: tasks.filter((task) => task.id !== id), - }; -} +import Page from './Page'; export default function App() { - const [state, setState] = useState(initialState); - - const { taskTitle, tasks } = state; + const { taskTitle, tasks } = useSelector((state) => state); + const dispatch = useDispatch(); - function handleChangeTitle(event) { - setState(updateTaskTitle(state, event.target.value)); + function handleChangeTitle(value) { + dispatch(updateTaskTitle(value)); } function handleClickAddTask() { - setState(addTask(state)); + dispatch(addTask()); } function handleClickDeleteTask(id) { - setState(deleteTask(state, id)); + dispatch(deleteTask(id)); } return ( handleChangeTitle(e.target.value)} onClickAddTask={handleClickAddTask} tasks={tasks} onClickDeleteTask={handleClickDeleteTask} From f633727e341b2fa8edd8feb37f826f5675736334 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 14:42:12 +0900 Subject: [PATCH 22/55] =?UTF-8?q?reducer=EC=97=90=EC=84=9C=20=EB=A7=A4?= =?UTF-8?q?=EA=B0=9C=EB=B3=80=EC=88=98=20=EA=B8=B0=EB=B3=B8=EA=B0=92?= =?UTF-8?q?=EA=B3=BC=20switch-case=EA=B8=B0=EB=B3=B8=EA=B0=92=EC=9D=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 2 +- src/reducer.test.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/reducer.js b/src/reducer.js index 209ecffb1..50b134aa7 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -1,4 +1,4 @@ -const initialState = { +export const initialState = { newId: 100, taskTitle: '', tasks: [], diff --git a/src/reducer.test.js b/src/reducer.test.js index 7d9f5d1f9..5e6937489 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -1,4 +1,4 @@ -import reducer from './reducer'; +import reducer, { initialState } from './reducer'; import { updateTaskTitle, addTask, @@ -82,4 +82,9 @@ describe('reducer', () => { expect(tasks).toHaveLength(1); }); }); + + context('when invalid action is given', () => { + const newState = reducer(undefined, { type: 'invaild' }); + expect(initialState).toEqual(newState); + }); }); From 9adaf7df9266670231c6fa583e32bda631b8ae1c Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 15:08:41 +0900 Subject: [PATCH 23/55] =?UTF-8?q?user-Event=EB=A5=BC=20=EC=84=A4=EC=B9=98?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 166 +++++++++++++++------------------------------- package.json | 1 + 2 files changed, 54 insertions(+), 113 deletions(-) diff --git a/package-lock.json b/package-lock.json index 029905387..73dff381f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@testing-library/user-event": "^13.1.9", "react": "^17.0.2", "react-dom": "^17.0.2", "react-redux": "^7.2.4", @@ -43,7 +44,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, "dependencies": { "@babel/highlight": "^7.12.13" } @@ -319,8 +319,7 @@ "node_modules/@babel/helper-validator-identifier": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==" }, "node_modules/@babel/helper-validator-option": { "version": "7.12.17", @@ -355,7 +354,6 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.14.0", "chalk": "^2.0.0", @@ -1387,7 +1385,6 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", - "dev": true, "dependencies": { "core-js-pure": "^3.0.0", "regenerator-runtime": "^0.13.4" @@ -2121,7 +2118,6 @@ "version": "26.6.2", "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", @@ -2137,7 +2133,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2152,7 +2147,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2168,7 +2162,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2179,14 +2172,12 @@ "node_modules/@jest/types/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2195,7 +2186,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -2246,7 +2236,6 @@ "version": "7.31.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.0.tgz", "integrity": "sha512-0X7ACg4YvTRDFMIuTOEj6B4NpN7i3F/4j5igOcTI5NC5J+N4TribNdErCHOZF1LBWhhcyfwxelVwvoYNMUXTOA==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -2265,7 +2254,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2280,7 +2268,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2296,7 +2283,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2307,14 +2293,12 @@ "node_modules/@testing-library/dom/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/@testing-library/dom/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2323,7 +2307,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -2436,11 +2419,25 @@ "react-dom": "*" } }, + "node_modules/@testing-library/user-event": { + "version": "13.1.9", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.1.9.tgz", + "integrity": "sha512-NZr0zL2TMOs2qk+dNlqrAdbaRW5dAmYwd1yuQ4r7HpkVEOj0MWuUjDWwKhcLd/atdBy8ZSMHSKp+kXSQe47ezg==", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@types/aria-query": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", - "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==", - "dev": true + "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" }, "node_modules/@types/babel__core": { "version": "7.1.14", @@ -2540,14 +2537,12 @@ "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -2556,7 +2551,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } @@ -2592,8 +2586,7 @@ "node_modules/@types/node": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", - "dev": true + "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.0", @@ -2657,7 +2650,6 @@ "version": "15.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", - "dev": true, "dependencies": { "@types/yargs-parser": "*" } @@ -2665,8 +2657,7 @@ "node_modules/@types/yargs-parser": { "version": "20.2.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", - "dev": true + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" }, "node_modules/@types/yauzl": { "version": "2.9.1", @@ -3042,7 +3033,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true, "engines": { "node": ">=8" } @@ -3051,7 +3041,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -3100,7 +3089,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, "dependencies": { "@babel/runtime": "^7.10.2", "@babel/runtime-corejs3": "^7.10.2" @@ -4002,7 +3990,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4439,7 +4426,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -4447,8 +4433,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "node_modules/colorette": { "version": "1.2.2", @@ -4656,7 +4641,6 @@ "version": "3.12.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==", - "dev": true, "hasInstallScript": true, "funding": { "type": "opencollective", @@ -5204,8 +5188,7 @@ "node_modules/dom-accessibility-api": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", - "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==", - "dev": true + "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==" }, "node_modules/domexception": { "version": "2.0.1", @@ -5486,7 +5469,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -7318,7 +7300,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, "engines": { "node": ">=4" } @@ -10800,7 +10781,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", - "dev": true, "bin": { "lz-string": "bin/bin.js" } @@ -12591,7 +12571,6 @@ "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, "dependencies": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -12606,7 +12585,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -12621,7 +12599,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -12632,8 +12609,7 @@ "node_modules/pretty-format/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/process-nextick-args": { "version": "2.0.1", @@ -12941,8 +12917,7 @@ "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-redux": { "version": "7.2.4", @@ -15078,7 +15053,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -17449,7 +17423,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", - "dev": true, "requires": { "@babel/highlight": "^7.12.13" } @@ -17706,8 +17679,7 @@ "@babel/helper-validator-identifier": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==" }, "@babel/helper-validator-option": { "version": "7.12.17", @@ -17742,7 +17714,6 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.14.0", "chalk": "^2.0.0", @@ -18549,7 +18520,6 @@ "version": "7.14.0", "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.0.tgz", "integrity": "sha512-0R0HTZWHLk6G8jIk0FtoX+AatCtKnswS98VhXwGImFc759PJRp4Tru0PQYZofyijTFUr+gT8Mu7sgXVJLQ0ceg==", - "dev": true, "requires": { "core-js-pure": "^3.0.0", "regenerator-runtime": "^0.13.4" @@ -19128,7 +19098,6 @@ "version": "26.6.2", "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", @@ -19141,7 +19110,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -19150,7 +19118,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -19160,7 +19127,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -19168,20 +19134,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -19231,7 +19194,6 @@ "version": "7.31.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.0.tgz", "integrity": "sha512-0X7ACg4YvTRDFMIuTOEj6B4NpN7i3F/4j5igOcTI5NC5J+N4TribNdErCHOZF1LBWhhcyfwxelVwvoYNMUXTOA==", - "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -19247,7 +19209,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -19256,7 +19217,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -19266,7 +19226,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -19274,20 +19233,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -19371,11 +19327,18 @@ "@testing-library/dom": "^7.28.1" } }, + "@testing-library/user-event": { + "version": "13.1.9", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-13.1.9.tgz", + "integrity": "sha512-NZr0zL2TMOs2qk+dNlqrAdbaRW5dAmYwd1yuQ4r7HpkVEOj0MWuUjDWwKhcLd/atdBy8ZSMHSKp+kXSQe47ezg==", + "requires": { + "@babel/runtime": "^7.12.5" + } + }, "@types/aria-query": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", - "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==", - "dev": true + "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" }, "@types/babel__core": { "version": "7.1.14", @@ -19475,14 +19438,12 @@ "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", - "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", - "dev": true + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==" }, "@types/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, "requires": { "@types/istanbul-lib-coverage": "*" } @@ -19491,7 +19452,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, "requires": { "@types/istanbul-lib-report": "*" } @@ -19527,8 +19487,7 @@ "@types/node": { "version": "15.3.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-15.3.0.tgz", - "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==", - "dev": true + "integrity": "sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -19592,7 +19551,6 @@ "version": "15.0.13", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", - "dev": true, "requires": { "@types/yargs-parser": "*" } @@ -19600,8 +19558,7 @@ "@types/yargs-parser": { "version": "20.2.0", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", - "dev": true + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==" }, "@types/yauzl": { "version": "2.9.1", @@ -19928,14 +19885,12 @@ "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -19979,7 +19934,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, "requires": { "@babel/runtime": "^7.10.2", "@babel/runtime-corejs3": "^7.10.2" @@ -20673,7 +20627,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -21017,7 +20970,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -21025,8 +20977,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colorette": { "version": "1.2.2", @@ -21203,8 +21154,7 @@ "core-js-pure": { "version": "3.12.1", "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.12.1.tgz", - "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==", - "dev": true + "integrity": "sha512-1cch+qads4JnDSWsvc7d6nzlKAippwjUlf6vykkTLW53VSV+NkE6muGBToAjEA8pG90cSfcud3JgVmW2ds5TaQ==" }, "core-util-is": { "version": "1.0.2", @@ -21644,8 +21594,7 @@ "dom-accessibility-api": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", - "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==", - "dev": true + "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==" }, "domexception": { "version": "2.0.1", @@ -21872,8 +21821,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "2.0.0", @@ -23290,8 +23238,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.2", @@ -25942,8 +25889,7 @@ "lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", - "dev": true + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=" }, "make-dir": { "version": "3.1.0", @@ -27328,7 +27274,6 @@ "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, "requires": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -27340,7 +27285,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -27349,7 +27293,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -27357,8 +27300,7 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" } } }, @@ -27615,8 +27557,7 @@ "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "react-redux": { "version": "7.2.4", @@ -29342,7 +29283,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } diff --git a/package.json b/package.json index cf023a429..755704189 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "webpack-dev-server": "^3.11.2" }, "dependencies": { + "@testing-library/user-event": "^13.1.9", "react": "^17.0.2", "react-dom": "^17.0.2", "react-redux": "^7.2.4", From d3d0fa02164530dfdbbd47f3aff61cfda2318624 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 15:41:51 +0900 Subject: [PATCH 24/55] =?UTF-8?q?given2=EB=A5=BC=20=EC=84=A4=EC=B9=98?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 1 + jest.config.js | 1 + package-lock.json | 13 +++++++++++++ package.json | 1 + 4 files changed, 16 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index 03110529d..b97a3b69c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,6 +25,7 @@ module.exports = { Feature: 'readonly', Scenario: 'readonly', context: 'readonly', + given: 'readonly', }, rules: { indent: ['error', 2], diff --git a/jest.config.js b/jest.config.js index d61e77449..2aaa5494c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,6 @@ module.exports = { setupFilesAfterEnv: [ + 'given2/setup', 'jest-plugin-context/setup', './jest.setup', ], diff --git a/package-lock.json b/package-lock.json index 73dff381f..f700d9ba6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.23.2", "eslint-plugin-react-hooks": "^4.2.0", + "given2": "^2.1.7", "jest": "^26.6.3", "jest-plugin-context": "^2.9.0", "puppeteer": "^9.1.1", @@ -7136,6 +7137,12 @@ "gherkin-javascript": "bin/gherkin" } }, + "node_modules/given2": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/given2/-/given2-2.1.7.tgz", + "integrity": "sha512-fI3VamsjN2euNVguGpSt2uExyDSMfJoK+SwDxbmV+Thf3v4oF6KKZAFE3LHHuT+PYyMwCsJYXO01TW3euFdPGA==", + "dev": true + }, "node_modules/glob": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", @@ -23110,6 +23117,12 @@ "integrity": "sha1-aEu7A63STq9731RPWAM+so+zxtU=", "dev": true }, + "given2": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/given2/-/given2-2.1.7.tgz", + "integrity": "sha512-fI3VamsjN2euNVguGpSt2uExyDSMfJoK+SwDxbmV+Thf3v4oF6KKZAFE3LHHuT+PYyMwCsJYXO01TW3euFdPGA==", + "dev": true + }, "glob": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", diff --git a/package.json b/package.json index 755704189..4aced5f57 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.23.2", "eslint-plugin-react-hooks": "^4.2.0", + "given2": "^2.1.7", "jest": "^26.6.3", "jest-plugin-context": "^2.9.0", "puppeteer": "^9.1.1", From 96d00559ace4438c213b91243b7f4fed24219fd8 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 15:47:20 +0900 Subject: [PATCH 25/55] =?UTF-8?q?eslint=EC=84=A4=EC=A0=95=EC=9D=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 4 + package-lock.json | 630 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + 3 files changed, 636 insertions(+) diff --git a/.eslintrc.js b/.eslintrc.js index b97a3b69c..ab70e10ea 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,6 +5,8 @@ module.exports = { jest: true, }, extends: [ + 'plugin:testing-library/react', + 'plugin:jest-dom/recommended', 'plugin:react/recommended', 'airbnb', ], @@ -53,5 +55,7 @@ module.exports = { 'react/prop-types': 'off', 'react/react-in-jsx-scope': 'off', + + 'testing-library/prefer-screen-queries': 'off', }, }; diff --git a/package-lock.json b/package-lock.json index f700d9ba6..ae1977874 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,9 +28,11 @@ "eslint": "^7.26.0", "eslint-config-airbnb": "^18.2.1", "eslint-plugin-import": "^2.23.2", + "eslint-plugin-jest-dom": "^3.9.0", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.23.2", "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-testing-library": "^4.6.0", "given2": "^2.1.7", "jest": "^26.6.3", "jest-plugin-context": "^2.9.0", @@ -2194,6 +2196,41 @@ "node": ">=8" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@sideway/address": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", @@ -2670,6 +2707,175 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.24.0.tgz", + "integrity": "sha512-IwTT2VNDKH1h8RZseMH4CcYBz6lTvRoOLDuuqNZZoThvfHEhOiZPQCow+5El3PtyxJ1iDr6UXZwYtE3yZQjhcw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.24.0", + "@typescript-eslint/types": "4.24.0", + "@typescript-eslint/typescript-estree": "4.24.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.24.0.tgz", + "integrity": "sha512-9+WYJGDnuC9VtYLqBhcSuM7du75fyCS/ypC8c5g7Sdw7pGL4NDTbeH38eJPfzIydCHZDoOgjloxSAA3+4l/zsA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.24.0", + "@typescript-eslint/visitor-keys": "4.24.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.24.0.tgz", + "integrity": "sha512-tkZUBgDQKdvfs8L47LaqxojKDE+mIUmOzdz7r+u+U54l3GDkTpEbQ1Jp3cNqqAU9vMUCBA1fitsIhm7yN0vx9Q==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.24.0.tgz", + "integrity": "sha512-kBDitL/by/HK7g8CYLT7aKpAwlR8doshfWz8d71j97n5kUa5caHWvY0RvEUEanL/EqBJoANev8Xc/mQ6LLwXGA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.24.0", + "@typescript-eslint/visitor-keys": "4.24.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.24.0.tgz", + "integrity": "sha512-4ox1sjmGHIxjEDBnMCtWFFhErXtKA1Ec0sBpuz0fqf3P+g3JFGyTxxbF06byw0FRsPnnbq44cKivH7Ks1/0s6g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.24.0", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", @@ -5149,6 +5355,27 @@ "node": ">= 10.14.2" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -5830,6 +6057,25 @@ "node": ">=4" } }, + "node_modules/eslint-plugin-jest-dom": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-3.9.0.tgz", + "integrity": "sha512-Ou3cuAAY9s6pYZv+KKPa9XquSzUAWW2CgE5al7cQ0yew25w/kp5kNsUJgESb3Pj00Y6pzvznepppL2sk7UOQKg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.9.6", + "@testing-library/dom": "^7.28.1", + "requireindex": "^1.2.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "eslint": ">=6.8" + } + }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", @@ -5918,6 +6164,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-testing-library": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-4.6.0.tgz", + "integrity": "sha512-s1ewfnLs8BF+apZ0kIvZhe5ejDgLtawIhc5Mec4aTJGQdrse6tP/RffWicwPENWh8SpmbetcklSR+14/jsnvGw==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "^4.24.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -6673,6 +6935,23 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -6691,6 +6970,15 @@ "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, + "node_modules/fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/faye-websocket": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", @@ -10915,6 +11203,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -12830,6 +13127,26 @@ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -13387,6 +13704,15 @@ "path-parse": "^1.0.5" } }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -13501,6 +13827,16 @@ "node": "*" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -13554,6 +13890,29 @@ "node": ">=0.12.0" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -15566,6 +15925,21 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -15636,6 +16010,20 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", @@ -19158,6 +19546,32 @@ } } }, + "@nodelib/fs.scandir": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.4", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.4", + "fastq": "^1.6.0" + } + }, "@sideway/address": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.2.tgz", @@ -19577,6 +19991,113 @@ "@types/node": "*" } }, + "@typescript-eslint/experimental-utils": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.24.0.tgz", + "integrity": "sha512-IwTT2VNDKH1h8RZseMH4CcYBz6lTvRoOLDuuqNZZoThvfHEhOiZPQCow+5El3PtyxJ1iDr6UXZwYtE3yZQjhcw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/scope-manager": "4.24.0", + "@typescript-eslint/types": "4.24.0", + "@typescript-eslint/typescript-estree": "4.24.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.24.0.tgz", + "integrity": "sha512-9+WYJGDnuC9VtYLqBhcSuM7du75fyCS/ypC8c5g7Sdw7pGL4NDTbeH38eJPfzIydCHZDoOgjloxSAA3+4l/zsA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.24.0", + "@typescript-eslint/visitor-keys": "4.24.0" + } + }, + "@typescript-eslint/types": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.24.0.tgz", + "integrity": "sha512-tkZUBgDQKdvfs8L47LaqxojKDE+mIUmOzdz7r+u+U54l3GDkTpEbQ1Jp3cNqqAU9vMUCBA1fitsIhm7yN0vx9Q==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.24.0.tgz", + "integrity": "sha512-kBDitL/by/HK7g8CYLT7aKpAwlR8doshfWz8d71j97n5kUa5caHWvY0RvEUEanL/EqBJoANev8Xc/mQ6LLwXGA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.24.0", + "@typescript-eslint/visitor-keys": "4.24.0", + "debug": "^4.1.1", + "globby": "^11.0.1", + "is-glob": "^4.0.1", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "dependencies": { + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "globby": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.24.0.tgz", + "integrity": "sha512-4ox1sjmGHIxjEDBnMCtWFFhErXtKA1Ec0sBpuz0fqf3P+g3JFGyTxxbF06byw0FRsPnnbq44cKivH7Ks1/0s6g==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.24.0", + "eslint-visitor-keys": "^2.0.0" + } + }, "@webassemblyjs/ast": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", @@ -21564,6 +22085,23 @@ "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + }, + "dependencies": { + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + } + } + }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -22210,6 +22748,17 @@ } } }, + "eslint-plugin-jest-dom": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest-dom/-/eslint-plugin-jest-dom-3.9.0.tgz", + "integrity": "sha512-Ou3cuAAY9s6pYZv+KKPa9XquSzUAWW2CgE5al7cQ0yew25w/kp5kNsUJgESb3Pj00Y6pzvznepppL2sk7UOQKg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.9.6", + "@testing-library/dom": "^7.28.1", + "requireindex": "^1.2.0" + } + }, "eslint-plugin-jsx-a11y": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", @@ -22277,6 +22826,15 @@ "dev": true, "requires": {} }, + "eslint-plugin-testing-library": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-4.6.0.tgz", + "integrity": "sha512-s1ewfnLs8BF+apZ0kIvZhe5ejDgLtawIhc5Mec4aTJGQdrse6tP/RffWicwPENWh8SpmbetcklSR+14/jsnvGw==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "^4.24.0" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -22772,6 +23330,20 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-glob": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -22790,6 +23362,15 @@ "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "faye-websocket": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", @@ -26014,6 +26595,12 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -27493,6 +28080,12 @@ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -27933,6 +28526,12 @@ } } }, + "requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -28026,6 +28625,12 @@ "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", "dev": true }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -28063,6 +28668,15 @@ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -29692,6 +30306,15 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -29747,6 +30370,13 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "dev": true, + "peer": true + }, "unbox-primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", diff --git a/package.json b/package.json index 4aced5f57..be1fa6555 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,11 @@ "eslint": "^7.26.0", "eslint-config-airbnb": "^18.2.1", "eslint-plugin-import": "^2.23.2", + "eslint-plugin-jest-dom": "^3.9.0", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.23.2", "eslint-plugin-react-hooks": "^4.2.0", + "eslint-plugin-testing-library": "^4.6.0", "given2": "^2.1.7", "jest": "^26.6.3", "jest-plugin-context": "^2.9.0", From 52fc06f0a85b4adbcfa0e91e2848770867baeca0 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 15:48:12 +0900 Subject: [PATCH 26/55] =?UTF-8?q?App=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC?= =?UTF-8?q?=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 116 +++++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 3fe4ee6cd..2a4cec630 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -6,75 +6,71 @@ import App from './App'; jest.mock('react-redux'); -it('renders tasks', () => { - useSelector.mockImplementation((selector) => selector({ - taskTitle: 'new Title', - tasks: [{ id: 1, title: 'codesoom' }], - })); - - const { getByText } = render(); - expect(getByText('codesoom')).toBeInTheDocument(); -}); +describe('App', () => { + let dispatch; + beforeEach(() => { + dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + }); -it('adds task to tasks with 추가 button', () => { - useSelector.mockImplementation((selector) => selector({ - taskTitle: 'new Title', - tasks: [{ id: 1, title: 'codesoom' }], - })); + it('renders tasks', () => { + useSelector.mockImplementation((selector) => selector( + { tasks: [{ id: 1, title: 'codesoom' }] }, + )); - const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); + const { getByText } = render(); + expect(getByText('codesoom')).toBeInTheDocument(); + }); - const { getByRole } = render(); - userEvent.click(getByRole('button', { name: '추가' })); + it('adds task to tasks with 추가 button', () => { + useSelector.mockImplementation((selector) => selector( + { tasks: [{ id: 1, title: 'codesoom' }] }, + )); - expect(dispatch).toBeCalledWith({ type: 'AddTask' }); -}); + const { getByRole } = render(); + userEvent.click(getByRole('button', { name: '추가' })); -it('deletes task from tasks with 완료 button', () => { - useSelector.mockImplementation((selector) => selector({ - taskTitle: 'new Title', - tasks: [{ id: 1, title: 'codesoom' }], - })); + expect(dispatch).toBeCalledWith({ type: 'AddTask' }); + }); - const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); + it('deletes task from tasks with 완료 button', () => { + useSelector.mockImplementation((selector) => selector( + { tasks: [{ id: 1, title: 'codesoom' }] }, + )); + + const { getByRole, getByText } = render(); + userEvent.click(getByRole('button', { name: '완료' })); + + userEvent.click( + within(getByText('codesoom')) + .getByRole('button', { name: '완료' }), + ); + + expect(dispatch).toBeCalledWith({ + type: 'DeleteTask', + payload: { + id: 1, + }, + }); + }); - const { getByRole, getByText } = render(); - userEvent.click(getByRole('button', { name: '완료' })); + it('updates taskTitle wiht input control', () => { + useSelector.mockImplementation((selector) => selector( + { taskTitle: '', tasks: [] }, + )); - userEvent.click( - within(getByText('codesoom')) - .getByRole('button', { name: '완료' }), - ); + const { getByRole } = render(); - expect(dispatch).toBeCalledWith({ - type: 'DeleteTask', - payload: { - id: 1, - }, - }); -}); + userEvent.type( + getByRole('textbox', { name: '할 일' }), + 'codesoom', + ); -it('updates taskTitle', () => { - useSelector.mockImplementation((selector) => selector({ - taskTitle: '', - tasks: [], - })); - - const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); - const { getByRole } = render(); - - userEvent.type( - getByRole('textbox', { name: '할 일' }), - 'codesoom', - ); - - expect(dispatch).toHaveBeenLastCalledWith({ - type: 'UpdateTaskTitle', - payload: { - taskTitle: 'm', - }, + expect(dispatch).toHaveBeenLastCalledWith({ + type: 'UpdateTaskTitle', + payload: { + taskTitle: 'm', + }, + }); }); }); From e462aa81d64ac61468e285aa9b06be7c9010ed64 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Mon, 24 May 2021 15:51:46 +0900 Subject: [PATCH 27/55] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20ex?= =?UTF-8?q?pect=EB=AC=B8=EC=9D=84=20=EC=82=AD=EC=A0=9C=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/reducer.test.js b/src/reducer.test.js index 5e6937489..a054ae5a1 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -49,7 +49,6 @@ describe('reducer', () => { const { tasks } = newState; expect(tasks).toHaveLength(0); - expect(tasks).toEqual([]); }); }); From bf249024e3fd4c2a54ce6dc3286857327946cb7f Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 11:01:12 +0900 Subject: [PATCH 28/55] =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=ED=97=A8=EB=93=A4=EB=9F=AC=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 477ed08f9..d4d5a54a5 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -12,8 +12,8 @@ export default function App() { const { taskTitle, tasks } = useSelector((state) => state); const dispatch = useDispatch(); - function handleChangeTitle(value) { - dispatch(updateTaskTitle(value)); + function handleChangeTitle(e) { + dispatch(updateTaskTitle(e.target.value)); } function handleClickAddTask() { @@ -26,10 +26,10 @@ export default function App() { return ( handleChangeTitle(e.target.value)} + onChangeTitle={handleChangeTitle} onClickAddTask={handleClickAddTask} - tasks={tasks} onClickDeleteTask={handleClickDeleteTask} /> ); From 1e47de1b2113d2d9e97d649fd6f8e50dac0227e9 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 11:02:37 +0900 Subject: [PATCH 29/55] =?UTF-8?q?userEvent=EC=97=90=EC=84=9C=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=ED=95=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=EB=A5=BC=20fir?= =?UTF-8?q?eEvent=EB=A5=BC=20=EB=8F=84=EC=9E=85=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 2a4cec630..3be8908e1 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -1,4 +1,4 @@ -import { render, within } from '@testing-library/react'; +import { fireEvent, render, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useDispatch, useSelector } from 'react-redux'; @@ -61,15 +61,15 @@ describe('App', () => { const { getByRole } = render(); - userEvent.type( + fireEvent.change( getByRole('textbox', { name: '할 일' }), - 'codesoom', + { target: { value: 'codesoom' } }, ); - expect(dispatch).toHaveBeenLastCalledWith({ + expect(dispatch).toBeCalledWith({ type: 'UpdateTaskTitle', payload: { - taskTitle: 'm', + taskTitle: 'codesoom', }, }); }); From 76fe63fd428edeb990a9979b3bacff0818d8a9e8 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 11:14:58 +0900 Subject: [PATCH 30/55] =?UTF-8?q?=EA=B0=9C=EB=B0=9C=EA=B3=BC=EC=A0=95=20?= =?UTF-8?q?=EC=A4=91=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=98=EA=B2=8C=20?= =?UTF-8?q?=EB=82=A8=EA=B2=A8=EC=A7=84=20=ED=81=B4=EB=A6=AD=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=EB=A5=BC=20=EC=A0=9C=EA=B1=B0=ED=95=98?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 3be8908e1..0a275570f 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -38,8 +38,7 @@ describe('App', () => { { tasks: [{ id: 1, title: 'codesoom' }] }, )); - const { getByRole, getByText } = render(); - userEvent.click(getByRole('button', { name: '완료' })); + const { getByText } = render(); userEvent.click( within(getByText('codesoom')) From ce7105e42258628c6bf274bcb4b39f8407c2a36b Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 11:43:58 +0900 Subject: [PATCH 31/55] =?UTF-8?q?mock=20clear=EC=9D=84=20=EC=9D=B4?= =?UTF-8?q?=EC=9A=A9=ED=95=B4=20let=EC=9D=84=20=EC=A0=9C=EA=B1=B0=ED=95=98?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 0a275570f..28c8030e0 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -7,9 +7,9 @@ import App from './App'; jest.mock('react-redux'); describe('App', () => { - let dispatch; + const dispatch = jest.fn(); beforeEach(() => { - dispatch = jest.fn(); + dispatch.mockClear(); useDispatch.mockImplementation(() => dispatch); }); From 3e8c75501105eb038bc61c3797ae0010ed1145e5 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 11:44:51 +0900 Subject: [PATCH 32/55] =?UTF-8?q?=EC=98=A4=ED=83=80=EB=A5=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 28c8030e0..fc16ae4f1 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -53,7 +53,7 @@ describe('App', () => { }); }); - it('updates taskTitle wiht input control', () => { + it('updates taskTitle with input control', () => { useSelector.mockImplementation((selector) => selector( { taskTitle: '', tasks: [] }, )); From 529cd26df9d8c637b3cbf425d5babb403143ad2c Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 11:51:00 +0900 Subject: [PATCH 33/55] =?UTF-8?q?context=EC=9D=98=20=EB=8C=80=EB=B9=84?= =?UTF-8?q?=EB=A5=BC=20=EA=B3=A0=EB=A0=A4=ED=95=98=EC=97=AC=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=EB=A5=BC=20=EC=88=98=EC=A0=95=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.test.js | 110 +++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/src/reducer.test.js b/src/reducer.test.js index a054ae5a1..545200818 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -6,84 +6,88 @@ import { } from './actions'; describe('reducer', () => { - describe('updateTaskTitle', () => { - it('updates title of task', () => { - const state = { - taskTitle: '', - }; + context('with invalid action', () => { + it('returns same state', () => { + const newState = reducer(undefined, { type: 'invaild' }); + expect(initialState).toEqual(newState); + }); + }); - const newState = reducer(state, updateTaskTitle('newTitle')); + context('with valid action', () => { + describe('updateTaskTitle', () => { + it('updates title of task', () => { + const state = { + taskTitle: '', + }; - expect(newState.taskTitle).toBe('newTitle'); + const newState = reducer(state, updateTaskTitle('newTitle')); + + expect(newState.taskTitle).toBe('newTitle'); + }); }); - }); - describe('addTask', () => { - context('with title', () => { - it('adds new task to tasks', () => { + describe('addTask', () => { + context('with title', () => { + it('adds new task to tasks', () => { + const state = { + taskTitle: 'new Title', + newId: 100, + tasks: [], + }; + + const newState = reducer(state, addTask()); + + const { tasks } = newState; + expect(tasks).toHaveLength(1); + expect(tasks[0]).toEqual({ id: 100, title: 'new Title' }); + }); + }); + + context('without title', () => { const state = { - taskTitle: 'new Title', + taskTitle: '', newId: 100, tasks: [], }; - const newState = reducer(state, addTask()); + const action = { + type: 'AddTask', + }; + + const newState = reducer(state, action); const { tasks } = newState; - expect(tasks).toHaveLength(1); - expect(tasks[0]).toEqual({ id: 100, title: 'new Title' }); + expect(tasks).toHaveLength(0); }); }); - context('without title', () => { - const state = { - taskTitle: '', - newId: 100, - tasks: [], - }; - - const action = { - type: 'AddTask', - }; + describe('deleteTask', () => { + context('with existing id', () => { + it('delete task from tasks', () => { + const state = { + taskTitle: 'new Title', + newId: 100, + tasks: [{ id: 1, title: 'codeSoom' }], + }; - const newState = reducer(state, action); + const newState = reducer(state, deleteTask(1)); - const { tasks } = newState; - expect(tasks).toHaveLength(0); - }); - }); + const { tasks } = newState; + expect(tasks).toHaveLength(0); + }); + }); - describe('deleteTask', () => { - context('with existing id', () => { - it('delete task from tasks', () => { + context('with non-existing id', () => { const state = { taskTitle: 'new Title', newId: 100, tasks: [{ id: 1, title: 'codeSoom' }], }; - const newState = reducer(state, deleteTask(1)); + const newState = reducer(state, deleteTask(2)); const { tasks } = newState; - expect(tasks).toHaveLength(0); + expect(tasks).toHaveLength(1); }); }); - - context('with non-existing id', () => { - const state = { - taskTitle: 'new Title', - newId: 100, - tasks: [{ id: 1, title: 'codeSoom' }], - }; - - const newState = reducer(state, deleteTask(2)); - - const { tasks } = newState; - expect(tasks).toHaveLength(1); - }); - }); - - context('when invalid action is given', () => { - const newState = reducer(undefined, { type: 'invaild' }); - expect(initialState).toEqual(newState); }); }); From 5b812ac48aa493a0aa0b9c5dc4e4a4c92833433a Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 11:59:57 +0900 Subject: [PATCH 34/55] =?UTF-8?q?=EC=95=A1=EC=85=98=ED=83=80=EC=9E=85?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=9D=84=20=EC=9D=BD=EA=B8=B0=20=EC=A2=8B?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/actions.js | 6 +++--- src/reducer.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/actions.js b/src/actions.js index 7d021b843..6c4a46631 100644 --- a/src/actions.js +++ b/src/actions.js @@ -1,16 +1,16 @@ export const updateTaskTitle = (newTitle) => ({ - type: 'UpdateTaskTitle', + type: 'tasks/updateTitle', payload: { taskTitle: newTitle, }, }); export const addTask = () => ({ - type: 'AddTask', + type: 'tasks/addNewTask', }); export const deleteTask = (id) => ({ - type: 'DeleteTask', + type: 'tasks/deleteTask', payload: { id, }, diff --git a/src/reducer.js b/src/reducer.js index 50b134aa7..5b2a20d14 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -8,13 +8,13 @@ export default function reducer(state = initialState, action) { const { newId, tasks, taskTitle } = state; switch (action.type) { - case ('UpdateTaskTitle'): + case ('tasks/updateTitle'): return { ...state, taskTitle: action.payload.taskTitle, }; - case ('AddTask'): + case ('tasks/addNewTask'): if (taskTitle === '') { return state; } @@ -25,7 +25,7 @@ export default function reducer(state = initialState, action) { tasks: [...tasks, { id: newId, title: taskTitle }], }; - case ('DeleteTask'): + case ('tasks/deleteTask'): return { ...state, tasks: tasks.filter((task) => task.id !== action.payload.id), From e81648da5651a404226fc295075d9b81c3a19c4e Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 12:19:01 +0900 Subject: [PATCH 35/55] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EC=97=90=EC=84=9C=20=EC=95=A1=EC=85=98=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=EC=A7=81=EC=A0=91=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EB=A7=90=EA=B3=A0=20=EC=95=A1=EC=85=98?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=A8=EC=88=98=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 22 +++++++++------------- src/reducer.test.js | 6 +----- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index fc16ae4f1..3597e789d 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -2,6 +2,12 @@ import { fireEvent, render, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useDispatch, useSelector } from 'react-redux'; +import { + updateTaskTitle, + addTask, + deleteTask, +} from './actions'; + import App from './App'; jest.mock('react-redux'); @@ -30,7 +36,7 @@ describe('App', () => { const { getByRole } = render(); userEvent.click(getByRole('button', { name: '추가' })); - expect(dispatch).toBeCalledWith({ type: 'AddTask' }); + expect(dispatch).toBeCalledWith(addTask()); }); it('deletes task from tasks with 완료 button', () => { @@ -45,12 +51,7 @@ describe('App', () => { .getByRole('button', { name: '완료' }), ); - expect(dispatch).toBeCalledWith({ - type: 'DeleteTask', - payload: { - id: 1, - }, - }); + expect(dispatch).toBeCalledWith(deleteTask(1)); }); it('updates taskTitle with input control', () => { @@ -65,11 +66,6 @@ describe('App', () => { { target: { value: 'codesoom' } }, ); - expect(dispatch).toBeCalledWith({ - type: 'UpdateTaskTitle', - payload: { - taskTitle: 'codesoom', - }, - }); + expect(dispatch).toBeCalledWith(updateTaskTitle('codesoom')); }); }); diff --git a/src/reducer.test.js b/src/reducer.test.js index 545200818..69d029703 100644 --- a/src/reducer.test.js +++ b/src/reducer.test.js @@ -49,11 +49,7 @@ describe('reducer', () => { tasks: [], }; - const action = { - type: 'AddTask', - }; - - const newState = reducer(state, action); + const newState = reducer(state, addTask()); const { tasks } = newState; expect(tasks).toHaveLength(0); From 0d64e7ad0a62e7b5b64a0d1abc5f021c6dfd3f06 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 12:24:05 +0900 Subject: [PATCH 36/55] =?UTF-8?q?=EB=A6=AC=EB=93=80=EC=84=9C=EC=97=90?= =?UTF-8?q?=EC=84=9C=20switch=EB=AC=B8=EC=9D=84=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/reducer.js | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/reducer.js b/src/reducer.js index 5b2a20d14..b541180fa 100644 --- a/src/reducer.js +++ b/src/reducer.js @@ -7,31 +7,30 @@ export const initialState = { export default function reducer(state = initialState, action) { const { newId, tasks, taskTitle } = state; - switch (action.type) { - case ('tasks/updateTitle'): - return { - ...state, + const operatorOnState = { + 'tasks/updateTitle': (oldState) => ({ + ...oldState, taskTitle: action.payload.taskTitle, - }; + }), - case ('tasks/addNewTask'): - if (taskTitle === '') { - return state; - } - return { - ...state, - newId: newId + 1, - taskTitle: '', - tasks: [...tasks, { id: newId, title: taskTitle }], - }; + 'tasks/addNewTask': (oldState) => { + if (taskTitle === '') { + return oldState; + } + return { + ...oldState, + newId: newId + 1, + taskTitle: '', + tasks: [...tasks, { id: newId, title: taskTitle }], + }; + }, - case ('tasks/deleteTask'): - return { - ...state, + 'tasks/deleteTask': (oldState) => ({ + ...oldState, tasks: tasks.filter((task) => task.id !== action.payload.id), - }; + }), + }; - default: - return state; - } + const getNewState = operatorOnState[action.type]; + return getNewState ? getNewState(state) : state; } From b0c928e4212bbe7e5398025b6851c2b368c8da0e Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 12:54:32 +0900 Subject: [PATCH 37/55] =?UTF-8?q?=EB=B0=98=EB=B3=B5=EB=90=98=EB=8A=94=20us?= =?UTF-8?q?eSelector=20mock=20implementation=EC=BD=94=EB=93=9C=EB=A5=BC=20?= =?UTF-8?q?beforeEach=EB=A1=9C=20=EC=98=AE=EA=B2=A8=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 3597e789d..e77cabb19 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -17,22 +17,21 @@ describe('App', () => { beforeEach(() => { dispatch.mockClear(); useDispatch.mockImplementation(() => dispatch); - }); - it('renders tasks', () => { useSelector.mockImplementation((selector) => selector( - { tasks: [{ id: 1, title: 'codesoom' }] }, + { + taskTitle: '', + tasks: [{ id: 1, title: 'codesoom' }], + }, )); + }); + it('renders tasks', () => { const { getByText } = render(); expect(getByText('codesoom')).toBeInTheDocument(); }); it('adds task to tasks with 추가 button', () => { - useSelector.mockImplementation((selector) => selector( - { tasks: [{ id: 1, title: 'codesoom' }] }, - )); - const { getByRole } = render(); userEvent.click(getByRole('button', { name: '추가' })); @@ -40,10 +39,6 @@ describe('App', () => { }); it('deletes task from tasks with 완료 button', () => { - useSelector.mockImplementation((selector) => selector( - { tasks: [{ id: 1, title: 'codesoom' }] }, - )); - const { getByText } = render(); userEvent.click( @@ -55,10 +50,6 @@ describe('App', () => { }); it('updates taskTitle with input control', () => { - useSelector.mockImplementation((selector) => selector( - { taskTitle: '', tasks: [] }, - )); - const { getByRole } = render(); fireEvent.change( From 3e519967c485f9c46abb5e978f393ce37f60bfcf Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 17:13:52 +0900 Subject: [PATCH 38/55] =?UTF-8?q?toBeInTheDocument=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=97=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B0=80=EB=8F=85=EC=84=B1=EC=9D=84=20=EA=B0=9C=EC=84=A0?= =?UTF-8?q?=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Input.test.jsx | 2 +- src/List.test.jsx | 6 +++--- src/Page.test.jsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Input.test.jsx b/src/Input.test.jsx index ee1a8bcbc..b8349132f 100644 --- a/src/Input.test.jsx +++ b/src/Input.test.jsx @@ -14,7 +14,7 @@ test('Input', () => { /> )); - expect(getByDisplayValue('기존 할 일')).not.toBeNull(); + expect(getByDisplayValue('기존 할 일')).toBeInTheDocument(); fireEvent.change(getByLabelText('할 일'), { target: { value: '무언가 하기' }, diff --git a/src/List.test.jsx b/src/List.test.jsx index 977ea0364..f62a38ede 100644 --- a/src/List.test.jsx +++ b/src/List.test.jsx @@ -37,8 +37,8 @@ describe('List', () => { it('renders tasks', () => { const { getByText } = renderList(tasks); - expect(getByText(/Task-1/)).not.toBeNull(); - expect(getByText(/Task-2/)).not.toBeNull(); + expect(getByText(/Task-1/)).toBeInTheDocument(); + expect(getByText(/Task-2/)).toBeInTheDocument(); }); it('renders “완료” button to delete a task', () => { @@ -58,7 +58,7 @@ describe('List', () => { const { getByText } = renderList(tasks); - expect(getByText(/할 일이 없어요/)).not.toBeNull(); + expect(getByText(/할 일이 없어요/)).toBeInTheDocument(); }); }); }); diff --git a/src/Page.test.jsx b/src/Page.test.jsx index 6e176f1ff..9894ce585 100644 --- a/src/Page.test.jsx +++ b/src/Page.test.jsx @@ -22,8 +22,8 @@ test('Page', () => { /> )); - expect(getByText(/Task-1/)).not.toBeNull(); - expect(getByText(/Task-2/)).not.toBeNull(); + expect(getByText(/Task-1/)).toBeInTheDocument(); + expect(getByText(/Task-2/)).toBeInTheDocument(); fireEvent.click(getByText('추가')); From 406ce5f5fc07b7566b9802af3d15c49ad46ff0c7 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 17:18:12 +0900 Subject: [PATCH 39/55] =?UTF-8?q?=ED=8F=B4=EB=8D=94=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=EB=A5=BC=20=EB=B3=80=EA=B2=BD=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {src/__mock__ => __mock__}/react-redux.js | 0 src/App.jsx | 4 ++-- src/App.test.jsx | 2 +- src/index.jsx | 2 +- src/{ => presentational}/Input.jsx | 0 src/{ => presentational}/Input.test.jsx | 0 src/{ => presentational}/Item.jsx | 0 src/{ => presentational}/Item.test.jsx | 0 src/{ => presentational}/List.jsx | 0 src/{ => presentational}/List.test.jsx | 0 src/{ => presentational}/Page.jsx | 0 src/{ => presentational}/Page.test.jsx | 0 src/{ => redux}/actions.js | 0 src/{ => redux}/reducer.js | 0 src/{ => redux}/reducer.test.js | 0 src/{ => redux}/store.js | 0 16 files changed, 4 insertions(+), 4 deletions(-) rename {src/__mock__ => __mock__}/react-redux.js (100%) rename src/{ => presentational}/Input.jsx (100%) rename src/{ => presentational}/Input.test.jsx (100%) rename src/{ => presentational}/Item.jsx (100%) rename src/{ => presentational}/Item.test.jsx (100%) rename src/{ => presentational}/List.jsx (100%) rename src/{ => presentational}/List.test.jsx (100%) rename src/{ => presentational}/Page.jsx (100%) rename src/{ => presentational}/Page.test.jsx (100%) rename src/{ => redux}/actions.js (100%) rename src/{ => redux}/reducer.js (100%) rename src/{ => redux}/reducer.test.js (100%) rename src/{ => redux}/store.js (100%) diff --git a/src/__mock__/react-redux.js b/__mock__/react-redux.js similarity index 100% rename from src/__mock__/react-redux.js rename to __mock__/react-redux.js diff --git a/src/App.jsx b/src/App.jsx index d4d5a54a5..8069da7ab 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,9 +4,9 @@ import { updateTaskTitle, addTask, deleteTask, -} from './actions'; +} from './redux/actions'; -import Page from './Page'; +import Page from './presentational/Page'; export default function App() { const { taskTitle, tasks } = useSelector((state) => state); diff --git a/src/App.test.jsx b/src/App.test.jsx index e77cabb19..d337c2861 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -6,7 +6,7 @@ import { updateTaskTitle, addTask, deleteTask, -} from './actions'; +} from './redux/actions'; import App from './App'; diff --git a/src/index.jsx b/src/index.jsx index 7dc6b2529..f6f4a5813 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -2,7 +2,7 @@ import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import App from './App'; -import store from './store'; +import store from './redux/store'; ReactDOM.render( ( diff --git a/src/Input.jsx b/src/presentational/Input.jsx similarity index 100% rename from src/Input.jsx rename to src/presentational/Input.jsx diff --git a/src/Input.test.jsx b/src/presentational/Input.test.jsx similarity index 100% rename from src/Input.test.jsx rename to src/presentational/Input.test.jsx diff --git a/src/Item.jsx b/src/presentational/Item.jsx similarity index 100% rename from src/Item.jsx rename to src/presentational/Item.jsx diff --git a/src/Item.test.jsx b/src/presentational/Item.test.jsx similarity index 100% rename from src/Item.test.jsx rename to src/presentational/Item.test.jsx diff --git a/src/List.jsx b/src/presentational/List.jsx similarity index 100% rename from src/List.jsx rename to src/presentational/List.jsx diff --git a/src/List.test.jsx b/src/presentational/List.test.jsx similarity index 100% rename from src/List.test.jsx rename to src/presentational/List.test.jsx diff --git a/src/Page.jsx b/src/presentational/Page.jsx similarity index 100% rename from src/Page.jsx rename to src/presentational/Page.jsx diff --git a/src/Page.test.jsx b/src/presentational/Page.test.jsx similarity index 100% rename from src/Page.test.jsx rename to src/presentational/Page.test.jsx diff --git a/src/actions.js b/src/redux/actions.js similarity index 100% rename from src/actions.js rename to src/redux/actions.js diff --git a/src/reducer.js b/src/redux/reducer.js similarity index 100% rename from src/reducer.js rename to src/redux/reducer.js diff --git a/src/reducer.test.js b/src/redux/reducer.test.js similarity index 100% rename from src/reducer.test.js rename to src/redux/reducer.test.js diff --git a/src/store.js b/src/redux/store.js similarity index 100% rename from src/store.js rename to src/redux/store.js From f3fa683caf3e0007e2f4d82925201b176863f6d3 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 19:45:55 +0900 Subject: [PATCH 40/55] =?UTF-8?q?InputContainer=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=9E=91=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 14 +------------- src/container/InputContainer.jsx | 3 +++ src/container/InputContainer.test.jsx | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 src/container/InputContainer.jsx create mode 100644 src/container/InputContainer.test.jsx diff --git a/src/App.test.jsx b/src/App.test.jsx index d337c2861..7e3081baa 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -1,9 +1,8 @@ -import { fireEvent, render, within } from '@testing-library/react'; +import { render, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useDispatch, useSelector } from 'react-redux'; import { - updateTaskTitle, addTask, deleteTask, } from './redux/actions'; @@ -48,15 +47,4 @@ describe('App', () => { expect(dispatch).toBeCalledWith(deleteTask(1)); }); - - it('updates taskTitle with input control', () => { - const { getByRole } = render(); - - fireEvent.change( - getByRole('textbox', { name: '할 일' }), - { target: { value: 'codesoom' } }, - ); - - expect(dispatch).toBeCalledWith(updateTaskTitle('codesoom')); - }); }); diff --git a/src/container/InputContainer.jsx b/src/container/InputContainer.jsx new file mode 100644 index 000000000..49d4b9704 --- /dev/null +++ b/src/container/InputContainer.jsx @@ -0,0 +1,3 @@ +export default function InputContainer() { + +} diff --git a/src/container/InputContainer.test.jsx b/src/container/InputContainer.test.jsx new file mode 100644 index 000000000..48c1327bb --- /dev/null +++ b/src/container/InputContainer.test.jsx @@ -0,0 +1,22 @@ +import { fireEvent, render } from '@testing-library/react'; +import { useDispatch, useSelector } from 'react-redux'; + +import InputContainer from './InputContainer'; +import { updateTaskTitle } from '../redux/actions'; + +jest.mock('react-redux'); + +it('updates taskTitle with input control', () => { + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + useSelector.mockImplementation((selector) => selector({ taskTitle: '' })); + + const { getByRole } = render(); + + fireEvent.change( + getByRole('textbox', { name: '할 일' }), + { target: { value: 'codesoom' } }, + ); + + expect(dispatch).toBeCalledWith(updateTaskTitle('codesoom')); +}); From 70b673e515502ca07d74896b8c70bb18fc2279b8 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:02:26 +0900 Subject: [PATCH 41/55] =?UTF-8?q?InputContainer=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/container/InputContainer.jsx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/container/InputContainer.jsx b/src/container/InputContainer.jsx index 49d4b9704..61e854a5f 100644 --- a/src/container/InputContainer.jsx +++ b/src/container/InputContainer.jsx @@ -1,3 +1,28 @@ +import { useDispatch, useSelector } from 'react-redux'; + +import Input from '../presentational/Input'; +import { + updateTaskTitle, + addTask, +} from '../redux/actions'; + export default function InputContainer() { + const { taskTitle } = useSelector((state) => state); + const dispatch = useDispatch(); + + function handleChangeTitle(e) { + dispatch(updateTaskTitle(e.target.value)); + } + + function handleClickAddTask() { + dispatch(addTask()); + } + return ( + + ); } From 9be1239e3442f50445ecb7fcfcfa0d079c4d0ad8 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:06:18 +0900 Subject: [PATCH 42/55] =?UTF-8?q?App=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9D=BC=EB=B6=80=EB=A5=BC=20InputContainer=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EC=98=AE=EA=B2=A8=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 8 -------- src/container/InputContainer.test.jsx | 14 +++++++++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 7e3081baa..26a70b134 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -3,7 +3,6 @@ import userEvent from '@testing-library/user-event'; import { useDispatch, useSelector } from 'react-redux'; import { - addTask, deleteTask, } from './redux/actions'; @@ -30,13 +29,6 @@ describe('App', () => { expect(getByText('codesoom')).toBeInTheDocument(); }); - it('adds task to tasks with 추가 button', () => { - const { getByRole } = render(); - userEvent.click(getByRole('button', { name: '추가' })); - - expect(dispatch).toBeCalledWith(addTask()); - }); - it('deletes task from tasks with 완료 button', () => { const { getByText } = render(); diff --git a/src/container/InputContainer.test.jsx b/src/container/InputContainer.test.jsx index 48c1327bb..5dccd75b8 100644 --- a/src/container/InputContainer.test.jsx +++ b/src/container/InputContainer.test.jsx @@ -2,7 +2,10 @@ import { fireEvent, render } from '@testing-library/react'; import { useDispatch, useSelector } from 'react-redux'; import InputContainer from './InputContainer'; -import { updateTaskTitle } from '../redux/actions'; +import { + updateTaskTitle, + addTask, +} from '../redux/actions'; jest.mock('react-redux'); @@ -20,3 +23,12 @@ it('updates taskTitle with input control', () => { expect(dispatch).toBeCalledWith(updateTaskTitle('codesoom')); }); + +it('adds task to tasks with 추가 button', () => { + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + const { getByRole } = render(); + fireEvent.click(getByRole('button', { name: '추가' })); + + expect(dispatch).toBeCalledWith(addTask()); +}); From a3e5891d13bdbec294e9d68d70b25a16336424d2 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:10:19 +0900 Subject: [PATCH 43/55] =?UTF-8?q?Input=EC=9D=98=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=95=98=EA=B3=A0=20=EB=A0=8C=EB=8D=94?= =?UTF-8?q?=EB=A7=81=EC=9D=84=20=ED=99=95=EC=9D=B8=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A7=8C=20=EB=82=A8=EA=B2=A8?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/presentational/Input.test.jsx | 32 ++++++++----------------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/presentational/Input.test.jsx b/src/presentational/Input.test.jsx index b8349132f..c6ad17d50 100644 --- a/src/presentational/Input.test.jsx +++ b/src/presentational/Input.test.jsx @@ -1,28 +1,12 @@ -import { render, fireEvent } from '@testing-library/react'; - +import { render } from '@testing-library/react'; import Input from './Input'; -test('Input', () => { - const handleChange = jest.fn(); - const handleClick = jest.fn(); - - const { getByDisplayValue, getByLabelText, getByText } = render(( - - )); - - expect(getByDisplayValue('기존 할 일')).toBeInTheDocument(); - - fireEvent.change(getByLabelText('할 일'), { - target: { value: '무언가 하기' }, - }); - - expect(handleChange).toBeCalled(); - - fireEvent.click(getByText('추가')); +it('renders input control', () => { + const { getByPlaceholderText } = render(); + expect(getByPlaceholderText('할 일을 입력해 주세요')).toBeInTheDocument(); +}); - expect(handleClick).toBeCalled(); +it('renders 추가 button', () => { + const { getByRole } = render(); + expect(getByRole('button', { name: '추가' })).toBeInTheDocument(); }); From 0126875e1fbb12d2cca39b591b00ca1215d1bf4f Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:12:38 +0900 Subject: [PATCH 44/55] =?UTF-8?q?InputContainer=EC=9D=84=20=EC=83=81?= =?UTF-8?q?=EC=9C=84=EC=97=90=EC=84=9C=20Input=EB=8C=80=EC=8B=A0=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EA=B2=8C=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 15 +-------------- src/presentational/Page.jsx | 9 ++------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 8069da7ab..ea0860eba 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,25 +1,15 @@ import { useDispatch, useSelector } from 'react-redux'; import { - updateTaskTitle, - addTask, deleteTask, } from './redux/actions'; import Page from './presentational/Page'; export default function App() { - const { taskTitle, tasks } = useSelector((state) => state); + const { tasks } = useSelector((state) => state); const dispatch = useDispatch(); - function handleChangeTitle(e) { - dispatch(updateTaskTitle(e.target.value)); - } - - function handleClickAddTask() { - dispatch(addTask()); - } - function handleClickDeleteTask(id) { dispatch(deleteTask(id)); } @@ -27,9 +17,6 @@ export default function App() { return ( ); diff --git a/src/presentational/Page.jsx b/src/presentational/Page.jsx index 535513a29..0929570c4 100644 --- a/src/presentational/Page.jsx +++ b/src/presentational/Page.jsx @@ -1,18 +1,13 @@ -import Input from './Input'; +import InputContainer from '../container/InputContainer'; import List from './List'; export default function Page({ - taskTitle, onChangeTitle, onClickAddTask, tasks, onClickDeleteTask, }) { return (

To-do

- + Date: Tue, 25 May 2021 20:14:47 +0900 Subject: [PATCH 45/55] =?UTF-8?q?InputContainer=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=97=90=EC=84=9C=20beforeEach=EB=A1=9C=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EC=9D=84=20=EC=A0=9C=EA=B1=B0=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/container/InputContainer.test.jsx | 37 +++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/container/InputContainer.test.jsx b/src/container/InputContainer.test.jsx index 5dccd75b8..7d12a823f 100644 --- a/src/container/InputContainer.test.jsx +++ b/src/container/InputContainer.test.jsx @@ -9,26 +9,31 @@ import { jest.mock('react-redux'); -it('updates taskTitle with input control', () => { +describe('InputContainer', () => { const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); - useSelector.mockImplementation((selector) => selector({ taskTitle: '' })); + beforeEach(() => { + dispatch.mockClear(); + useDispatch.mockImplementation(() => dispatch); + }); - const { getByRole } = render(); + it('updates taskTitle with input control', () => { + useSelector.mockImplementation((selector) => selector({ taskTitle: '' })); - fireEvent.change( - getByRole('textbox', { name: '할 일' }), - { target: { value: 'codesoom' } }, - ); + const { getByRole } = render(); - expect(dispatch).toBeCalledWith(updateTaskTitle('codesoom')); -}); + fireEvent.change( + getByRole('textbox', { name: '할 일' }), + { target: { value: 'codesoom' } }, + ); -it('adds task to tasks with 추가 button', () => { - const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); - const { getByRole } = render(); - fireEvent.click(getByRole('button', { name: '추가' })); + expect(dispatch).toBeCalledWith(updateTaskTitle('codesoom')); + }); + + it('adds task to tasks with 추가 button', () => { + const { getByRole } = render(); + + fireEvent.click(getByRole('button', { name: '추가' })); - expect(dispatch).toBeCalledWith(addTask()); + expect(dispatch).toBeCalledWith(addTask()); + }); }); From 8e42a7bdd3dad4abb678f256b5dfbf6a805c690e Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:21:37 +0900 Subject: [PATCH 46/55] =?UTF-8?q?List=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=ED=95=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/presentational/List.test.jsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/presentational/List.test.jsx b/src/presentational/List.test.jsx index f62a38ede..ceab6e11d 100644 --- a/src/presentational/List.test.jsx +++ b/src/presentational/List.test.jsx @@ -1,4 +1,4 @@ -import { render, fireEvent } from '@testing-library/react'; +import { render } from '@testing-library/react'; import List from './List'; @@ -44,11 +44,7 @@ describe('List', () => { it('renders “완료” button to delete a task', () => { const { getAllByText } = renderList(tasks); - const buttons = getAllByText('완료'); - - fireEvent.click(buttons[0]); - - expect(handleClickDelete).toBeCalledWith(1); + expect(getAllByText(/완료/)).toHaveLength(tasks.length); }); }); From ef975fb9aa75a491c64f263e655e5868920879c6 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:27:48 +0900 Subject: [PATCH 47/55] =?UTF-8?q?ListContainer=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A5=BC=20=EC=9E=91=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 26 +++---------------------- src/container/ListContainer.jsx | 0 src/container/ListContainer.test.jsx | 29 ++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 src/container/ListContainer.jsx create mode 100644 src/container/ListContainer.test.jsx diff --git a/src/App.test.jsx b/src/App.test.jsx index 26a70b134..17006d197 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -1,19 +1,13 @@ -import { render, within } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { render } from '@testing-library/react'; import { useDispatch, useSelector } from 'react-redux'; -import { - deleteTask, -} from './redux/actions'; - import App from './App'; jest.mock('react-redux'); describe('App', () => { - const dispatch = jest.fn(); - beforeEach(() => { - dispatch.mockClear(); + it('renders tasks', () => { + const dispatch = jest.fn(); useDispatch.mockImplementation(() => dispatch); useSelector.mockImplementation((selector) => selector( @@ -22,21 +16,7 @@ describe('App', () => { tasks: [{ id: 1, title: 'codesoom' }], }, )); - }); - - it('renders tasks', () => { const { getByText } = render(); expect(getByText('codesoom')).toBeInTheDocument(); }); - - it('deletes task from tasks with 완료 button', () => { - const { getByText } = render(); - - userEvent.click( - within(getByText('codesoom')) - .getByRole('button', { name: '완료' }), - ); - - expect(dispatch).toBeCalledWith(deleteTask(1)); - }); }); diff --git a/src/container/ListContainer.jsx b/src/container/ListContainer.jsx new file mode 100644 index 000000000..e69de29bb diff --git a/src/container/ListContainer.test.jsx b/src/container/ListContainer.test.jsx new file mode 100644 index 000000000..cf0ea6ec0 --- /dev/null +++ b/src/container/ListContainer.test.jsx @@ -0,0 +1,29 @@ +import { fireEvent, render, within } from '@testing-library/react'; +import { useDispatch, useSelector } from 'react-redux'; + +import ListContainer from './ListContainer'; +import { deleteTask } from '../redux/actions'; + +jest.mock('react-redux'); + +describe('ListContainer', () => { + it('deletes task from tasks with 완료 button', () => { + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + useSelector.mockImplementation((selector) => selector( + { + taskTitle: '', + tasks: [{ id: 1, title: 'codesoom' }], + }, + )); + + const { getByText } = render(); + + fireEvent.click( + within(getByText('codesoom')) + .getByRole('button', { name: '완료' }), + ); + + expect(dispatch).toBeCalledWith(deleteTask(1)); + }); +}); From 5893201c733acc2bbcd309c850d8dde46da56657 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:30:00 +0900 Subject: [PATCH 48/55] =?UTF-8?q?ListContainer=EB=A5=BC=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/container/ListContainer.jsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/container/ListContainer.jsx b/src/container/ListContainer.jsx index e69de29bb..ee9274a3c 100644 --- a/src/container/ListContainer.jsx +++ b/src/container/ListContainer.jsx @@ -0,0 +1,20 @@ +import { useDispatch, useSelector } from 'react-redux'; + +import List from '../presentational/List'; +import { deleteTask } from '../redux/actions'; + +export default function ListContainer() { + const { tasks } = useSelector((state) => state); + const dispatch = useDispatch(); + + function handleClickDeleteTask(id) { + dispatch(deleteTask(id)); + } + + return ( + + ); +} From afdd9aa9c7ea09c57e20db9cac5a9617e2cd7ca3 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:31:20 +0900 Subject: [PATCH 49/55] =?UTF-8?q?ListContainer=EB=A5=BC=20=EC=83=81?= =?UTF-8?q?=EC=9C=84=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=82=AC=EC=9A=A9=ED=95=98=EA=B2=8C=ED=95=98?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 18 +----------------- src/presentational/Page.jsx | 11 +++-------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index ea0860eba..92af82206 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,23 +1,7 @@ -import { useDispatch, useSelector } from 'react-redux'; - -import { - deleteTask, -} from './redux/actions'; - import Page from './presentational/Page'; export default function App() { - const { tasks } = useSelector((state) => state); - const dispatch = useDispatch(); - - function handleClickDeleteTask(id) { - dispatch(deleteTask(id)); - } - return ( - + ); } diff --git a/src/presentational/Page.jsx b/src/presentational/Page.jsx index 0929570c4..a477cb725 100644 --- a/src/presentational/Page.jsx +++ b/src/presentational/Page.jsx @@ -1,17 +1,12 @@ import InputContainer from '../container/InputContainer'; -import List from './List'; +import ListContainer from '../container/ListContainer'; -export default function Page({ - tasks, onClickDeleteTask, -}) { +export default function Page() { return (

To-do

- +
); } From 396502d7e9294d11dc2cd4f47d78ac23df76182e Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:32:44 +0900 Subject: [PATCH 50/55] =?UTF-8?q?Page=EB=A5=BC=20TodoPage=EB=A1=9C=20renam?= =?UTF-8?q?e=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 4 ++-- src/presentational/{Page.jsx => TodoPage.jsx} | 2 +- src/presentational/{Page.test.jsx => TodoPage.test.jsx} | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/presentational/{Page.jsx => TodoPage.jsx} (85%) rename src/presentational/{Page.test.jsx => TodoPage.test.jsx} (93%) diff --git a/src/App.jsx b/src/App.jsx index 92af82206..5760282d2 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,7 @@ -import Page from './presentational/Page'; +import TodoPage from './presentational/TodoPage'; export default function App() { return ( - + ); } diff --git a/src/presentational/Page.jsx b/src/presentational/TodoPage.jsx similarity index 85% rename from src/presentational/Page.jsx rename to src/presentational/TodoPage.jsx index a477cb725..b8b031b50 100644 --- a/src/presentational/Page.jsx +++ b/src/presentational/TodoPage.jsx @@ -1,7 +1,7 @@ import InputContainer from '../container/InputContainer'; import ListContainer from '../container/ListContainer'; -export default function Page() { +export default function TodoPage() { return (

To-do

diff --git a/src/presentational/Page.test.jsx b/src/presentational/TodoPage.test.jsx similarity index 93% rename from src/presentational/Page.test.jsx rename to src/presentational/TodoPage.test.jsx index 9894ce585..89bb68952 100644 --- a/src/presentational/Page.test.jsx +++ b/src/presentational/TodoPage.test.jsx @@ -1,6 +1,6 @@ import { render, fireEvent } from '@testing-library/react'; -import Page from './Page'; +import TodoPage from './TodoPage'; test('Page', () => { const handleChangeTitle = jest.fn(); @@ -13,7 +13,7 @@ test('Page', () => { ]; const { getByText } = render(( - Date: Tue, 25 May 2021 20:43:40 +0900 Subject: [PATCH 51/55] =?UTF-8?q?=EC=85=80=EB=A0=89=ED=84=B0=EB=A1=9C=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EA=B0=92=EB=A7=8C=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EC=97=90=EC=84=9C=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/container/InputContainer.jsx | 2 +- src/container/ListContainer.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/container/InputContainer.jsx b/src/container/InputContainer.jsx index 61e854a5f..ac3b5d8d9 100644 --- a/src/container/InputContainer.jsx +++ b/src/container/InputContainer.jsx @@ -7,7 +7,7 @@ import { } from '../redux/actions'; export default function InputContainer() { - const { taskTitle } = useSelector((state) => state); + const taskTitle = useSelector((state) => state.taskTitle); const dispatch = useDispatch(); function handleChangeTitle(e) { diff --git a/src/container/ListContainer.jsx b/src/container/ListContainer.jsx index ee9274a3c..71d98aa26 100644 --- a/src/container/ListContainer.jsx +++ b/src/container/ListContainer.jsx @@ -4,7 +4,7 @@ import List from '../presentational/List'; import { deleteTask } from '../redux/actions'; export default function ListContainer() { - const { tasks } = useSelector((state) => state); + const tasks = useSelector((state) => state.tasks); const dispatch = useDispatch(); function handleClickDeleteTask(id) { From 9122174253c31fdac826b6c0e89e6dfcc0996213 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:44:04 +0900 Subject: [PATCH 52/55] =?UTF-8?q?=EC=BB=A8=ED=85=8C=EC=9D=B4=EB=84=88?= =?UTF-8?q?=EB=A5=BC=20=EB=8F=84=EC=9E=85=ED=95=98=EB=A9=B4=EC=84=9C=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=B4=EC=A7=84=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=82=AD=EC=A0=9C=ED=95=98?= =?UTF-8?q?=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/presentational/TodoPage.test.jsx | 32 +++++++--------------------- 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/presentational/TodoPage.test.jsx b/src/presentational/TodoPage.test.jsx index 89bb68952..455cd621b 100644 --- a/src/presentational/TodoPage.test.jsx +++ b/src/presentational/TodoPage.test.jsx @@ -1,31 +1,15 @@ -import { render, fireEvent } from '@testing-library/react'; +import { render } from '@testing-library/react'; +import { useSelector } from 'react-redux'; import TodoPage from './TodoPage'; -test('Page', () => { - const handleChangeTitle = jest.fn(); - const handleClickAddTask = jest.fn(); - const handleClickDeleteTask = jest.fn(); +jest.mock('react-redux'); - const tasks = [ - { id: 1, title: 'Task-1' }, - { id: 2, title: 'Task-2' }, - ]; +it('renders header', () => { + const initialState = { taskTitle: '', tasks: [] }; + useSelector.mockImplementation((selector) => selector(initialState)); - const { getByText } = render(( - - )); + const { getByText } = render(); - expect(getByText(/Task-1/)).toBeInTheDocument(); - expect(getByText(/Task-2/)).toBeInTheDocument(); - - fireEvent.click(getByText('추가')); - - expect(handleClickAddTask).toBeCalled(); + expect(getByText('To-do')).toBeInTheDocument(); }); From e87f398586e10c555d055a348cc382b11514964b Mon Sep 17 00:00:00 2001 From: yujonglee Date: Tue, 25 May 2021 20:44:32 +0900 Subject: [PATCH 53/55] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EA=B0=80=201?= =?UTF-8?q?=EA=B0=9C=EB=BF=90=EC=9D=B4=EB=9D=BC=20=EA=B5=B3=EC=9D=B4=20?= =?UTF-8?q?=EB=AC=B6=EC=96=B4=EC=A4=84=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20descibe=EB=B8=94=EB=9F=AD=EC=9D=84=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=ED=95=98=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.test.jsx | 24 ++++++++++----------- src/container/ListContainer.test.jsx | 32 +++++++++++++--------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/src/App.test.jsx b/src/App.test.jsx index 17006d197..e20bb19a9 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -5,18 +5,16 @@ import App from './App'; jest.mock('react-redux'); -describe('App', () => { - it('renders tasks', () => { - const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); +it('renders To-do tasks', () => { + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); - useSelector.mockImplementation((selector) => selector( - { - taskTitle: '', - tasks: [{ id: 1, title: 'codesoom' }], - }, - )); - const { getByText } = render(); - expect(getByText('codesoom')).toBeInTheDocument(); - }); + useSelector.mockImplementation((selector) => selector( + { + taskTitle: '', + tasks: [{ id: 1, title: 'codesoom' }], + }, + )); + const { getByText } = render(); + expect(getByText('codesoom')).toBeInTheDocument(); }); diff --git a/src/container/ListContainer.test.jsx b/src/container/ListContainer.test.jsx index cf0ea6ec0..84458a09c 100644 --- a/src/container/ListContainer.test.jsx +++ b/src/container/ListContainer.test.jsx @@ -6,24 +6,22 @@ import { deleteTask } from '../redux/actions'; jest.mock('react-redux'); -describe('ListContainer', () => { - it('deletes task from tasks with 완료 button', () => { - const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); - useSelector.mockImplementation((selector) => selector( - { - taskTitle: '', - tasks: [{ id: 1, title: 'codesoom' }], - }, - )); +it('deletes task from tasks with 완료 button', () => { + const dispatch = jest.fn(); + useDispatch.mockImplementation(() => dispatch); + useSelector.mockImplementation((selector) => selector( + { + taskTitle: '', + tasks: [{ id: 1, title: 'codesoom' }], + }, + )); - const { getByText } = render(); + const { getByText } = render(); - fireEvent.click( - within(getByText('codesoom')) - .getByRole('button', { name: '완료' }), - ); + fireEvent.click( + within(getByText('codesoom')) + .getByRole('button', { name: '완료' }), + ); - expect(dispatch).toBeCalledWith(deleteTask(1)); - }); + expect(dispatch).toBeCalledWith(deleteTask(1)); }); From 803fe8346c90afdc1d6255dbd0942f3dde98694b Mon Sep 17 00:00:00 2001 From: yujonglee Date: Wed, 26 May 2021 09:33:38 +0900 Subject: [PATCH 54/55] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20To?= =?UTF-8?q?doPage=EB=A5=BC=20=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EA=B7=B8=20=EB=82=B4=EC=9A=A9=EC=9D=84=20App=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EC=98=AE=EA=B2=A8=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.jsx | 9 +++++++-- src/App.test.jsx | 17 ++++++----------- src/presentational/TodoPage.jsx | 12 ------------ src/presentational/TodoPage.test.jsx | 15 --------------- 4 files changed, 13 insertions(+), 40 deletions(-) delete mode 100644 src/presentational/TodoPage.jsx delete mode 100644 src/presentational/TodoPage.test.jsx diff --git a/src/App.jsx b/src/App.jsx index 5760282d2..5decd38f5 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,7 +1,12 @@ -import TodoPage from './presentational/TodoPage'; +import InputContainer from './container/InputContainer'; +import ListContainer from './container/ListContainer'; export default function App() { return ( - +
+

To-do

+ + +
); } diff --git a/src/App.test.jsx b/src/App.test.jsx index e20bb19a9..d80b5636e 100644 --- a/src/App.test.jsx +++ b/src/App.test.jsx @@ -1,20 +1,15 @@ import { render } from '@testing-library/react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import App from './App'; jest.mock('react-redux'); -it('renders To-do tasks', () => { - const dispatch = jest.fn(); - useDispatch.mockImplementation(() => dispatch); +it('renders header', () => { + const initialState = { taskTitle: '', tasks: [] }; + useSelector.mockImplementation((selector) => selector(initialState)); - useSelector.mockImplementation((selector) => selector( - { - taskTitle: '', - tasks: [{ id: 1, title: 'codesoom' }], - }, - )); const { getByText } = render(); - expect(getByText('codesoom')).toBeInTheDocument(); + + expect(getByText('To-do')).toBeInTheDocument(); }); diff --git a/src/presentational/TodoPage.jsx b/src/presentational/TodoPage.jsx deleted file mode 100644 index b8b031b50..000000000 --- a/src/presentational/TodoPage.jsx +++ /dev/null @@ -1,12 +0,0 @@ -import InputContainer from '../container/InputContainer'; -import ListContainer from '../container/ListContainer'; - -export default function TodoPage() { - return ( -
-

To-do

- - -
- ); -} diff --git a/src/presentational/TodoPage.test.jsx b/src/presentational/TodoPage.test.jsx deleted file mode 100644 index 455cd621b..000000000 --- a/src/presentational/TodoPage.test.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import { render } from '@testing-library/react'; -import { useSelector } from 'react-redux'; - -import TodoPage from './TodoPage'; - -jest.mock('react-redux'); - -it('renders header', () => { - const initialState = { taskTitle: '', tasks: [] }; - useSelector.mockImplementation((selector) => selector(initialState)); - - const { getByText } = render(); - - expect(getByText('To-do')).toBeInTheDocument(); -}); From 72a27f6e99fde0a9eb369fa49e8814d3754417a7 Mon Sep 17 00:00:00 2001 From: yujonglee Date: Wed, 26 May 2021 09:34:57 +0900 Subject: [PATCH 55/55] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=93=A4?= =?UTF-8?q?=EC=9D=84=20describe=EB=B8=94=EB=9F=AD=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=AC=B6=EC=96=B4=EB=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/presentational/Input.test.jsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/presentational/Input.test.jsx b/src/presentational/Input.test.jsx index c6ad17d50..461a59282 100644 --- a/src/presentational/Input.test.jsx +++ b/src/presentational/Input.test.jsx @@ -1,12 +1,14 @@ import { render } from '@testing-library/react'; import Input from './Input'; -it('renders input control', () => { - const { getByPlaceholderText } = render(); - expect(getByPlaceholderText('할 일을 입력해 주세요')).toBeInTheDocument(); -}); +describe('Input', () => { + it('renders input control', () => { + const { getByPlaceholderText } = render(); + expect(getByPlaceholderText('할 일을 입력해 주세요')).toBeInTheDocument(); + }); -it('renders 추가 button', () => { - const { getByRole } = render(); - expect(getByRole('button', { name: '추가' })).toBeInTheDocument(); + it('renders 추가 button', () => { + const { getByRole } = render(); + expect(getByRole('button', { name: '추가' })).toBeInTheDocument(); + }); });