diff --git a/.babelrc b/.babelrc index 585e6f0a4..8567e4e87 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,3 @@ { - "presets": ["airbnb", "@babel/preset-typescript"], - "plugins": ["@emotion"] + "presets": ["airbnb", "@babel/preset-typescript"] } \ No newline at end of file diff --git a/README.fr.md b/README.fr.md index 80da66e26..a1f533d02 100644 --- a/README.fr.md +++ b/README.fr.md @@ -36,7 +36,7 @@

- +

@@ -124,6 +124,13 @@ Après avoir cloné ce référentiel, les développeurs peuvent simplement exéc - télécharger les snapshots actuels en mémoire - titres déclaratifs dans la barre latérale des actions +

Quoi de neuf !

+Reactime 20.0 inclut plusieurs améliorations clés sous le capot pour améliorer les performances et résoudre les bogues existants, ainsi qu'une UX remaniée pour atteindre la compatibilité WCAG. + +Nous avons résolu plusieurs bogues persistants, y compris un problème majeur qui faisait planter les applications utilisant Reactime lors de l'utilisation de la fonctionnalité de connexion ou de soumission. Dans le cadre de nos efforts pour améliorer les performances globales de Reactime, nous avons continué à implémenter TypeScript dans toute la base de code et créé de nouveaux tests avec React Testing Library. Nous avons également rendu les tests plus robustes, améliorant les tests existants et corrigeant les environnements de test défectueux. Enfin, nous avons mis à jour Reactime en supprimant certains codes et packages obsolètes, réduisant ainsi les erreurs de compilation. + +Nous avons mis à jour l'UX, en recherchant la cohérence avec les directives pour l'accessibilité des contenus Web (WCAG). Plus précisément, nous avons amélioré la taille et la conception des éléments cibles dans Reactime et soigneusement choisi de nouveaux contrastes de couleurs. + ## En savoir plus - [Time-Travel State with Reactime](https://medium.com/better-programming/time-traveling-state-with-reactime-6-0-53fdc3ae2a20) @@ -202,6 +209,14 @@ Après avoir cloné ce référentiel, les développeurs peuvent simplement exéc - **Ngoc Zwolinski** - [@ngoczwolinski](https://github.com/ngoczwolinski) - **Peter Lam** - [@dev-plam](https://github.com/dev-plam) - **Zachary Freeman** - [@zacharydfreeman](https://github.com/zacharydfreeman/) +- **Jackie Yuan** - [@yuanjackie1](https://github.com/yuanjackie1) +- **Jasmine Noor** - [@jasnoo](https://github.com/jasnoo) +- **Minzo Kim** - [@minzo-kim](https://github.com/minzo-kim) +- **Mark Teets** - [@MarkTeets](https://github.com/MarkTeets) +- **Nick Huemmer** - [@NickHuemmer](https://github.com/ElDuke717) +- **James McCollough** - [@j-mccoll](https://github.com/j-mccoll) +- **Mike Bednarz** - [@mikebednarz](https://github.com/mikebednarz) +- **Sergei Liubchenko** - [@sergeylvq](https://github.com/sergeylvq) ## License diff --git a/README.md b/README.md index 3de52a7f2..8d89cfc7d 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@

- +

@@ -47,7 +47,7 @@ be viewed in Diff mode.

- +


@@ -60,10 +60,6 @@ name.

- - ### 🔹 Components Comparison When toggled to a specific snapshot, a visualization of the individual @@ -73,11 +69,6 @@ each component upon hovering.

-

- -

-
- ### 🔹 Recording Whenever state is changed (whenever setState, useState is called), this @@ -87,7 +78,7 @@ snapshot will be displayed in Chrome DevTools under the Reactime panel.

- +


@@ -147,15 +138,15 @@ of the structure and interfaces of the codebase.

What's New!

-Reactime 19.0 comes with UI updates to enhance the developer's experience, as well as a much-needed revamping of the codebase to reflect current industry standards and better maintainability for future contributors. +Reactime 20.0 includes several key improvements under the hood to improve performance and resolve existing bugs, as well as a revamped UX to achieve WCAG compatibility. -UI Updates +Under the Hood -To handle displaying large amounts of data, we have changed how nested structures like objects and arrays are displayed to now be collapsible and scrollable. In addition, we've updated component information to include the necessary component "key" information, and data now also persists on hover, eliminating the need to leave the cursor in one place. +We have resolved several persistent bugs, including a major issue that caused apps using Reactime to crash when using login or submit functionality. As part of our effort to improve Reactime performance overall, we have continued to implement TypeScript throughout the codebase and created new tests with React Testing Library. We have also made testing more robust, improving existing tests and fixing broken test environments. Lastly, we have upgraded Reactime by removing some deprecated code and packages, reducing compilation errors. -Under the Hood +Accessibility -We are happy to say that we've migrated from Enzyme to React Testing Library to eliminate the need for the Enzyme adapter, converted from JavaScript to TypeScript to ensure type safety, and updated the traversal of the React Fiber Tree to accurately extract useState data for previously unsupported edge cases. +We have updated the UX, seeking consistency with the Web Content Accessibility Guidelines (WCAG). Specifically, we have improved the size and design of target elements throughout Reactime and carefully chosen new color contrasts to ensure WCAG compatibility. If you would like to read more about previous releases, click here! @@ -231,7 +222,7 @@ Node v16.16.0, please use script 'npm run devlegacy' | 'npm run buildlegacy' ## Read More -- [It's time for Reactime 19.0!](linkhere) +- [It's time for Reactime 20.0!](linkhere) ## Authors @@ -318,6 +309,10 @@ Node v16.16.0, please use script 'npm run devlegacy' | 'npm run buildlegacy' - **Jasmine Noor** - [@jasnoo](https://github.com/jasnoo) - **Minzo Kim** - [@minzo-kim](https://github.com/minzo-kim) - **Mark Teets** - [@MarkTeets](https://github.com/MarkTeets) +- **Nick Huemmer** - [@NickHuemmer](https://github.com/ElDuke717) +- **James McCollough** - [@j-mccoll](https://github.com/j-mccoll) +- **Mike Bednarz** - [@mikebednarz](https://github.com/mikebednarz) +- **Sergei Liubchenko** - [@sergeylvq](https://github.com/sergeylvq) ## License diff --git a/README.rus.md b/README.rus.md index 5ff1d8c0d..b63498e15 100644 --- a/README.rus.md +++ b/README.rus.md @@ -19,19 +19,20 @@

- +

-Reactime 18.0 вводит ряд новых и улучшенных функций, направленных на оптимизацию производительности и улучшение совместимости. -С поддержкой Next.js и Remix, увеличенной покрытия тестов (93% на бэкенде, необходимо больше на фронтенде) и структурных улучшений в кодовой базе. -Кроме того, мы гордимся анонсом запуска нашего вновь переработанного веб-сайта, который служит центром для последних обновлений и информации о Reactime. -Для помощи в отладке мы включили демонстрационные приложения для Next.js и Remix, что позволяет будущим итераторам тестировать и устранять ошибки с большей легкостью и эффективностью. +Reactime 20.0 + +Reactime 20.0 включает в себя несколько ключевых улучшений для повышения производительности и устранения существующих ошибок, а также переработанный пользовательский интерфейс для обеспечения совместимости с WCAG. + +Мы исправили несколько постоянных ошибок, в том числе серьезную проблему, которая приводила к сбою приложения, использующих Reactime, при использовании функций входа или отправки. Мы продолжили внедрять TypeScript в кодовую базу и создали новые тесты с библиотекой тестирования React. Мы также сделали тестирование более надежным, улучшив существующие тесты и исправив неработающие тесты. Наконец, мы обновили Reactime, удалив некоторый устаревший код и пакеты, уменьшив количество ошибок компиляции. + +Мы обновили взаимодействие с пользователем, в соответствие с требованиями Руководства по доступности веб-контента (WCAG). В частности, мы улучшили размер и дизайн целевых элементов в Reactime и тщательно выбрали новые цветовые контрасты. Reactime - расширение для дебаггинга/отладки React приложений. Оно создает снэпшоты при каждом изменении состояния (state) и позволяет пользованию прыгать на любое предыдущее состояние (state).  В настоящее время Reactime поддерживает React приложения с классовыми, функциональными компонентами, хуками и Context API. -В Reactime версии 7.0 отлажены баги предыдущих версий, улучшена визуализация данных отношений между компонентами. Также новая версия включает в себя расширенную документацию для разработчиков, которые хотят работать над приложением. - После загрузки Reactime вы можете протестировать его полную функциональность на любом вашем React приложении в режиме разработки (dev mode). В продакшен режиме вы можете только работать с картой компонентов. ## Установка @@ -90,19 +91,6 @@ Reactime beta поддерживает приложения, написанны После клонирования репозитория, вы можете использовать команду `npm run docs` в корневой папке, которая генерирует файл в браузере `/docs/index.html`. Это упростит знакомство с приложением и поможет вам ознакомиться со структурой и интерфейсом существующего кода. -### Дополнительный функционал - -- identifying unnecessary re-renders -- hover functionality to view tooltip details on state visualizations -- ability to pan and zoom on state visualizations -- a dropdown to support development of projects on multiple tabs -- a slider to move through snapshots quickly -- a play button to move through snapshots automatically -- a lock button, which stops recording each snapshot -- a persist button to keep snapshots upon refresh (handy when changing code and debugging) -- download/upload the current snapshots in memory -- declarative titles in the actions sidebar - ## Узнать больше о Reactime и React Fiber - [Time-Travel State with Reactime](https://medium.com/better-programming/time-traveling-state-with-reactime-6-0-53fdc3ae2a20) @@ -111,6 +99,7 @@ Reactime beta поддерживает приложения, написанны - [Deep in Weeds with Reactime, Concurrent React_fiberRoot, and Browser History Caching](https://itnext.io/deep-in-the-weeds-with-reactime-concurrent-react-fiberroot-and-browser-history-caching-7ce9d7300abb) ## Авторы + - **Ben Margolius** - [@benmarg](https://github.com/benmarg) - **Eric Yun** - [@ericsngyun](https://github.com/ericsngyun) - **James Nghiem** - [@jemzir](https://github.com/jemzir) @@ -180,6 +169,14 @@ Reactime beta поддерживает приложения, написанны - **Ngoc Zwolinski** - [@ngoczwolinski](https://github.com/ngoczwolinski) - **Peter Lam** - [@dev-plam](https://github.com/dev-plam) - **Zachary Freeman** - [@zacharydfreeman](https://github.com/zacharydfreeman/) +- **Jackie Yuan** - [@yuanjackie1](https://github.com/yuanjackie1) +- **Jasmine Noor** - [@jasnoo](https://github.com/jasnoo) +- **Minzo Kim** - [@minzo-kim](https://github.com/minzo-kim) +- **Mark Teets** - [@MarkTeets](https://github.com/MarkTeets) +- **Nick Huemmer** - [@NickHuemmer](https://github.com/ElDuke717) +- **James McCollough** - [@j-mccoll](https://github.com/j-mccoll) +- **Mike Bednarz** - [@mikebednarz](https://github.com/mikebednarz) +- **Sergei Liubchenko** - [@sergeylvq](https://github.com/sergeylvq) ## License diff --git a/assets/v19/Overview.gif b/assets/v19/Overview.gif deleted file mode 100644 index f417e2ada..000000000 Binary files a/assets/v19/Overview.gif and /dev/null differ diff --git a/assets/v19/history.gif b/assets/v19/history.gif deleted file mode 100644 index 348088872..000000000 Binary files a/assets/v19/history.gif and /dev/null differ diff --git a/assets/v19/map.gif b/assets/v19/map.gif deleted file mode 100644 index b2ddebee9..000000000 Binary files a/assets/v19/map.gif and /dev/null differ diff --git a/assets/v19/performance.gif b/assets/v19/performance.gif deleted file mode 100644 index fa35d90ba..000000000 Binary files a/assets/v19/performance.gif and /dev/null differ diff --git a/assets/v19/tree-and-diff.gif b/assets/v19/tree-and-diff.gif deleted file mode 100644 index 5f772a507..000000000 Binary files a/assets/v19/tree-and-diff.gif and /dev/null differ diff --git a/assets/v20/Overview.gif b/assets/v20/Overview.gif new file mode 100644 index 000000000..fc49f5300 Binary files /dev/null and b/assets/v20/Overview.gif differ diff --git a/assets/v20/history.gif b/assets/v20/history.gif new file mode 100644 index 000000000..5f2574fc2 Binary files /dev/null and b/assets/v20/history.gif differ diff --git a/assets/v20/map.gif b/assets/v20/map.gif new file mode 100644 index 000000000..003cf1917 Binary files /dev/null and b/assets/v20/map.gif differ diff --git a/demo-app-remix/server.js b/demo-app-remix/server.ts similarity index 94% rename from demo-app-remix/server.js rename to demo-app-remix/server.ts index 0efad6abe..1d7ef3982 100644 --- a/demo-app-remix/server.js +++ b/demo-app-remix/server.ts @@ -28,7 +28,7 @@ app.use(morgan("tiny")); app.all( "*", process.env.NODE_ENV === "development" - ? (req, res, next) => { + ? (req: any, res: any, next: any) => { purgeRequireCache(); return createRequestHandler({ @@ -41,7 +41,7 @@ app.all( mode: process.env.NODE_ENV, }) ); -const port = process.env.PORT || 3003; +const port: number | string = process.env.PORT || 3003; app.listen(port, () => { console.log(`Express server listening on port ${port}`); diff --git a/demo-app-remix/tsconfig.json b/demo-app-remix/tsconfig.json index 20f8a386a..0de0b2ee4 100644 --- a/demo-app-remix/tsconfig.json +++ b/demo-app-remix/tsconfig.json @@ -1,5 +1,5 @@ { - "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx", "server.ts"], "compilerOptions": { "lib": ["DOM", "DOM.Iterable", "ES2019"], "isolatedModules": true, diff --git a/demo-app/src/client/style.css b/demo-app/src/client/style.css index 68284a5b0..a5c315ab6 100644 --- a/demo-app/src/client/style.css +++ b/demo-app/src/client/style.css @@ -1,8 +1,18 @@ +@import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap'); + +:root { + --primary-red-color: #F00008; + --background-color1: #f6f6f6; + --secondary-blue-color: #62d6fb; + --fire-rose-red: #FF6569; + --secondary-color: #6288fb; + --text-color: #330002; +} body { margin: 0; - font-family: Arial, Helvetica, sans-serif; - background-color: #FFF4F4; + font-family: 'Lato', sans-serif; + background-color: var(--background-color1); } h1, h2, h4 { @@ -12,7 +22,19 @@ h1, h2, h4 { /* Navbar */ .nav { - background-color: #FF6569; + background-image: linear-gradient( + 0deg, + hsl(358deg 100% 47%) 5%, + hsl(359deg 90% 51%) 24%, + hsl(360deg 91% 54%) 33%, + hsl(360deg 93% 57%) 41%, + hsl(360deg 94% 59%) 48%, + hsl(360deg 95% 60%) 54%, + hsl(359deg 97% 62%) 61%, + hsl(359deg 98% 64%) 69%, + hsl(359deg 99% 65%) 79%, + hsl(358deg 100% 67%) 100% +); display: flex; justify-content: space-evenly; @@ -75,7 +97,7 @@ h1, h2, h4 { } .box { - background-color: #62d6fb; + background-color: var(--secondary-blue-color); border-style: solid; border-color: #ffffff; border-radius: 5px; @@ -87,7 +109,7 @@ h1, h2, h4 { } #reset { - color: #FF6569; + color: var(--primary-red-color); font-size: 1.5em; background-color: #ffffff; @@ -105,7 +127,7 @@ h1, h2, h4 { #reset:hover { color: #ffffff; - background-color: #FF6569 + background-color: var(--primary-red-color) } /* Counter */ @@ -131,7 +153,7 @@ h1, h2, h4 { color: #ffffff; font-size: 1.5em; - background-color: #FF6569; + background-color: var(--primary-red-color); border-style: solid; border-color: #ffffff; border-radius: 5px; @@ -145,11 +167,11 @@ h1, h2, h4 { } .increment:hover { - background-color: #62d6fb; + background-color: var(--secondary-blue-color); } .hook-data-section { - border: 2px solid #FF6569; + border: 2px solid --primary-red-color; border-radius: 5px; margin: 10px 0; padding: 8px; diff --git a/high-contrast-colors.md b/high-contrast-colors.md new file mode 100644 index 000000000..69eb3dd6b --- /dev/null +++ b/high-contrast-colors.md @@ -0,0 +1,17 @@ +## High Contrast Colors to Help with Color Blindness +- Dark Blue (#000080) +- Light Blue (#ADD8E6) +- Dark Green (#006400) +- Light Green (#90EE90) +- Dark Red (#8B0000) +- Light Red (#FFC0CB) +- Dark Purple (#800080) +- Light Purple (#BA55D3) +- Dark Yellow (#FFD700) +- Light Yellow (#FFFFE0) +- Dark Orange (#FF8C00) +- Light Orange (#FFA500) +- Dark Brown (#8B4513) +- Light Brown (#D2691E) +- Dark Gray (#A9A9A9) +- Light Gray (#D3D3D3) \ No newline at end of file diff --git a/package.json b/package.json index fe1acc643..c23b55494 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "Hien Nguyen", "Jack Crish", "Jackie Yuan", + "James McCollough", "James Nghiem", "Jasmine Noor", "Joseph Park", @@ -70,9 +71,11 @@ "Lance Ziegler", "Lina Shin", "Mark Teets", + "Mike Bednarz", "Minzo Kim", "Nathanael Wa Mwenze", "Ngoc Zwolinski", + "Nick Huemmer", "Peter Lam", "Prasanna Malla", "Rajeeb Banstola", @@ -81,6 +84,7 @@ "Rocky Lin", "Ruth Anam", "Ryan Dang", + "Sergei Liubchenko", "Sierra Swaby", "Tania Lind", "Viet Nguyen", @@ -95,7 +99,6 @@ "@babel/preset-env": "^7.12.7", "@babel/preset-react": "^7.12.7", "@babel/preset-typescript": "^7.21.5", - "@emotion/babel-plugin": "^11.7.2", "@inrupt/jest-jsdom-polyfills": "^1.6.2", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^13.4.0", @@ -152,8 +155,6 @@ "webpack-cli": "^3.3.12" }, "dependencies": { - "@emotion/react": "^11.9.0", - "@emotion/styled": "^11.8.1", "@fortawesome/fontawesome-free": "^5.15.1", "@fortawesome/fontawesome-svg-core": "^1.2.32", "@fortawesome/free-regular-svg-icons": "^5.15.1", diff --git a/reactime-website b/reactime-website index da8391a58..c26af6f6f 160000 --- a/reactime-website +++ b/reactime-website @@ -1 +1 @@ -Subproject commit da8391a58578b2d6dbbdcd050642d8a145716515 +Subproject commit c26af6f6f3e4949e89c2036dd8cedafba8592756 diff --git a/src/README.md b/src/README.md index 68381d283..6f3650571 100644 --- a/src/README.md +++ b/src/README.md @@ -47,17 +47,15 @@ Similar approach for Next.js and Remix demo apps ## Linting _Before_ beginning development, especially on teams, make sure to configure your linter and code formatting to conform to one unified setting (We recommend [the Airbnb style guide](https://github.com/airbnb/javascript)!) This will make reviewing PRs much more readable and less error-prone.   -  +  -# Possible Avenues for Future Iterators -Here are some notes on the current state of Reactime and considerations for future development. - -## Testing +# Possible Avenues for Future Iterators -For Reactime unit tests, pre-v.19 there were tests built out in two places. Backend tests were in backend >\_\_tests\_\_. Frontend tests were in src > app >\_\_tests\_\_. In v19, we specifically focused on rebuilding front tests to use React Testing Library (RTL) + Jest. Previously, front end testing existed but utilized Enzyme + Jest . Our decision to move to RTL stemmed on the fact that Enzyme did not support React V17 (third party Enzyme adaptor libraries were created to provide support to previous React versions, but were still very much out of date) and that Enzyme is no longer industry standard. We began the process of creating new frontend tests but they are not complete and this is a great place for future iterators to build out more. Since the new suite of RTL tests are not fully complete, we have kept the older Enzyme tests within the codebase to be referenced (src > app > __tests__enzyme). However, these will not be included in the tests run in the testing scripts. +Here are some notes on the current state of Reactime and considerations for future development. ## Including Support for Hooks Beyond useState -Reactime currently shows data stored via useState, but does not show data stored via other hooks such as useContext or useReducer. While showing this data would be simple, maintaining the time travel functionality of Reactime with these hooks would not. *Please see file demo-app/src/client/Components/ButtonsWithMoreHooks.jsx for more details.* + +Reactime currently shows data stored via useState, but does not show data stored via other hooks such as useContext or useReducer. While showing this data would be simple, maintaining the time travel functionality of Reactime with these hooks would not. _Please see file demo-app/src/client/Components/ButtonsWithMoreHooks.jsx for more details._ To see how hook data is stored on the fiber tree: @@ -71,12 +69,12 @@ To see how hook data is stored on the fiber tree: Any changes to console.logs in Reactime can be seen by refreshing the browser the app is running in. ## Replace Functionality for Outdated Packages -Packages emotion/core and material-ui/core haven't been updated to use React 18. This is the reason npm install --force is necessary when installing the dependencies of Reactime. Replacing the functionality these packages perform and removing them from Reactime would ensure compatibility moving forward. -React Developer Tools has deprecated \_\_REACT\_DEVTOOLS\_GLOBAL\_HOOK\_\_, which Reactime uses to extract a running application's fiber tree. At the time of the release of Reactime 19 (May 2023), this tool still works reliably to deliver said fiber tree. This will likely be the case until the React version (React version 18.2 at time of writing) undergoes updates that diverge beyond compatibility with \_\_REACT\_DEVTOOLS\_GLOBAL\_HOOK\_\_. At this time, Reactime will need to change how it extracts an application's fiber tree. +Material-ui/core hasn't been updated to use React 18. This is the reason npm install --force is necessary when installing the dependencies of Reactime. Replacing the functionality this package performs and removing it from Reactime would ensure compatibility moving forward. -Changing how Reactime extracts the fiber tree before said React version update may yeild diminishing result, as whatever method will also need to be updated to match React's breaking updates. +React Developer Tools has deprecated \_\_REACT_DEVTOOLS_GLOBAL_HOOK\_\_, which Reactime uses to extract a running application's fiber tree. At the time of the release of Reactime 20 (June 2023), this tool still works reliably to deliver said fiber tree. This will likely be the case until the React version (React version 18.2 at time of writing) undergoes updates that diverge beyond compatibility with \_\_REACT_DEVTOOLS_GLOBAL_HOOK\_\_. At this time, Reactime will need to change how it extracts an application's fiber tree. +Changing how Reactime extracts the fiber tree before said React version update may yield diminishing result, as whatever method will also need to be updated to match React's breaking updates. ## Redux @@ -84,7 +82,6 @@ Can Reactime be integrated with Redux compatibility so applications using Redux Yes, but it would be very time-consuming and not the most feasible option while Redux devtools exists already. With how Redux devtools is currently set up, a developer is unable to use Redux devtools as a third-party user and integrate its functionality into their own application, as Redux devtools is meant to be used directly on an application using Redux for state-tracking purposes. Since the devtools do not appear to have a public API for integrated use in an application or it simply does not exist, Redux devtools would need to be rebuilt from the ground up and then integrated into Reactime, or built into Reactime directly still from scratch. - # File Structure In the _src_ folder, there are three directories we care about: _app_, _backend_, and _extension_. @@ -93,14 +90,13 @@ In the _src_ folder, there are three directories we care about: _app_, _backend_ src/ ├── app/ # Frontend code │   ├── __tests__/ # React Testing Library -│   ├── __tests__enzyme/ # Legacy Enzyme tests │   ├── actions/ # Redux action creators │   ├── components/ # React components │   ├── constants/ # │   ├── containers/ # More React components │   ├── reducers/ # Redux mechanism for updating state │   ├── styles/ # -│   ├── FrontendTypes.ts # Library of typescript interfaces +│   ├── FrontendTypes.ts # Library of typescript interfaces │   ├── index.tsx # Starting point for root App component │   ├── module.d.ts # │   └── store.tsx # @@ -126,8 +122,7 @@ src/ │   ├── index.ts # Starting point for backend functionality │   ├── index.d.ts # Definitely Type file for Index │   ├── module.d.ts # -│   ├── package.json # -│   ├── puppeteerServer.js # +│   ├── puppeteerServer.ts # │ ├── extension/ # Chrome Extension code │   ├── build/ # Destination for bundles and manifest.json (Chrome config file) @@ -156,7 +151,6 @@ All the diagrams of data flows are available on [MIRO](https://miro.com/app/boar - Like regular web apps, Chrome Extensions are event-based. The background script is where one typically monitors for browser triggers (e.g. events like closing a tab, for example). The content script is what allows us to read or write to our target web application, usually as a result of [messages passed](https://developer.chrome.com/extensions/messaging) from the background script. - These two files help us handle requests both from the web browser and from the Reactime extension itself - ## Data Flow Architecture The general flow of data is described in the following steps: @@ -170,7 +164,6 @@ The general flow of data is described in the following steps: 3. Likewise, when Reactime emits an action due to user interaction -- a "jump" request for example -- a message will be passed from Reactime via the background script to the content script. Then, the content script will pass a message to the target application containing a payload that represents the state the user wants the DOM to reflect or "jump" to. - One important thing to note here is that this jump action must be dispatched in the target application (i.e. _backend_ land), because only there do we have direct access to the DOM. - # Reacti.me Website: See [Reacti.me README](https://github.com/reactimetravel/reactime-website/blob/main/README.md) for instruction of how to update the website @@ -238,7 +231,18 @@ Some relevant sections are reproduced below: 2. The chrome extension "front-end" **(_NOT_ the interface of the browser, this is an important distinction.)** - In other words, a background script works as a sort of middleman, directly maintaining connection with its parent extension, and acting as a proxy enabling communication between it and the content script. +# Launching to Chrome Web Store + +Once you are ready for launch, follow these steps to simplify deployment to the Chrome Web Store: + + 1. Run npm run build in Reactime to build the production version of Reactime + 2. Right click on the build folder and click “compress” to make a compressed zip version of the build folder. The compressed zip is what you will upload to the Chrome Web Store + 3. Navigate to the Chrome Web Store Developer Dashboard (logged in with Reactime credentials). Go to Build > Package > Upload new package, and when prompted, upload the build.zip file + 4. Update the Store Listing and that’s it! Click “Submit for review” and wait for the Chrome store to process your request + # Past Medium Articles for Reference + +- [Reactime 20: Reactime just keeps getting better!](https://medium.com/@njhuemmer/reactime-just-keeps-getting-better-b37659ff8b71) - [Reactime 19: What time is it? It’s still Reactime!](https://medium.com/@minzo.kim/what-time-is-it-its-still-reactime-d496adfa908c) - [Reactime 18.0. Better than ever](https://medium.com/@zdf2424/reactime-18-0-better-than-ever-148b81606257) - [Reactime v17.0.0: Now with support for the Context API, and a modern UI](https://medium.com/@reactime/reactime-v17-0-0-now-with-support-for-the-context-api-and-a-modern-ui-f0edf9e54dae) diff --git a/src/app/__tests__/ActionContainer.test.tsx b/src/app/__tests__/ActionContainer.test.tsx index a4611db55..dda84da08 100644 --- a/src/app/__tests__/ActionContainer.test.tsx +++ b/src/app/__tests__/ActionContainer.test.tsx @@ -5,6 +5,7 @@ import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import ActionContainer from '../containers/ActionContainer'; import { useStoreContext } from '../store'; +import TravelContainer from '../containers/TravelContainer'; const state = { tabs: { @@ -143,8 +144,22 @@ describe('unit testing for ActionContainer', () => { expect(screen.getByText('MockSwitchApp')).toBeInTheDocument(); }); - test('Click works on clear button', async () => { + test('Click works on clear button', () => { fireEvent.click(screen.getAllByRole('button')[0]); - await expect(dispatch).toHaveBeenCalledTimes(1); + expect(dispatch).toHaveBeenCalledTimes(1); }); }); + +describe('integration testing for ActionContainer', () => { + beforeEach(() => { + mockeduseStoreContext.mockClear(); + dispatch.mockClear(); + render(); + render(); + }); + + test('Slider resets on clear button', () => { + fireEvent.click(screen.getAllByRole('button')[0]); + expect(screen.getByRole('slider')).toHaveStyle('left: 0'); + }); +}); \ No newline at end of file diff --git a/src/app/__tests__/ButtonContainer.test.tsx b/src/app/__tests__/ButtonContainer.test.tsx index 0b13d6efb..6ef30f9f5 100644 --- a/src/app/__tests__/ButtonContainer.test.tsx +++ b/src/app/__tests__/ButtonContainer.test.tsx @@ -5,6 +5,8 @@ import { TextEncoder } from 'util'; global.TextEncoder = TextEncoder; import ButtonsContainer from '../containers/ButtonsContainer'; import { useStoreContext } from '../store'; +import userEvent from '@testing-library/user-event'; +import { toggleMode } from '../actions/actions'; // const { Steps } = require('intro.js-react'); jest.mock('../store'); @@ -24,9 +26,8 @@ describe('Unit testing for ButtonContainer', () => { sliderIndex: 0, viewIndex: -1, mode: { - paused: false, + paused: true, locked: false, - persist: false, }, }, }, @@ -46,16 +47,15 @@ describe('Unit testing for ButtonContainer', () => { dispatch.mockClear(); mockedUsedStoreContext.mockClear(); currentTab.mode = { - paused: false, - persist: false, + paused: true, }; }); describe('When button container is loaded', () => { - test('should have 4 buttons ', () => { + test('it should have 4 buttons', () => { render(); expect(screen.getAllByRole('button')).toHaveLength(4); - expect(screen.getAllByRole('button')[0]).toHaveTextContent('Unlocked'); + expect(screen.getAllByRole('button')[0]).toHaveTextContent('Locked'); expect(screen.getAllByRole('button')[1]).toHaveTextContent('Download'); expect(screen.getAllByRole('button')[2]).toHaveTextContent('Upload'); expect(screen.getAllByRole('button')[3]).toHaveTextContent('Tutorial'); @@ -64,12 +64,30 @@ describe('Unit testing for ButtonContainer', () => { describe('When view is unlock', () => { test('Button should show as unlocked', () => { + state.tabs['87'].mode.paused = false; + render(); + expect(screen.getAllByRole('button')[0]).toHaveTextContent('Unlocked'); + }); + }); + + describe('When view is lock', () => { + test('Button should show as locked', () => { state.tabs['87'].mode.paused = true; render(); expect(screen.getAllByRole('button')[0]).toHaveTextContent('Locked'); }); }); + describe('Clicking pause-button toggles locked/unlocked', () => { + test('When button is unlocked and it is clicked', async () => { + render(); + const button = screen.getAllByRole('button')[0]; + await userEvent.click(button); + expect(dispatch).toHaveBeenCalledWith(toggleMode('paused')); + }); + }); + + describe('Upload/Download', () => { test('Clicking upload and download buttons', async () => { render(); diff --git a/src/app/__tests__/ErrorMsg.test.tsx b/src/app/__tests__/ErrorMsg.test.tsx index 6cb6f76e0..c6c8177ad 100644 --- a/src/app/__tests__/ErrorMsg.test.tsx +++ b/src/app/__tests__/ErrorMsg.test.tsx @@ -13,8 +13,6 @@ const props = { launchContent: null, }; -const parseError = jest.fn(); - describe('unit testing for ErrorContainer.tsx', () => { describe('When there are no errors', () => { test('Returns empty div', () => { @@ -34,7 +32,7 @@ describe('unit testing for ErrorContainer.tsx', () => { }); }); - describe("when there's a Content Script Errorr", () => { + describe("when there's a Content Script Error", () => { test('Content Script Error related text shows', () => { props.status.contentScriptLaunched = false; render(); diff --git a/src/app/__tests__/Loader.test.tsx b/src/app/__tests__/Loader.test.tsx index 9db60b351..a60438323 100644 --- a/src/app/__tests__/Loader.test.tsx +++ b/src/app/__tests__/Loader.test.tsx @@ -6,7 +6,7 @@ import Loader from '../components/Loader'; describe('unit testing for Loader.tsx', () => { test('renders a loading icon', () => { const { container } = render(); - expect(container.firstChild).toHaveClass('css-xp4o0b'); + expect(container.firstChild).toHaveClass('css-1tm071a'); }); test('renders a fail icon', () => { diff --git a/src/app/__tests__/MainContainer.test.tsx b/src/app/__tests__/MainContainer.test.tsx index f1ff56563..e5a4e0202 100644 --- a/src/app/__tests__/MainContainer.test.tsx +++ b/src/app/__tests__/MainContainer.test.tsx @@ -23,11 +23,13 @@ jest.mock('../containers/TravelContainer', () => (props) => { mockTravelContainer(props); return
mockTravelContainer
; }); + const mockButtonsContainer = jest.fn(); jest.mock('../containers/ButtonsContainer', () => (props) => { mockButtonsContainer(props); return
mockButtonsContainer
; }); + const mockErrorContainer = jest.fn(); jest.mock('../containers/ErrorContainer', () => (props) => { mockErrorContainer(props); diff --git a/src/app/__tests__/MainSlider.test.tsx b/src/app/__tests__/MainSlider.test.tsx index 81b4e3417..383b58735 100644 --- a/src/app/__tests__/MainSlider.test.tsx +++ b/src/app/__tests__/MainSlider.test.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { render, screen, fireEvent } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { TextEncoder } from 'util'; global.TextEncoder = TextEncoder; @@ -40,21 +40,11 @@ describe('Unit testing for MainSlider.jsx', () => { snapshotsLength: 3, }; - const state = { - tabs: { - 100: { - sliderIndex: 1, - }, - }, - currentTab: 100, - }; - - // currently not working :( likely needs to correctly handle understanding what tab it should currently be at test('Component should have min, max, value with correct values to indicate slider position when there are multiple snapshots', () => { render(); expect(screen.getByRole('slider')).toHaveAttribute('aria-valuemax', '2'); expect(screen.getByRole('slider')).toHaveAttribute('aria-valuemin', '0'); - // expect(screen.getByRole('slider')).toHaveAttribute('aria-valuenow','0') + expect(screen.getByRole('slider')).toHaveAttribute('aria-valuenow','0') }); }); }); diff --git a/src/app/__tests__/TravelContainer.test.tsx b/src/app/__tests__/TravelContainer.test.tsx index a93b6c45d..729a981b5 100644 --- a/src/app/__tests__/TravelContainer.test.tsx +++ b/src/app/__tests__/TravelContainer.test.tsx @@ -15,7 +15,6 @@ const state = { currentTab: 87, }; -const play = jest.fn(); const dispatch = jest.fn(); jest.mock('../store'); @@ -48,6 +47,7 @@ describe('All elements appear in the TravelContainer module', () => { test('MainSlider exists in document', () => { expect(screen.getByText('MockSlider')).toBeInTheDocument(); }); + test('Dropdown exists in document', () => { expect(screen.getByText('mockDropDown')).toBeInTheDocument(); }); @@ -57,7 +57,7 @@ describe('All elements appear in the TravelContainer module', () => { expect(buttons[1]).toHaveTextContent('<'); }); - test('Foward button exists in document', () => { + test('Forward button exists in document', () => { let buttons = screen.getAllByRole('button'); expect(buttons[2]).toHaveTextContent('>'); }); @@ -69,18 +69,18 @@ describe('Testing backward and forward button', () => { render(); }); - test('Clicking < Button button will triger button', async () => { + test('Clicking < Button button will trigger button', () => { let buttons = screen.getAllByRole('button'); expect(buttons[1]).toHaveTextContent('<'); fireEvent.click(buttons[1]); - await expect(dispatch).toHaveBeenCalledTimes(1); + expect(dispatch).toHaveBeenCalledTimes(1); }); - test('Clicking > Button button will triger button', async () => { + test('Clicking > Button button will trigger button', () => { let buttons = screen.getAllByRole('button'); expect(buttons[2]).toHaveTextContent('>'); fireEvent.click(buttons[2]); - await expect(dispatch).toHaveBeenCalledTimes(1); + expect(dispatch).toHaveBeenCalledTimes(1); }); }); @@ -94,33 +94,34 @@ describe('Testing play/pause button', () => { const playButton = screen.getByTestId('play-button-test'); expect(playButton).toBeInTheDocument(); }); + test('Play initially says Play', () => { render(); const playButton = screen.getByTestId('play-button-test'); expect(playButton.textContent).toBe('Play'); }); - test('Clicking Play button will triger button', async () => { + test('Clicking Play button will trigger button', () => { render(); const playButton = screen.getByTestId('play-button-test'); expect(playButton.textContent).toBe('Play'); fireEvent.click(playButton); - await expect(dispatch).toHaveBeenCalledTimes(1); + expect(dispatch).toHaveBeenCalledTimes(1); }); - test('Play says Pause when `Playing` is set to False', () => { + test('Play says Pause when `Playing` is set to true', () => { state.tabs[87].playing = true; render(); const playButton = screen.getByTestId('play-button-test'); expect(playButton.textContent).toBe('Pause'); }); - test('Clicking Pause button will trigger button', async () => { + test('Clicking Pause button will trigger button', () => { render(); const playButton = screen.getByTestId('play-button-test'); expect(playButton.textContent).toBe('Pause'); fireEvent.click(playButton); - await expect(dispatch).toHaveBeenCalledTimes(1); + expect(dispatch).toHaveBeenCalledTimes(1); state.tabs[87].playing = false; }); }); diff --git a/src/app/__tests__/Tutorial.test.tsx b/src/app/__tests__/Tutorial.test.tsx index b6e6a3d12..40f76702a 100644 --- a/src/app/__tests__/Tutorial.test.tsx +++ b/src/app/__tests__/Tutorial.test.tsx @@ -16,32 +16,45 @@ const props = { let currentStepIndex = 5; describe('Before Tutorial is entered', () => { - test('How to use button exists', () => { + test('Tutorial button exists', () => { render(); expect(screen.getByText('Tutorial')).toBeInTheDocument(); }); - test('User clicking "How to use" while on map tab button starts map tutorial ', () => { + test('User clicking tutorial button while on map tab starts map tutorial ', () => { props.currentTabInApp = 'map'; - render(); fireEvent.click(screen.getByRole('button')); expect( - screen.getByText('A performance and state managment tool for React apps.'), + screen.getByText('A performance and state management tool for React apps.'), ).toBeInTheDocument(); }); - test('User clicking "How to use" while on performance tab button starts performance tutorial ', () => { + test('User clicking tutorial button while on performance tab starts performance tutorial ', () => { props.currentTabInApp = 'performance'; render(); fireEvent.click(screen.getByRole('button')); expect(screen.getByText('Performance Tab')).toBeInTheDocument(); }); - test('User clicking "How to use" while on performance comparison tab, no tutorial available ', () => { - props.currentTabInApp = 'performance-comparison'; - currentStepIndex = 1; + test('User clicking tutorial button while on history tab starts history tutorial ', () => { + props.currentTabInApp = 'history'; + render(); + fireEvent.click(screen.getByRole('button')); + expect(screen.getByText('History Tab')).toBeInTheDocument(); + }); + + test('User clicking tutorial button while on web metrics tab starts web metrics tutorial ', () => { + props.currentTabInApp = 'webmetrics'; + render(); + fireEvent.click(screen.getByRole('button')); + expect(screen.getByText('Webmetrics Tab')).toBeInTheDocument(); + }); + + test('User clicking tutorial button while on tree tab starts tree tutorial ', () => { + props.currentTabInApp = 'tree'; render(); fireEvent.click(screen.getByRole('button')); + expect(screen.getByText('Tree Tab')).toBeInTheDocument(); }); }); diff --git a/src/app/__tests__/action.test.tsx b/src/app/__tests__/action.test.tsx index 28a82eb62..9ea51dc21 100644 --- a/src/app/__tests__/action.test.tsx +++ b/src/app/__tests__/action.test.tsx @@ -1,8 +1,9 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; import user from '@testing-library/user-event'; import '@testing-library/jest-dom/extend-expect'; // needed this to extend the jest-dom assertions (ex toHaveTextContent) import Action from '../components/Action'; +import { changeView, changeSlider } from '../actions/actions'; // @ts-ignore Action.cleanTime = jest.fn().mockReturnValue(); @@ -53,10 +54,47 @@ describe('unit testing for Action.tsx', () => { expect(screen.getByPlaceholderText('Snapshot: 3.0')).toBeInTheDocument(); }); - test("when there's no have no duration data", () => { + test("when there's no duration data", () => { props.componentData = undefined; render(); expect(screen.getAllByRole('button')[0]).toHaveTextContent('NO TIME'); }); + + test('When actualDuration exceeds 60, time should be formatted correctly', () => { + props.componentData.actualDuration = 75; + render(); + expect(screen.getAllByRole('button')[0]).toHaveTextContent('+01:15.00'); + }); + + test('Using the ArrowUp key on Action snapshot should trigger handleOnKeyDown', () => { + render(); + fireEvent.keyDown(screen.getByRole('presentation'), {key: 'ArrowUp', code: 'ArrowUp', charCode: 38}); + expect(props.handleOnkeyDown).toHaveBeenCalled(); + }); + + test('Using the ArrowDown key on Action snapshot should trigger handleOnKeyDown', () => { + render(); + fireEvent.keyDown(screen.getByRole('presentation'), {key: 'ArrowDown', code: 'ArrowDown', charCode: 40}); + expect(props.handleOnkeyDown).toHaveBeenCalled(); + }); + + test('Using the Enter key on Action snapshot should trigger handleOnKeyDown', () => { + render(); + fireEvent.keyDown(screen.getByRole('presentation'), {key: 'Enter', code: 'Enter', charCode: 13}); + expect(props.handleOnkeyDown).toHaveBeenCalled(); + }); + + test('Clicking the snapshot should trigger onClick', () => { + render(); + fireEvent.click(screen.getByRole('presentation')); + expect(props.dispatch).toHaveBeenCalledWith(changeView(props.index));; + }); + + test('Clicking Jump button should trigger changeSlider and changeView', () => { + render(); + fireEvent.click(screen.getAllByRole('button')[1]); + expect(props.dispatch).toHaveBeenCalledWith(changeSlider(props.index)); + expect(props.dispatch).toHaveBeenCalledWith(changeView(props.index)); + }); }); }); diff --git a/src/app/__tests__enzyme/ignore/ActionContainer.test.tsx b/src/app/__tests__enzyme/ignore/ActionContainer.test.tsx deleted file mode 100644 index 483e8fc30..000000000 --- a/src/app/__tests__enzyme/ignore/ActionContainer.test.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable react/jsx-filename-extension */ - -import { shallow, configure } from 'enzyme'; -import React from 'react'; -import Adapter from 'enzyme-adapter-react-16'; -import ActionContainer from '../containers/ActionContainer'; -import { useStoreContext } from '../store'; -import { emptySnapshots } from '../actions/actions'; -import Action from '../components/Action'; -import RouteDescription from '../components/RouteDescription'; - -configure({ adapter: new (Adapter as any)() }); - -const state = { - tabs: { - 87: { - snapshots: [1, 2, 3, 4], - hierarchy: { - index: 0, - name: 1, - branch: 0, - stateSnapshot: { - state: {}, - children: [ - { - state: { test: 'test' }, - name: 'App', - componentData: { actualDuration: 3.5 }, - }, - ], - route: { - id: 1, - url: 'http://localhost:8080/', - }, - }, - children: [ - { - index: 1, - name: 2, - branch: 0, - stateSnapshot: { - state: {}, - children: [ - { - state: { test: 'test' }, - name: 'App', - componentData: { actualDuration: 3.5 }, - }, - ], - route: { - id: 2, - url: 'http://localhost:8080/', - }, - }, - children: [ - { - index: 2, - name: 3, - branch: 0, - stateSnapshot: { - state: {}, - children: [ - { - state: { test: 'test' }, - name: 'App', - componentData: { actualDuration: 3.5 }, - }, - ], - route: { - id: 3, - url: 'http://localhost:8080/', - }, - }, - children: [ - { - index: 3, - name: 4, - branch: 0, - stateSnapshot: { - state: {}, - children: [ - { - state: { test: 'test' }, - name: 'App', - componentData: { actualDuration: 3.5 }, - }, - ], - route: { - id: 4, - url: 'http://localhost:8080/test/', - }, - }, - children: [], - }, - ], - }, - ], - }, - ], - }, - currLocation: { - index: 0, - name: 1, - branch: 0, - }, - sliderIndex: 0, - viewIndex: -1, - }, - }, - currentTab: 87, -}; - -const dispatch = jest.fn(); - -jest.mock('../store'); -useStoreContext.mockImplementation(() => [state, dispatch]); - -let wrapper; - -// actionView={true} must be passed in to in beforeEach() to deal with new -// conditional rendering in ActionContainer that shows/hides time-travel functionality - -beforeEach(() => { - wrapper = shallow(); - // wrapper2 = shallow(); - useStoreContext.mockClear(); - dispatch.mockClear(); -}); - -describe('testing the emptySnapshot button', () => { - test('emptySnapshot button should dispatch action upon click', () => { - wrapper.find('.empty-button').simulate('click'); - expect(dispatch.mock.calls.length).toBe(1); - }); - test('emptying snapshots should send emptySnapshot action to dispatch', () => { - wrapper.find('.empty-button').simulate('click'); - expect(dispatch.mock.calls[0][0]).toEqual(emptySnapshots()); - }); -}); - -test('number of RouteDescription components should reflect number of unique routes', () => { - expect(wrapper.find(RouteDescription).length).toBe(2); -}); diff --git a/src/app/__tests__enzyme/ignore/ButtonsContainer.test.tsx b/src/app/__tests__enzyme/ignore/ButtonsContainer.test.tsx deleted file mode 100644 index f8675e26a..000000000 --- a/src/app/__tests__enzyme/ignore/ButtonsContainer.test.tsx +++ /dev/null @@ -1,89 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable react/jsx-filename-extension */ -import { shallow, configure } from 'enzyme'; -import React from 'react'; -import Adapter from 'enzyme-adapter-react-16'; -import ButtonsContainer from '../containers/ButtonsContainer'; -import { useStoreContext } from '../store'; -import { toggleMode } from '../actions/actions'; - -configure({ adapter: new (Adapter as any)() }); - -const state = { - tabs: { - 87: { - snapshots: [1, 2, 3, 4], - sliderIndex: 0, - viewIndex: -1, - mode: { - paused: false, - locked: false, - persist: false, - }, - }, - }, - currentTab: 87, -}; - -const currentTab = state.tabs[state.currentTab]; - -const dispatch = jest.fn(); - -jest.mock('../../../node_modules/intro.js/introjs.css', () => jest.fn()); -jest.mock('../store'); -useStoreContext.mockImplementation(() => [state, dispatch]); - -let wrapper; - -describe('testing the bottom buttons', () => { - beforeEach(() => { - wrapper = shallow(); - dispatch.mockClear(); - useStoreContext.mockClear(); - currentTab.mode = { - paused: false, - persist: false, - }; - }); - - describe('pause button testing', () => { - beforeEach(() => { - wrapper.find('.pause-button').simulate('click'); - }); - test('pause button dispatches upon click', () => { - expect(dispatch.mock.calls.length).toBe(1); - }); - - test('pause button dispatches toggleMode action', () => { - expect(dispatch.mock.calls[0][0]).toEqual(toggleMode('paused')); - }); - - test('pause button displays state', () => { - expect(wrapper.find('.pause-button').text()).toBe('Lock'); - state.tabs[state.currentTab].mode.paused = true; - wrapper = shallow(); - expect(wrapper.find('.pause-button').text()).toBe('Unlock'); - }); - }); - - describe.skip('persist button testing', () => { - beforeEach(() => { - wrapper.find('.persist-button').simulate('click'); - }); - - test('persist button dispatches upon click', () => { - expect(dispatch.mock.calls.length).toBe(1); - }); - - test('persist button dispatches toggleMode action', () => { - expect(dispatch.mock.calls[0][0]).toEqual(toggleMode('persist')); - }); - - test('persist button displays state', () => { - expect(wrapper.find('.persist-button').text()).toBe('Persist'); - state.tabs[state.currentTab].mode.persist = true; - wrapper = shallow(); - expect(wrapper.find('.persist-button').text()).toBe('Unpersist'); - }); - }); -}); diff --git a/src/app/__tests__enzyme/ignore/ComponentMap.test.tsx b/src/app/__tests__enzyme/ignore/ComponentMap.test.tsx deleted file mode 100644 index 1e1b3a626..000000000 --- a/src/app/__tests__enzyme/ignore/ComponentMap.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint:disable */ - -import * as d3 from 'd3'; - -describe('D3Canvas Testing', () => { - const getCanvas = () => { - return d3.select('#canvas'); - }; - - it('should exist', () => { - expect(getCanvas()).not.toBeNull(); - }); -}); - -describe('D3 Node Testing', () => { - const getNodes = () => { - return d3.select('g'); - }; - - it('should exist', () => { - expect(getNodes()).not.toBeNull(); - }); -}); diff --git a/src/app/__tests__enzyme/ignore/Diff.test.tsx b/src/app/__tests__enzyme/ignore/Diff.test.tsx deleted file mode 100644 index 6214f734a..000000000 --- a/src/app/__tests__enzyme/ignore/Diff.test.tsx +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-var-requires */ -import React from 'react'; -import { configure, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { useStoreContext } from '../store'; - -const Diff = require('../components/Diff').default; - -configure({ adapter: new (Adapter as any)() }); - -jest.mock('../store'); - -describe('Unit testing for Diff.jsx', () => { - let wrapper; - const props = { - show: false, - snapshot: [ - { - children: [ - { - state: { total: 12, next: 5, operation: null }, - }, - ], - }, - ], - }; - - const state = { - currentTab: 100, - tabs: { 100: { snapshots: [1, 2, 3, 4], viewIndex: 1, sliderIndex: 1 } }, - }; - - useStoreContext.mockImplementation(() => [state]); - - const delta = { children: {} }; // expect delta to be an obj - const html = 'html'; // expect html to be a string - const previous = { state: 'string', children: {} }; // expect previous to be an obj - - beforeEach(() => { - // eslint-disable-next-line react/jsx-props-no-spreading - wrapper = shallow(); - }); - - describe('delta', () => { - it('delta variable should be an object, with a property children', () => { - expect(typeof delta).toBe('object'); - expect(delta).toHaveProperty('children'); - }); - }); - - describe('html', () => { - it('html variable should be a string', () => { - expect(typeof html).toBe('string'); - }); - }); - - describe('previous', () => { - it('previous variable should be a object', () => { - expect(previous).toHaveProperty('state'); - expect(previous).toHaveProperty('children'); - expect(typeof previous).toBe('object'); - }); - }); - - describe('Diff Component', () => { - it('Check if Diff component is a div', () => { - expect(wrapper.type()).toEqual('div'); - }); - it('Check if Diff component inner text value is a string', () => { - expect(typeof wrapper.text()).toEqual('string'); - }); - it('Check if previous and delta is defined Diff should not have text content "No state change detected. Trigger an event to change state"', () => { - expect(wrapper.textContent).not.toEqual( - 'No state change detected. Trigger an event to change state', - ); - }); - }); -}); diff --git a/src/app/__tests__enzyme/ignore/DiffRoute.test.tsx b/src/app/__tests__enzyme/ignore/DiffRoute.test.tsx deleted file mode 100644 index 33ac03ab0..000000000 --- a/src/app/__tests__enzyme/ignore/DiffRoute.test.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-var-requires */ -import React from 'react'; -import { configure, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import { MemoryRouter as Router, Switch } from 'react-router-dom'; - -const DiffRoute = require('../components/DiffRoute').default; - -const props = { - snapshot: [{}], -}; - -configure({ adapter: new (Adapter as any)() }); -let wrapper; - -describe('DiffRoute props', () => { - it('should have a property called snapshot', () => { - expect(props).toHaveProperty('snapshot'); - }); - it('props snapshot value should be an array', () => { - expect(Array.isArray(props.snapshot)).toBe(true); - }); -}); - -describe('DiffRoute component', () => { - beforeEach(() => { - wrapper = shallow(); - }); - it('should contain a router component', () => { - expect(wrapper.find(Router).type()).toEqual(Router); - }); - it('div tag in Router should have a classname "navbar', () => { - expect(wrapper.find('.navbar').type()).toBe('div'); - }); - it('router should have a switch component', () => { - expect(wrapper.find(Switch).type()).toEqual(Switch); - }); -}); - -// remaining tests: -// check if router component has a div with a navlik component -// check if navlinks go to appropriate routes, and text shows Tree and Raw -// check if routes in switch have appropriate props diff --git a/src/app/__tests__enzyme/ignore/History.test.tsx b/src/app/__tests__enzyme/ignore/History.test.tsx deleted file mode 100644 index 34e118c8d..000000000 --- a/src/app/__tests__enzyme/ignore/History.test.tsx +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint:disable */ - -import * as d3 from 'd3'; - -describe('D3 Canvas Testing', () => { - const getCanvas = () => d3.select('#canvas'); - - it('should render', () => { - expect(getCanvas()).not.toBeNull(); - }); -}); - -describe('D3 Node Testing', () => { - const getNodes = () => d3.select('g'); - - it('should render', () => { - expect(getNodes()).not.toBeNull(); - }); -}); diff --git a/src/app/__tests__enzyme/ignore/MainContainer.test.tsx b/src/app/__tests__enzyme/ignore/MainContainer.test.tsx deleted file mode 100644 index d4303d452..000000000 --- a/src/app/__tests__enzyme/ignore/MainContainer.test.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/no-empty-function */ -/* eslint-disable @typescript-eslint/no-var-requires */ -/* eslint-disable react/jsx-filename-extension */ -import { shallow, configure } from 'enzyme'; -import React from 'react'; -import Adapter from 'enzyme-adapter-react-16'; -import MainContainer from '../containers/MainContainer'; -import { useStoreContext } from '../store'; - -import ActionContainer from '../containers/ActionContainer'; -import StateContainer from '../containers/StateContainer'; -import TravelContainer from '../containers/TravelContainer'; -import ButtonsContainer from '../containers/ButtonsContainer'; -import ErrorContainer from '../containers/ErrorContainer'; - -const chrome = require('sinon-chrome'); - -configure({ adapter: new (Adapter as any)() }); - -const state = { - tabs: {}, - currentTab: null, -}; - -const dispatch = jest.fn(); -jest.mock('../../../node_modules/intro.js/introjs.css', () => jest.fn()); -jest.mock('../store'); -useStoreContext.mockImplementation(() => [state, dispatch]); - -let wrapper; -global.chrome = chrome; -const port = { - onMessage: { - addListener: () => {}, - }, - onDisconnect: { - addListener: () => {}, - }, -}; -chrome.runtime.connect.returns(port); - -beforeEach(() => { - wrapper = shallow(); - useStoreContext.mockClear(); - dispatch.mockClear(); -}); - -describe('MainContainer rendering', () => { - test('With no snapshots, should not render any containers', () => { - expect(wrapper.find(ErrorContainer).length).toBe(1); - expect(wrapper.find(ActionContainer).length).toBe(0); - expect(wrapper.find(StateContainer).length).toBe(0); - expect(wrapper.find(TravelContainer).length).toBe(0); - expect(wrapper.find(ButtonsContainer).length).toBe(0); - }); - test('With snapshots, should render all containers', () => { - state.currentTab = 87; - state.tabs[87] = { - snapshots: [{}], - status: { - contentScriptLaunched: true, - reactDevToolsInstalled: true, - targetPageisaReactApp: true, - }, - viewIndex: -1, - sliderIndex: 0, - mode: {}, - }; - - wrapper = shallow(); - expect(wrapper.find(ActionContainer).length).toBe(1); - expect(wrapper.find(StateContainer).length).toBe(1); - expect(wrapper.find(TravelContainer).length).toBe(1); - expect(wrapper.find(ButtonsContainer).length).toBe(1); - }); -}); diff --git a/src/app/__tests__enzyme/ignore/MainSlider.test.tsx b/src/app/__tests__enzyme/ignore/MainSlider.test.tsx deleted file mode 100644 index 3f365f730..000000000 --- a/src/app/__tests__enzyme/ignore/MainSlider.test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable react/jsx-props-no-spreading */ -import { shallow, configure } from 'enzyme'; -import React from 'react'; -import Adapter from 'enzyme-adapter-react-16'; -import Slider from 'rc-slider'; -import Tooltip from 'rc-tooltip'; -import MainSlider from '../components/MainSlider'; - -import { useStoreContext } from '../store'; - -configure({ adapter: new (Adapter as any)() }); - -jest.mock('../store'); -// the handle function in MainSlider returns out a Tooltip Component -const handle = Tooltip; - -describe('Unit testing for MainSlider.jsx', () => { - let wrapper; - const props = { - snapshotsLength: 1, - }; - - const state = { - tabs: { - 100: { - sliderIndex: 1, - }, - }, - currentTab: 100, - }; - - const dispatch = jest.fn(); - useStoreContext.mockImplementation(() => [state, dispatch]); - - beforeEach(() => { - wrapper = shallow(); - dispatch.mockClear(); - }); - it('Component should return component from rc-slider library', () => { - expect(wrapper.type()).toEqual(Slider); - }); - it('Component should have min, max, value, and handle props', () => { - expect(wrapper.props()).toHaveProperty('min'); - expect(wrapper.props()).toHaveProperty('max'); - expect(wrapper.props()).toHaveProperty('value'); - expect(wrapper.props()).toHaveProperty('handle'); - }); - it('Prop type tests on component', () => { - expect(typeof wrapper.prop('min')).toEqual('number'); - expect(typeof wrapper.prop('max')).toEqual('number'); - expect(typeof wrapper.prop('value')).toEqual('number'); - expect(typeof wrapper.prop('handle')).toEqual('function'); - }); - - describe('Testing for handle functional component', () => { - // this doesnt work, not sure how to implement yet - // the handle function should return a Tooltip component - // eslint-disable-next-line jest/no-test-prefixes - // eslint-disable-next-line jest/no-disabled-tests - it.skip('handle prop should return component from rc-tooltip library', () => { - expect(wrapper.prop('handle')()).toEqual(handle); - }); - }); -}); diff --git a/src/app/__tests__enzyme/ignore/RouteDescription.test.tsx b/src/app/__tests__enzyme/ignore/RouteDescription.test.tsx deleted file mode 100644 index b1fc02619..000000000 --- a/src/app/__tests__enzyme/ignore/RouteDescription.test.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable react/jsx-filename-extension */ - -import React from 'react'; -import { shallow, configure, render } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import Action from '../components/Action'; -import RouteDescription from '../components/RouteDescription'; - -configure({ adapter: new (Adapter as any)() }); - -describe('Unit testing RouteDescription', () => { - const actionsArr: JSX.Element[] = []; - - actionsArr.push( - null} - sliderIndex={0} - handleOnkeyDown={(e, i) => null} - viewIndex={undefined} - isCurrIndex={false} - routePath='http://localhost:3000/home' - />, - ); - - actionsArr.push( - null} - sliderIndex={0} - handleOnkeyDown={(e, i) => null} - viewIndex={undefined} - isCurrIndex={false} - routePath='http://localhost:3000/home' - />, - ); - - const wrapper = shallow(); - - test('Renders the correct number of Action components', () => { - expect(wrapper.find(Action).length).toBe(2); - }); - - test('Renders a single ".route" class', () => { - expect(wrapper.find('.route').length).toBe(1); - }); - - test('Renders an h3 tag with the correct pathname "Route: "', () => { - expect(wrapper.find('h3').text()).toBe('Route: /home'); - }); -}); diff --git a/src/app/__tests__enzyme/ignore/SwitchApp.test.tsx b/src/app/__tests__enzyme/ignore/SwitchApp.test.tsx deleted file mode 100644 index 632cb56e3..000000000 --- a/src/app/__tests__enzyme/ignore/SwitchApp.test.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import React from 'react'; -import Select from 'react-select'; -import { configure, shallow } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; -import SwitchApp from '../components/SwitchApp'; - -import { useStoreContext } from '../store'; - -configure({ adapter: new (Adapter as any)() }); - -jest.mock('../store'); - -describe('Unit testing for SwitchApp.jsx', () => { - let wrapper; - - const state = { - currentTab: 100, - tabs: { - 100: { - snapshots: [1, 2, 3, 4], - viewIndex: 1, - sliderIndex: 1, - title: 'component', - }, - }, - }; - const dropdownCurrTabLabel = { - value: 100, - label: 'component', - }; - // mockImplementation creates a mock function call - const dispatch = jest.fn(); - - // mockImplementation creates a mock state - useStoreContext.mockImplementation(() => [state, dispatch]); - - beforeEach(() => { - wrapper = shallow(); - dispatch.mockClear(); - }); - - describe('SwitchApp Component', () => { - beforeEach(() => { - wrapper.find('.tab-select-container').simulate('change', {}); - }); - it('SwitchApp component returns