├── .gitignore ├── LICENSE ├── README.md ├── declaration.d.ts ├── docker ├── .dockerignore ├── .travis.yml ├── Dockerfile ├── README-Docker.md └── docker-compose.yml ├── package.json ├── public ├── AccLens_Demo.gif ├── demos │ ├── acc.gif │ ├── endpoint.gif │ ├── guest-login.gif │ ├── signup-login.gif │ ├── snyk-auth-testdep.gif │ ├── snyk-enable.gif │ ├── snyk-fixdep.gif │ ├── snyk-test-app.gif │ └── test-menu.gif ├── electron.jsx ├── generateTest.png ├── icon.icns ├── icon.png ├── inapp-test-demo-run-test.gif ├── index.html ├── mainPage.png ├── manifest.json └── runTest.png ├── server ├── controllers │ ├── cookieController.js │ ├── sessionController.js │ ├── testStateController.js │ └── userController.js ├── models │ ├── sessionModel.js │ ├── testStateModel.js │ └── userModel.js ├── routes │ └── router.js └── server.js ├── src ├── App.jsx ├── App.module.scss ├── __tests__ │ ├── Action.test.jsx │ ├── Assertion.test.jsx │ ├── Hooks.test.js │ ├── LeftPanelTests │ │ ├── hooksLeftPanel.test.js │ │ ├── leftPanel.test.js │ │ ├── leftPanelRedux.test.js │ │ └── puppeteerLeftPanel.test.tsx │ ├── ProjectLoaderTests │ │ └── projectLoader.test.js │ ├── ReduxTestMenu.test.js │ ├── globalReducer.test.js │ ├── puppeteerReducer.test.ts │ ├── reactReducer.test.js │ ├── reduxTestCase.test.js │ ├── reduxTestCaseReducer.test.ts │ ├── spec.e2e.js │ ├── spec.integra.js │ └── spec.test.js ├── assets │ ├── icons │ │ └── add-black-18dp.svg │ ├── images │ │ ├── close.png │ │ ├── content-save-outline.png │ │ ├── describe.png │ │ ├── describe2.png │ │ ├── describehelp.png │ │ ├── drag-vertical.png │ │ ├── file-document-outline.svg │ │ ├── file-export.png │ │ ├── folder-open.png │ │ ├── folder-outline.svg │ │ ├── folder_open.png │ │ ├── google-chrome.png │ │ ├── help-circle.png │ │ ├── home.png │ │ ├── leaf.png │ │ ├── menu.png │ │ ├── minus-box-outline.png │ │ ├── newReact.png │ │ ├── plus-box.png │ │ ├── plus.png │ │ ├── spearmintHomepage.png │ │ ├── testfile.png │ │ └── visual-studio-code.png │ └── stylesheets │ │ ├── colors.scss │ │ ├── fonts.scss │ │ ├── global.scss │ │ └── reset.scss ├── components │ ├── AccTestComponent │ │ ├── AccTestTypes │ │ │ ├── AccTestTypes.module.scss │ │ │ └── AccTestTypes.tsx │ │ ├── CatTagFilter │ │ │ ├── CatTagFilter.module.scss │ │ │ └── CatTagFilter.tsx │ │ ├── DescribeRenderer │ │ │ ├── DescribeRenderer.module.scss │ │ │ └── DescribeRenderer.tsx │ │ ├── ItRenderer │ │ │ ├── ItRenderer.module.scss │ │ │ └── ItRenderer.tsx │ │ ├── PuppeteerUrl │ │ │ └── PuppeteerUrl.tsx │ │ └── StandardTagFilter │ │ │ ├── StandardTagFilter.module.scss │ │ │ └── StandardTagFilter.tsx │ ├── AutoComplete │ │ ├── AutoComplete.jsx │ │ ├── AutoComplete.module.scss │ │ ├── AutoCompleteMockData.jsx │ │ └── AutoCompleteMockData.module.scss │ ├── BrowserView │ │ ├── BrowserView.jsx │ │ └── BrowserView.module.scss │ ├── EditorView │ │ ├── EditorView.jsx │ │ └── EditorView.module.scss │ ├── EndpointTestComponent │ │ ├── Endpoint.module.scss │ │ ├── Endpoint.tsx │ │ ├── EndpointAssertion.tsx │ │ └── JestMatchers.ts │ ├── FileDirectory │ │ ├── FileDirectory.jsx │ │ └── FileDirectory.module.scss │ ├── GetTests │ │ ├── GetTests.js │ │ └── GetTests.module.scss │ ├── Modals │ │ ├── ExportFileModal.jsx │ │ ├── GetTestsModal.jsx │ │ ├── Modal.jsx │ │ ├── Modal.module.scss │ │ ├── UploadTestModal.jsx │ │ └── modalHooks.js │ ├── NavBar │ │ ├── NavBar.jsx │ │ └── NavBar.module.scss │ ├── OpenFolder │ │ ├── OpenFolderButton.jsx │ │ └── OpenFolderButton.module.scss │ ├── PuppeteerTestComponent │ │ ├── PaintTiming │ │ │ ├── PaintTiming.jsx │ │ │ └── PaintTiming.module.scss │ │ └── PuppeteerBrowerSetting │ │ │ └── PuppeteerBrowserSetting.jsx │ ├── ReactHooksTestComponent │ │ ├── HookUpdates │ │ │ ├── HookUpdates.jsx │ │ │ └── HookUpdates.module.scss │ │ ├── HooksAssertion.jsx │ │ └── HooksCallback.jsx │ ├── ReactTestComponent │ │ ├── Action │ │ │ ├── Action.jsx │ │ │ ├── Action.module.scss │ │ │ └── eventTypesList.js │ │ ├── Assertion │ │ │ ├── Assertion.jsx │ │ │ ├── Assertion.module.scss │ │ │ └── matcherTypesList.js │ │ ├── CustomInput │ │ │ ├── CustomInput.jsx │ │ │ └── CustomInput.module.scss │ │ ├── DescribeRenderer │ │ │ ├── DescribeRenderer.jsx │ │ │ └── DescribeRenderer.module.scss │ │ ├── ItRenderer │ │ │ ├── ItRenderer.jsx │ │ │ └── ItRenderer.module.scss │ │ ├── MockData │ │ │ ├── MockData.jsx │ │ │ ├── MockData.module.scss │ │ │ ├── MockDataKey.jsx │ │ │ └── MockDataKey.module.scss │ │ └── Render │ │ │ ├── Prop.jsx │ │ │ ├── Prop.module.scss │ │ │ ├── Render.jsx │ │ │ └── Render.module.scss │ ├── ReduxTestComponent │ │ ├── ActionCreator │ │ │ ├── ActionCreator.jsx │ │ │ └── ActionCreator.module.scss │ │ ├── Middleware │ │ │ ├── Middleware.jsx │ │ │ └── Middleware.module.scss │ │ ├── Reducer │ │ │ ├── Reducer.jsx │ │ │ └── Reducer.module.scss │ │ └── Thunk │ │ │ ├── Thunk.jsx │ │ │ └── Thunk.module.scss │ ├── SearchInput │ │ ├── SearchInput.jsx │ │ └── SearchInput.scss │ ├── Terminal │ │ └── TerminalView.tsx │ ├── TestCase │ │ ├── AccTestCase.tsx │ │ ├── EndpointTestCase.tsx │ │ ├── EndpointTestStatements.tsx │ │ ├── HooksTestCase.tsx │ │ ├── HooksTestStatements.tsx │ │ ├── PuppeteerTestCase.tsx │ │ ├── PuppeteerTestStatements.tsx │ │ ├── ReactContainer.module.scss │ │ ├── ReactTestCase.jsx │ │ ├── ReactTestStatements.jsx │ │ ├── ReduxTestCase.tsx │ │ ├── ReduxTestStatements.tsx │ │ ├── SecTestCase.tsx │ │ ├── TestCase.module.scss │ │ └── importOptions.ts │ ├── TestMenu │ │ ├── AccTestMenu.tsx │ │ ├── EndpointTestMenu.tsx │ │ ├── HooksTestMenu.tsx │ │ ├── PuppeteerTestMenu.tsx │ │ ├── ReactTestMenu.jsx │ │ ├── ReduxTestMenu.tsx │ │ ├── SecTestMenu.tsx │ │ ├── TestMenu.module.scss │ │ └── testMenuHooks.js │ ├── ToolTip │ │ ├── ToolTip.jsx │ │ ├── ToolTip.scss │ │ ├── ToolTipAsync.jsx │ │ └── ToolTipMatcher.jsx │ └── UploadTest │ │ ├── UploadTest.js │ │ └── UploadTest.module.scss ├── context │ ├── actions │ │ ├── accTestCaseActions.ts │ │ ├── endpointTestCaseActions.ts │ │ ├── globalActions.js │ │ ├── hooksTestCaseActions.ts │ │ ├── mockDataActions.js │ │ ├── puppeteerTestCaseActions.ts │ │ ├── reactTestCaseActions.js │ │ ├── reduxTestCaseActions.ts │ │ └── secTestCaseActions.ts │ ├── reducers │ │ ├── accTestCaseReducer.ts │ │ ├── endpointTestCaseReducer.ts │ │ ├── globalReducer.js │ │ ├── hooksTestCaseReducer.ts │ │ ├── mockDataReducer.js │ │ ├── puppeteerTestCaseReducer.ts │ │ ├── reactTestCaseReducer.js │ │ ├── reduxTestCaseReducer.ts │ │ └── secTestCaseReducer.ts │ └── useGenerateTest.jsx ├── index.js ├── pages │ ├── About │ │ ├── About.module.scss │ │ └── About.tsx │ ├── LeftPanel │ │ ├── LeftPanel.jsx │ │ └── LeftPanel.module.scss │ ├── ProjectLoader │ │ ├── ProjectLoader.jsx │ │ └── ProjectLoader.module.scss │ ├── RightPanel │ │ ├── RightPanel.jsx │ │ └── RightPanel.module.scss │ └── TestFile │ │ └── TestFile.jsx └── utils │ ├── accTypes.ts │ ├── endpointTypes.ts │ ├── hooksTypes.ts │ ├── puppeteerTypes.ts │ ├── reduxTypes.ts │ ├── secTypes.ts │ └── terminalTypes.ts ├── tsconfig.json └── webpack.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # Custom ignore files 107 | /out 108 | /build 109 | .DS_Store 110 | package-lock.json 111 | .dccache 112 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2021 spearmintjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /declaration.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.scss' { 2 | const content: Record; 3 | export default content; 4 | } 5 | 6 | declare module 'react-beautiful-dnd' -------------------------------------------------------------------------------- /docker/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | Dockerfile 3 | .git 4 | .gitignore 5 | .dockerignore 6 | .env 7 | package-lock.json -------------------------------------------------------------------------------- /docker/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node 4 | cache: 5 | directories: 6 | - node_modules 7 | script: 8 | - npm test 9 | deploy: 10 | skip_cleanup: true 11 | on: master -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 2 | RUN apt-get update && apt-get install \ 3 | git libx11-xcb1 libxcb-dri3-0 libxtst6 libnss3 libatk-bridge2.0-0 libgtk-3-0 libxss1 libasound2 \ 4 | -yq --no-install-suggests --no-install-recommends \ 5 | && apt-get clean && rm -rf /var/lib/apt/lists/* 6 | RUN useradd -d /spearmint spearmint 7 | USER spearmint 8 | WORKDIR /spearmint 9 | COPY package.json . 10 | RUN npm run install-once 11 | COPY . . 12 | EXPOSE 3000 13 | USER root 14 | RUN chown root /spearmint/node_modules/electron/dist/chrome-sandbox 15 | RUN chmod 4755 /spearmint/node_modules/electron/dist/chrome-sandbox 16 | USER spearmint 17 | CMD ["npm", "start"] 18 | -------------------------------------------------------------------------------- /docker/README-Docker.md: -------------------------------------------------------------------------------- 1 | # About 2 | A previous Spearmint team attempted to containerize the Spearmint application. As of version 0.8.0, these files do not work. However, we wanted to preserve them in case future open-source contributers would like to attempt to re-contanerize the application. -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | frontend: 4 | container_name: frontend 5 | image: frontend 6 | security_opt: 7 | - seccomp=profile.json 8 | environment: 9 | - DISPLAY=host.docker.internal:0 10 | stdin_open: true 11 | ports: 12 | - "3000:3000" 13 | networks: 14 | - spearmint 15 | backend: 16 | container_name: backend 17 | image: backend 18 | ports: 19 | - "3001:3001" 20 | networks: 21 | - spearmint 22 | networks: 23 | spearmint: 24 | driver: bridge 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spearmint", 3 | "version": "0.8.0", 4 | "description": "An open-source developer tool that simplifies testing and hopes to help increase awareness about web accessibility.", 5 | "main": "public/electron.jsx", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "electron-forge start", 9 | "start-dev": "electron .", 10 | "watch": "webpack --config webpack.config.ts --watch", 11 | "package": "electron-forge package", 12 | "make": "electron-forge make" 13 | }, 14 | "keywords": [], 15 | "author": "team spearmint", 16 | "license": "ISC", 17 | "dependencies": { 18 | "@babel/core": "^7.15.0", 19 | "@babel/preset-env": "^7.15.0", 20 | "@babel/preset-react": "^7.14.5", 21 | "@capacitor/screen-reader": "^1.0.6", 22 | "@codemirror/lang-javascript": "^0.19.3", 23 | "@material-ui/core": "^4.12.3", 24 | "@material-ui/icons": "^4.11.2", 25 | "@uiw/react-codemirror": "^4.2.4", 26 | "babel-loader": "^8.2.2", 27 | "bcrypt": "^5.0.1", 28 | "classnames": "^2.3.1", 29 | "codemirror": "^5.64.0", 30 | "concurrently": "^6.4.0", 31 | "cookie-parser": "^1.4.6", 32 | "css-loader": "^6.2.0", 33 | "dotenv": "^10.0.0", 34 | "electron-devtools-installer": "^3.2.0", 35 | "electron-squirrel-startup": "^1.0.0", 36 | "express": "^4.17.1", 37 | "fix-path": "^3.0.0", 38 | "js-beautify": "^1.14.0", 39 | "mongoose": "^6.0.14", 40 | "node-fetch": "^3.1.0", 41 | "node-pty": "^0.10.1", 42 | "react": "^17.0.2", 43 | "react-autosuggest": "^10.1.0", 44 | "react-beautiful-dnd": "^13.1.0", 45 | "react-dom": "^17.0.2", 46 | "react-modal": "^3.14.4", 47 | "sass": "^1.37.5", 48 | "sass-loader": "^12.1.0", 49 | "save-dev": "0.0.1-security", 50 | "snyk": "^1.790.0", 51 | "style-loader": "^3.2.1", 52 | "webpack": "^5.50.0", 53 | "webpack-cli": "^4.7.2", 54 | "xterm": "^4.15.0", 55 | "xterm-for-react": "^1.0.4" 56 | }, 57 | "devDependencies": { 58 | "@babel/preset-typescript": "^7.15.0", 59 | "@electron-forge/cli": "^6.0.0-beta.61", 60 | "@electron-forge/maker-deb": "^6.0.0-beta.61", 61 | "@electron-forge/maker-rpm": "^6.0.0-beta.61", 62 | "@electron-forge/maker-squirrel": "^6.0.0-beta.61", 63 | "@electron-forge/maker-zip": "^6.0.0-beta.61", 64 | "@types/webpack-dev-server": "^3.11.5", 65 | "@typescript-eslint/parser": "^5.6.0", 66 | "axe-core": "^4.3.5", 67 | "electron": "^13.6.3", 68 | "electron-rebuild": "^3.2.5", 69 | "electron-reload": "^2.0.0-alpha.1", 70 | "eslint-plugin-import": "^2.25.3", 71 | "jest": "^27.4.5", 72 | "nodemon": "^2.0.15", 73 | "regenerator-runtime": "^0.13.9", 74 | "ts-node": "^10.2.0", 75 | "typescript": "^4.3.5", 76 | "webpack-dev-server": "^3.11.2" 77 | }, 78 | "config": { 79 | "forge": { 80 | "packagerConfig": {}, 81 | "makers": [ 82 | { 83 | "name": "@electron-forge/maker-squirrel", 84 | "config": { 85 | "name": "spearmint" 86 | } 87 | }, 88 | { 89 | "name": "@electron-forge/maker-zip", 90 | "platforms": [ 91 | "darwin" 92 | ] 93 | }, 94 | { 95 | "name": "@electron-forge/maker-deb", 96 | "config": {} 97 | }, 98 | { 99 | "name": "@electron-forge/maker-rpm", 100 | "config": {} 101 | } 102 | ] 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /public/AccLens_Demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/AccLens_Demo.gif -------------------------------------------------------------------------------- /public/demos/acc.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/acc.gif -------------------------------------------------------------------------------- /public/demos/endpoint.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/endpoint.gif -------------------------------------------------------------------------------- /public/demos/guest-login.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/guest-login.gif -------------------------------------------------------------------------------- /public/demos/signup-login.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/signup-login.gif -------------------------------------------------------------------------------- /public/demos/snyk-auth-testdep.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/snyk-auth-testdep.gif -------------------------------------------------------------------------------- /public/demos/snyk-enable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/snyk-enable.gif -------------------------------------------------------------------------------- /public/demos/snyk-fixdep.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/snyk-fixdep.gif -------------------------------------------------------------------------------- /public/demos/snyk-test-app.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/snyk-test-app.gif -------------------------------------------------------------------------------- /public/demos/test-menu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/demos/test-menu.gif -------------------------------------------------------------------------------- /public/generateTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/generateTest.png -------------------------------------------------------------------------------- /public/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/icon.icns -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/icon.png -------------------------------------------------------------------------------- /public/inapp-test-demo-run-test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/inapp-test-demo-run-test.gif -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/mainPage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/mainPage.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "spearmint", 3 | "name": "spearmint", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /public/runTest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/public/runTest.png -------------------------------------------------------------------------------- /server/controllers/cookieController.js: -------------------------------------------------------------------------------- 1 | const cookieController = {}; 2 | 3 | // Middleware to initialize a cookie when user logs in 4 | cookieController.setSSIDCookie = (req, res, next) => { 5 | res.cookie('ssid', JSON.stringify(res.locals.userId).replace(/\"/g, '')); 6 | return next(); 7 | }; 8 | 9 | // Middleware to delete a cookie upon user logging out 10 | cookieController.deleteCookie = (req, res, next) => { 11 | res.clearCookie('ssid'); 12 | return next(); 13 | }; 14 | 15 | module.exports = cookieController; 16 | -------------------------------------------------------------------------------- /server/controllers/sessionController.js: -------------------------------------------------------------------------------- 1 | // Import the session model that defines schema of session 2 | const Session = require('../models/sessionModel'); 3 | 4 | const sessionController = {}; 5 | 6 | // Middleware to initialize a session upon successful login 7 | sessionController.startSession = (req, res, next) => { 8 | Session.create({ cookieId: res.locals.userId }, (err, result) => { 9 | if (err && err.code !== 11000) return next(err); 10 | res.locals.ssid = res.locals.userId; 11 | return next(); 12 | }); 13 | }; 14 | 15 | // Middleware to end currently active sessions, if any 16 | sessionController.endSession = (req, res, next) => { 17 | Session.deleteMany({ cookieId: req.cookies.ssid }, (err) => { 18 | if (err) return next(err); 19 | return next(); 20 | }); 21 | }; 22 | 23 | // Middleware to check if entered user is currently already logged in 24 | sessionController.isLoggedIn = (req, res, next) => { 25 | Session.find({ cookieId: req.cookies.ssid }, (err, data) => { 26 | if (err) return next(err); 27 | if (data.length === 0) return next('User Not Logged In'); 28 | return next(); 29 | }); 30 | }; 31 | 32 | module.exports = sessionController; 33 | -------------------------------------------------------------------------------- /server/controllers/testStateController.js: -------------------------------------------------------------------------------- 1 | // Import test state model that defines the structure of test stored in DB 2 | const TestState = require('../models/testStateModel'); 3 | const testStateController = {}; 4 | 5 | // Middleware to validate the data we're using to attempt to create a new document to the MongoDB 6 | testStateController.validate = (req, res, next) => { 7 | try { 8 | const { testName, testType, testState } = req.body; 9 | const userId = req.cookies.ssid; 10 | 11 | // if any type doesnt match the model, pass error log into next() 12 | if (typeof userId !== 'string' || 13 | typeof testName !== 'string' || 14 | typeof testType !== 'string' || 15 | typeof testState !== 'object') return next({ log: 'Encountered a type error' }); 16 | 17 | // else save a newTestState to res.locals so we can pass it forward to the doc upload middleware 18 | res.locals.newTestState = { 19 | userId, 20 | testName, 21 | testType, 22 | testState 23 | } 24 | 25 | return next(); 26 | } 27 | catch (err) { 28 | return next('Validation process failed') 29 | } 30 | } 31 | 32 | // Middleware to upload a passed test into DB 33 | testStateController.upload = (req, res, next) => { 34 | try { 35 | // if we've reached upload, the data from which we're attempting to create a new document 36 | // has been validated. therefore we invoke models.create() passing in the object that is our new document 37 | // as well as a callback to handle any error in the process of writing this new doc to the database 38 | TestState.create( 39 | res.locals.newTestState, 40 | (err) => { 41 | if (err) return next('Upload Failed'); 42 | return next(); 43 | } 44 | ); 45 | } 46 | catch (err) { 47 | return next('Document creation function error'); 48 | } 49 | }; 50 | 51 | // Middleware too get all saved tests of current user and of selected type 52 | testStateController.getTests = (req, res, next) => { 53 | TestState.find({ userId: req.cookies.ssid, testType: req.params.testType }, (err, result) => { 54 | // If an error occurs, invoke error handler with err object 55 | if (err) return next(err); 56 | // Save resulting tests array to locals object 57 | res.locals.tests = result; 58 | return next(); 59 | }); 60 | }; 61 | 62 | module.exports = testStateController; 63 | -------------------------------------------------------------------------------- /server/controllers/userController.js: -------------------------------------------------------------------------------- 1 | const User = require('../models/userModel'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const userController = {}; 5 | 6 | // Middleware to encrypt passwords using bcrypt 7 | userController.bcrypt = (req, res, next) => { 8 | // The cost factor determines how much time is needed to calculate a single bcrypt hash 9 | const saltRounds = 10; 10 | // Destructure password from request body 11 | const { password } = req.body; 12 | // Generate the salt by passing in saltRounds (cost factor) 13 | bcrypt.genSalt(saltRounds, (err, salt) => { 14 | // Hash a password by passing in the plaintext into the hash function 15 | bcrypt.hash(password, salt, (err, hash) => { 16 | // Save encrypted password into res.locals to be accessed later 17 | res.locals.encryptedPassword = hash; 18 | return next(); 19 | }); 20 | }); 21 | }; 22 | 23 | // Middleware to save user information in database 24 | userController.signup = (req, res, next) => { 25 | // collection.create method to insert new user 26 | User.create( 27 | // Pass in username from request body and encrypted password 28 | { username: req.body.username, password: res.locals.encryptedPassword }, 29 | // Callback to handle results of query 30 | (err, newUser) => { 31 | // If there is an error, invoke global error handler 32 | if (err) return next(err); 33 | // Save user ID into response locals 34 | res.locals.userId = newUser._id; 35 | // Inovke next middleware 36 | return next(); 37 | } 38 | ); 39 | }; 40 | 41 | // Middleware to check credentials and log user into application 42 | userController.login = (req, res, next) => { 43 | // Collection.find method to look for all user instances with passed username 44 | User.find({ username: req.body.username }, (err, result) => { 45 | // If there is an error, invoke global error handler 46 | if (err) return next(err); 47 | // If there are no matching usernames, invoke global error handler 48 | if (result.length === 0) return next('Incorrect username/password combo'); 49 | // If there is a user with passed username, use the bcrypt.compare method to compare plaintext password with encrypted password 50 | bcrypt.compare(req.body.password, result[0].password, (err, match) => { 51 | // If an error occurs in the compare method, invoke global error handler 52 | if (err) return next(err); 53 | // If there is a match, invoke next middleware 54 | if (match) { 55 | res.locals.userId = result[0]._id; 56 | return next(); 57 | } 58 | // If there is no match, invoke global error handler 59 | return next('Incorrect username/password combination'); 60 | }); 61 | }); 62 | }; 63 | 64 | userController.getUsers = (req, res, next) => { 65 | // Collection.find method to look for all user instances with passed username 66 | User.find({}, (err, result) => { 67 | // If there is an error, invoke global error handler 68 | if (err) return next(err); 69 | res.locals.users = result; 70 | return next(); 71 | }); 72 | }; 73 | 74 | 75 | module.exports = userController; 76 | -------------------------------------------------------------------------------- /server/models/sessionModel.js: -------------------------------------------------------------------------------- 1 | // Import mongoose for MongoDB object modeling 2 | const mongoose = require('mongoose'); 3 | // Schema constructor 4 | const Schema = mongoose.Schema; 5 | 6 | // Initialize a new schema object for collection 'session' 7 | const sessionSchema = new Schema({ 8 | // Save user ID 9 | cookieId: { type: String, required: true, unique: true }, 10 | createdAt: { type: Date, default: Date.now }, 11 | }); 12 | 13 | module.exports = mongoose.model('Session', sessionSchema); 14 | -------------------------------------------------------------------------------- /server/models/testStateModel.js: -------------------------------------------------------------------------------- 1 | // Import mongoose for MongoDB object modeling 2 | const mongoose = require('mongoose'); 3 | // Schema constructor 4 | const Schema = mongoose.Schema; 5 | 6 | // Initialize a new schema object for collection 'testState' 7 | const testStateSchema = new Schema({ 8 | // Save ID of user that saves test 9 | userId: { type: String, required: true }, 10 | // Save name of test as user input 11 | testName: { type: String, required: true }, 12 | // Save corresponding type of test 13 | testType: { type: String, required: true }, 14 | // Save test state object 15 | testState: { type: Object, required: true }, 16 | }); 17 | 18 | // Mongoose does not validate the types of the properties specified in schema 19 | // It will only coerce the properties to equal the types specified above 20 | // Therefore implementing data validation inside testStateController.upload 21 | 22 | module.exports = mongoose.model('testState', testStateSchema); 23 | -------------------------------------------------------------------------------- /server/models/userModel.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config({ path: __dirname + '/./../../.env' }); 2 | // Import mongoose for MongoDB object modeling 3 | const mongoose = require('mongoose'); 4 | 5 | const MONGO_URI = `mongodb+srv://ericgpark:${process.env.MONGO_PW}@spearmint.j5ikp.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`; 6 | 7 | mongoose 8 | .connect(MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true }) 9 | .then(() => console.log('Connected to Mongo DB Successfully')) 10 | .catch((err) => console.log(err)); 11 | 12 | const Schema = mongoose.Schema; 13 | 14 | // Initialize a new schema object for collection 'user' 15 | const userSchema = new Schema({ 16 | // Save username and password of user 17 | username: { type: String, require: true, unique: true }, 18 | password: { type: String, require: true }, 19 | }); 20 | 21 | module.exports = mongoose.model('user', userSchema); 22 | -------------------------------------------------------------------------------- /server/routes/router.js: -------------------------------------------------------------------------------- 1 | // Import Express to streamline server logic with router 2 | const express = require('express'); 3 | // Import all relevant controller objects equipped with middleware 4 | const userController = require('../controllers/userController'); 5 | const cookieController = require('../controllers/cookieController'); 6 | const sessionController = require('../controllers/sessionController'); 7 | const testStateController = require('../controllers/testStateController'); 8 | // const githubController = require('../controllers/githubController'); 9 | 10 | // Initialize an express router 11 | const router = express.Router(); 12 | 13 | // Set up route for post requests to /signup 14 | router.post( 15 | '/signup', 16 | // Bcrypt middleware to encrypt user password 17 | userController.bcrypt, 18 | // Signup middleware to sign user up with encrypted credentials 19 | userController.signup, 20 | // Anonymous middleware to send back valid response 21 | (req, res) => { 22 | res.status(200) 23 | .json('Sign Up Successful'); 24 | } 25 | ); 26 | 27 | // Set up route for post requests to /login 28 | router.post( 29 | '/login', 30 | // Login middleware checks encrypted credentials 31 | userController.login, 32 | // Cookie middleware to set up a new cookie 33 | cookieController.setSSIDCookie, 34 | // Session middleware to initialize new session 35 | sessionController.startSession, 36 | // Anonymous middleware to send back valid response 37 | (req, res) => { 38 | console.log('ssid:', res.locals.ssid); 39 | res.status(200).json({ ssid: res.locals.ssid }); 40 | } 41 | ); 42 | 43 | // Set up route for get requests to /logout 44 | router.get( 45 | '/logout', 46 | // Session middleware to end any existing sessions 47 | sessionController.endSession, 48 | // Anonymous middleware to send back valid response 49 | (req, res) => { 50 | res.status(200).json('Logged Out Successfully'); 51 | } 52 | ); 53 | 54 | // Set up route for post requests to /upload 55 | router.post( 56 | '/upload', 57 | // Session middleware to check if current user is signed in 58 | sessionController.isLoggedIn, 59 | // Middleware to validate whether our data fits the model 60 | testStateController.validate, 61 | // Upload middleware to save passed test object into DB 62 | testStateController.upload, 63 | // Anonymous middleware to send back valid response 64 | (req, res) => { 65 | res.status(200).json('Test Uploaded Successfully'); 66 | } 67 | ); 68 | 69 | // Set up route for get requests to /getTests with type passed as param 70 | router.get( 71 | '/getTests/:testType', 72 | // Session middleware to check if current user is signed in 73 | sessionController.isLoggedIn, 74 | // GetTests middleware to retrieve all saved tests from DB 75 | testStateController.getTests, 76 | // Anonymous middleware to send back valid response 77 | (req, res) => { 78 | res.status(200).json(res.locals.tests); 79 | } 80 | ); 81 | 82 | module.exports = router; -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const cookieParser = require('cookie-parser'); 4 | const router = require('./routes/router'); 5 | const PORT = 3001; 6 | 7 | app.use(express.json()); 8 | app.use(express.urlencoded({ extended: true })); 9 | app.use(cookieParser()); 10 | 11 | app.use('/', router); 12 | 13 | // Any other request is caught here 14 | app.use((req, res) => res.status(404).send('Error 404: No content found')); 15 | 16 | // Express global error handler 17 | app.use((err, req, res, next) => { 18 | const defaultErr = { 19 | log: 'Express error handler caught unknown middleware error', 20 | status: 500, 21 | message: { err: 'An error occurred' }, 22 | }; 23 | const errorObj = Object.assign({}, defaultErr, err); 24 | console.log(errorObj.log, ' ', err); 25 | return res.status(errorObj.status).json(err); 26 | }); 27 | 28 | // Start server 29 | app.listen(PORT, () => { 30 | console.log(`Server listening on port: ${PORT}`); 31 | }); 32 | 33 | module.exports = app; -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { useReducer } from 'react'; 2 | import styles from './App.module.scss'; 3 | import { GlobalContext, globalState, globalReducer } from './context/reducers/globalReducer'; 4 | import ProjectLoader from './pages/ProjectLoader/ProjectLoader.jsx'; 5 | import NavBar from './components/NavBar/NavBar'; 6 | import LeftPanel from './pages/LeftPanel/LeftPanel'; 7 | import RightPanel from './pages/RightPanel/RightPanel'; 8 | // import About from './pages/About/About'; 9 | 10 | const App = () => { 11 | const [global, dispatchToGlobal] = useReducer(globalReducer, globalState); 12 | 13 | if (!global.isProjectLoaded) { 14 | return ( 15 |
16 | {/* pass global state and dispatch function as prop to context provider for child components */} 17 | 18 | {/* */} 19 | 20 | 21 |
22 | ); 23 | } 24 | return ( 25 | /** 26 | * Wrap the components that we want to share the unique states with. 27 | * You can only provide one value to a Provider. 28 | * - In order to avoid creating separate Contexts, wrap multiples in an array (ex: testCase and dispatchToTestCase). 29 | * 30 | * 31 | * NOTE: This concept is similar to Redux and how it provides the store to your top-level component and all of its children. 32 | * We just have to create separate providers for each reducer because we don’t have a global store ala Redux. 33 | * 34 | * 35 | * We access the value that we gave to the Provider through useContext 36 | */ 37 |
50 | 51 | {global.isProjectLoaded === 'about' ? ( 52 | <> 53 | 54 | 55 | {' '} 56 | 57 | ) : ( 58 | <> 59 | 60 | 61 | 62 | )} 63 | {global.isRightPanelOpen ? : ''} 64 | 65 |
66 | ); 67 | }; 68 | 69 | export default App; 70 | -------------------------------------------------------------------------------- /src/App.module.scss: -------------------------------------------------------------------------------- 1 | @import 'assets/stylesheets/global'; 2 | @import 'assets/stylesheets/reset'; 3 | @import 'assets/stylesheets/fonts'; 4 | @import 'assets/stylesheets/colors'; 5 | 6 | //file directory is open but right panel is closed 7 | #fileDirectoryOpenRightPanelClosed { 8 | display: grid; 9 | grid-template-columns: 280px auto; 10 | grid-template-rows: 100vh; 11 | grid-template-areas: 'navBar leftPanel'; 12 | background-color: $light-gray3; 13 | } 14 | 15 | //both open 16 | #fileDirectoryOpenRightPanelOpen { 17 | display: grid; 18 | grid-template-columns: 280px auto 40%; 19 | grid-template-rows: 100vh; 20 | grid-template-areas: 'navBar leftPanel rightPanel'; 21 | background-color: $light-gray3; 22 | } 23 | 24 | //file directory is closed but right panel is open 25 | #fileDirectoryClosedRightPanelOpen { 26 | display: grid; 27 | grid-template-columns: 48px auto 50%; 28 | grid-template-rows: 100vh; 29 | grid-template-areas: 'navBar leftPanel rightPanel'; 30 | background-color: $light-gray3; 31 | } 32 | 33 | //both closed 34 | #fileDirectoryClosedRightPanelClosed { 35 | display: grid; 36 | grid-template-columns: 48px auto; 37 | grid-template-rows: 100vh; 38 | grid-template-areas: 'navBar leftPanel'; 39 | background-color: $light-gray3; 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/__tests__/Action.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import '@testing-library/jest-dom/extend-expect'; 4 | import { ReactTestCaseContext } from '../context/reducers/reactTestCaseReducer'; 5 | import { MockDataContext } from '../context/reducers/mockDataReducer'; 6 | import Action from '../components/ReactTestComponent/Action/Action'; 7 | 8 | const dispatchToReactTextCase = jest.fn(); 9 | const dispatchToMockData = jest.fn(); 10 | 11 | const reactTestCaseState = { 12 | describeId: 'describe0', 13 | itId: 'it0', 14 | statementId: 'statement0', 15 | statement: { 16 | id: 'statement0', 17 | itId: 'it0', 18 | describeId: 'describe0', 19 | type: 'action', 20 | eventType: '', 21 | eventValue: null, 22 | queryVariant: '', 23 | querySelector: '', 24 | queryValue: '', 25 | suggestions: [], 26 | }, 27 | }; 28 | 29 | const mockDataState = { 30 | mockData: [], 31 | hasMockData: false, 32 | }; 33 | 34 | describe('Assertion ', () => { 35 | it('renders without crashing', () => { 36 | const div = document.createElement('div'); 37 | render( 38 | 39 | 40 | 41 | 42 | 43 | ); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/__tests__/Assertion.test.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import '@testing-library/jest-dom/extend-expect'; 4 | import { ReactTestCaseContext } from '../context/reducers/reactTestCaseReducer'; 5 | import { MockDataContext } from '../context/reducers/mockDataReducer'; 6 | import Assertion from '../components/ReactTestComponent/Assertion/Assertion'; 7 | 8 | const dispatchToReactTextCase = jest.fn(); 9 | const dispatchToMockData = jest.fn(); 10 | 11 | const reactTestCaseState = { 12 | describeId: 'describe0', 13 | itId: 'it0', 14 | statementId: 'statement0', 15 | statement: { 16 | id: 'statement0', 17 | itId: 'it0', 18 | describeId: 'describe0', 19 | type: 'assertion', 20 | queryVariant: '', 21 | querySelector: '', 22 | queryValue: '', 23 | isNot: false, 24 | matcherType: '', 25 | matcherValue: '', 26 | suggestions: [], 27 | }, 28 | }; 29 | 30 | const mockDataState = { 31 | mockData: [], 32 | hasMockData: false, 33 | }; 34 | 35 | describe('Assertion ', () => { 36 | it('renders without crashing', () => { 37 | // const div = document.createElement('div'); 38 | 39 | const { getByText, getAllByRole, debug } = render( 40 | 41 | 42 | 43 | 44 | 45 | ); 46 | expect(getByText('Assertion')).toBeInTheDocument; 47 | 48 | expect(getAllByRole('textbox')).toBeInTheDocument; 49 | 50 | 51 | debug(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/__tests__/Hooks.test.js: -------------------------------------------------------------------------------- 1 | import { renderHook, act, cleanup } from '@testing-library/react-hooks'; 2 | import useToggleModal from '../components/TestMenu/testMenuHooks'; 3 | 4 | afterEach(cleanup); 5 | describe('asomsdfak', () => { 6 | test('hooks should render', () => { 7 | const { result } = renderHook(() => useToggleModal('redux')); 8 | expect(result.current.title).toBe('redux'); 9 | expect(result.current.isModalOpen).toBe(false); 10 | expect(typeof result.current.openModal).toBe('function'); 11 | }); 12 | 13 | test('openModal should work', () => { 14 | const { result } = renderHook(() => useToggleModal('redux')); 15 | 16 | act(() => { 17 | result.current.openModal(); 18 | }); 19 | expect(result.current.title).toBe('New Test'); 20 | expect(result.current.isModalOpen).toBe(true); 21 | }); 22 | 23 | test('openScriptModal should work', () => { 24 | const { result } = renderHook(() => useToggleModal('redux')); 25 | 26 | act(() => { 27 | result.current.openScriptModal(); 28 | }); 29 | expect(result.current.title).toBe('redux'); 30 | expect(result.current.isModalOpen).toBe(true); 31 | }); 32 | 33 | test('closeModal should work', () => { 34 | const { result } = renderHook(() => useToggleModal('redux')); 35 | 36 | act(() => { 37 | result.current.closeModal(); 38 | }); 39 | expect(result.current.title).toBe('redux'); 40 | expect(result.current.isModalOpen).toBe(false); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/__tests__/LeftPanelTests/hooksLeftPanel.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import HooksTestCase from '../../../components/TestCase/HooksTestCase'; 3 | import { GlobalContext } from '../../../context/reducers/globalReducer'; 4 | import { TestFileModalContext } from '../../../context/reducers/testFileModalReducer'; 5 | import { HooksTestCaseContext } from '../../../context/reducers/hooksTestCaseReducer'; 6 | 7 | import { mount } from 'enzyme'; 8 | import { configure } from 'enzyme'; 9 | import Adapter from 'enzyme-adapter-react-16'; 10 | 11 | configure({ adapter: new Adapter() }); 12 | 13 | let wrapper, 14 | globalM, 15 | dispatchToGlobal, 16 | hooksTestCase, 17 | dispatchToHooksTestCase, 18 | testFileModal, 19 | dispatchToTestFileModal; 20 | 21 | beforeEach(() => { 22 | globalM = { 23 | url: null, 24 | isProjectLoaded: false, 25 | fileTree: null, 26 | componentName: '', 27 | isFileDirectoryOpen: true, 28 | rightPanelDisplay: 'browserView', 29 | displayedFileCode: '', 30 | isFolderOpen: {}, 31 | isFileHighlighted: '', 32 | projectFilePath: '', 33 | filePathMap: {}, 34 | }; 35 | dispatchToGlobal = jest.fn(); 36 | 37 | testFileModal = { 38 | isTestModalOpen: true, 39 | }; 40 | dispatchToTestFileModal = jest.fn(); 41 | 42 | hooksTestCase = { 43 | hooksTestStatement: '', 44 | hooksStatements: [], 45 | }; 46 | dispatchToHooksTestCase = jest.fn(); 47 | 48 | wrapper = mount( 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | ); 57 | 58 | jest.resetModules(); 59 | }); 60 | 61 | describe('testing hooks left panel', () => { 62 | it('renders the hooks test case with corresponding buttons', () => { 63 | expect(wrapper.text()).toContain('Context'); 64 | expect(wrapper.text()).toContain('Hook: Updates'); 65 | expect(wrapper.text()).toContain('Hook: Rendering'); 66 | }); 67 | 68 | it('hook: render button dispatches to test case', () => { 69 | const renderBtn = wrapper.find('.hookRenderButton'); 70 | renderBtn.simulate('click'); 71 | expect(dispatchToHooksTestCase).toHaveBeenCalled(); 72 | }); 73 | 74 | it('hook: updates button dispatches to test case', () => { 75 | const updatesBtn = wrapper.find('.hookUpdatesButton'); 76 | updatesBtn.simulate('click'); 77 | expect(dispatchToHooksTestCase).toHaveBeenCalled(); 78 | }); 79 | 80 | it('context button dispatches to test case', () => { 81 | const contextBtn = wrapper.find('.contextButton'); 82 | contextBtn.simulate('click'); 83 | expect(dispatchToHooksTestCase).toHaveBeenCalled(); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /src/__tests__/LeftPanelTests/leftPanelRedux.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReduxTestCase from '../../../components/TestCase/ReduxTestCase'; 3 | import { GlobalContext } from '../../../context/reducers/globalReducer'; 4 | import { ReduxTestCaseContext } from '../../../context/reducers/reduxTestCaseReducer'; 5 | import { TestFileModalContext } from '../../../context/reducers/testFileModalReducer'; 6 | import { mount, configure } from 'enzyme'; 7 | import Adapter from 'enzyme-adapter-react-16'; 8 | 9 | configure({ adapter: new Adapter() }); 10 | 11 | let wrapper, 12 | globalM, 13 | dispatchToGlobal, 14 | reduxTestCase, 15 | dispatchToReduxTestCase, 16 | testFileModal, 17 | dispatchToTestFileModal; 18 | 19 | beforeEach(() => { 20 | globalM = { 21 | url: null, 22 | isProjectLoaded: false, 23 | fileTree: null, 24 | componentName: '', 25 | isFileDirectoryOpen: true, 26 | rightPanelDisplay: 'browserView', 27 | displayedFileCode: '', 28 | isFolderOpen: {}, 29 | isFileHighlighted: '', 30 | projectFilePath: '', 31 | filePathMap: {}, 32 | }; 33 | dispatchToGlobal = jest.fn(); 34 | reduxTestCase = { 35 | reduxTestStatement: '', 36 | reduxStatements: [], 37 | }; 38 | 39 | testFileModal = {}; 40 | dispatchToTestFileModal = jest.fn(); 41 | 42 | dispatchToReduxTestCase = jest.fn(); 43 | 44 | wrapper = mount( 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ); 53 | 54 | jest.resetModules(); 55 | }); 56 | 57 | describe('testing left panel redux test menu', () => { 58 | it('renders the redux menu with initial buttons and first render boxes', () => { 59 | expect(wrapper.text()).toContain('Reducer'); 60 | expect(wrapper.text()).toContain('Action Creator'); 61 | expect(wrapper.text()).toContain('Async Action Creator'); 62 | expect(wrapper.text()).toContain('Middleware'); 63 | }); 64 | 65 | it('onclick function is invoked when reducer button is clicked', () => { 66 | const button = wrapper.find('[data-testid="reducerButton"]'); 67 | button.simulate('click'); 68 | expect(dispatchToReduxTestCase).toHaveBeenCalled(); 69 | }); 70 | 71 | it('onclick function is invoked when action creator button is clicked', () => { 72 | const button = wrapper.find('[data-testid="actionCreatorButton"]'); 73 | button.simulate('click'); 74 | expect(dispatchToReduxTestCase).toHaveBeenCalled(); 75 | }); 76 | 77 | it('onclick function is invoked when async action creator button is clicked', () => { 78 | const button = wrapper.find('[data-testid="asyncButton"]'); 79 | button.simulate('click'); 80 | expect(dispatchToReduxTestCase).toHaveBeenCalled(); 81 | }); 82 | 83 | it('onclick function is invoked when middleware button is clicked', () => { 84 | const button = wrapper.find('[data-testid="middlewareButton"]'); 85 | button.simulate('click'); 86 | expect(dispatchToReduxTestCase).toHaveBeenCalled(); 87 | }); 88 | 89 | it('there should be 5 buttons', () => { 90 | expect(wrapper.find('button').length).toEqual(5); 91 | }); 92 | }); 93 | -------------------------------------------------------------------------------- /src/__tests__/LeftPanelTests/puppeteerLeftPanel.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, cleanup } from '@testing-library/react'; 3 | import { PuppeteerTestCaseContext } from '../../../context/reducers/puppeteerTestCaseReducer'; 4 | import PuppeteerTestCase from '../../../components/TestCase/PuppeteerTestCase'; 5 | import { TestFileModalContext } from '../../../context/reducers/testFileModalReducer'; 6 | import '@testing-library/jest-dom/extend-expect'; 7 | 8 | const testFileModal = { 9 | isTestModalOpen: false, 10 | }; 11 | 12 | const dispatchToPuppeteerTestCase = jest.fn(); 13 | const dispatchToTestFileModal = jest.fn(); 14 | 15 | afterEach(cleanup); 16 | 17 | describe('Puppeteer Left Panel', () => { 18 | it('should render the puppeteer test menu with two buttons: [New Test +] and [Paint Timing]', () => { 19 | const puppeteerTestCase = { 20 | puppeteerStatements: [], 21 | 22 | statementId: 0, 23 | }; 24 | const { getByTestId } = render( 25 | 26 | 27 | 28 | 29 | 30 | ); 31 | expect(getByTestId('puppeteerNewTestButton')).toHaveTextContent('New Test +'); 32 | expect(getByTestId('puppeteerPaintTimingButton')).toHaveTextContent('Paint Timing'); 33 | }); 34 | 35 | it('should render a paint timing form with corresponding fields if a paint timing test statement has been created', () => { 36 | const puppeteerTestCase = { 37 | puppeteerStatements: [ 38 | { 39 | describe: 'Home page performance', 40 | firstPaintIt: 'should have its first paint in less than 100 ms', 41 | firstPaintTime: '100', 42 | hasBrowserOption: true, 43 | id: 0, 44 | type: 'paintTiming', 45 | url: 'http://localhost:8080/', 46 | browserOptions: [ 47 | { 48 | id: 0, 49 | optionKey: 'headless', 50 | optionValue: 'false', 51 | }, 52 | ], 53 | FCPIt: 'should have its first contentful paint in less than 200 ms', 54 | FCPtTime: '200', 55 | LCPIt: 'should have its largest contentful paint paint in less than 300 ms', 56 | LCPTime: '300', 57 | browserOptionId: 1, 58 | }, 59 | ], 60 | 61 | statementId: 1, 62 | }; 63 | const { getByText } = render( 64 | 65 | 66 | 67 | 68 | 69 | ); 70 | 71 | expect(getByText('Describe')).toBeInTheDocument(); 72 | expect(getByText('URL')).toBeInTheDocument(); 73 | expect(getByText('First Paint')).toBeInTheDocument(); 74 | expect(getByText('First Contentful Paint')).toBeInTheDocument(); 75 | expect(getByText('Largest Contentful Paint')).toBeInTheDocument(); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /src/__tests__/ProjectLoaderTests/projectLoader.test.js: -------------------------------------------------------------------------------- 1 | it('displays browser view of when URL is correctly inputted', () => {}); 2 | 3 | it(`omitting 'www' from URL still displays browser view`, () => {}); 4 | 5 | it('displays file directory of project that is loaded', () => {}); 6 | 7 | it(`displays project's name on the top of the file directory view`, () => {}); 8 | -------------------------------------------------------------------------------- /src/__tests__/ReduxTestMenu.test.js: -------------------------------------------------------------------------------- 1 | window.require = jest.fn(); 2 | 3 | import { ReduxTestCaseState } from '../utils/reduxTypes'; 4 | 5 | import React from 'react'; 6 | import { render, screen } from '@testing-library/react'; 7 | import '@testing-library/jest-dom/extend-expect'; 8 | import { ReduxTestCaseContext } from '../context/reducers/reduxTestCaseReducer'; 9 | import { MockDataContext } from '../context/reducers/mockDataReducer'; 10 | import ReduxTestMenu from '../components/TestMenu/ReduxTestMenu'; 11 | 12 | const dispatchToReduxTextCase = jest.fn(); 13 | const dispatchToMockData = jest.fn(); 14 | 15 | export const reduxTestCaseState: ReduxTestCaseState = { 16 | reduxTestStatement: '' /* the test description */, 17 | reduxStatements: [] /* both of the cards on the page at open. Each card gets an id */, 18 | }; 19 | 20 | const mockDataState = { 21 | mockData: [], 22 | hasMockData: false, 23 | }; 24 | 25 | describe('should render ReduxTestCase component', () => { 26 | it('renders Test Menu', () => { 27 | const { getByText, debug } = render(); 28 | 29 | 30 | ; 31 | 32 | ; 33 | expect(getByText('test')); 34 | screen.debug(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/__tests__/reduxTestCase.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import '@testing-library/jest-dom/extend-expect'; 4 | import ReduxTestCase from '../components/TestCase/ReduxTestCase'; 5 | 6 | describe('should render ReduxTestCase component', () => { 7 | const { getByRole, debug } = render(); 8 | 9 | screen.debug(); 10 | }); 11 | -------------------------------------------------------------------------------- /src/__tests__/spec.e2e.js: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application; 2 | const path = require('path'); 3 | const chai = require('chai'); 4 | const chaiAsPromised = require('chai-as-promised'); 5 | 6 | // specifies the path of the application to launch 7 | const electronPath = require('electron'); 8 | 9 | // tell spectron to look and use the main.js file + package.json located 2 levels above 10 | const appPath = path.join(__dirname, '../..'); 11 | 12 | 13 | // instantiates the spearmint application given the optional paramaters of the Application API 14 | const app = new Application({ 15 | path: electronPath, // string path to the Electron application executable to launch 16 | args: [appPath], // array of paths to find the executable files and package.json 17 | }); 18 | 19 | // define the use of chai and chai as promised packages 20 | global.before(function () { 21 | chai.should(); 22 | chai.use(chaiAsPromised); 23 | }); 24 | 25 | describe('Application Accessibility Audit', function () { 26 | this.timeout(10000); 27 | 28 | beforeEach(function () { 29 | return app.start(); 30 | }); 31 | 32 | afterEach(function () { 33 | if (app && app.isRunning()) { 34 | return app.stop(); 35 | } 36 | }); 37 | 38 | it('Audits Accessibility', function (done) { 39 | app.client.auditAccessibility().then(function (audit) { 40 | if (audit.failed) { 41 | console.error('Please address the following accessibility issues in your application: \n', audit.results) 42 | } 43 | else { 44 | console.log('No accessibility issues have been found.') 45 | } 46 | done() 47 | }) 48 | }); 49 | }); -------------------------------------------------------------------------------- /src/__tests__/spec.integra.js: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application; 2 | const path = require('path'); 3 | 4 | // specifies the path of the application to launch 5 | const electronPath = require('electron'); 6 | 7 | // tell spectron to look and use the main.js file + package.json located 2 levels above 8 | const appPath = path.join(__dirname, '../..'); 9 | 10 | // instantiates the spearmint application given the optional paramaters of the Application API 11 | const app = new Application({ 12 | path: electronPath, // string path to the Electron application executable to launch 13 | args: [appPath], // array of paths to find the executable files and package.json 14 | }); 15 | 16 | 17 | describe('Application Accessibility Audit', function () { 18 | this.timeout(10000); 19 | 20 | beforeEach(function () { 21 | return app.start(); 22 | }); 23 | 24 | afterEach(function () { 25 | if (app && app.isRunning()) { 26 | return app.stop(); 27 | } 28 | }); 29 | 30 | it('Audits Accessibility', function () { 31 | return app.client.auditAccessibility().then(function (audit) { 32 | if (audit.failed) { 33 | console.error('Please address the following accessibility issues in your application: \n', audit.results) 34 | } 35 | else { 36 | console.log('No accessibility issues have been found.') 37 | } 38 | }) 39 | }); 40 | }); -------------------------------------------------------------------------------- /src/__tests__/spec.test.js: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application; 2 | const assert = require('assert'); 3 | const electronPath = require('electron'); // Require Electron from the binaries included in node_modules. 4 | const path = require('path'); 5 | 6 | describe('Application launch', function() { 7 | beforeEach(() => { 8 | this.app = new Application({ 9 | path: electronPath, 10 | args: [path.join(__dirname, '../../public/electron.js')], 11 | }); 12 | return this.app.start(); 13 | }); 14 | 15 | afterEach(() => { 16 | if (this.app && this.app.isRunning()) { 17 | return this.app.stop(); 18 | } 19 | }); 20 | 21 | test('shows an initial window', async () => { 22 | return this.app.client.getWindowCount().then(function(count) { 23 | assert.equal(count, 2); 24 | // Please note that getWindowCount() will return 2 if `dev tools` are opened. 25 | // assert.equal(count, 2) 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/assets/icons/add-black-18dp.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/close.png -------------------------------------------------------------------------------- /src/assets/images/content-save-outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/content-save-outline.png -------------------------------------------------------------------------------- /src/assets/images/describe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/describe.png -------------------------------------------------------------------------------- /src/assets/images/describe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/describe2.png -------------------------------------------------------------------------------- /src/assets/images/describehelp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/describehelp.png -------------------------------------------------------------------------------- /src/assets/images/drag-vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/drag-vertical.png -------------------------------------------------------------------------------- /src/assets/images/file-document-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/file-export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/file-export.png -------------------------------------------------------------------------------- /src/assets/images/folder-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/folder-open.png -------------------------------------------------------------------------------- /src/assets/images/folder-outline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/folder_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/folder_open.png -------------------------------------------------------------------------------- /src/assets/images/google-chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/google-chrome.png -------------------------------------------------------------------------------- /src/assets/images/help-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/help-circle.png -------------------------------------------------------------------------------- /src/assets/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/home.png -------------------------------------------------------------------------------- /src/assets/images/leaf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/leaf.png -------------------------------------------------------------------------------- /src/assets/images/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/menu.png -------------------------------------------------------------------------------- /src/assets/images/minus-box-outline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/minus-box-outline.png -------------------------------------------------------------------------------- /src/assets/images/newReact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/newReact.png -------------------------------------------------------------------------------- /src/assets/images/plus-box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/plus-box.png -------------------------------------------------------------------------------- /src/assets/images/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/plus.png -------------------------------------------------------------------------------- /src/assets/images/spearmintHomepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/spearmintHomepage.png -------------------------------------------------------------------------------- /src/assets/images/testfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/testfile.png -------------------------------------------------------------------------------- /src/assets/images/visual-studio-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oslabs-beta/spearmint-fresh/4aaa8b58838587edd008f8d89203f02ae23b2b2f/src/assets/images/visual-studio-code.png -------------------------------------------------------------------------------- /src/assets/stylesheets/colors.scss: -------------------------------------------------------------------------------- 1 | $mint: #038181; 2 | $mint2: #02c3c33f; 3 | $mint3: #0fa9a95c; 4 | $dark-gray: #808080; 5 | $light-gray: #d5d5d5; 6 | $light-gray2: #f6f8f9; 7 | $light-gray3: #fafcfc; 8 | $light-gray4: #bceeeed7; 9 | -------------------------------------------------------------------------------- /src/assets/stylesheets/fonts.scss: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Comfortaa|Open+Sans|Raleway|Oxygen&display=swap); 2 | 3 | $comfortaa: 'Comfortaa', cursive; 4 | $openSans: 'Open Sans', sans-serif; 5 | $oxygen: 'Oxygen', sans-serif; 6 | $raleway: 'Raleway', sans-serif; 7 | -------------------------------------------------------------------------------- /src/assets/stylesheets/global.scss: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, 6 | body, 7 | #contents { 8 | height: 100%; 9 | } 10 | 11 | html { 12 | font-size: 62.5%; 13 | } 14 | 15 | a { 16 | text-decoration: none; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/AccTestComponent/AccTestTypes/AccTestTypes.module.scss: -------------------------------------------------------------------------------- 1 | #AccTestTypesComponent{ 2 | margin-right: 35px; 3 | } 4 | 5 | #AccTestTypesLabel { 6 | display: block; 7 | margin-bottom: 6px; 8 | } 9 | 10 | .AccTestTypesInput{ 11 | margin-top: 4px; 12 | min-height: 35px; 13 | } -------------------------------------------------------------------------------- /src/components/AccTestComponent/AccTestTypes/AccTestTypes.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './AccTestTypes.module.scss'; 3 | 4 | const AccTestTypes = ({ dispatch, action, currTypes }) => { 5 | const handleChange = (e: React.ChangeEvent) => { 6 | dispatch(action(e.target.value)); 7 | }; 8 | 9 | return ( 10 |
11 | 14 | 19 |
20 | ); 21 | }; 22 | 23 | export default AccTestTypes; 24 | -------------------------------------------------------------------------------- /src/components/AccTestComponent/CatTagFilter/CatTagFilter.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/fonts.scss'; 2 | @import '../../../assets/stylesheets/colors.scss'; 3 | 4 | #CatTagFilter { 5 | font-weight: bold; 6 | font-size: 0.75rem; 7 | position: relative; 8 | margin-left: 5px; 9 | margin-top: 10px; 10 | z-index: 3; 11 | 12 | #accTestCatTypes:focus { 13 | border: 2px solid darkblue; 14 | } 15 | } -------------------------------------------------------------------------------- /src/components/AccTestComponent/CatTagFilter/CatTagFilter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './CatTagFilter.module.scss'; 3 | 4 | const CatTagFilter = ({ dispatch, tagAction, textAction, itId, catTag }) => { 5 | const handleChange = (e: React.ChangeEvent) => { 6 | dispatch(tagAction(itId, e.target.value)); 7 | if (e.target.value === 'none') dispatch(textAction(`Component is accessible regarding all axe-core categories.`, itId)); 8 | else dispatch(textAction(`Component is accessible regarding ${e.target.value}.`, itId)); 9 | }; 10 | 11 | return ( 12 |
13 | 14 | 30 |
31 | ); 32 | }; 33 | 34 | export default CatTagFilter; 35 | -------------------------------------------------------------------------------- /src/components/AccTestComponent/DescribeRenderer/DescribeRenderer.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/fonts.scss'; 2 | @import '../../../assets/stylesheets/colors.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #describeBlock { 6 | position: relative; 7 | background-color: white; 8 | border-radius: 3px; 9 | padding: 1rem; 10 | margin-top: 10px; 11 | box-shadow: 1px 1px 5px gray; 12 | display: flex; 13 | flex-direction: column; 14 | z-index: 0; 15 | 16 | .describeClose { 17 | position: absolute; 18 | top: 5px; 19 | right: 5px; 20 | font-size: 1.25rem; 21 | z-index: 3; 22 | transition: 250ms; 23 | 24 | &:hover { 25 | color: red; 26 | cursor: pointer; 27 | font-size: 1.5rem; 28 | font-weight: bold; 29 | } 30 | } 31 | 32 | .separator { 33 | position: absolute; 34 | top: 0; 35 | left: 0; 36 | width: 100%; 37 | height: 100px; 38 | // background-color: rgba(128, 128, 128, 0.20); 39 | background-color: #02c3c33f; 40 | border-bottom: 2px solid gray; 41 | opacity: 100%; 42 | z-index: 0; 43 | } 44 | 45 | .describeLabel { 46 | font-weight: bold; 47 | font-size: 0.9rem; 48 | z-index: 3; 49 | font-family: $oxygen; 50 | } 51 | 52 | .describeStatement { 53 | border: none; 54 | border-bottom: 1px solid $mint; 55 | background-color: rgba(0, 0, 0, 0); 56 | margin-top: .8rem; 57 | margin-bottom: .8rem; 58 | font-size: 0.9rem; 59 | z-index: 3; 60 | } 61 | 62 | .buttonContainer { 63 | display: flex; 64 | justify-content: center; 65 | align-items: center; 66 | height: 30px; 67 | margin-top: 1rem; 68 | 69 | .addIt { 70 | height: auto; 71 | color: white; 72 | padding: 0.5rem; 73 | border-radius: 5px; 74 | background-color: $mint; 75 | 76 | &:hover { 77 | background-color: white; 78 | color: $mint; 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/components/AccTestComponent/ItRenderer/ItRenderer.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | 4 | #ItRenderer { 5 | position: relative; 6 | display: flex; 7 | flex-direction: column; 8 | margin-top: 1.5rem; 9 | padding: 0.5rem; 10 | background-color: $light-gray2; 11 | border-radius: 3px; 12 | box-shadow: 2px 2px 5px gray; 13 | height: 100px; 14 | 15 | .itClose { 16 | position: absolute; 17 | font-size: 1.25rem; 18 | top: 5px; 19 | right: 5px; 20 | transition: 250ms; 21 | cursor: pointer; 22 | z-index: 3; 23 | 24 | &:hover { 25 | color: red; 26 | font-size: 1.5rem; 27 | font-weight: bold; 28 | } 29 | } 30 | 31 | .itStatement { 32 | position: absolute; 33 | bottom: 15px; 34 | width: 97.4%; 35 | padding: 0.1rem; 36 | padding-left: 0.4rem; 37 | font-size: 1.1em; 38 | border-bottom: 1px solid $mint; 39 | background-color: rgba(0, 0, 0, 0); 40 | } 41 | 42 | .buttonsContainer { 43 | margin-top: 1rem; 44 | display: flex; 45 | justify-content: space-evenly; 46 | align-items: center; 47 | } 48 | 49 | .reactButton { 50 | height: auto; 51 | font-size: 1rem; 52 | background-color: rgba(0, 0, 0, 0); 53 | border: none; 54 | min-width: 150px; 55 | border-radius: 3px; 56 | font-family: $oxygen; 57 | text-align: center; 58 | transition: 150ms; 59 | color: $mint; 60 | 61 | &:hover { 62 | font-size: 1.1rem; 63 | } 64 | 65 | i { 66 | margin-right: 0.5rem; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/components/AccTestComponent/ItRenderer/ItRenderer.tsx: -------------------------------------------------------------------------------- 1 | import React, { ChangeEvent, useContext } from 'react'; 2 | import cn from 'classnames'; 3 | import { Draggable } from 'react-beautiful-dnd'; 4 | import { AccTestCaseContext } from '../../../context/reducers/accTestCaseReducer'; 5 | import CatTagFilter from '../CatTagFilter/CatTagFilter'; 6 | 7 | import { 8 | deleteItStatement, 9 | } from '../../../context/actions/accTestCaseActions'; 10 | 11 | import styles from './ItRenderer.module.scss'; 12 | 13 | const ItRenderer = ({ 14 | itStatements, 15 | describeId, 16 | updateItStatementText, 17 | updateItCatTag, 18 | }) => { 19 | 20 | const [, dispatchToAccTestCase] = useContext(AccTestCaseContext); 21 | 22 | const deleteItStatementHandleClick = (e: ChangeEvent) => { 23 | const itId = e.target.id; 24 | dispatchToAccTestCase(deleteItStatement(describeId, itId)); 25 | }; 26 | 27 | const deleteItStatementOnKeyUp = (e) => { 28 | if (e.charCode === 13) { 29 | const itId = e.target.id; 30 | dispatchToAccTestCase(deleteItStatement(describeId, itId)); 31 | } 32 | } 33 | 34 | return itStatements.allIds[describeId].map((id: string, i: number) => ( 35 | 40 | {(provided) => ( 41 |
48 | 49 | 56 | 57 | 64 | 65 |

{itStatements.byId[id].text}

66 |
67 | 68 |
69 | )} 70 |
71 | )); 72 | }; 73 | 74 | export default ItRenderer; 75 | -------------------------------------------------------------------------------- /src/components/AccTestComponent/PuppeteerUrl/PuppeteerUrl.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | // import styles used in AccTestTypes for input labels et al. 3 | import styles from '../AccTestTypes/AccTestTypes.module.scss'; 4 | 5 | const AccTestTypes = ({ dispatch, action }) => { 6 | const handleChange = (e: React.ChangeEvent) => { 7 | dispatch(action(e.target.value)); 8 | }; 9 | 10 | return ( 11 |
12 | 13 | 14 | 15 |
16 | ); 17 | }; 18 | 19 | export default AccTestTypes; 20 | -------------------------------------------------------------------------------- /src/components/AccTestComponent/StandardTagFilter/StandardTagFilter.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/fonts.scss'; 2 | @import '../../../assets/stylesheets/colors.scss'; 3 | 4 | #StandardTagFilter { 5 | font-weight: bold; 6 | font-size: 0.8rem; 7 | position: relative; 8 | margin-top: 10px; 9 | z-index: 3; 10 | 11 | #accTestStandardTypes:focus { 12 | border: 2px solid darkblue; 13 | } 14 | } -------------------------------------------------------------------------------- /src/components/AccTestComponent/StandardTagFilter/StandardTagFilter.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './StandardTagFilter.module.scss'; 3 | 4 | const StandardTagFilter = ({ dispatch, tagAction, textAction, describeId, standardTag }) => { 5 | const handleChange = (e: React.ChangeEvent) => { 6 | dispatch(tagAction(describeId, e.target.value)); 7 | if (e.target.value === 'none') dispatch(textAction(`Component is accessible according to all standards enforced by axe-core.`, describeId)); 8 | else dispatch(textAction(`Component is accessible according to ${e.target.value} standards.`, describeId)); 9 | }; 10 | 11 | return ( 12 |
13 | 14 | 25 |
26 | ); 27 | }; 28 | 29 | export default StandardTagFilter; 30 | -------------------------------------------------------------------------------- /src/components/AutoComplete/AutoComplete.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AutoSuggest from 'react-autosuggest'; 3 | import styles from './AutoComplete.module.scss'; 4 | import { updateAction, updateAssertion } from '../../context/actions/reactTestCaseActions'; 5 | import { eventTypesList } from '../ReactTestComponent/Action/eventTypesList'; 6 | import { matcherTypesList } from '../ReactTestComponent/Assertion/matcherTypesList'; 7 | 8 | const AutoComplete = ({ statement, statementType, dispatchToTestCase }) => { 9 | let updatedAction = { ...statement }; 10 | let updatedAssertion = { ...statement }; 11 | 12 | const handleChangeValue = (e, { newValue }) => { 13 | if (statementType === 'action') { 14 | updatedAction.eventType = newValue; 15 | dispatchToTestCase(updateAction(updatedAction)); 16 | } else { 17 | updatedAssertion.matcherType = newValue; 18 | dispatchToTestCase(updateAssertion(updatedAssertion)); 19 | } 20 | }; 21 | 22 | const inputProps = { 23 | placeholder: 24 | statementType === 'action' ? 'eg. click, change, keypress' : 'eg. toHaveTextValue ', 25 | value: 26 | statementType === 'action' 27 | ? statement.eventType 28 | : statementType === 'assertion' 29 | ? statement.matcherType 30 | : statementType === 'assertion' && updatedAssertion.isNot 31 | ? `not.${statement.matcherType}` 32 | : null, 33 | 34 | onChange: handleChangeValue, 35 | }; 36 | 37 | const getSuggestions = (value) => { 38 | const inputValue = value.trim().toLowerCase(); 39 | const inputLength = inputValue.length; 40 | if (statementType === 'action') { 41 | return inputLength === 0 42 | ? [] 43 | : eventTypesList.filter( 44 | (eventType) => eventType.name.toLowerCase().slice(0, inputLength) === inputValue 45 | ); 46 | } else { 47 | return inputLength === 0 48 | ? [] 49 | : matcherTypesList.filter( 50 | (matcherType) => matcherType.name.toLowerCase().slice(0, inputLength) === inputValue 51 | ); 52 | } 53 | }; 54 | 55 | const onSuggestionsFetchRequested = ({ value }) => { 56 | if (statementType === 'action') { 57 | updatedAction.suggestions = getSuggestions(value); 58 | dispatchToTestCase(updateAction(updatedAction)); 59 | } else { 60 | updatedAssertion.suggestions = getSuggestions(value); 61 | dispatchToTestCase(updateAssertion(updatedAssertion)); 62 | } 63 | }; 64 | 65 | const onSuggestionsClearRequested = () => { 66 | if (statementType === 'action') { 67 | updatedAction.suggestions = []; 68 | dispatchToTestCase(updateAction(updatedAction)); 69 | } else { 70 | updatedAssertion.suggestions = []; 71 | dispatchToTestCase(updateAssertion(updatedAssertion)); 72 | } 73 | }; 74 | 75 | let getSuggestionValue; 76 | updatedAssertion.isNot 77 | ? (getSuggestionValue = (suggestion) => `not.${suggestion.name}`) 78 | : (getSuggestionValue = (suggestion) => suggestion.name); 79 | 80 | let renderSuggestion; 81 | 82 | updatedAssertion.isNot 83 | ? (renderSuggestion = (suggestion) =>
not.{suggestion.name}
) 84 | : (renderSuggestion = (suggestion) =>
{suggestion.name}
); 85 | 86 | return ( 87 | 96 | ); 97 | }; 98 | 99 | export default AutoComplete; 100 | -------------------------------------------------------------------------------- /src/components/AutoComplete/AutoComplete.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/colors.scss'; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | 4 | .container { 5 | position: relative; 6 | } 7 | 8 | .input { 9 | width: 185px; 10 | padding: '10px 20px'; 11 | font-family: $oxygen; 12 | font-weight: 300; 13 | font-size: 12; 14 | letter-spacing: 0.5px; 15 | border: '1px solid #aaa'; 16 | } 17 | 18 | .inputFocused { 19 | outline: none; 20 | } 21 | 22 | .inputOpen { 23 | border-bottom-left-radius: 0; 24 | border-bottom-right-radius: 0; 25 | } 26 | 27 | .suggestionsContainer { 28 | display: none; 29 | } 30 | 31 | .suggestionsContainerOpen { 32 | display: block; 33 | position: absolute; 34 | top: 26px; 35 | width: 100%; 36 | border: 1px solid $light-gray; 37 | background-color: #fff; 38 | font-family: $oxygen; 39 | font-weight: 300; 40 | letter-spacing: 0.5px; 41 | font-size: 16px; 42 | border-radius: 0 0 4px 4px; 43 | z-index: 2; 44 | } 45 | 46 | .suggestionsList { 47 | margin: 0; 48 | padding: 0; 49 | list-style-type: none; 50 | height: 200px; 51 | overflow-y: scroll; 52 | } 53 | 54 | .suggestion { 55 | cursor: pointer; 56 | padding: 10px 20px; 57 | } 58 | 59 | .suggestionHighlighted { 60 | background-color: $light-gray4; 61 | } 62 | -------------------------------------------------------------------------------- /src/components/AutoComplete/AutoCompleteMockData.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import styles from '../AutoComplete/AutoCompleteMockData.module.scss'; 3 | import AutoSuggest from 'react-autosuggest'; 4 | import { 5 | updateAction, 6 | updateAssertion, 7 | updateProp, 8 | } from '../../context/actions/reactTestCaseActions'; 9 | import { MockDataContext } from '../../context/reducers/mockDataReducer'; 10 | 11 | const AutoCompleteMockData = ({ 12 | statement, 13 | statementType, 14 | dispatchToTestCase, 15 | propType, 16 | renderId, 17 | propId, 18 | propKey, 19 | propValue, 20 | }) => { 21 | let updatedAction = { ...statement }; 22 | let updatedAssertion = { ...statement }; 23 | 24 | const [{ mockData }] = useContext(MockDataContext); 25 | const [mockDataValue, setMockDataValue] = useState(''); 26 | const [mockDataSuggestions, setMockDataSuggestions] = useState([]); 27 | const mockOptionsList = []; 28 | 29 | const handleChangeValue = (event, { newValue }) => { 30 | setMockDataValue(newValue); 31 | if (statementType === 'action') { 32 | updatedAction.eventValue = newValue; 33 | dispatchToTestCase(updateAction(updatedAction)); 34 | } else if (statementType === 'assertion') { 35 | updatedAssertion.queryValue = newValue; 36 | dispatchToTestCase(updateAssertion(updatedAssertion)); 37 | } else if (propType === 'prop') { 38 | dispatchToTestCase(updateProp(renderId, propId, propKey, newValue)); 39 | } 40 | }; 41 | 42 | mockData.forEach((mockDatum) => { 43 | let name = mockDatum.name.charAt(0).toUpperCase() + mockDatum.name.slice(1); 44 | mockDatum.fieldKeys.forEach((key) => { 45 | mockOptionsList.push({ value: `mock${name}.${key.fieldKey}` }); 46 | }); 47 | mockOptionsList.push({ value: `[mock${name}]` }); 48 | mockOptionsList.push({ value: `{mock${name}}` }); 49 | }); 50 | 51 | const getSuggestions = (mockDataValue) => { 52 | // const inputValue = mockDataValue.trim().toLowerCase(); 53 | const inputLength = 1; 54 | return inputLength === 0 ? [] : mockOptionsList.filter((mockOption) => mockOption.value); 55 | }; 56 | 57 | const shouldRenderSuggestions = () => { 58 | return true; 59 | }; 60 | 61 | const getSuggestionValue = (suggestion) => suggestion.value; 62 | const renderSuggestion = (suggestion) =>
{suggestion.value}
; 63 | 64 | const onSuggestionsFetchRequested = ({ value }) => { 65 | setMockDataSuggestions(getSuggestions(value)); 66 | }; 67 | const onSuggestionsClearRequested = () => { 68 | setMockDataSuggestions([]); 69 | }; 70 | 71 | const inputProps = { 72 | placeholder: 'Enter or select a value.', 73 | value: propValue, 74 | onChange: handleChangeValue, 75 | }; 76 | 77 | return ( 78 | 88 | ); 89 | }; 90 | 91 | export default AutoCompleteMockData; 92 | -------------------------------------------------------------------------------- /src/components/AutoComplete/AutoCompleteMockData.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/colors.scss'; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | 4 | .container { 5 | position: relative; 6 | } 7 | 8 | .input { 9 | // width: 185px; 10 | width: 185px; 11 | padding: '10px 20px'; 12 | font-family: $oxygen; 13 | font-weight: 300; 14 | font-size: 12; 15 | letter-spacing: 0.5px; 16 | background-color: red($color: #ed0909); 17 | border: '1px solid #aaa'; 18 | } 19 | 20 | .inputFocused { 21 | outline: none; 22 | } 23 | 24 | .inputOpen { 25 | border-bottom-left-radius: 0; 26 | border-bottom-right-radius: 0; 27 | } 28 | 29 | .suggestionsContainer { 30 | display: none; 31 | } 32 | 33 | .suggestionsContainerOpen { 34 | display: block; 35 | position: absolute; 36 | top: 26px; 37 | width: 185px; 38 | border: 1px solid $light-gray; 39 | background-color: #fff; 40 | font-family: $oxygen; 41 | font-weight: 300; 42 | letter-spacing: 0.5px; 43 | font-size: 16px; 44 | border-radius: 0 0 4px 4px; 45 | z-index: 2; 46 | } 47 | 48 | .suggestionsList { 49 | margin: 0; 50 | padding: 0; 51 | list-style-type: none; 52 | height: 200px; 53 | overflow-y: scroll; 54 | } 55 | 56 | .suggestion { 57 | cursor: pointer; 58 | padding: 10px 20px; 59 | } 60 | 61 | .suggestionHighlighted { 62 | background-color: $light-gray4; 63 | } 64 | -------------------------------------------------------------------------------- /src/components/BrowserView/BrowserView.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/colors.scss'; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | 4 | #browserView { 5 | display: flex; 6 | justify-content: center; 7 | height: 75vh; 8 | width: auto; 9 | } 10 | 11 | #browserAddress { 12 | display: flex; 13 | justify-content: center; 14 | flex-wrap: nowrap; 15 | align-items: center; 16 | border-radius: 10px; 17 | margin: 5px; 18 | width: 97%; 19 | text-indent: 10px; 20 | } 21 | 22 | #browswerComponentTopLevelDiv{ 23 | display: flex; 24 | flex: 1; 25 | flex-direction: column; 26 | } 27 | 28 | #accessLensContainer{ 29 | display: flex; 30 | flex-direction: column; 31 | height: 115px; 32 | min-width: 100%; 33 | overflow-x: scroll; 34 | overflow-y: hidden; 35 | white-space: nowrap; 36 | justify-content: center; 37 | } 38 | 39 | #accessLensCheckBoxes{ 40 | display: flex; 41 | justify-content: center; 42 | flex-wrap: wrap; 43 | align-items: center; 44 | width:auto; 45 | background-color: $mint2; 46 | border: $mint2; 47 | border-width: .05em; 48 | border-bottom-left-radius: 4px; 49 | border-bottom-right-radius: 4px; 50 | border-style: solid; 51 | } 52 | 53 | #accessLensLabel { 54 | display: flex; 55 | justify-content: center; 56 | background-color: $mint; 57 | color: white; 58 | font-size: 18px; 59 | font-family: $oxygen; 60 | height: auto; 61 | width: 100%; 62 | border: $mint; 63 | border-top-left-radius: 4px; 64 | border-top-right-radius: 4px; 65 | border-style: solid; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/components/EditorView/EditorView.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import CodeMirror from '@uiw/react-codemirror'; 3 | import { javascript } from '@codemirror/lang-javascript'; 4 | import { GlobalContext } from '../../context/reducers/globalReducer'; 5 | import { updateFile } from '../../context/actions/globalActions'; 6 | import styles from './EditorView.module.scss'; 7 | 8 | const { ipcRenderer } = require('electron'); 9 | 10 | 11 | const Editor = () => { 12 | const [{ file, filePath }, dispatchToGlobal] = useContext(GlobalContext); 13 | const [wasSaved, setWasSaved] = useState(''); 14 | let editedText = ''; 15 | 16 | // const options = { 17 | // selectOnLineNumbers: true, 18 | // wordWrap: 'wordWrapColumn', 19 | // wordWrapColumn: 90, 20 | // autoIndent: true, 21 | // colorDecorators: true, 22 | // wrappingIndent: 'indent', 23 | // automaticLayout: true, 24 | // codeLens: true, 25 | // // Added specific fontfamily and fontsize to address Windows curson misalignment issue 26 | // fontFamily: 'courier new', 27 | // fontSize: 12, 28 | // }; 29 | 30 | // const editorDidMount = () => { 31 | // editor.setTheme('light-dark'); 32 | // }; 33 | 34 | const updatafile = (newValue, e) => { 35 | editedText = newValue; 36 | if (wasSaved.length) setWasSaved(''); 37 | }; 38 | const saveFile = () => { 39 | if (editedText.length) { 40 | dispatchToGlobal(updateFile(editedText)); 41 | if (!filePath.length) setWasSaved('Preview Saved, be sure to export file'); 42 | } else setWasSaved('No Changes to Save'); 43 | if (filePath.length && editedText.length) { 44 | // Send main process the filePath and editedText in obj to save 45 | const reply = ipcRenderer.sendSync('EditorView.saveFile', filePath, editedText); 46 | // Upon reply from main process, update wasSaved state 47 | setWasSaved(reply); 48 | } 49 | }; 50 | 51 | const fileType = filePath.split('.')[1]; 52 | const extensionChecker = { 53 | png: 1, 54 | jpg: 1, 55 | gif: 1, 56 | }; 57 | 58 | return ( 59 |
60 |
setWasSaved('')}> 61 | 73 |
74 |
75 | 78 | {wasSaved} 79 |
80 |
81 | ); 82 | }; 83 | 84 | export default Editor; 85 | -------------------------------------------------------------------------------- /src/components/EditorView/EditorView.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/colors.scss'; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | 4 | #save { 5 | margin: 5px; 6 | height: 40px; 7 | width: 110px; 8 | color: $mint; 9 | background-color: white; 10 | opacity: 0.8; 11 | font-family: $oxygen; 12 | font-size: 14px; 13 | border-radius: 5px; 14 | border: 0.5px $light-gray solid; 15 | position: relative; 16 | } 17 | 18 | #save:hover { 19 | background-color: rgb(180, 180, 180); 20 | color: white; 21 | border-radius: 5px; 22 | } 23 | 24 | #span { 25 | font-family: -apple-system, system-ui, 'Segoe UI', Helvetica, Arial, sans-serif, 26 | 'Apple Color Emoji', 'Segoe UI Emoji'; 27 | line-height: 1.5; 28 | position: relative; 29 | color: rgb(90, 90, 90); 30 | } 31 | -------------------------------------------------------------------------------- /src/components/EndpointTestComponent/JestMatchers.ts: -------------------------------------------------------------------------------- 1 | const jestMatchers: string[] = [ 2 | '', 3 | 'to Be', 4 | 'to Equal (object)', 5 | 'to Have Been Called', 6 | 'to Have Been Called Times (number)', 7 | 'to Have Been Called With (arg1,...)', 8 | 'to Have Been Last Called With (arg1,...)', 9 | 'to Have Been Nth Called With (nth call, arg1,...)', 10 | 'to Have Length (number)', 11 | 'to Have Property (keyPath, value[optional])', 12 | 'to Be Close To (number, number of digits[optional])', 13 | 'to Be Defined', 14 | 'to Be Undefined', 15 | 'to Be Falsy', 16 | 'to Be Truthy', 17 | 'to Be NaN', 18 | 'to Be Greater Than (number)', 19 | 'to Be Greater Than Or Equal (number)', 20 | 'to Be Less Than (number)', 21 | 'to Be Less Than Or Equal (number)', 22 | 'to Be Instance Of (Class)', 23 | 'to Contain (item in an array)', 24 | 'to Contain Equal (an object in an array)', 25 | 'to Match (regexp or string)', 26 | 'to Match Object (object)', 27 | 'to Srict Equal (object)', 28 | 'to Throw (error[optional])', 29 | ]; 30 | 31 | //for mock fuctions only: 32 | // 'to Have Returned', 33 | // 'to Have Returned __ Times (number)', 34 | // 'to Have Last Returned With', 35 | // ]; 36 | 37 | export default jestMatchers; 38 | -------------------------------------------------------------------------------- /src/components/FileDirectory/FileDirectory.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/colors.scss'; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | 4 | #fileDirectory { 5 | grid-area: fileDirectory; 6 | padding: 0px; 7 | width: 200px; 8 | height: 100vh; 9 | margin-left: 50px; 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | font-size: 12px; 14 | background-color: white; 15 | overflow: auto; 16 | border-right: 1px dotted $mint; 17 | z-index: 1; 18 | 19 | ul { 20 | list-style-type: none; 21 | margin-left: 15px; 22 | text-align: left; 23 | } 24 | li { 25 | margin-top: 3px; 26 | text-align: left; 27 | } 28 | #explorer { 29 | margin: 0; 30 | padding: 10%; 31 | color: $mint; 32 | font-family: $oxygen; 33 | letter-spacing: 1px; 34 | vertical-align: middle; 35 | font-weight: bold; 36 | height: 1px; 37 | background-color: #f0f8f8; 38 | border-bottom: 0.5px dotted $mint; 39 | } 40 | } 41 | #file { 42 | width: 18px; 43 | height: 18px; 44 | margin-right: 6px; 45 | float: left; 46 | } 47 | #folder { 48 | margin-right: 6px; 49 | } 50 | #dirButton { 51 | text-decoration: none; 52 | color: $dark-gray; 53 | background-color: transparent; 54 | border: none; 55 | font-family: $oxygen; 56 | text-align: left; 57 | vertical-align: middle; 58 | width: 97%; 59 | } 60 | 61 | #dirButton:hover { 62 | background-color: #f0f8f8; 63 | border-radius: 3px; 64 | } 65 | 66 | #dirButtonHilighted { 67 | text-align: left; 68 | background-color: #f0f8f8; 69 | border: none; 70 | border-radius: 3px; 71 | width: 97%; 72 | } 73 | -------------------------------------------------------------------------------- /src/components/GetTests/GetTests.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import styles from './GetTests.module.scss'; 3 | import GetTestsModal from '../Modals/GetTestsModal'; 4 | 5 | const GetTests = ({ testType }) => { 6 | const [getTestsModalIsOpen, setGetTestsModalIsOpen] = useState(false); 7 | 8 | const handleOpenGetTestsModal = () => { 9 | setGetTestsModalIsOpen(true); 10 | }; 11 | 12 | return ( 13 | <> 14 | 17 | {getTestsModalIsOpen ? ( 18 | 23 | ) : null} 24 | 25 | ); 26 | }; 27 | 28 | export default GetTests; 29 | -------------------------------------------------------------------------------- /src/components/GetTests/GetTests.module.scss: -------------------------------------------------------------------------------- 1 | @import './../../assets/stylesheets/colors.scss'; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | 4 | .navBtn { 5 | padding: 0; 6 | border: 0; 7 | margin-top: 15px; 8 | margin-bottom: 40px; 9 | cursor: pointer; 10 | background-color: transparent; 11 | :focus { 12 | outline: 2px solid darkblue; 13 | } 14 | } 15 | 16 | .icons { 17 | width: 28px; 18 | height: 28px; 19 | } 20 | 21 | #getTestBtn { 22 | margin-top: 10px; 23 | padding-left: 1rem; 24 | font-size: 12px; 25 | text-align: left; 26 | width: 250px; 27 | height: 1.5rem; 28 | color: $dark-gray; 29 | box-shadow: none; 30 | cursor: pointer; 31 | -webkit-appearance: none; 32 | -moz-appearance: none; 33 | :focus { 34 | outline: 2px solid darkblue; 35 | } 36 | } 37 | 38 | #getTestBtn:focus { 39 | outline: 2px solid darkblue; 40 | } 41 | 42 | .tooltip { 43 | visibility: hidden; 44 | width: 120px; 45 | background: black; 46 | color: white; 47 | position: absolute; 48 | padding: 5px 0; 49 | text-align: center; 50 | border-radius: 8px; 51 | margin: 0 auto; 52 | z-index: 3; 53 | } 54 | 55 | .navBtn:hover .tooltip { 56 | visibility: visible; 57 | margin-left: 5px; 58 | } 59 | 60 | .navBtn:active .tooltip { 61 | visibility: hidden; 62 | } 63 | -------------------------------------------------------------------------------- /src/components/NavBar/NavBar.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * nav pannel 3 | * to export files, switch views, or open a new folder 4 | */ 5 | 6 | import React, { useState, useContext } from 'react'; 7 | import styles from './NavBar.module.scss'; 8 | import { GlobalContext } from '../../context/reducers/globalReducer'; 9 | import { 10 | toggleFileDirectory, 11 | toggleExportBool, 12 | } from '../../context/actions/globalActions'; 13 | import FileDirectory from '../FileDirectory/FileDirectory'; 14 | import OpenFolder from '../OpenFolder/OpenFolderButton'; 15 | import ExportFileModal from '../Modals/ExportFileModal'; 16 | 17 | const menuIcon = require('../../assets/images/menu.png'); 18 | const exportIcon = require('../../assets/images/file-export.png'); 19 | 20 | const NavBar = ({ inAboutPage }) => { 21 | const [{ fileTree, isFileDirectoryOpen }, dispatchToGlobal] = 22 | useContext(GlobalContext); 23 | const [isExportModalOpen, setIsExportModalOpen] = useState(false); 24 | 25 | /* opens/closes the filedirectory */ 26 | const handleToggleFileDirectory = () => { 27 | dispatchToGlobal(toggleFileDirectory()); 28 | }; 29 | 30 | /* exports the file (when true) */ 31 | const openExportModal = () => { 32 | dispatchToGlobal(toggleExportBool()); 33 | setIsExportModalOpen(true); 34 | }; 35 | /* 36 | * renders: buttons + icons for navbar, exportFileModal, boxes to open new folder and enter url, file directory 37 | */ 38 | return ( 39 |
40 | {/* File Explorer */} 41 | 45 | {/* Export */} 46 | 50 | {!inAboutPage && ( 51 | 55 | )} 56 | {/* Open Folder */} 57 | 58 | {isFileDirectoryOpen && } 59 |
60 | ); 61 | }; 62 | 63 | export default NavBar; 64 | -------------------------------------------------------------------------------- /src/components/NavBar/NavBar.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/colors.scss'; 2 | 3 | #navBar { 4 | grid-area: navBar; 5 | background-color: $mint; 6 | height: 100vh; 7 | width: 48px; 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | justify-content: flex-start; 12 | } 13 | 14 | .navBtn { 15 | padding: 0; 16 | border: 0; 17 | margin-top: 15px; 18 | margin-bottom: 40px; 19 | cursor: pointer; 20 | background-color: transparent; 21 | :focus { 22 | outline: 2px solid darkblue 23 | } 24 | } 25 | 26 | .icons { 27 | width: 28px; 28 | height: 28px; 29 | } 30 | 31 | .tooltip { 32 | visibility: hidden; 33 | width: 120px; 34 | background: black; 35 | color: white; 36 | position: absolute; 37 | padding: 5px 0; 38 | text-align: center; 39 | border-radius: 8px; 40 | margin: 0 auto; 41 | z-index: 3; 42 | } 43 | 44 | .navBtn:hover .tooltip { 45 | visibility: visible; 46 | margin-left: 5px; 47 | } 48 | 49 | #inAboutPage { 50 | @extend #navBar; 51 | float: left; 52 | position: fixed; 53 | top: 0; 54 | left: 0; 55 | } 56 | -------------------------------------------------------------------------------- /src/components/OpenFolder/OpenFolderButton.module.scss: -------------------------------------------------------------------------------- 1 | @import './../../assets/stylesheets/colors.scss'; 2 | 3 | .navBtn { 4 | padding: 0; 5 | border: 0; 6 | margin-top: 15px; 7 | margin-bottom: 40px; 8 | cursor: pointer; 9 | background-color: transparent; 10 | :focus { 11 | outline: 2px solid darkblue; 12 | } 13 | } 14 | 15 | .icons { 16 | width: 28px; 17 | height: 28px; 18 | } 19 | 20 | #openBtn { 21 | margin-top: 10px; 22 | padding-left: 1rem; 23 | font-size: 12px; 24 | text-align: left; 25 | width: 250px; 26 | height: 1.5rem; 27 | color: $dark-gray; 28 | box-shadow: none; 29 | cursor: pointer; 30 | -webkit-appearance: none; 31 | -moz-appearance: none; 32 | :focus { 33 | outline: 2px solid darkblue; 34 | } 35 | } 36 | 37 | #openBtn:focus{ 38 | outline: 2px solid darkblue 39 | } 40 | 41 | .tooltip { 42 | visibility: hidden; 43 | width: 120px; 44 | background: black; 45 | color: white; 46 | position: absolute; 47 | padding: 5px 0; 48 | text-align: center; 49 | border-radius: 8px; 50 | margin: 0 auto; 51 | z-index: 3; 52 | } 53 | 54 | .navBtn:hover .tooltip { 55 | visibility: visible; 56 | margin-left: 5px; 57 | } 58 | 59 | .navBtn:active .tooltip { 60 | visibility: hidden; 61 | } 62 | -------------------------------------------------------------------------------- /src/components/PuppeteerTestComponent/PaintTiming/PaintTiming.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #modal { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | } 14 | 15 | #header { 16 | @include box-header-alignment; 17 | justify-content: flex-start; 18 | display: flex; 19 | align-items: center; 20 | img { 21 | width: 20px; 22 | height: 20px; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | h3 { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | } 31 | 32 | #testingFieldsGrid { 33 | display: grid; 34 | grid-template-columns: 1fr 1fr 1fr; 35 | } 36 | #groupFlexbox { 37 | display: flex; 38 | align-items: center; 39 | margin-bottom: 15px; 40 | justify-content: space-between; 41 | } 42 | 43 | #inputFlexBox { 44 | display: flex; 45 | align-items: center; 46 | width: 100%; 47 | input { 48 | margin-right: 0.5rem; 49 | width: inherit; 50 | } 51 | } 52 | 53 | #time { 54 | width: 30%; 55 | input { 56 | width: 100%; 57 | } 58 | } 59 | 60 | #renderCheckbox { 61 | display: flex; 62 | input { 63 | align-self: center; 64 | } 65 | } 66 | 67 | #browserOptionsFlexBox { 68 | display: flex; 69 | justify-content: center; 70 | align-items: center; 71 | input { 72 | width: 240px; 73 | margin: 0 4px 4px 0px; 74 | } 75 | img { 76 | margin-bottom: 5px; 77 | } 78 | } 79 | 80 | #browserOptions { 81 | font-size: 13px; 82 | margin-bottom: 0; 83 | padding: 6px 0; 84 | display: flex; 85 | width: 60%; 86 | justify-content: space-between; 87 | } 88 | 89 | #options { 90 | margin: 5px 0 15px; 91 | button { 92 | font-size: 12px; 93 | padding-top: 5px; 94 | border: none; 95 | font-family: $raleway; 96 | font-weight: bold; 97 | text-align: left; 98 | } 99 | } 100 | 101 | #optionBox { 102 | hr { 103 | border: 1px solid $light-gray; 104 | margin-top: 0; 105 | } 106 | } 107 | 108 | #hastooltip { 109 | margin-left: 0.2rem; 110 | @include hastooltip($tooltip-transition-in-duration: 0.3s); 111 | } 112 | 113 | #tooltip { 114 | min-width: 10em; 115 | padding: 0.5em 0.75em; 116 | 117 | box-shadow: 0 0.05em 0.15em rgba(black, 0.1); 118 | @include tooltip; 119 | } 120 | -------------------------------------------------------------------------------- /src/components/ReactHooksTestComponent/HookUpdates/HookUpdates.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #hookUpdates { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | } 14 | 15 | #hookUpdatesHeader { 16 | @include box-header-alignment; 17 | justify-content: flex-start; 18 | display: flex; 19 | align-items: center; 20 | img { 21 | width: 20px; 22 | height: 20px; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | h3 { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | } 31 | 32 | #hooksFlexBox { 33 | display: flex; 34 | align-items: center; 35 | margin-bottom: 15px; 36 | } 37 | 38 | #hooks { 39 | width: 50%; 40 | margin-right: 7%; 41 | input { 42 | margin-top: 6px; 43 | width: 100%; 44 | } 45 | position: relative; 46 | } 47 | #cbFlexBox { 48 | display: flex; 49 | align-items: center; 50 | margin-bottom: 15px; 51 | } 52 | 53 | #cb { 54 | width: 50%; 55 | margin-right: 7%; 56 | input { 57 | margin-top: 6px; 58 | width: 100%; 59 | } 60 | } 61 | #stateFlexBox { 62 | display: flex; 63 | align-items: center; 64 | margin-bottom: 15px; 65 | } 66 | 67 | #state { 68 | width: 50%; 69 | margin-right: 7%; 70 | input { 71 | margin-top: 6px; 72 | width: 100%; 73 | } 74 | } 75 | 76 | .buttonsContainer { 77 | margin-top: 1rem; 78 | display: flex; 79 | justify-content: space-evenly; 80 | align-items: center; 81 | } 82 | 83 | .assertionButton { 84 | // height: auto; 85 | font-size: 1rem; 86 | background-color: rgba(0, 0, 0, 0); 87 | border: none; 88 | min-width: 150px; 89 | border-radius: 3px; 90 | font-family: $oxygen; 91 | text-align: center; 92 | transition: 150ms; 93 | color: $mint; 94 | 95 | &:hover { 96 | font-size: 1.05rem; 97 | } 98 | i { 99 | margin-right: 0.5rem; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/components/ReactHooksTestComponent/HooksCallback.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import styles from '../EndpointTestComponent/Endpoint.module.scss'; 3 | import { HooksTestCaseContext } from '../../context/reducers/hooksTestCaseReducer'; 4 | import { deleteCallbackFunc, updateCallbackFunc } from '../../context/actions/hooksTestCaseActions'; 5 | 6 | const closeIcon = require('../../assets/images/close.png'); 7 | 8 | const HooksCallback = ({ callbackFunc, index, id }) => { 9 | const [, dispatchToHooksTestCase] = useContext(HooksTestCaseContext); 10 | 11 | const handleClickDeleteCallbackFunc = () => { 12 | dispatchToHooksTestCase(deleteCallbackFunc(index, id)); 13 | }; 14 | 15 | const handleChangeUpdateCallbackFunc = (e, field) => { 16 | const updatedCallbackFunc = { ...callbackFunc, [field]: e.target.value }; 17 | dispatchToHooksTestCase(updateCallbackFunc(index, id, updatedCallbackFunc)); 18 | }; 19 | 20 | return ( 21 | <> 22 |
23 | 24 |
25 | handleChangeUpdateCallbackFunc(e, 'callbackFunc')} 31 | /> 32 |
33 |
34 | 35 | close 41 | 42 | ); 43 | }; 44 | 45 | export default HooksCallback; 46 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Action/Action.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #action { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | } 14 | 15 | #actionHeader { 16 | @include box-header-alignment; 17 | justify-content: flex-start; 18 | display: flex; 19 | align-items: center; 20 | img { 21 | width: 20px; 22 | height: 20px; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | h3 { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | } 31 | 32 | .queryLabel { 33 | font-weight: bolder; 34 | margin-bottom: 5px; 35 | display: block; 36 | } 37 | 38 | #queryFlexBox { 39 | display: flex; 40 | align-items: center; 41 | width: 100%; 42 | } 43 | 44 | #eventTypeFlexBox { 45 | display: flex; 46 | align-items: center; 47 | margin-bottom: 15px; 48 | } 49 | 50 | #eventType { 51 | width: 50%; 52 | margin-right: 7%; 53 | input { 54 | margin-top: 6px; 55 | width: 100%; 56 | } 57 | } 58 | 59 | .eventValueMock { 60 | input { 61 | margin-top: 6px; 62 | } 63 | } 64 | 65 | .eventValue { 66 | input { 67 | width: 185px; 68 | margin-top: 6px; 69 | display: block; 70 | } 71 | } 72 | 73 | #eventTypeVal { 74 | width: 43%; 75 | } 76 | 77 | #querySelector { 78 | margin-right: 9%; 79 | select { 80 | font-family: $raleway; 81 | width: 100%; 82 | height: 25px; 83 | margin: 0 3px 0 0; 84 | background-color: white; 85 | border: 1px solid $light-gray; 86 | font-size: 12px; 87 | letter-spacing: 0.5px; 88 | color: $dark-gray; 89 | } 90 | } 91 | 92 | #dropdownFlex { 93 | display: flex; 94 | align-items: center; 95 | width: 111%; 96 | } 97 | 98 | #query { 99 | input { 100 | width: 100%; 101 | } 102 | } 103 | 104 | #hastooltip { 105 | @include hastooltip($tooltip-transition-in-duration: 0.3s); 106 | } 107 | 108 | #tooltip { 109 | min-width: 10em; 110 | padding: 0.5em 0.75em; 111 | 112 | box-shadow: 0 0.05em 0.15em rgba(black, 0.1); 113 | @include tooltip; 114 | } 115 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Action/eventTypesList.js: -------------------------------------------------------------------------------- 1 | export const eventTypesList = [ 2 | // Clipboard Events 3 | { 4 | name: 'copy', 5 | }, 6 | { 7 | name: 'cut', 8 | }, 9 | { 10 | name: 'paste', 11 | }, 12 | // Composition Events 13 | { 14 | name: 'compositionEnd', 15 | }, 16 | { 17 | name: 'compositionStart', 18 | }, 19 | { 20 | name: 'compositionUpdate', 21 | }, 22 | // Keyboard Events 23 | { 24 | name: 'keyDown', 25 | }, 26 | { 27 | name: 'keyPress', 28 | }, 29 | { 30 | name: 'keyUp', 31 | }, 32 | // Focus Events 33 | { 34 | name: 'focus', 35 | }, 36 | { 37 | name: 'blur', 38 | }, 39 | { 40 | name: 'focusIn', 41 | }, 42 | { 43 | name: 'focusOut', 44 | }, 45 | // Form Events 46 | { 47 | name: 'change', 48 | }, 49 | { 50 | name: 'input', 51 | }, 52 | { 53 | name: 'invalid', 54 | }, 55 | { 56 | name: 'submit', 57 | }, 58 | // Mouse Events 59 | { 60 | name: 'click', 61 | }, 62 | { 63 | name: 'contextMenu', 64 | }, 65 | { 66 | name: 'dblClick', 67 | }, 68 | { 69 | name: 'drag', 70 | }, 71 | { 72 | name: 'dragEnd', 73 | }, 74 | { 75 | name: 'dragEnter', 76 | }, 77 | { 78 | name: 'dragExit', 79 | }, 80 | { 81 | name: 'dragLeave', 82 | }, 83 | { 84 | name: 'dragOver', 85 | }, 86 | { 87 | name: 'dragStart', 88 | }, 89 | { 90 | name: 'mouseDown', 91 | }, 92 | { 93 | name: 'mouseEnter', 94 | }, 95 | { 96 | name: 'mouseLeave', 97 | }, 98 | { 99 | name: 'mouseMove', 100 | }, 101 | { 102 | name: 'mouseOut', 103 | }, 104 | { 105 | name: 'mouseOver', 106 | }, 107 | { 108 | name: 'mouseUp', 109 | }, 110 | // Selection Events 111 | { 112 | name: 'select', 113 | }, 114 | // Touch Events 115 | { 116 | name: 'touchCancel', 117 | }, 118 | { 119 | name: 'touchEnd', 120 | }, 121 | { 122 | name: 'touchMove', 123 | }, 124 | { 125 | name: 'touchStart', 126 | }, 127 | // UI Events 128 | { 129 | name: 'scroll', 130 | }, 131 | // Wheel Events 132 | { 133 | name: 'wheel', 134 | }, 135 | // Media Events 136 | { 137 | name: 'abort', 138 | }, 139 | { 140 | name: 'canPlay', 141 | }, 142 | { 143 | name: 'canPlayThrough', 144 | }, 145 | { 146 | name: 'durationChange', 147 | }, 148 | { 149 | name: 'emptied', 150 | }, 151 | { 152 | name: 'encrypted', 153 | }, 154 | { 155 | name: 'ended', 156 | }, 157 | { 158 | name: 'loadedData', 159 | }, 160 | { 161 | name: 'loadedMetadata', 162 | }, 163 | { 164 | name: 'loadStart', 165 | }, 166 | { 167 | name: 'pause', 168 | }, 169 | { 170 | name: 'play', 171 | }, 172 | { 173 | name: 'playing', 174 | }, 175 | { 176 | name: 'progress', 177 | }, 178 | { 179 | name: 'rateChange', 180 | }, 181 | { 182 | name: 'seeked', 183 | }, 184 | { 185 | name: 'seeking', 186 | }, 187 | { 188 | name: 'stalled', 189 | }, 190 | { 191 | name: 'suspend', 192 | }, 193 | { 194 | name: 'timeUpdate', 195 | }, 196 | { 197 | name: 'volumeChange', 198 | }, 199 | { 200 | name: 'waiting', 201 | }, 202 | // Image Events 203 | { 204 | name: 'load', 205 | }, 206 | { 207 | name: 'error', 208 | }, 209 | // Animation Events 210 | { 211 | name: 'animationStart', 212 | }, 213 | { 214 | name: 'animationEnd', 215 | }, 216 | { 217 | name: 'animationIteration', 218 | }, 219 | // Transition Events 220 | { 221 | name: 'transitionEnd', 222 | }, 223 | ]; 224 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Assertion/Assertion.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #assertion { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | } 14 | 15 | #assertionHeader { 16 | @include box-header-alignment; 17 | justify-content: flex-start; 18 | display: flex; 19 | align-items: center; 20 | img { 21 | width: 20px; 22 | height: 20px; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | h3 { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | } 31 | .queryLabel { 32 | margin-bottom: 5px; 33 | display: block; 34 | } 35 | 36 | #queryFlexBox { 37 | display: flex; 38 | align-items: center; 39 | width: 100%; 40 | margin-bottom: 20px; 41 | } 42 | // #queryVariant { 43 | // top: auto; 44 | // bottom: 100%; 45 | // } 46 | #querySelector { 47 | margin-right: 10%; 48 | select { 49 | font-family: $raleway; 50 | width: 100%; 51 | height: 25px; 52 | margin: 0 3px 0 0; 53 | background-color: white; 54 | border: 1px solid $light-gray; 55 | font-size: 12px; 56 | letter-spacing: 0.5px; 57 | color: $dark-gray; 58 | } 59 | } 60 | 61 | #dropdownFlex { 62 | display: flex; 63 | align-items: center; 64 | width: 111%; 65 | } 66 | 67 | // #query { 68 | // input { 69 | // width: 140%; 70 | // } 71 | // } 72 | 73 | #hastooltip { 74 | @include hastooltip($tooltip-transition-in-duration: 0.3s); 75 | } 76 | 77 | #tooltip { 78 | min-width: 15em; 79 | padding: 0.5em 0.75em; 80 | box-shadow: 0 0.05em 0.15em rgba(black, 0.1); 81 | @include tooltip; 82 | } 83 | 84 | #matcherLabelFlexBox { 85 | display: flex; 86 | div { 87 | font-size: 12px; 88 | } 89 | justify-content: space-between; 90 | width: 185px; 91 | align-items: center; 92 | margin-bottom: 8px; 93 | } 94 | 95 | #valueFlexBox { 96 | display: flex; 97 | div { 98 | font-size: 12px; 99 | } 100 | justify-content: space-between; 101 | width: 185px; 102 | align-items: center; 103 | margin-bottom: 8px; 104 | } 105 | 106 | #matcherFlexBox { 107 | display: flex; 108 | div { 109 | font-size: 12px; 110 | } 111 | justify-content: space-between; 112 | width: 250px; 113 | align-items: flex-end; 114 | margin-bottom: 8px; 115 | padding-top: -2rem; 116 | } 117 | #autoTool { 118 | display: flex; 119 | align-items: center; 120 | justify-content: space-between; 121 | } 122 | #matcherLeft { 123 | display: flex; 124 | align-items: center; 125 | flex-direction: column; 126 | } 127 | #matcherAuto { 128 | margin-right: 15%; 129 | display: inline; 130 | } 131 | #matcherInput { 132 | width: 200px; 133 | } 134 | 135 | #lastAssertion { 136 | padding: 15px; 137 | } 138 | 139 | #matcherVal { 140 | display: flex; 141 | div { 142 | font-size: 12px; 143 | } 144 | margin-left: 78px; 145 | justify-content: space-between; 146 | width: 185px; 147 | align-items: center; 148 | 149 | input { 150 | width: 185px; 151 | display: block; 152 | margin-top: 6px; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Assertion/matcherTypesList.js: -------------------------------------------------------------------------------- 1 | export const matcherTypesList = [ 2 | { 3 | name: 'toHaveTextContent', 4 | }, 5 | { 6 | name: 'toBeInTheDocument', 7 | }, 8 | { 9 | name: 'toContainHTML', 10 | }, 11 | { 12 | name: 'toContainElement', 13 | }, 14 | { 15 | name: 'toHaveAttribute', 16 | }, 17 | { 18 | name: 'toHaveClass', 19 | }, 20 | { 21 | name: 'toHaveStyle', 22 | }, 23 | { 24 | name: 'toBeDisabled', 25 | }, 26 | { 27 | name: 'toBeEnabled', 28 | }, 29 | { 30 | name: 'toBeEmpty', 31 | }, 32 | { 33 | name: 'toBeInvalid', 34 | }, 35 | { 36 | name: 'toBeRequired', 37 | }, 38 | { 39 | name: 'toBeValid', 40 | }, 41 | { 42 | name: 'toBeVisible', 43 | }, 44 | { 45 | name: 'toHaveFocus', 46 | }, 47 | { 48 | name: 'toHaveFormValues', 49 | }, 50 | ]; 51 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/CustomInput/CustomInput.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import cn from 'classnames'; 3 | import styles from './CustomInput.module.scss'; 4 | 5 | const CustomInput = ({ id, label, placeholder, handleChange, value, bold }) => { 6 | return ( 7 |
8 | 11 | 20 |
21 | ); 22 | }; 23 | 24 | export default CustomInput; 25 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/CustomInput/CustomInput.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/fonts.scss'; 2 | @import '../../../assets/stylesheets/colors.scss'; 3 | 4 | .customInputContainer { 5 | width: 90%; 6 | margin: 1rem; 7 | box-sizing: border-box; 8 | 9 | .customInput { 10 | width: 100%; 11 | padding: 0.1rem; 12 | padding-left: 0.4rem; 13 | font-size: 0.75rem; 14 | font-family: $openSans; 15 | border: none; 16 | border-bottom: 1px solid $mint; 17 | background-color: rgba(0, 0, 0, 0); 18 | 19 | &:focus { 20 | outline: none; 21 | border-bottom: 1.5px solid $mint; 22 | } 23 | } 24 | 25 | .label { 26 | margin-bottom: 2rem; 27 | } 28 | 29 | .bold { 30 | font-weight: bold; 31 | font-size: 1.1rem; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/DescribeRenderer/DescribeRenderer.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from 'react'; 2 | import cn from 'classnames'; 3 | import { Draggable, Droppable } from 'react-beautiful-dnd'; 4 | import ItRenderer from '../ItRenderer/ItRenderer'; 5 | import styles from './DescribeRenderer.module.scss'; 6 | import { deleteDescribeBlock, addItstatement } from '../../../context/actions/reactTestCaseActions'; 7 | 8 | const DescribeRenderer = ({ 9 | dispatcher, 10 | describeBlocks, 11 | itStatements, 12 | statements, 13 | handleChangeDescribeText, 14 | handleChangeItStatementText, 15 | type, 16 | }) => { 17 | const deleteDescribeBlockHandleClick = (e) => { 18 | e.stopPropagation(); 19 | const describeId = e.target.id; 20 | dispatcher(deleteDescribeBlock(describeId)); 21 | }; 22 | 23 | const deleteReactDescribeBlockOnKeyUp = (e) => { 24 | if (e.charCode === 13) { 25 | const describeId = e.target.id; 26 | dispatcher(deleteDescribeBlock(describeId)); 27 | } 28 | }; 29 | const addItStatementHandleClick = (e) => { 30 | const describeId = e.target.id; 31 | dispatcher(addItstatement(describeId)); 32 | }; 33 | 34 | return describeBlocks.allIds.map((id, i) => ( 35 | 36 | {(provided) => ( 37 |
43 | 46 | 47 | 54 | 55 | 64 |
65 | 66 | 67 | {(innerProvided) => ( 68 |
69 | 77 | {innerProvided.placeholder} 78 |
79 | )} 80 |
81 |
82 | 85 |
86 |
87 | )} 88 |
89 | )); 90 | }; 91 | 92 | export default DescribeRenderer; 93 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/DescribeRenderer/DescribeRenderer.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/fonts.scss'; 2 | @import '../../../assets/stylesheets/colors.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #describeBlock { 6 | position: relative; 7 | background-color: white; 8 | border-radius: 3px; 9 | padding: 1rem; 10 | margin-top: 10px; 11 | box-shadow: 1px 1px 5px gray; 12 | display: flex; 13 | flex-direction: column; 14 | z-index: 3; 15 | margin-top: 1rem; 16 | 17 | .describeClose { 18 | position: absolute; 19 | top: 5px; 20 | right: 5px; 21 | font-size: 1.25rem; 22 | z-index: 3; 23 | transition: 250ms; 24 | 25 | &:hover { 26 | color: red; 27 | cursor: pointer; 28 | font-size: 1.5rem; 29 | font-weight: bold; 30 | } 31 | } 32 | 33 | .separator { 34 | position: absolute; 35 | top: 0; 36 | left: 0; 37 | width: 100%; 38 | height: 65px; 39 | background-color: #02c3c33f; 40 | border-bottom: 2px solid gray; 41 | opacity: 100%; 42 | z-index: 0; 43 | } 44 | 45 | .describeLabel { 46 | font-weight: bold; 47 | font-size: 0.9rem; 48 | z-index: 3; 49 | font-family: $oxygen; 50 | } 51 | 52 | .describeInput { 53 | border: none; 54 | background-color: rgba(0, 0, 0, 0); 55 | margin-top: 0.3rem; 56 | font-size: 0.9rem; 57 | z-index: 3; 58 | } 59 | 60 | .buttonContainer { 61 | display: flex; 62 | justify-content: center; 63 | align-items: center; 64 | height: 30px; 65 | margin-top: 1rem; 66 | 67 | .addIt { 68 | height: auto; 69 | color: white; 70 | padding: 0.5rem; 71 | border-radius: 5px; 72 | background-color: $mint; 73 | 74 | &:hover { 75 | background-color: white; 76 | color: $mint; 77 | } 78 | } 79 | } 80 | } 81 | 82 | /*Animation for Describe block*/ 83 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/ItRenderer/ItRenderer.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | 4 | #ItRenderer { 5 | position: relative; 6 | display: flex; 7 | flex-direction: column; 8 | margin-top: 1.5rem; 9 | padding: 0.5rem; 10 | background-color: $light-gray2; 11 | border-radius: 3px; 12 | box-shadow: 2px 2px 5px gray; 13 | animation: swing-in-top-fwd 0.5s cubic-bezier(0.175, 0.885, 0.320, 1.275) both; 14 | 15 | .itClose { 16 | position: absolute; 17 | font-size: 1.25rem; 18 | top: 5px; 19 | right: 5px; 20 | transition: 250ms; 21 | cursor: pointer; 22 | 23 | &:hover { 24 | color: red; 25 | font-size: 1.5rem; 26 | font-weight: bold; 27 | } 28 | } 29 | 30 | .buttonsContainer { 31 | margin-top: 1rem; 32 | display: flex; 33 | justify-content: space-evenly; 34 | align-items: center; 35 | } 36 | 37 | .reactButton { 38 | height: auto; 39 | font-size: 1rem; 40 | background-color: rgba(0, 0, 0, 0); 41 | border: none; 42 | min-width: 150px; 43 | border-radius: 3px; 44 | font-family: $oxygen; 45 | text-align: center; 46 | transition: 150ms; 47 | color: $mint; 48 | 49 | &:hover { 50 | font-size: 1.1rem; 51 | } 52 | 53 | i { 54 | margin-right: 0.5rem; 55 | } 56 | } 57 | } 58 | /*animation for it block*/ 59 | @-webkit-keyframes swing-in-top-fwd { 60 | 0% { 61 | -webkit-transform: rotateX(-100deg); 62 | transform: rotateX(-100deg); 63 | -webkit-transform-origin: top; 64 | transform-origin: top; 65 | opacity: 0; 66 | } 67 | 100% { 68 | -webkit-transform: rotateX(0deg); 69 | transform: rotateX(0deg); 70 | -webkit-transform-origin: top; 71 | transform-origin: top; 72 | opacity: 1; 73 | } 74 | } 75 | @keyframes swing-in-top-fwd { 76 | 0% { 77 | -webkit-transform: rotateX(-100deg); 78 | transform: rotateX(-100deg); 79 | -webkit-transform-origin: top; 80 | transform-origin: top; 81 | opacity: 0; 82 | } 83 | 100% { 84 | -webkit-transform: rotateX(0deg); 85 | transform: rotateX(0deg); 86 | -webkit-transform-origin: top; 87 | transform-origin: top; 88 | opacity: 1; 89 | } 90 | } 91 | 92 | .swing-in-top-fwd { 93 | -webkit-animation: swing-in-top-fwd 0.5s cubic-bezier(0.175, 0.885, 0.320, 1.275) both; 94 | animation: swing-in-top-fwd 0.5s cubic-bezier(0.175, 0.885, 0.320, 1.275) both; 95 | } -------------------------------------------------------------------------------- /src/components/ReactTestComponent/MockData/MockData.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * the card for adding mock data 3 | * renders : 4 | * - mockDataKey (as mockDataFieldKey) 5 | * - the labels in the card (name, key, type) 6 | */ 7 | 8 | import React from 'react'; 9 | import styles from './MockData.module.scss'; 10 | import { 11 | deleteMockData, 12 | addMockDataKey, 13 | updateMockDataName, 14 | } from '../../../context/actions/mockDataActions'; 15 | import MockDataFieldKey from './MockDataKey'; 16 | 17 | const plusIcon = require('../../../assets/images/plus.png'); 18 | const closeIcon = require('../../../assets/images/close.png'); 19 | 20 | const MockData = ({ mockDatumId, dispatchToMockData, fieldKeys }) => { 21 | const handleClickAdd = (e, id) => { 22 | e.stopPropagation(); 23 | dispatchToMockData(addMockDataKey(id)); 24 | }; 25 | 26 | const handleClickDelete = (e) => { 27 | e.stopPropagation(); 28 | dispatchToMockData(deleteMockData(mockDatumId)); 29 | }; 30 | 31 | const handleClickUpdate = (e) => { 32 | e.stopPropagation(); 33 | dispatchToMockData(updateMockDataName(mockDatumId, e.target.value)); 34 | }; 35 | 36 | const mockDataFieldKeys = fieldKeys.map((key) => ( 37 | 45 | )); 46 | 47 | return ( 48 |
49 | close 50 |
51 | 52 | 53 |
54 |
55 | 58 | 61 |
62 |
63 |
64 | {mockDataFieldKeys} 65 | 69 |
70 |
71 | ); 72 | }; 73 | 74 | export default MockData; 75 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/MockData/MockData.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #mockData { 6 | @include box-styling; 7 | padding: 5px 10px 10px 8px; 8 | hr { 9 | border: 1px solid $light-gray; 10 | margin-top: 0; 11 | } 12 | 13 | button:hover { 14 | color: $mint; 15 | } 16 | button { 17 | font-size: 12px; 18 | width: 30%; 19 | padding-top: 5px; 20 | border: none; 21 | font-family: $raleway; 22 | font-weight: bold; 23 | text-align: left; 24 | } 25 | 26 | input { 27 | width: 38%; 28 | } 29 | } 30 | 31 | #close { 32 | float: right; 33 | } 34 | #mockDataHeader { 35 | padding: 10px 0; 36 | vertical-align: middle; 37 | } 38 | 39 | #keys { 40 | font-size: 13px; 41 | margin-bottom: 0; 42 | display: flex; 43 | width: 61%; 44 | justify-content: space-between; 45 | } 46 | 47 | #keyList { 48 | margin-top: 5px; 49 | } 50 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/MockData/MockDataKey.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * the data for each field key and type in the card for mock data 3 | */ 4 | 5 | import React from 'react'; 6 | import styles from './MockDataKey.module.scss'; 7 | import { deleteMockDataKey, updateMockDataKey } from '../../../context/actions/mockDataActions'; 8 | 9 | const minusIcon = require('../../../assets/images/minus-box-outline.png'); 10 | 11 | const MockDataKey = ({ dispatchToMockData, mockDatumId, mockDatumKeyId, fieldKey, fieldType }) => { 12 | const handleChangeDelete = (e) => { 13 | e.stopPropagation(); 14 | dispatchToMockData(deleteMockDataKey(mockDatumId, mockDatumKeyId)); 15 | }; 16 | 17 | const handleChangeUpdateFieldKey = (e) => { 18 | e.stopPropagation(); 19 | dispatchToMockData(updateMockDataKey(mockDatumId, mockDatumKeyId, e.target.value, fieldType)); 20 | }; 21 | 22 | const handleChangeUpdateFieldType = (e) => { 23 | e.stopPropagation(); 24 | dispatchToMockData(updateMockDataKey(mockDatumId, mockDatumKeyId, fieldKey, e.target.value)); 25 | }; 26 | 27 | return ( 28 |
29 |
30 | 36 | 51 | delete 52 |
53 |
54 | ); 55 | }; 56 | 57 | export default MockDataKey; 58 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/MockData/MockDataKey.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | 3 | #mockDataKey { 4 | margin: 0 10px 5px 12px; 5 | img { 6 | width: 15px; 7 | height: 15px; 8 | cursor: pointer; 9 | } 10 | 11 | input { 12 | width: 50%; 13 | display: inline-block; 14 | margin-right: 20px; 15 | } 16 | 17 | select { 18 | width: 38%; 19 | height: 25px; 20 | margin-right: 10px; 21 | background-color: white; 22 | border: 1px solid $light-gray; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Render/Prop.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * ? 3 | */ 4 | 5 | import React from 'react'; 6 | import styles from './Prop.module.scss'; 7 | import { deleteProp, updateProp } from '../../../context/actions/reactTestCaseActions'; 8 | import AutoCompleteMockData from '../../AutoComplete/AutoCompleteMockData'; 9 | 10 | const minusIcon = require('../../../assets/images/minus-box-outline.png'); 11 | 12 | const Prop = ({ statementId, propId, propKey, propValue, dispatchToTestCase }) => { 13 | const handleClickDeleteProp = (e) => { 14 | e.stopPropagation(); 15 | dispatchToTestCase(deleteProp(statementId, propId)); 16 | }; 17 | 18 | const handleChangeUpdatePropKey = (e) => { 19 | e.stopPropagation(); 20 | dispatchToTestCase(updateProp(statementId, propId, e.target.value, propValue)); 21 | }; 22 | 23 | const handleChangeUpdatePropValue = (e) => { 24 | e.stopPropagation(); 25 | dispatchToTestCase(updateProp(statementId, propId, propKey, e.target.value)); 26 | }; 27 | 28 | return ( 29 |
30 | 31 | 38 | {/* */} 47 | delete 48 |
49 | ); 50 | }; 51 | 52 | export default Prop; 53 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Render/Prop.module.scss: -------------------------------------------------------------------------------- 1 | @import './../../../assets/stylesheets/colors.scss'; 2 | 3 | #renderPropsFlexBox { 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | 8 | input { 9 | width: 240px; 10 | margin: 0 4px 4px 0px; 11 | } 12 | 13 | img { 14 | margin-bottom: 5px; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Render/Render.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * functionlity to add and update props for the render 3 | */ 4 | 5 | import React, { useContext } from 'react'; 6 | import cn from 'classnames'; 7 | import styles from './Render.module.scss'; 8 | import { ReactTestCaseContext } from '../../../context/reducers/reactTestCaseReducer'; 9 | 10 | import { deleteRender, addProp } from '../../../context/actions/reactTestCaseActions'; 11 | import Prop from './Prop'; 12 | 13 | const Render = ({ statement, statementId, describeId, itId }) => { 14 | const [{ statements }, dispatchToReactTestCase] = useContext(ReactTestCaseContext); 15 | 16 | const handleClickAddProp = () => { 17 | dispatchToReactTestCase(addProp(statementId)); 18 | }; 19 | 20 | const handleClickDeleteRender = () => { 21 | dispatchToReactTestCase(deleteRender(statementId)); 22 | }; 23 | 24 | return ( 25 |
26 |
27 | 28 | Rendering: {statements.componentName} 29 | 30 | 33 | 37 |
38 |
39 | {statement.props.length > 0 && ( 40 |
41 |
42 | 45 | 48 |
49 |
50 | {statement.props.map((prop, i) => { 51 | return ( 52 | 60 | ); 61 | })} 62 |
63 | )} 64 |
65 |
66 | ); 67 | }; 68 | 69 | export default Render; 70 | -------------------------------------------------------------------------------- /src/components/ReactTestComponent/Render/Render.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #RenderContainer { 6 | position: relative; 7 | height: auto; 8 | border: 1px solid black; 9 | padding: 1rem; 10 | @include box-styling; 11 | font-family: $raleway; 12 | letter-spacing: 0.5px; 13 | 14 | .renderHeader { 15 | display: flex; 16 | justify-content: space-between; 17 | align-items: center; 18 | margin-bottom: 1rem; 19 | 20 | .header { 21 | font-size: 0.9rem; 22 | font-weight: bold; 23 | color: $mint; 24 | 25 | .componentName { 26 | font-family: 'Lucida Console', monospace; 27 | } 28 | } 29 | 30 | .addPropBtn { 31 | font-size: 1rem; 32 | cursor: pointer; 33 | position: absolute; 34 | top: 5px; 35 | right: 5px; 36 | 37 | &:hover { 38 | color: green; 39 | } 40 | } 41 | .addProps { 42 | height: auto; 43 | font-size: 0.85rem; 44 | background-color: rgba(0, 0, 0, 0); 45 | border: none; 46 | min-width: 150px; 47 | border-radius: 3px; 48 | font-family: $oxygen; 49 | text-align: center; 50 | transition: 150ms; 51 | 52 | &:hover { 53 | font-size: 0.9rem; 54 | } 55 | } 56 | 57 | .deleteRender { 58 | position: absolute; 59 | top: 2px; 60 | right: 2px; 61 | transition: 250ms; 62 | 63 | &:hover { 64 | cursor: pointer; 65 | color: red; 66 | font-size: 1rem; 67 | font-weight: bold; 68 | } 69 | } 70 | } 71 | 72 | #renderProp { 73 | font-size: 13px; 74 | margin-bottom: 0; 75 | padding: 6px 0; 76 | display: flex; 77 | width: 60%; 78 | justify-content: space-between; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/components/ReduxTestComponent/ActionCreator/ActionCreator.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #actionCreator { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | } 14 | 15 | #actionCreatorHeader { 16 | @include box-header-alignment; 17 | justify-content: flex-start; 18 | display: flex; 19 | align-items: center; 20 | img { 21 | width: 20px; 22 | height: 20px; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | h3 { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | } 31 | 32 | #filesFlexBox { 33 | display: flex; 34 | align-items: center; 35 | margin-bottom: 15px; 36 | } 37 | 38 | #files { 39 | width: 50%; 40 | margin-right: 7%; 41 | input { 42 | margin-top: 6px; 43 | width: 100%; 44 | } 45 | position: relative; 46 | } 47 | 48 | #actionFlexBox { 49 | display: flex; 50 | align-items: center; 51 | margin-bottom: 15px; 52 | } 53 | 54 | #actions { 55 | width: 50%; 56 | margin-right: 7%; 57 | input { 58 | margin-top: 6px; 59 | width: 100%; 60 | } 61 | } 62 | 63 | #payloadFlexBox { 64 | display: flex; 65 | align-items: center; 66 | width: 100%; 67 | } 68 | 69 | #payloadKey { 70 | width: 50%; 71 | margin-right: 7%; 72 | input { 73 | margin-top: 6px; 74 | width: 100%; 75 | } 76 | } 77 | 78 | #payloadType { 79 | margin-right: 7%; 80 | width: 50%; 81 | select { 82 | margin-top: 6px; 83 | font-family: $raleway; 84 | width: 100%; 85 | height: 25px; 86 | background-color: white; 87 | border: 1px solid $light-gray; 88 | font-size: 12px; 89 | letter-spacing: 0.5px; 90 | color: $dark-gray; 91 | } 92 | } 93 | 94 | // #dropdownFlex { 95 | // display: flex; 96 | // align-items: center; 97 | // width: 111%; 98 | // } 99 | -------------------------------------------------------------------------------- /src/components/ReduxTestComponent/Middleware/Middleware.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #middleware { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | } 14 | 15 | #middlewareHeader { 16 | @include box-header-alignment; 17 | justify-content: flex-start; 18 | display: flex; 19 | align-items: center; 20 | img { 21 | width: 20px; 22 | height: 20px; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | h3 { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | } 31 | 32 | .queryLabel { 33 | margin-bottom: 5px; 34 | display: block; 35 | } 36 | 37 | #queryFlexBox { 38 | display: flex; 39 | align-items: center; 40 | width: 100%; 41 | } 42 | 43 | #eventTypeFlexBox { 44 | display: flex; 45 | align-items: center; 46 | margin-bottom: 15px; 47 | } 48 | 49 | #eventType { 50 | width: 50%; 51 | margin-right: 7%; 52 | input { 53 | margin-top: 6px; 54 | width: 100%; 55 | } 56 | } 57 | 58 | .eventValue { 59 | // width: 50%; 60 | input { 61 | width: 90%; 62 | margin-top: 6px; 63 | } 64 | } 65 | 66 | #eventTypeVal { 67 | width: 43%; 68 | } 69 | 70 | #querySelector { 71 | margin-right: 9%; 72 | select { 73 | font-family: $raleway; 74 | width: 100%; 75 | height: 25px; 76 | margin: 0 3px 0 0; 77 | background-color: white; 78 | border: 1px solid $light-gray; 79 | font-size: 12px; 80 | letter-spacing: 0.5px; 81 | color: $dark-gray; 82 | } 83 | } 84 | 85 | #dropdownFlex { 86 | display: flex; 87 | align-items: center; 88 | width: 102%; 89 | } 90 | 91 | #query { 92 | input { 93 | width: 148%; 94 | } 95 | } 96 | 97 | #hastooltip { 98 | @include hastooltip($tooltip-transition-in-duration: 0.3s); 99 | } 100 | 101 | #tooltip { 102 | min-width: 10em; 103 | padding: 0.5em 0.75em; 104 | 105 | box-shadow: 0 0.05em 0.15em rgba(black, 0.1); 106 | @include tooltip; 107 | } 108 | 109 | #middlewareBox { 110 | width: 50%; 111 | margin-right: 7%; 112 | input { 113 | margin-top: 6px; 114 | width: 100%; 115 | margin-bottom: 1%; 116 | } 117 | position: relative; 118 | } 119 | 120 | #middlewareDrop { 121 | margin-right: 7%; 122 | width: 50%; 123 | select { 124 | margin-top: 7px; 125 | font-family: $raleway; 126 | width: 100%; 127 | height: 25px; 128 | background-color: white; 129 | border: 1px solid $light-gray; 130 | font-size: 12px; 131 | letter-spacing: 0.5px; 132 | color: $dark-gray; 133 | margin-bottom: 11%; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/components/ReduxTestComponent/Reducer/Reducer.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/colors.scss'; 2 | @import '../../../assets/stylesheets/fonts.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #reducer { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | margin: 0; 14 | } 15 | 16 | #reducerHeader { 17 | @include box-header-alignment; 18 | justify-content: flex-start; 19 | display: flex; 20 | align-items: center; 21 | img { 22 | width: 20px; 23 | height: 20px; 24 | margin: 0; 25 | padding: 0; 26 | } 27 | h3 { 28 | margin: 0; 29 | padding: 0; 30 | } 31 | } 32 | 33 | #reducerNameFlexBox { 34 | display: flex; 35 | align-items: center; 36 | margin-bottom: 15px; 37 | } 38 | 39 | #reducerName { 40 | width: 50%; 41 | margin-right: 7%; 42 | input { 43 | margin-top: 6px; 44 | width: 100%; 45 | } 46 | position: relative; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/components/ReduxTestComponent/Thunk/Thunk.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../../assets/stylesheets/fonts.scss'; 2 | @import '../../../assets/stylesheets/colors.scss'; 3 | @import '../../../pages/LeftPanel/LeftPanel.module.scss'; 4 | 5 | #modal { 6 | @include box-styling; 7 | font-family: $raleway; 8 | letter-spacing: 0.5px; 9 | } 10 | 11 | #close { 12 | float: right; 13 | } 14 | 15 | #header { 16 | @include box-header-alignment; 17 | justify-content: flex-start; 18 | display: flex; 19 | align-items: center; 20 | img { 21 | width: 20px; 22 | height: 20px; 23 | margin: 0; 24 | padding: 0; 25 | } 26 | h3 { 27 | margin: 0; 28 | padding: 0; 29 | } 30 | } 31 | 32 | #groupFlexbox { 33 | display: flex; 34 | align-items: center; 35 | margin-bottom: 15px; 36 | } 37 | 38 | #labelInput { 39 | width: 50%; 40 | margin-right: 7%; 41 | input { 42 | margin-top: 6px; 43 | width: 100%; 44 | } 45 | position: relative; 46 | } 47 | 48 | #dropdownWrapper { 49 | margin-right: 9%; 50 | select { 51 | font-family: $raleway; 52 | width: 100%; 53 | height: 25px; 54 | margin: 0 3px 0 0; 55 | background-color: white; 56 | border: 1px solid $light-gray; 57 | font-size: 12px; 58 | letter-spacing: 0.5px; 59 | color: $dark-gray; 60 | } 61 | } 62 | 63 | #dropdownFlex { 64 | display: flex; 65 | align-items: center; 66 | width: 100%; 67 | margin-top: 6px; 68 | } 69 | 70 | #inputFlexBox { 71 | display: flex; 72 | align-items: center; 73 | width: 100%; 74 | } 75 | 76 | #hastooltip { 77 | @include hastooltip($tooltip-transition-in-duration: 0.3s); 78 | } 79 | 80 | #tooltip { 81 | min-width: 10em; 82 | padding: 0.5em 0.75em; 83 | 84 | box-shadow: 0 0.05em 0.15em rgba(black, 0.1); 85 | @include tooltip; 86 | } 87 | -------------------------------------------------------------------------------- /src/components/SearchInput/SearchInput.scss: -------------------------------------------------------------------------------- 1 | .search-container { 2 | position: relative; 3 | } 4 | 5 | ul.options li:hover { 6 | font-weight: bold; 7 | color: #00b4cc; 8 | cursor: pointer; 9 | transition: 0.3s all; 10 | } 11 | 12 | ul.options li.option-active { 13 | background: whitesmoke; 14 | color: #00b4cc; 15 | } 16 | 17 | .options { 18 | background-color: white; 19 | overflow: auto; 20 | position: absolute; 21 | z-index: 1; 22 | width: -webkit-fill-available; 23 | } 24 | 25 | .react-test-options { 26 | background-color: white; 27 | overflow: auto; 28 | position: absolute; 29 | z-index: 4; 30 | width: 137px; 31 | } 32 | ul.react-test-options li:hover { 33 | font-weight: bold; 34 | color: #00b4cc; 35 | cursor: pointer; 36 | transition: 0.3s all; 37 | } 38 | 39 | ul.react-test-options li.option-active { 40 | background: whitesmoke; 41 | color: #00b4cc; 42 | } 43 | 44 | .flex-container { 45 | display: flex; 46 | align-items: center; 47 | margin-bottom: 15px; 48 | } 49 | 50 | .flex-item { 51 | width: 200px; 52 | margin-right: 7%; 53 | input { 54 | margin-top: 6px; 55 | width: 100%; 56 | } 57 | position: relative; 58 | } 59 | -------------------------------------------------------------------------------- /src/components/Terminal/TerminalView.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, ChangeEvent } from 'react'; 2 | import { XTerm } from 'xterm-for-react'; 3 | import { TerminalType } from '../../utils/terminalTypes'; 4 | 5 | const { Terminal } = require('xterm'); 6 | const ipc = require('electron').ipcRenderer; 7 | 8 | const terminalArgs: TerminalType = { 9 | fontSize: 15, 10 | // Currently rows are hardcoded, next step is to make terminal sizing dynamic. 11 | rows: 30, 12 | fontFamily: 'monospace', 13 | theme: { 14 | background: '#002a36', 15 | }, 16 | }; 17 | 18 | const term = new Terminal(terminalArgs); 19 | 20 | const TerminalView = () => { 21 | useEffect(() => { 22 | // console.log(global.projectFilePath); 23 | term.open(document.getElementsByClassName('terminal')[0]); 24 | // when we have input events (e), we would send the data to the main processor 25 | term.onData((e: ChangeEvent) => { 26 | ipc.send('terminal.toTerm', e); 27 | }); 28 | // when incoming Data comes back to the main process, this ipc renderer 29 | // will take it and writes it to xterm monitor 30 | ipc.on('terminal.incData', (event, data: string) => { 31 | term.write(data); 32 | }); 33 | }, []); 34 | 35 | return ; 36 | }; 37 | 38 | export default TerminalView; 39 | -------------------------------------------------------------------------------- /src/components/TestCase/EndpointTestStatements.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import Endpoint from '../EndpointTestComponent/Endpoint'; 3 | import { EndpointTestCaseContext } from '../../context/reducers/endpointTestCaseReducer'; 4 | import { EndpointObj } from '../../utils/endpointTypes'; 5 | 6 | const EndpointTestStatements = () => { 7 | const [{ endpointStatements }, dispatch] = useContext(EndpointTestCaseContext); 8 | 9 | return ( 10 | <> 11 | {endpointStatements.map((statement: EndpointObj, i: number) => { 12 | switch (statement.type) { 13 | /* add statements here. Ex: */ 14 | case 'endpoint': 15 | return ( 16 | 22 | ); 23 | default: 24 | return <>; 25 | } 26 | })} 27 | 28 | ); 29 | }; 30 | 31 | export default EndpointTestStatements; 32 | -------------------------------------------------------------------------------- /src/components/TestCase/HooksTestCase.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useRef, useEffect } from 'react'; 2 | import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd'; 3 | import styles from './TestCase.module.scss'; 4 | import { HooksTestCaseContext } from '../../context/reducers/hooksTestCaseReducer'; 5 | import { 6 | updateHooksTestStatement, 7 | updateStatementsOrder, 8 | } from '../../context/actions/hooksTestCaseActions'; 9 | import HooksTestMenu from '../TestMenu/HooksTestMenu'; 10 | import HooksTestStatements from './HooksTestStatements'; 11 | import { HooksStatements } from '../../utils/hooksTypes'; 12 | 13 | const HooksTestCase = () => { 14 | const [{ hooksStatements }, dispatchToHooksTestCase] = useContext(HooksTestCaseContext); 15 | 16 | 17 | 18 | const handleUpdateHooksTestStatement = (e: React.ChangeEvent) => { 19 | dispatchToHooksTestCase(updateHooksTestStatement(e.target.value)); 20 | }; 21 | 22 | const reorder = (list: Array, startIndex: number, endIndex: number) => { 23 | const result = Array.from(list); 24 | const [removed] = result.splice(startIndex, 1); 25 | result.splice(endIndex, 0, removed); 26 | return result; 27 | }; 28 | 29 | const onDragEnd = (result: DropResult) => { 30 | if (!result.destination) { 31 | return; 32 | } 33 | if (result.destination.index === result.source.index) { 34 | return; 35 | } 36 | const reorderedStatements: Array = reorder( 37 | hooksStatements, 38 | result.source.index, 39 | result.destination.index 40 | ); 41 | dispatchToHooksTestCase(updateStatementsOrder(reorderedStatements)); 42 | }; 43 | return ( 44 | <> 45 | 48 |
49 |
50 | +Describe Block 51 |
52 |
53 | 59 |
60 |
61 | 62 | 63 | {(provided) => ( 64 |
65 | 66 | {provided.placeholder} 67 |
68 | )} 69 |
70 |
71 | 72 | ); 73 | }; 74 | 75 | export default HooksTestCase; 76 | -------------------------------------------------------------------------------- /src/components/TestCase/HooksTestStatements.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import HookUpdates from '../ReactHooksTestComponent/HookUpdates/HookUpdates'; 3 | import { HooksTestCaseContext } from '../../context/reducers/hooksTestCaseReducer'; 4 | import { HooksStatements } from '../../utils/hooksTypes'; 5 | import importOptionsSwitch from './importOptions'; 6 | import SearchInput from '../SearchInput/SearchInput'; 7 | import { updateHooksFilePath } from '../../context/actions/hooksTestCaseActions'; 8 | import '../SearchInput/SearchInput.scss'; 9 | import { GlobalContext } from '../../context/reducers/globalReducer'; 10 | 11 | const HooksTestStatements = () => { 12 | const [{ hooksStatements }, dispatchToHooksTestCase] = useContext(HooksTestCaseContext); 13 | const { isHooksOn } = importOptionsSwitch(hooksStatements); 14 | const [{ filePathMap }] = useContext(GlobalContext); 15 | 16 | let hImports = null; 17 | if (isHooksOn) { 18 | hImports = ( 19 |
20 | 31 |
32 | ); 33 | } 34 | return ( 35 | <> 36 | {hImports} 37 | {hooksStatements.map((statement: HooksStatements, i: number) => { 38 | switch (statement.type) { 39 | case 'hooks': 40 | return ; 41 | default: 42 | return <>; 43 | } 44 | })} 45 | 46 | ); 47 | }; 48 | 49 | export default HooksTestStatements; 50 | -------------------------------------------------------------------------------- /src/components/TestCase/PuppeteerTestCase.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useRef, useEffect } from 'react'; 2 | import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd'; 3 | import { PuppeteerTestCaseContext } from '../../context/reducers/puppeteerTestCaseReducer'; 4 | import PuppeteerTestMenu from '../TestMenu/PuppeteerTestMenu'; 5 | import PuppeteerTestStatements from './PuppeteerTestStatements'; 6 | import { updateStatementsOrder } from '../../context/actions/puppeteerTestCaseActions'; 7 | import { PuppeteerStatements } from '../../utils/puppeteerTypes'; 8 | 9 | //additions fo previously ExportFileModal functionality 10 | import styles from './TestCase.module.scss'; 11 | 12 | const PuppeteerTestCase = () => { 13 | const [{ puppeteerStatements }, dispatchToPuppeteerTestCase] = useContext( 14 | PuppeteerTestCaseContext 15 | ); 16 | 17 | const testDescription = useRef(null); 18 | 19 | useEffect(() => { 20 | if (testDescription && testDescription.current) { 21 | testDescription.current.focus(); 22 | } 23 | }, []); 24 | 25 | const reorder = (list: Array, startIndex: number, endIndex: number) => { 26 | const result = Array.from(list); 27 | const [removed] = result.splice(startIndex, 1); 28 | result.splice(endIndex, 0, removed); 29 | return result; 30 | }; 31 | 32 | const onDragEnd = (result: DropResult) => { 33 | if (!result.destination) { 34 | return; 35 | } 36 | if (result.destination.index === result.source.index) { 37 | return; 38 | } 39 | const reorderedStatements: Array = reorder( 40 | puppeteerStatements, 41 | result.source.index, 42 | result.destination.index 43 | ); 44 | dispatchToPuppeteerTestCase(updateStatementsOrder(reorderedStatements)); 45 | }; 46 | 47 | return ( 48 |
49 | 52 |
53 | 54 | 55 | {(provided: any) => ( 56 |
57 | 58 | {provided.placeholder} 59 |
60 | )} 61 |
62 |
63 |
64 | ); 65 | }; 66 | 67 | export default PuppeteerTestCase; 68 | -------------------------------------------------------------------------------- /src/components/TestCase/PuppeteerTestStatements.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import PaintTiming from '../PuppeteerTestComponent/PaintTiming/PaintTiming'; 3 | import { PuppeteerTestCaseContext } from '../../context/reducers/puppeteerTestCaseReducer'; 4 | import { PuppeteerStatements } from '../../utils/puppeteerTypes'; 5 | 6 | const PuppeteerTestStatements = () => { 7 | const [{ puppeteerStatements }] = useContext(PuppeteerTestCaseContext); 8 | 9 | return ( 10 | <> 11 | {puppeteerStatements.map((statement: PuppeteerStatements, i: number) => { 12 | switch (statement.type) { 13 | case 'paintTiming': 14 | return ; 15 | default: 16 | return <>; 17 | } 18 | })} 19 | 20 | ); 21 | }; 22 | 23 | export default PuppeteerTestStatements; 24 | -------------------------------------------------------------------------------- /src/components/TestCase/ReactContainer.module.scss: -------------------------------------------------------------------------------- 1 | @import '/../../assets/stylesheets/colors.scss'; 2 | 3 | 4 | #ReactContainer { 5 | .describeBlockContainer { 6 | background-color: white; 7 | box-sizing: border-box; 8 | width: 100%; 9 | padding: 1rem; 10 | margin-top: 1rem; 11 | box-shadow: 0 0.05em 0.15em rgba(black, 0.1); 12 | 13 | .describe { 14 | font-size: 1.25rem; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/components/TestCase/ReactTestStatements.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Action from '../ReactTestComponent/Action/Action'; 3 | import Assertion from '../ReactTestComponent/Assertion/Assertion'; 4 | import Render from '../ReactTestComponent/Render/Render'; 5 | 6 | const ReactTestStatements = ({ statements, itId, describeId }) => { 7 | // filter out ids not belonging to the correct describe block and itStatement 8 | const filterStatements = statements.allIds.filter((id) => { 9 | return statements.byId[id].describeId === describeId && statements.byId[id].itId === itId; 10 | }); 11 | 12 | return filterStatements.map((id, i) => { 13 | switch (statements.byId[id].type) { 14 | case 'action': 15 | return ( 16 | 23 | ); 24 | case 'assertion': 25 | return ( 26 | 33 | ); 34 | case 'render': 35 | return ( 36 | 43 | ); 44 | default: 45 | return <>; 46 | } 47 | }); 48 | }; 49 | 50 | export default ReactTestStatements; 51 | -------------------------------------------------------------------------------- /src/components/TestCase/ReduxTestCase.tsx: -------------------------------------------------------------------------------- 1 | //not using useRef or useEffect which are both react hooks... 2 | import React, { useContext, useRef, useEffect } from 'react'; 3 | // if react-beautiful-dnd is declared in declaration.d.ts then eslint becomes unhappy about DropResult 4 | import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd'; 5 | import styles from './TestCase.module.scss'; 6 | import { ReduxTestCaseContext } from '../../context/reducers/reduxTestCaseReducer'; 7 | 8 | import { 9 | updateReduxTestStatement, 10 | updateStatementsOrder, 11 | } from '../../context/actions/reduxTestCaseActions'; 12 | import ReduxTestMenu from '../TestMenu/ReduxTestMenu'; 13 | import ReduxTestStatements from './ReduxTestStatements'; 14 | import { ReduxStatements } from '../../utils/reduxTypes'; 15 | 16 | const ReduxTestCase = () => { 17 | interface Ref { 18 | current: any; 19 | } 20 | 21 | const [{ reduxTestStatement, reduxStatements }, dispatchToReduxTestCase] = useContext( 22 | ReduxTestCaseContext 23 | ); 24 | 25 | 26 | 27 | const handleUpdateReduxTestStatement = (e: React.ChangeEvent) => { 28 | dispatchToReduxTestCase(updateReduxTestStatement(e.target.value)); 29 | }; 30 | 31 | const reorder = (list: ReduxStatements[], startIndex: number, endIndex: number) => { 32 | const result = Array.from(list); 33 | const [removed] = result.splice(startIndex, 1); 34 | result.splice(endIndex, 0, removed); 35 | return result; 36 | }; 37 | 38 | const onDragEnd = (result: DropResult) => { 39 | if (!result.destination) { 40 | return; 41 | } 42 | if (result.destination.index === result.source.index) { 43 | return; 44 | } 45 | const reorderedStatements: Array = reorder( 46 | reduxStatements, 47 | result.source.index, 48 | result.destination.index 49 | ); 50 | dispatchToReduxTestCase(updateStatementsOrder(reorderedStatements)); 51 | }; 52 | 53 | return ( 54 |
55 | 58 |
59 |
60 | 61 | 68 |
69 |
70 | 71 | 72 | 73 | {(provided: any) => ( 74 |
75 | 76 | {provided.placeholder} 77 |
78 | )} 79 |
80 |
81 |
82 | ); 83 | }; 84 | 85 | export default ReduxTestCase; 86 | -------------------------------------------------------------------------------- /src/components/TestCase/TestCase.module.scss: -------------------------------------------------------------------------------- 1 | @import './../../assets/stylesheets/fonts.scss'; 2 | @import './../../assets/stylesheets/colors.scss'; 3 | @import '../../pages/LeftPanel/LeftPanel.module.scss'; 4 | // @import '../EndpointTestComponent/Endpoint.module.scss'; 5 | 6 | .displays { 7 | display: block; 8 | } 9 | 10 | div { 11 | font-size: 12px; 12 | vertical-align: middle; 13 | } 14 | #head { 15 | position: fixed; 16 | z-index: 9999; 17 | } 18 | 19 | #testCaseHeader { 20 | margin: 15px 25px 15px 15px; 21 | } 22 | 23 | #testMockSection { 24 | margin-bottom: 50px; 25 | } 26 | 27 | #testStatement { 28 | margin-top: 3px; 29 | width: 93%; 30 | } 31 | 32 | #mockHeader { 33 | float: right; 34 | margin: 5px 26px; 35 | } 36 | 37 | #checkboxLabel { 38 | margin: 10px; 39 | } 40 | 41 | #mockDataHeader { 42 | padding: 0 2%; 43 | label { 44 | margin: 5px; 45 | vertical-align: middle; 46 | } 47 | img { 48 | width: 15px; 49 | } 50 | } 51 | 52 | #ReactTestCase { 53 | .header { 54 | display: flex; 55 | justify-content: space-between; 56 | align-items: center; 57 | margin-bottom: 1rem; 58 | padding: 1rem; 59 | 60 | .renderComponent { 61 | display: flex; 62 | justify-content: space-between; 63 | align-items: center; 64 | 65 | .renderLabel { 66 | font-family: $oxygen; 67 | font-size: 0.9rem; 68 | margin-right: 0.5rem; 69 | } 70 | 71 | .renderInput { 72 | display: block; 73 | margin-top: 0.5rem; 74 | width: 300px; 75 | border: none; 76 | border-bottom: 1px solid $mint; 77 | } 78 | } 79 | 80 | .mockBtn { 81 | height: auto; 82 | font-size: 0.85rem; 83 | background-color: rgba(0, 0, 0, 0); 84 | border: none; 85 | min-width: 150px; 86 | border-radius: 3px; 87 | font-family: $oxygen; 88 | text-align: center; 89 | transition: 150ms; 90 | 91 | &:hover { 92 | font-size: 0.9rem; 93 | } 94 | } 95 | 96 | .addIcon { 97 | margin-right: 0.25rem; 98 | } 99 | } 100 | } 101 | 102 | #labelInput { 103 | width: 100%; 104 | margin-right: 7%; 105 | input { 106 | margin-top: 6px; 107 | width: 100%; 108 | max-width: 500px; 109 | } 110 | position: relative; 111 | } 112 | 113 | #hastooltip { 114 | @include hastooltip($tooltip-transition-in-duration: 0.3s); 115 | img { 116 | height: 15px; 117 | width: 15px; 118 | margin-left: 2px; 119 | margin-top: -1px; 120 | } 121 | } 122 | 123 | #tooltip { 124 | min-width: 15em; 125 | padding: 0.5em 0.75em; 126 | box-shadow: 0 0.05em 0.15em rgba(black, 0.1); 127 | @include tooltip; 128 | } 129 | 130 | #dropdownWrapper { 131 | // margin-right: 9%; 132 | width: 43%; 133 | max-width: 225px; 134 | select { 135 | font-family: $raleway; 136 | width: 100%; 137 | height: 25px; 138 | margin: 0 3px 0 0; 139 | background-color: white; 140 | border: 1px solid $light-gray; 141 | font-size: 12px; 142 | letter-spacing: 0.5px; 143 | color: $dark-gray; 144 | } 145 | } 146 | 147 | #dropdownFlex { 148 | display: flex; 149 | align-items: center; 150 | margin-top: 6px; 151 | } 152 | 153 | #accTestDiv { 154 | display: flex; 155 | justify-content: flex-start; 156 | } 157 | 158 | #secTestBtn { 159 | 160 | min-height: 80px; 161 | padding: 16px; 162 | 163 | &:hover { 164 | font-size: 0.9rem; 165 | } 166 | } 167 | 168 | #secInfo { 169 | font-size: 14px !important; 170 | font-family: $oxygen; 171 | text-align: justify; 172 | line-height: 1.3; 173 | } -------------------------------------------------------------------------------- /src/components/TestCase/importOptions.ts: -------------------------------------------------------------------------------- 1 | interface statements { 2 | type: string; 3 | } 4 | export default function importOptionsSwitch(statements: statements[]) { 5 | let isReducerOn = false; 6 | let isMiddleWareOn = false; 7 | let isActionCreatorOn = false; 8 | let isAsyncOn = false; 9 | let isHooksOn = false; 10 | 11 | statements.forEach(({ type }) => { 12 | switch (type) { 13 | case 'reducer': 14 | isReducerOn = true; 15 | break; 16 | case 'middleware': 17 | isMiddleWareOn = true; 18 | break; 19 | case 'action-creator': 20 | isActionCreatorOn = true; 21 | break; 22 | case 'async': 23 | isAsyncOn = true; 24 | break; 25 | case 'hooks': 26 | isHooksOn = true; 27 | break; 28 | default: 29 | break; 30 | } 31 | }); 32 | return { 33 | isReducerOn, 34 | isMiddleWareOn, 35 | isActionCreatorOn, 36 | isAsyncOn, 37 | isHooksOn, 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/components/TestMenu/SecTestMenu.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useContext } from 'react'; 2 | import styles from '../TestMenu/TestMenu.module.scss'; 3 | import { GlobalContext } from '../../context/reducers/globalReducer'; 4 | import { openBrowserDocs } from '../../context/actions/globalActions'; 5 | import { createNewSecTest } from '../../context/actions/secTestCaseActions'; 6 | import Modal from '../Modals/Modal'; 7 | import useGenerateTest from '../../context/useGenerateTest.jsx'; 8 | import { 9 | updateFile, 10 | setFilePath, 11 | toggleRightPanel, 12 | setValidCode, 13 | setTestCase, 14 | toggleModal, 15 | } from '../../context/actions/globalActions'; 16 | import { SecTestCaseContext } from '../../context/reducers/secTestCaseReducer'; 17 | import { useToggleModal } from './testMenuHooks'; 18 | 19 | const SecTestMenu = () => { 20 | // link to Snyk docs 21 | const snykURL = 'https://docs.snyk.io/' 22 | 23 | /* initialize hooks */ 24 | // 25 | const { title, isModalOpen, openModal, openScriptModal, closeModal, } = useToggleModal('sec'); 26 | const [secTestCase, dispatchToSecTestCase] = useContext(SecTestCaseContext); 27 | const [{ projectFilePath, file, exportBool, isTestModalOpen }, dispatchToGlobal] = useContext(GlobalContext); 28 | 29 | // setValidCode to true on load. 30 | useEffect(() => { 31 | dispatchToGlobal(setValidCode(true)); 32 | }, []); 33 | 34 | // handle change to open Snyk docs on right panel 35 | const openDocs = () => { 36 | dispatchToGlobal(openBrowserDocs(snykURL)); 37 | }; 38 | 39 | const openNewTestModal = () => { 40 | if (!isTestModalOpen) dispatchToGlobal(toggleModal()); 41 | }; 42 | return ( 43 |
44 |
45 |
46 | 47 | 50 | {/* set a few of these properties to null since they are required to be present but accept any data type... just for testing*/} 51 | 59 |
60 |
64 |
65 |
66 |
67 | ); 68 | } 69 | 70 | export default SecTestMenu; -------------------------------------------------------------------------------- /src/components/TestMenu/TestMenu.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/colors.scss'; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | /** 4 | * ---------------------------------------- 5 | * animation slide-in-elliptic-top-fwd 6 | * ---------------------------------------- 7 | */ 8 | #testMenu { 9 | padding: 10px; 10 | text-align: center; 11 | display: flex; 12 | justify-content: space-between; 13 | width: 98%; 14 | margin-bottom: 10px; 15 | max-width: 800px; 16 | button { 17 | margin: 5px; 18 | height: 40px; 19 | width: 110px; 20 | color: $mint; 21 | background-color: $light-gray3; 22 | opacity: 0.8; 23 | font-family: $oxygen; 24 | font-size: 14px; 25 | border-radius: 5px; 26 | border: 0.5px $light-gray solid; 27 | } 28 | 29 | 30 | 31 | button:hover { 32 | background-color: white; 33 | color: $mint; 34 | border-radius: 5px; 35 | } 36 | } 37 | 38 | 39 | #left { 40 | float: left; 41 | button { 42 | color: $mint; 43 | background-color: white; 44 | } 45 | 46 | button:hover { 47 | background-color: $mint; 48 | color: white; 49 | } 50 | } 51 | 52 | #right { 53 | display: flex; 54 | flex-direction: column; 55 | align-items: center; 56 | button { 57 | color: white; 58 | background-color: $mint; 59 | margin-right: 4px; 60 | margin-bottom: 4px; 61 | } 62 | 63 | button:hover { 64 | background-color: white; 65 | color: $mint; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/components/TestMenu/testMenuHooks.js: -------------------------------------------------------------------------------- 1 | import { useState, useContext } from 'react'; 2 | import { GlobalContext } from '../../context/reducers/globalReducer'; 3 | import { setTabIndex } from '../../context/actions/globalActions'; 4 | 5 | export function useToggleModal(test) { 6 | const [isModalOpen, setIsModalOpen] = useState(false); 7 | const [title, setTitle] = useState(test); 8 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 9 | const [{ isFileDirectoryOpen }, dispatchToGlobal] = useContext(GlobalContext); 10 | 11 | const openModal = () => { 12 | setTitle('New Test'); 13 | setIsModalOpen(true); 14 | }; 15 | 16 | const openScriptModal = () => { 17 | setTitle(title); 18 | setIsModalOpen(true); 19 | dispatchToGlobal(setTabIndex(2)); 20 | }; 21 | 22 | const closeModal = () => { 23 | setIsModalOpen(false); 24 | setTitle(test); 25 | }; 26 | 27 | return { 28 | title, isModalOpen, openModal, openScriptModal, closeModal 29 | }; 30 | } 31 | 32 | export const validateInputs = (testSuite, testCaseState) => { 33 | let endpoint, assertion; 34 | switch (testSuite) { 35 | case 'endpoint': 36 | const { serverFilePath, addDB, dbFilePath, endpointStatements } = testCaseState; 37 | if (!serverFilePath || (addDB && !dbFilePath)) return false; 38 | for (endpoint of endpointStatements) { 39 | if (!endpoint.method || !endpoint.route) return false; 40 | for (assertion of endpoint.assertions) { 41 | if (!assertion.expectedResponse || !assertion.value || !assertion.matcher) return false; 42 | } 43 | } 44 | return true; 45 | case 'hooks': 46 | let hookTest, callback; 47 | for (hookTest of testCaseState) { 48 | if (!hookTest.hookFilePath || !hookTest.hook) return false; 49 | for (callback of hookTest.callbackFunc) { 50 | if (!callback.callbackFunc) { 51 | return false; 52 | } 53 | } 54 | for (assertion of hookTest.assertions) { 55 | if (!assertion.expectedState || !assertion.expectedValue || !assertion.matcher) 56 | return false; 57 | } 58 | } 59 | return true; 60 | default: 61 | return true; 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /src/components/ToolTip/ToolTip.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * the question mark notes for selectors 3 | */ 4 | 5 | import React from 'react'; 6 | import styles from './ToolTip.scss'; 7 | 8 | const ToolTip = ({ toolTipType }) => { 9 | const TOOLTIP_MAP = { 10 | '': 'Choose a selector', 11 | getBy: 12 | 'Returns the first matching node for a query, and throws an error if no elements match or if more than one match is found (use getAllBy instead).', 13 | getAllBy: 14 | 'Returns an array of all matching nodes for a query, and throws an error if no elements match.', 15 | queryBy: 16 | 'Returns the first matching node for a query, and return null if no elements match. This is useful for asserting an element is not present. This throws if more than one match is found (use queryAllBy instead).', 17 | queryAllBy: 18 | 'Returns an array of all matching nodes for a query, and return an empty array ([]) if no elements match.', 19 | findBy: 20 | 'Returns a promise which resolves when an element is found which matches the given query. The promise is rejected if no element is found or if more than one element is found after a default timeout of 4500ms. If you need to find more than one element, then use findAllBy.', 21 | findAllBy: 22 | 'Returns a promise which resolves to an array of elements when any elements are found which match the given query. The promise is rejected if no elements are found after a default timeout of 4500ms.', 23 | LabelText: 24 | 'This will search for the label that matches the given TextMatch, then find the element associated with that label.', 25 | PlaceholderText: 26 | 'This will search for all elements with a placeholder attribute and find one that matches the given TextMatch.', 27 | Text: 28 | 'This will search for all elements that have a text node with textContent matching the given TextMatch.', 29 | AltText: 30 | "This will return the element (normally an ) that has the given alt text. Note that it only supports elements which accept an alt attribute: , , and (intentionally excluding as it's deprecated).", 31 | Title: 'Returns the element that has the matching title attribute.', 32 | DisplayValue: 33 | 'Returns the input, textarea, or select element that has the matching display value.', 34 | Role: 35 | 'A shortcut to container.querySelector(`[role="${yourRole}"]`) (and it also accepts a TextMatch).', 36 | TestId: 37 | 'A shortcut to container.querySelector(`[data-testid="${yourId}"]`) (and it also accepts a TextMatch).', 38 | LCPTarget: 39 | 'The Largest Contentful Paint (LCP) metric reports the render time of the largest content element visible within the viewport. Provide a target value in ms.', 40 | FPTarget: 41 | 'The First Paint (FP) metric reports the time between navigation and when the browser renders the first pixels to the screen, rendering anything that is visually different from what was on the screen prior to navigation. Provide a target value in ms.', 42 | FCPTarget: 43 | "The First Contentful Paint (FCP) metric measures the time from when the page starts loading to when any part of the page's content is rendered on the screen. Provide a target value in ms.", 44 | }; 45 | 46 | // changed id from styles.tooltip to the string: "styles.tooltip" 47 | // As far as I can tell this isn't necessary 48 | return {TOOLTIP_MAP[toolTipType]}; 49 | }; 50 | 51 | export default ToolTip; 52 | -------------------------------------------------------------------------------- /src/components/ToolTip/ToolTip.scss: -------------------------------------------------------------------------------- 1 | @import '../../pages/LeftPanel/LeftPanel.module.scss'; 2 | 3 | #hastooltip { 4 | @include hastooltip($tooltip-transition-in-duration: 0.3s); 5 | } 6 | 7 | #tooltip { 8 | min-width: 10em; 9 | padding: 0.5em 0.75em; 10 | @include tooltip; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/ToolTip/ToolTipAsync.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * question mark notes for matchers 3 | */ 4 | 5 | import React from 'react'; 6 | import styles from './ToolTip.scss'; 7 | 8 | const ToolTipAsync = ({ toolTipType }) => { 9 | if (toolTipType.includes('.')) { 10 | toolTipType = toolTipType.replace(/\./g, ''); 11 | } 12 | const TOOLTIP_MAP_ASYNC = { 13 | '': 'Choose a matcher', 14 | object: 15 | "Must be an object.", 16 | expectedResponse: 'Must be an array of the expected action objects', 17 | 18 | }; 19 | 20 | // changed id from styles.tooltip to the string: "styles.tooltip" 21 | // As far as I can tell this isn't necessary 22 | return {TOOLTIP_MAP_ASYNC[toolTipType]}; 23 | // return {TOOLTIP_MAP_ASYNC}; 24 | }; 25 | 26 | export default ToolTipAsync; 27 | -------------------------------------------------------------------------------- /src/components/UploadTest/UploadTest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * functionality to save a test into the database 3 | */ 4 | 5 | import React, { useState } from 'react'; 6 | import styles from './UploadTest.module.scss'; 7 | import UploadTestModal from '../Modals/UploadTestModal'; 8 | 9 | const UploadTest = ({ testType }) => { 10 | const [uploadTestModalIsOpen, setUploadTestModalIsOpen] = useState(false); 11 | 12 | const handleOpenUploadTestModal = () => { 13 | setUploadTestModalIsOpen(true); 14 | }; 15 | 16 | return ( 17 | <> 18 | 21 | {uploadTestModalIsOpen ? ( 22 | 27 | ) : null} 28 | 29 | ); 30 | }; 31 | 32 | export default UploadTest; 33 | -------------------------------------------------------------------------------- /src/components/UploadTest/UploadTest.module.scss: -------------------------------------------------------------------------------- 1 | @import './../../assets/stylesheets/colors.scss'; 2 | 3 | .navBtn { 4 | padding: 0; 5 | border: 0; 6 | margin-top: 15px; 7 | margin-bottom: 40px; 8 | cursor: pointer; 9 | background-color: transparent; 10 | :focus { 11 | outline: 2px solid darkblue; 12 | } 13 | } 14 | 15 | .icons { 16 | width: 28px; 17 | height: 28px; 18 | } 19 | 20 | #saveTestBtn { 21 | margin-top: 10px; 22 | padding-left: 1rem; 23 | font-size: 12px; 24 | text-align: left; 25 | width: 250px; 26 | height: 1.5rem; 27 | color: $dark-gray; 28 | box-shadow: none; 29 | cursor: pointer; 30 | -webkit-appearance: none; 31 | -moz-appearance: none; 32 | :focus { 33 | outline: 2px solid darkblue; 34 | } 35 | } 36 | 37 | #saveTestBtn:focus { 38 | outline: 2px solid darkblue; 39 | } 40 | 41 | .tooltip { 42 | visibility: hidden; 43 | width: 120px; 44 | background: black; 45 | color: white; 46 | position: absolute; 47 | padding: 5px 0; 48 | text-align: center; 49 | border-radius: 8px; 50 | margin: 0 auto; 51 | z-index: 3; 52 | } 53 | 54 | .navBtn:hover .tooltip { 55 | visibility: visible; 56 | margin-left: 5px; 57 | } 58 | 59 | .navBtn:active .tooltip { 60 | visibility: hidden; 61 | } 62 | -------------------------------------------------------------------------------- /src/context/actions/accTestCaseActions.ts: -------------------------------------------------------------------------------- 1 | /* ------------------------------ Action Types ------------------------------ */ 2 | 3 | export const actionTypes = { 4 | ADD_DESCRIBE_BLOCK: 'ADD_DESCRIBE_BLOCK', 5 | DELETE_DESCRIBE_BLOCK: 'DELETE_DESCRIBE_BLOCK', 6 | UPDATE_DESCRIBE_TEXT: 'UPDATE_DESCRIBE_TEXT', 7 | UPDATE_DESCRIBE_ORDER: 'UPDATE_DESCRIBE_ORDER', 8 | UPDATE_DESCRIBE_STANDARD_TAG: 'UPDATE_DESCRIBE_STANDARD_TAG', 9 | 10 | ADD_ITSTATEMENT: 'ADD_ITSTATEMENT', 11 | DELETE_ITSTATEMENT: 'DELETE_ITSTATEMENT', 12 | UPDATE_ITSTATEMENT_TEXT: 'UPDATE_ITSTATEMENT_TEXT', 13 | UPDATE_ITSTATEMENT_ORDER: 'UPDATE_ITSTATEMENT_ORDER', 14 | UPDATE_IT_CAT_TAG: 'UPDATE_IT_CAT_TAG', 15 | 16 | CREATE_NEW_TEST: 'CREATE_NEW_TEST', 17 | OPEN_INFO_MODAL: 'OPEN_INFO_MODAL', 18 | CLOSE_INFO_MODAL: 'CLOSE_INFO_MODAL', 19 | 20 | UPDATE_FILE_PATH: 'UPDATE_FILE_PATH', 21 | UPDATE_TEST_TYPE: 'UPDATE_TEST_TYPE', 22 | CREATE_PUPPETEER_URL: 'CREATE_PUPPETEER_URL', 23 | 24 | REPLACE_TEST: 'REPLACE_TEST', 25 | }; 26 | 27 | /* --------------------------------- Actions -------------------------------- */ 28 | 29 | export const addDescribeBlock = () => ({ 30 | type: actionTypes.ADD_DESCRIBE_BLOCK, 31 | }); 32 | 33 | export const deleteDescribeBlock = (describeId: string) => ({ 34 | type: actionTypes.DELETE_DESCRIBE_BLOCK, 35 | describeId, 36 | }); 37 | 38 | export const updateDescribeText = (text: string, describeId: string) => ({ 39 | type: actionTypes.UPDATE_DESCRIBE_TEXT, 40 | text, 41 | describeId, 42 | }); 43 | 44 | export const updateDescribeOrder = (reorderedDescribe: Array) => ({ 45 | type: actionTypes.UPDATE_DESCRIBE_ORDER, 46 | reorderedDescribe, 47 | }); 48 | 49 | export const updateDescribeStandardTag = (describeId: string, standardTag: string) => ({ 50 | type: actionTypes.UPDATE_DESCRIBE_STANDARD_TAG, 51 | describeId, 52 | standardTag, 53 | }); 54 | 55 | export const addItStatement = (describeId: string) => ({ 56 | type: actionTypes.ADD_ITSTATEMENT, 57 | describeId, 58 | }); 59 | 60 | export const deleteItStatement = (describeId: string, itId: string) => ({ 61 | type: actionTypes.DELETE_ITSTATEMENT, 62 | describeId, 63 | itId, 64 | }); 65 | 66 | export const updateItStatementText = (text: string, itId: string) => ({ 67 | type: actionTypes.UPDATE_ITSTATEMENT_TEXT, 68 | itId, 69 | text, 70 | }); 71 | 72 | export const updateItStatementOrder = (reorderedIt: Array, describeId: string) => ({ 73 | type: actionTypes.UPDATE_ITSTATEMENT_ORDER, 74 | reorderedIt, 75 | describeId, 76 | }); 77 | 78 | export const updateItCatTag = (itId: string, catTag: string) => ({ 79 | type: actionTypes.UPDATE_IT_CAT_TAG, 80 | itId, 81 | catTag, 82 | }); 83 | 84 | export const createNewTest = () => ({ 85 | type: actionTypes.CREATE_NEW_TEST, 86 | }); 87 | 88 | export const openInfoModal = () => ({ 89 | type: actionTypes.OPEN_INFO_MODAL, 90 | }); 91 | 92 | export const closeInfoModal = () => ({ 93 | type: actionTypes.CLOSE_INFO_MODAL, 94 | }); 95 | 96 | export const updateFilePath = (fileName: string, filePath: string) => ({ 97 | type: actionTypes.UPDATE_FILE_PATH, 98 | fileName, 99 | filePath, 100 | }); 101 | 102 | export const updateTestType = (testType: string) => ({ 103 | type: actionTypes.UPDATE_TEST_TYPE, 104 | testType, 105 | }); 106 | 107 | export const createPuppeteerUrl = (puppeteerUrl: string) => ({ 108 | type: actionTypes.CREATE_PUPPETEER_URL, 109 | puppeteerUrl, 110 | }); 111 | 112 | export const accReplaceTest = (testState: object) => ({ 113 | type: actionTypes.REPLACE_TEST, 114 | testState, 115 | }); 116 | -------------------------------------------------------------------------------- /src/context/actions/globalActions.js: -------------------------------------------------------------------------------- 1 | export const actionTypes = { 2 | SET_PROJECT_URL: 'SET_PROJECT_URL', 3 | LOAD_PROJECT: 'LOAD_PROJECT', 4 | CREATE_FILE_TREE: 'CREATE_FILE_TREE', 5 | TOGGLE_FILE_DIRECTORY: 'TOGGLE_FILE_DIRECTORY', 6 | CLOSE_RIGHT_PANEL: 'CLOSE_RIGHT_PANEL', 7 | TOGGLE_RIGHT_PANEL: 'TOGGLE_RIGHT_PANEL', 8 | TOGGLE_FOLDER_VIEW: 'TOGGLE_FOLDER_VIEW', 9 | HIGHLIGHT_FILE: 'HIGHLIGHT_FILE', 10 | SET_PROJECT_FILE_PATH: 'SET_PROJECT_FILE_PATH', 11 | SET_FILE_PATH_MAP: 'SET_FILE_PATH_MAP', 12 | 13 | //added 14 | SET_TEST_CASE: 'SET_TEST_CASE', 15 | TOGGLE_MODAL: 'TOGGLE_MODAL', 16 | UPDATE_FILE: 'UPDATE_FILE', 17 | OPEN_BROWSER_DOCS: 'OPEN_BROWSER_DOCS', 18 | RESET_TO_PROJECT_URL: 'RESET_TO_PROJECT_URL', // formerly NEW_TEST_CLOSE_BROWSER_DOCS 19 | TOGGLE_EXPORT_BOOL: 'TOGGLE_EXPORT_BOOL', 20 | SET_FILE_PATH: 'SET_FILE_PATH', 21 | SET_VALID_CODE: 'SET_VALID_CODE', 22 | SET_TAB_INDEX: 'SET_TAB_INDEX', 23 | 24 | UPLOAD_TEST: 'UPLOAD_TEST', 25 | 26 | SET_GUEST: 'SET_GUEST' 27 | }; 28 | 29 | export const setProjectUrl = (url) => ({ 30 | type: actionTypes.SET_PROJECT_URL, 31 | url, 32 | }); 33 | 34 | export const loadProject = (load) => ({ 35 | type: actionTypes.LOAD_PROJECT, 36 | load, 37 | }); 38 | 39 | export const createFileTree = (fileTree) => ({ 40 | type: actionTypes.CREATE_FILE_TREE, 41 | fileTree, 42 | }); 43 | 44 | export const toggleFileDirectory = () => ({ 45 | type: actionTypes.TOGGLE_FILE_DIRECTORY, 46 | }); 47 | 48 | export const closeRightPanel = () => ({ 49 | type: actionTypes.CLOSE_RIGHT_PANEL, 50 | }); 51 | 52 | export const toggleRightPanel = (display) => ({ 53 | type: actionTypes.TOGGLE_RIGHT_PANEL, 54 | display, 55 | }); 56 | 57 | export const toggleFolderView = (filePath) => ({ 58 | type: actionTypes.TOGGLE_FOLDER_VIEW, 59 | filePath, 60 | }); 61 | 62 | export const highlightFile = (fileName) => ({ 63 | type: actionTypes.HIGHLIGHT_FILE, 64 | fileName, 65 | }); 66 | 67 | export const setProjectFilePath = (projectFilePath) => ({ 68 | type: actionTypes.SET_PROJECT_FILE_PATH, 69 | projectFilePath, 70 | }); 71 | 72 | export const setFilePathMap = (filePathMap) => ({ 73 | type: actionTypes.SET_FILE_PATH_MAP, 74 | filePathMap, 75 | }); 76 | 77 | //added 78 | export const setTestCase = (testCase) => ({ 79 | type: actionTypes.SET_TEST_CASE, 80 | testCase, 81 | }); 82 | 83 | export const toggleModal = () => ({ 84 | type: actionTypes.TOGGLE_MODAL, 85 | }); 86 | 87 | export const updateFile = (testString) => ({ 88 | type: actionTypes.UPDATE_FILE, 89 | testString, 90 | }); 91 | 92 | export const openBrowserDocs = (docsUrl) => ({ 93 | type: actionTypes.OPEN_BROWSER_DOCS, 94 | docsUrl, 95 | }); 96 | 97 | export const resetToProjectUrl = () => ({ 98 | type: actionTypes.RESET_TO_PROJECT_URL, 99 | }); 100 | 101 | export const toggleExportBool = () => ({ 102 | type: actionTypes.TOGGLE_EXPORT_BOOL, 103 | }); 104 | 105 | export const setFilePath = (filePath) => ({ 106 | type: actionTypes.SET_FILE_PATH, 107 | filePath, 108 | }); 109 | 110 | export const setValidCode = (validCode) => ({ 111 | type: actionTypes.SET_VALID_CODE, 112 | validCode, 113 | }); 114 | 115 | export const setTabIndex = (tabIndex) => ({ 116 | type: actionTypes.SET_TAB_INDEX, 117 | tabIndex, 118 | }); 119 | 120 | export const uploadTest = (testState) => ({ 121 | type: actionTypes.UPLOAD_TEST, 122 | testState, 123 | }); 124 | 125 | export const setGuest = (guestState) => ({ 126 | type: actionTypes.SET_GUEST, 127 | guestState, 128 | }); -------------------------------------------------------------------------------- /src/context/actions/mockDataActions.js: -------------------------------------------------------------------------------- 1 | export const actionTypes = { 2 | TOGGLE_MOCK_DATA: 'TOGGLE_MOCK_DATA', 3 | ADD_MOCK_DATA: 'ADD_MOCK_DATA', 4 | DELETE_MOCK_DATA: 'DELETE_MOCK_DATA', 5 | UPDATE_MOCK_DATA_NAME: 'UPDATE_MOCK_DATA_NAME', 6 | 7 | ADD_MOCK_DATA_KEY: 'ADD_MOCK_DATA_KEY', 8 | DELETE_MOCK_DATA_KEY: 'DELETE_MOCK_DATA_KEY', 9 | UPDATE_MOCK_DATA_KEY: 'UPDATE_MOCK_DATA_KEY', 10 | 11 | CLEAR_MOCK_DATA: 'CLEAR_MOCK_DATA', 12 | }; 13 | 14 | export const toggleMockData = () => ({ 15 | type: actionTypes.TOGGLE_MOCK_DATA, 16 | }); 17 | 18 | export const createMockData = () => ({ 19 | type: actionTypes.ADD_MOCK_DATA, 20 | }); 21 | 22 | export const deleteMockData = (id) => ({ 23 | type: actionTypes.DELETE_MOCK_DATA, 24 | id, 25 | }); 26 | 27 | export const updateMockDataName = (id, name) => ({ 28 | type: actionTypes.UPDATE_MOCK_DATA_NAME, 29 | id, 30 | name, 31 | }); 32 | 33 | export const addMockDataKey = (id) => ({ 34 | type: actionTypes.ADD_MOCK_DATA_KEY, 35 | id, 36 | }); 37 | 38 | export const deleteMockDataKey = (mockDatumId, mockDatumKeyId) => ({ 39 | type: actionTypes.DELETE_MOCK_DATA_KEY, 40 | mockDatumId, 41 | mockDatumKeyId, 42 | }); 43 | 44 | export const updateMockDataKey = (mockDatumId, mockDatumKeyId, fieldKey, fieldType) => ({ 45 | type: actionTypes.UPDATE_MOCK_DATA_KEY, 46 | mockDatumId, 47 | mockDatumKeyId, 48 | fieldKey, 49 | fieldType, 50 | }); 51 | 52 | export const clearMockData = () => ({ 53 | type: actionTypes.CLEAR_MOCK_DATA, 54 | }); 55 | 56 | export const mockReplaceTest = (testState) => ({ 57 | type: actionTypes.REPLACE_TEST, 58 | testState, 59 | }); 60 | -------------------------------------------------------------------------------- /src/context/actions/puppeteerTestCaseActions.ts: -------------------------------------------------------------------------------- 1 | import { PuppeteerStatements } from '../../utils/puppeteerTypes'; 2 | 3 | export const actionTypes = { 4 | TOGGLE_PUPPETEER: 'TOGGLE_PUPPETEER', 5 | CREATE_NEW_PUPPETEER_TEST: 'CREATE_NEW_PUPPETEER_TEST', 6 | DELETE_PUPPETEER_TEST: 'DELETE_PUPPETEER_TEST', 7 | ADD_PUPPETEER_PAINT_TIMING: 'ADD_PUPPETEER_PAINT_TIMING', 8 | DELETE_PUPPETEER_PAINT_TIMING: 'DELETE_PUPPETEER_PAINT_TIMING', 9 | ADD_BROWSER_OPTIONS: 'ADD_BROWSER_OPTIONS', 10 | UPDATE_PAINT_TIMING: 'UPDATE_PAINT_TIMING', 11 | DELETE_BROWSER_OPTION: 'DELETE_BROWSER_OPTION', 12 | UPDATE_BROWSER_OPTION: 'UPDATE_BROWSER_OPTION', 13 | UPDATE_STATEMENTS_ORDER: 'UPDATE_STATEMENTS_ORDER', 14 | OPEN_INFO_MODAL: 'OPEN_INFO_MODAL', 15 | CLOSE_INFO_MODAL: 'CLOSE_INFO_MODAL', 16 | REPLACE_TEST: 'REPLACE_TEST', 17 | }; 18 | 19 | export const togglePuppeteer = () => ({ 20 | type: actionTypes.TOGGLE_PUPPETEER, 21 | }); 22 | 23 | export const createNewPuppeteerTest = () => ({ 24 | type: actionTypes.CREATE_NEW_PUPPETEER_TEST, 25 | }); 26 | 27 | export const deletePuppeteerTest = (id: number) => ({ 28 | type: actionTypes.DELETE_PUPPETEER_TEST, 29 | id, 30 | }); 31 | 32 | export const addPuppeteerPaintTiming = () => ({ 33 | type: actionTypes.ADD_PUPPETEER_PAINT_TIMING, 34 | }); 35 | 36 | export const addBrowserOption = (id: number) => ({ 37 | type: actionTypes.ADD_BROWSER_OPTIONS, 38 | id, 39 | }); 40 | 41 | export const deleteBrowserOption = (id: number, optionId: number) => ({ 42 | type: actionTypes.DELETE_BROWSER_OPTION, 43 | id, 44 | optionId, 45 | }); 46 | 47 | export const updatePaintTiming = (id: number, field: string, value: string) => ({ 48 | type: actionTypes.UPDATE_PAINT_TIMING, 49 | id, 50 | field, 51 | value, 52 | }); 53 | 54 | export const updateBrowserOption = ( 55 | id: number, 56 | field: string, 57 | value: string, 58 | optionId: number 59 | ) => ({ 60 | type: actionTypes.UPDATE_BROWSER_OPTION, 61 | id, 62 | field, 63 | value, 64 | optionId, 65 | }); 66 | 67 | export const updateStatementsOrder = (draggableStatements: Array) => ({ 68 | type: actionTypes.UPDATE_STATEMENTS_ORDER, 69 | draggableStatements, 70 | }); 71 | 72 | export const openInfoModal = () => { 73 | return { type: actionTypes.OPEN_INFO_MODAL }; 74 | }; 75 | 76 | export const closeInfoModal = () => { 77 | return { type: actionTypes.CLOSE_INFO_MODAL }; 78 | }; 79 | 80 | export const puppeteerReplaceTest = (testState: object) => ({ 81 | type: actionTypes.REPLACE_TEST, 82 | testState, 83 | }); 84 | -------------------------------------------------------------------------------- /src/context/actions/secTestCaseActions.ts: -------------------------------------------------------------------------------- 1 | /* ------------------------------ Action Types ------------------------------ */ 2 | 3 | export const actionTypes = { 4 | OPEN_INFO_MODAL: 'OPEN_INFO_MODAL', 5 | CLOSE_INFO_MODAL: 'CLOSE_INFO_MODAL', 6 | CREATE_NEW_SEC_TEST: 'CREATE_NEW_SEC_TEST', 7 | REPLACE_TEST: 'REPLACE_TEST' 8 | }; 9 | 10 | /* --------------------------------- Actions -------------------------------- */ 11 | 12 | export const openInfoModal = () => ({ 13 | type: actionTypes.OPEN_INFO_MODAL, 14 | }); 15 | 16 | export const closeInfoModal = () => ({ 17 | type: actionTypes.CLOSE_INFO_MODAL, 18 | }); 19 | 20 | export const createNewSecTest = () => ({ 21 | type: actionTypes.CREATE_NEW_SEC_TEST, 22 | }); 23 | 24 | export const secReplaceTest = (testState: object) => ({ 25 | type: actionTypes.REPLACE_TEST, 26 | testState, 27 | }); 28 | -------------------------------------------------------------------------------- /src/context/reducers/mockDataReducer.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import { actionTypes } from '../actions/mockDataActions'; 3 | 4 | export const MockDataContext = createContext([]); 5 | 6 | export const mockDataState = { 7 | mockData: [], 8 | hasMockData: false, 9 | }; 10 | 11 | let mockDatumId = 0; 12 | let mockDatumKeyId = 0; 13 | 14 | const createMockDatum = (id) => ({ 15 | id: mockDatumId++, 16 | name: '', 17 | fieldKeys: [], 18 | content: '', 19 | type: 'mockData', 20 | }); 21 | 22 | const createFieldKeys = (id) => ({ 23 | id: mockDatumKeyId++, 24 | fieldKey: '', 25 | fieldType: '', 26 | }); 27 | 28 | export const mockDataReducer = (state, action) => { 29 | Object.freeze(state); 30 | let mockData = state.mockData; 31 | 32 | switch (action.type) { 33 | case actionTypes.TOGGLE_MOCK_DATA: 34 | if (!state.hasMockData) { 35 | mockData.push(createMockDatum()); 36 | } 37 | return { 38 | ...state, 39 | mockData, 40 | hasMockData: !state.hasMockData, 41 | }; 42 | case actionTypes.ADD_MOCK_DATA: 43 | mockData.push(createMockDatum()); 44 | return { 45 | ...state, 46 | mockData, 47 | }; 48 | case actionTypes.DELETE_MOCK_DATA: 49 | mockData = mockData.filter((mockDatum) => mockDatum.id !== action.id); 50 | return { 51 | ...state, 52 | mockData, 53 | }; 54 | case actionTypes.UPDATE_MOCK_DATA_NAME: 55 | mockData = mockData.map((mockDatum) => { 56 | if (mockDatum.id === action.id) { 57 | mockDatum.name = action.name; 58 | } 59 | return mockDatum; 60 | }); 61 | return { 62 | ...state, 63 | mockData, 64 | }; 65 | case actionTypes.ADD_MOCK_DATA_KEY: 66 | mockData = mockData.map((mockDatum) => { 67 | if (mockDatum.id === action.id) { 68 | mockDatum.fieldKeys.push(createFieldKeys()); 69 | } 70 | return mockDatum; 71 | }); 72 | return { 73 | ...state, 74 | mockData, 75 | }; 76 | case actionTypes.DELETE_MOCK_DATA_KEY: 77 | mockData = mockData.map((mockDatum) => { 78 | if (mockDatum.id === action.mockDatumId) { 79 | mockDatum.fieldKeys = mockDatum.fieldKeys.filter( 80 | (key) => key.id !== action.mockDatumKeyId 81 | ); 82 | } 83 | return mockDatum; 84 | }); 85 | return { 86 | ...state, 87 | mockData, 88 | }; 89 | case actionTypes.UPDATE_MOCK_DATA_KEY: 90 | mockData = mockData.map((mockDatum) => { 91 | if (mockDatum.id === action.mockDatumId) { 92 | mockDatum.fieldKeys.map((fieldKey) => { 93 | if (fieldKey.id === action.mockDatumKeyId) { 94 | fieldKey.fieldKey = action.fieldKey; 95 | fieldKey.fieldType = action.fieldType; 96 | } 97 | return fieldKey; 98 | }); 99 | } 100 | return mockDatum; 101 | }); 102 | 103 | return { 104 | ...state, 105 | mockData, 106 | }; 107 | case actionTypes.CLEAR_MOCK_DATA: 108 | return { 109 | mockData: [], 110 | hasMockData: false, 111 | }; 112 | case actionTypes.REPLACE_TEST: { 113 | const { testState } = action; 114 | return testState; 115 | } 116 | default: 117 | return state; 118 | } 119 | }; 120 | -------------------------------------------------------------------------------- /src/context/reducers/secTestCaseReducer.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | import { SecTestCaseState, Action } from '../../utils/secTypes'; 3 | import { actionTypes } from '../actions/secTestCaseActions'; 4 | 5 | export const SecTestCaseContext: any = createContext([]); 6 | 7 | /* ------------------------- Security Test Case State ------------------------ */ 8 | 9 | export const secTestCaseState: SecTestCaseState = { 10 | modalOpen: true 11 | } 12 | 13 | /* ------------------------- Security Test Case Reducer ------------------------ */ 14 | 15 | export const secTestCaseReducer = (state: SecTestCaseState, action: Action) => { 16 | switch (action.type) { 17 | case actionTypes.OPEN_INFO_MODAL: { 18 | return { 19 | ...state, 20 | modalOpen: true 21 | } 22 | } 23 | case actionTypes.OPEN_INFO_MODAL: { 24 | return { 25 | ...state, 26 | modalOpen: true 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App.jsx'; 4 | 5 | ReactDOM.render( , 6 | document.getElementById('root')); -------------------------------------------------------------------------------- /src/pages/About/About.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/fonts.scss'; 2 | @import '../../assets/stylesheets/colors.scss'; 3 | 4 | #about { 5 | padding: 16px 50px; 6 | border-bottom-right-radius: 6px; 7 | border-bottom-left-radius: 6px; 8 | width: 1000px; 9 | margin-left: 70px; 10 | img { 11 | max-width: 90%; 12 | margin: 16px 5% 0 5%; 13 | } 14 | 15 | h2 { 16 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, 17 | Apple Color Emoji, Segoe UI Emoji; 18 | font-size: 1.5rem; 19 | padding-bottom: 0.3em; 20 | border-bottom: 1px solid #eaecef; 21 | margin-top: 24px; 22 | margin-bottom: 16px; 23 | font-weight: 600; 24 | line-height: 1.25; 25 | } 26 | ol { 27 | padding-left: 2em; 28 | margin-bottom: 16px; 29 | } 30 | li { 31 | text-align: -webkit-match-parent; 32 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, 33 | Apple Color Emoji, Segoe UI Emoji; 34 | font-size: 16px; 35 | line-height: 1.5; 36 | list-style-type: decimal; 37 | color: #24292e; 38 | display: list-item; 39 | text-align: left; 40 | } 41 | p { 42 | font-family: -apple-system, system-ui, 'Segoe UI', Helvetica, Arial, sans-serif, 43 | 'Apple Color Emoji', 'Segoe UI Emoji'; 44 | font-size: 16px; 45 | line-height: 1.5; 46 | margin-bottom: 16px; 47 | } 48 | 49 | blockquote { 50 | padding: 0 1em; 51 | color: #6a737d; 52 | border-left: 0.25em solid #dfe2e5; 53 | } 54 | 55 | code { 56 | font-size: 13.6px; 57 | word-break: normal; 58 | white-space: pre; 59 | background: transparent; 60 | font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; 61 | background-attachment: scroll; 62 | background-clip: border-box; 63 | border-color: rgb(36, 41, 46); 64 | border-radius: 6px; 65 | } 66 | 67 | button { 68 | color: white; 69 | background-color: $mint; 70 | margin-right: 4px; 71 | margin-bottom: 4px; 72 | margin: 5px; 73 | height: 40px; 74 | width: 110px; 75 | opacity: 0.8; 76 | font-family: $oxygen; 77 | font-size: 14px; 78 | border-radius: 5px; 79 | border: 0.5px $light-gray solid; 80 | } 81 | 82 | button:hover { 83 | background-color: white; 84 | color: $mint; 85 | } 86 | 87 | #container { 88 | display: flex; 89 | justify-content: center; 90 | } 91 | 92 | .text { 93 | // margin-left: 5px; 94 | font-weight: 300; 95 | font-family: $oxygen; 96 | letter-spacing: 1px; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/pages/LeftPanel/LeftPanel.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './LeftPanel.module.scss'; 3 | import TestFile from '../TestFile/TestFile'; 4 | 5 | const LeftPanel = () => ( 6 | <> 7 |
8 | 9 |
10 | 11 | ); 12 | 13 | export default LeftPanel; 14 | -------------------------------------------------------------------------------- /src/pages/LeftPanel/LeftPanel.module.scss: -------------------------------------------------------------------------------- 1 | @use 'sass:math' as math; 2 | @import '../../assets/stylesheets/fonts.scss'; 3 | @import '../../assets/stylesheets/colors.scss'; 4 | 5 | #leftPanel { 6 | grid-area: leftPanel; 7 | grid-column-start: 2; 8 | height: 100vh; 9 | padding-bottom: 20px; 10 | padding-top: 4px; 11 | padding-left: 0.5rem; 12 | padding-right: 0.5rem; 13 | font-family: $raleway; 14 | justify-content: space-evenly; 15 | min-width: 600px; // changed this to make dev easier w/ dev tools open 16 | overflow: auto; 17 | border-right: 0.5px dotted $mint; 18 | 19 | button { 20 | text-decoration: none; 21 | width: 20%; 22 | height: 10px; 23 | font-size: 13px; 24 | } 25 | 26 | input { 27 | font-family: $raleway; 28 | font-size: 12px; 29 | padding: 4px; 30 | } 31 | 32 | h3 { 33 | color: $mint; 34 | font-size: 14px; 35 | padding: 0.3em 0.5em; 36 | } 37 | } 38 | 39 | @mixin box-styling { 40 | background-color: white; 41 | padding: 10px 10px 22px 15px; 42 | margin: 10px 18px 0 8px; 43 | border: 1px solid transparent; 44 | border-radius: 4px; 45 | box-shadow: 1px 1px 15px rgba(21, 27, 38, 0.05); 46 | font-family: $raleway; 47 | 48 | img { 49 | margin: 2px; 50 | opacity: 0.8; 51 | width: 15px; 52 | height: 15px; 53 | } 54 | 55 | label { 56 | padding: 0.3em 0.5em; 57 | font-size: 12px; 58 | } 59 | 60 | p { 61 | font-size: 14px; 62 | padding: 5px; 63 | } 64 | } 65 | 66 | @mixin box-header-alignment { 67 | margin-bottom: 12px; 68 | 69 | h3 { 70 | float: left; 71 | font-size: 14px; 72 | } 73 | 74 | img { 75 | float: right; 76 | } 77 | } 78 | 79 | @mixin tooltip( 80 | $tooltip-arrow-base: 2em, 81 | $tooltip-arrow-length: 1em, 82 | $tooltip-border-width: 0, 83 | $tooltip-border-color: transparent, 84 | $tooltip-transition-out-duration: 0.3s 85 | ) { 86 | box-sizing: border-box; 87 | position: absolute; 88 | left: -230%; 89 | bottom: 100%; 90 | margin-bottom: $tooltip-arrow-length; 91 | background-color: $light-gray3; 92 | border: $mint solid 1px; 93 | font-size: 10px; 94 | text-align: left; 95 | line-height: 12px; 96 | width: 180px; 97 | 98 | visibility: hidden; 99 | opacity: 0; 100 | transform: translate(-50%, $tooltip-arrow-length); 101 | transition: visibility 0s linear $tooltip-transition-out-duration, 102 | opacity $tooltip-transition-out-duration ease-in 0s, 103 | transform $tooltip-transition-out-duration ease-in 0s; 104 | 105 | // Disable events. 106 | pointer-events: none; 107 | 108 | &::after { 109 | content: ''; 110 | position: absolute; 111 | top: 100%; 112 | left: 80%; 113 | width: 0; 114 | height: 0; 115 | // Draw a triangle. 116 | border-top: ($tooltip-arrow-length - $tooltip-border-width) solid $mint; 117 | border-left: (math.div($tooltip-arrow-base, 2)- $tooltip-border-width) solid transparent; 118 | border-right: (math.div($tooltip-arrow-base, 2) - $tooltip-border-width) solid transparent; 119 | // Center the triangle. 120 | margin-left: ($tooltip-border-width - math.div($tooltip-arrow-base, 2)); 121 | } 122 | } 123 | 124 | @mixin hastooltip($tooltip-transition-in-duration: 0.3s) { 125 | position: relative; 126 | // Prevent the tooltip from being clipped by its container. 127 | overflow: visible; 128 | 129 | // Display the tooltip on hover and on focus. 130 | &:hover, 131 | &:focus { 132 | #tooltip { 133 | visibility: visible; 134 | opacity: 1; 135 | transform: translate(-50%, 0); // horizontally centered 136 | transition: visibility 0s linear 0s, opacity $tooltip-transition-in-duration ease-out 0s, 137 | transform $tooltip-transition-in-duration ease-out 0s; 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/pages/ProjectLoader/ProjectLoader.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../assets/stylesheets/fonts.scss'; 2 | @import '../../assets/stylesheets/colors.scss'; 3 | 4 | #upperPart { 5 | width: 100%; 6 | height: 50vh; 7 | background-color: #038181; 8 | display: flex; 9 | flex-direction: column; 10 | justify-content: center; 11 | align-items: center; 12 | } 13 | 14 | #title { 15 | font-size: 4rem; 16 | text-align: center; 17 | vertical-align: bottom; 18 | font-family: 'comfortaa'; 19 | color: #fff; 20 | padding-top: 30px; 21 | margin-top: 30px; 22 | flex: 1; 23 | } 24 | 25 | #purpose { 26 | font-size: 1rem; 27 | text-align: center; 28 | font-family: 'comfortaa'; 29 | color: #fff; 30 | flex: 1; 31 | } 32 | 33 | #leaf { 34 | width: 48px; 35 | height: 48px; 36 | margin-bottom: 38px; 37 | margin-left: 5px; 38 | color: #fff; 39 | } 40 | 41 | #lowerPart { 42 | width: 100%; 43 | height: 50vh; 44 | background-color: $light-gray3; 45 | } 46 | 47 | #subText { 48 | font-size: 1.2rem; 49 | text-align: center; 50 | font-family: $oxygen; 51 | font-weight: 300; 52 | letter-spacing: 1px; 53 | color: $mint; 54 | padding: 20px; 55 | } 56 | 57 | #appBox { 58 | display: flex; 59 | justify-content: center; 60 | height: 25vh; 61 | } 62 | 63 | .contentBox { 64 | margin: 100px 80px; 65 | } 66 | 67 | #url { 68 | margin-top: 10px; 69 | padding-left: 1rem; 70 | font-size: 12px; 71 | width: 250px; 72 | height: 25px; 73 | color: rgb(128, 128, 128); 74 | } 75 | 76 | #openBtn { 77 | margin-top: 10px; 78 | padding-left: 1rem; 79 | font-size: 12px; 80 | text-align: left; 81 | width: 250px; 82 | color: $dark-gray; 83 | outline: none; 84 | border: 0.5px solid $light-gray; 85 | box-shadow: none; 86 | cursor: pointer; 87 | -webkit-appearance: none; 88 | -moz-appearance: none; 89 | } 90 | 91 | .number { 92 | font-weight: bold; 93 | letter-spacing: 1.5px; 94 | font-family: $oxygen; 95 | color: $mint; 96 | } 97 | 98 | .text { 99 | margin-left: 5px; 100 | font-weight: 300; 101 | font-family: $oxygen; 102 | letter-spacing: 1px; 103 | } 104 | 105 | #helpBtn { 106 | color: white; 107 | background-color: $mint; 108 | margin: 15px 4px 4px 4px; 109 | height: 40px; 110 | width: 110px; 111 | opacity: 0.8; 112 | font-family: $oxygen; 113 | font-size: 14px; 114 | border-radius: 5px; 115 | border: 0.5px $light-gray solid; 116 | } 117 | 118 | #helpBtn:hover { 119 | background-color: white; 120 | color: $mint; 121 | } 122 | #helpBtn:focus { 123 | outline: 1px solid darkblue; 124 | } 125 | 126 | #bottomDiv { 127 | display: flex; 128 | height: 25vh; 129 | justify-content: center; 130 | } 131 | 132 | .gitLogin { 133 | border: none; 134 | background-color: transparent; 135 | font-size: 14px; 136 | } 137 | 138 | #gitButton { 139 | margin-top: 13px; 140 | padding-left: 10px; 141 | } 142 | 143 | #loginBtn { 144 | font-size: 13px; 145 | } 146 | -------------------------------------------------------------------------------- /src/pages/RightPanel/RightPanel.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import styles from './RightPanel.module.scss'; 3 | import Tabs from '@material-ui/core/Tabs'; 4 | import Tab from '@material-ui/core/Tab'; 5 | import EditorView from './../../components/EditorView/EditorView'; 6 | import BrowserView from './../../components/BrowserView/BrowserView'; 7 | import { GlobalContext } from './../../context/reducers/globalReducer'; 8 | import { closeRightPanel, setTabIndex } from './../../context/actions/globalActions'; 9 | import TerminalView from './../../components/Terminal/TerminalView'; 10 | 11 | const RightPanel = () => { 12 | const [{ rightPanelDisplay, url, tabIndex }, dispatchToGlobal] = useContext(GlobalContext); 13 | 14 | return ( 15 |
16 | 17 | dispatchToGlobal(setTabIndex(newValue))} centered> 18 | 19 | 20 | 21 | 22 | 23 | {/* Editor Tab */} 24 | 27 | {/* Browser Tab */} 28 | 31 | {/* Test Terminal */} 32 | 35 |
36 | ); 37 | }; 38 | export default RightPanel; 39 | -------------------------------------------------------------------------------- /src/pages/RightPanel/RightPanel.module.scss: -------------------------------------------------------------------------------- 1 | #rightPanel { 2 | display: flex; 3 | flex-direction: column; 4 | grid-area: rightPanel; 5 | grid-column-start: 3; 6 | padding: 8px 7px 5px 5px; 7 | } 8 | #close { 9 | align-self: flex-end; 10 | margin-right: .5rem; 11 | cursor: pointer; 12 | } -------------------------------------------------------------------------------- /src/utils/accTypes.ts: -------------------------------------------------------------------------------- 1 | export interface AccTestCaseState { 2 | modalOpen: boolean; 3 | describeId: number; 4 | itId: number; 5 | statementId: number; 6 | propId: number; 7 | describeBlocks: DescribeBlocks 8 | itStatements: ItStatements; 9 | fileName: string; 10 | filePath: string; 11 | testType: string; 12 | puppeteerUrl: string; 13 | } 14 | export interface DescribeBlocks { 15 | byId: Object; 16 | allIds: Array; 17 | } 18 | export interface ItStatements { 19 | byId: Object; 20 | allIds: Object; 21 | } 22 | export interface Action { 23 | type: string; 24 | id?: string; 25 | draggableStatements?: Array; 26 | index?: number; 27 | text?: string; 28 | itId?: number; 29 | describeId?: number | string; 30 | reorderedDescribe?: Array; 31 | reorderedIt?: Array; 32 | fileName?: string; 33 | filePath?: string; 34 | describeBlocks: any[]; 35 | standardTag: string; 36 | catTag: string; 37 | } 38 | -------------------------------------------------------------------------------- /src/utils/endpointTypes.ts: -------------------------------------------------------------------------------- 1 | export interface EndpointStatements { 2 | id: number; 3 | type: string; 4 | [key: string]: any; 5 | } 6 | 7 | export interface EndpointTestCaseState { 8 | modalOpen: boolean; 9 | serverFilePath: string; 10 | serverFileName: string; 11 | endpointStatements: EndpointObj[]; 12 | dbFilePath: string; 13 | addDB: boolean | string; 14 | } 15 | 16 | export interface Action { 17 | type: string; 18 | id?: number; 19 | serverFileName?: string; 20 | serverFilePath?: string; 21 | draggableStatements?: Array; 22 | index?: number; 23 | text?: string; 24 | assertion?: Assertion; 25 | db?: string | boolean; 26 | dbFilePath?: string; 27 | } 28 | 29 | type EndpointKeyValues = number | string | boolean | Assertion[] | Header[]; 30 | 31 | interface forEndpoint { 32 | [index: string]: EndpointKeyValues; 33 | } 34 | 35 | export interface EndpointObj extends forEndpoint { 36 | id: number; 37 | type: string; 38 | testName: string; 39 | method: string; 40 | route: string; 41 | assertions: Assertion[]; 42 | headers: Header[]; 43 | post: boolean; 44 | postData: string; 45 | } 46 | 47 | export interface Assertion { 48 | id: number; 49 | expectedResponse: string; 50 | value: string; 51 | matcher: string; 52 | not: boolean; 53 | } 54 | 55 | export interface Header { 56 | id: number; 57 | headerName: string; 58 | headerValue: string; 59 | } 60 | 61 | export type EventTarget = { 62 | target: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; 63 | }; 64 | export interface EndpointTestMenuProps { 65 | dispatchToEndpointTestCase: (action: object) => void; 66 | } 67 | export interface EndpointTestStatementsProps extends EndpointTestMenuProps { 68 | endpointStatements: Array; 69 | } 70 | -------------------------------------------------------------------------------- /src/utils/hooksTypes.ts: -------------------------------------------------------------------------------- 1 | export interface HooksStatements { 2 | id: number; 3 | type: string; 4 | [key: string]: any; 5 | } 6 | 7 | export interface HooksTestCaseState { 8 | hookFileName: string; 9 | hookFilePath: string; 10 | hooksTestStatement: string; 11 | hooksStatements: Hooks[]; 12 | statementId: number; 13 | } 14 | 15 | export interface Assertion { 16 | id: number; 17 | expectedState: string; 18 | matcher: string; 19 | expectedValue: string; 20 | not: boolean; 21 | } 22 | export interface Callback { 23 | id: number; 24 | callbackFunc: string; 25 | } 26 | 27 | export interface Hooks { 28 | id: number; 29 | type: string; 30 | testName: string; 31 | hook: string; 32 | hookParams: string; 33 | assertions: Assertion[]; 34 | callbackFunc: Callback[]; 35 | typeof: boolean; 36 | hookFileName: string; 37 | hookFilePath: string; 38 | } 39 | /* ---------------------------- Actions In Reducer coming from hooksTestCaseActions ---------------------- */ 40 | 41 | export type HooksAction = 42 | | { 43 | type: 44 | | 'TOGGLE_HOOKS' 45 | | 'ADD_CONTEXT' 46 | | 'ADD_HOOK_UPDATES' 47 | | 'CREATE_NEW_HOOKS_TEST' 48 | | 'OPEN_INFO_MODAL' 49 | | 'CLOSE_INFO_MODAL' 50 | | 'REPLACE_TEST'; 51 | } 52 | | { type: 'UPDATE_HOOKS_TEST_STATEMENT'; hooksTestStatement: string } 53 | | { type: 'DELETE_CONTEXT' | 'DELETE_HOOK_UPDATES' | 'TOGGLE_TYPEOF' | 'ADD_CALLBACKFUNC'; id: number } 54 | | { 55 | type: 'UPDATE_CONTEXT'; 56 | id: number; 57 | queryVariant: string; 58 | querySelector: string; 59 | queryValue: string; 60 | values: string; 61 | textNodes: string; 62 | providerComponent: string; 63 | consumerComponent: string; 64 | context: string; 65 | } 66 | | { 67 | type: 'UPDATE_HOOK_UPDATES'; 68 | id: number; 69 | hook: string; 70 | hookFileName: string; 71 | hookFilePath: string; 72 | callbackFunc: string; 73 | managedState: string; 74 | updatedState: string; 75 | } 76 | | { type: 'UPDATE_HOOKS_FILEPATH'; hookFileName: string; hookFilePath: string } 77 | | { type: 'UPDATE_CONTEXT_FILEPATH'; contextFileName: string; contextFilePath: string } 78 | | { type: 'UPDATE_STATEMENTS_ORDER'; draggableStatements: Array } 79 | | { type: 'ADD_ASSERTION'; index: number } 80 | | { 81 | type: 'UPDATE_ASSERTION'; 82 | index: number; 83 | id: number; 84 | assertion: Assertion 85 | } 86 | | { type: 'DELETE_ASSERTION'; index: number; id: number } 87 | | { type: 'UPDATE_CALLBACKFUNC'; index: number; id: number; callbackFunc: Callback } 88 | | { type: 'DELETE_CALLBACKFUNC'; index: number; id: number; }; 89 | 90 | export interface HooksTestMenuProps { 91 | dispatchToHooksTestCase: (action: object) => void; 92 | } 93 | 94 | export interface HooksTestModalProps { 95 | isHooksModalOpen: boolean; 96 | closeHooksModal: () => void; 97 | } 98 | 99 | export interface HooksTestStatementsProps extends HooksTestMenuProps { 100 | hooksStatements: Array; 101 | } 102 | -------------------------------------------------------------------------------- /src/utils/puppeteerTypes.ts: -------------------------------------------------------------------------------- 1 | export interface PuppeteerTestMenuProps { 2 | dispatchToPuppeteerTestCase: (action: object) => void; 3 | } 4 | 5 | export interface PuppeteerTestModalProps { 6 | isPuppeteerModalOpen: boolean; 7 | closePuppeteerModal: () => void; 8 | } 9 | 10 | export interface PuppeteerTestStatementsProps extends PuppeteerTestMenuProps { 11 | puppeteerStatements: Array; 12 | } 13 | 14 | export interface PuppeteerTestCaseState { 15 | puppeteerStatements: Array; 16 | statementId: number; 17 | } 18 | 19 | export interface PuppeteerStatements { 20 | id: number; 21 | type: string; 22 | describe: string; 23 | url: string; 24 | browserOptions: Array; 25 | hasBrowserOption: boolean; 26 | browserOptionId: number; 27 | [key: string]: any; 28 | } 29 | 30 | export interface BrowserOptions { 31 | id: number; 32 | optionKey: string; 33 | optionValue: string; 34 | [key: string]: any; 35 | } 36 | 37 | export type PuppeteerAction = 38 | | { 39 | type: 40 | | 'TOGGLE_PUPPETEER' 41 | | 'CREATE_NEW_PUPPETEER_TEST' 42 | | 'ADD_PUPPETEER_PAINT_TIMING' 43 | | 'OPEN_INFO_MODAL' 44 | | 'CLOSE_INFO_MODAL' 45 | | 'REPLACE_TEST'; testState: any 46 | } 47 | | { type: 'DELETE_PUPPETEER_TEST' | 'ADD_BROWSER_OPTIONS'; id: number } 48 | | { type: 'DELETE_BROWSER_OPTION'; id: number; optionId: number } 49 | | { type: 'UPDATE_PAINT_TIMING'; id: number; field: string; value: string } 50 | | { type: 'UPDATE_BROWSER_OPTION'; id: number; field: string; value: string; optionId: number } 51 | | { type: 'UPDATE_STATEMENTS_ORDER'; draggableStatements: Array } 52 | -------------------------------------------------------------------------------- /src/utils/secTypes.ts: -------------------------------------------------------------------------------- 1 | export interface SecTestCaseState { 2 | modalOpen: boolean; 3 | } 4 | 5 | export interface Action { 6 | type: string; 7 | } -------------------------------------------------------------------------------- /src/utils/terminalTypes.ts: -------------------------------------------------------------------------------- 1 | export interface TerminalType { 2 | fontSize: number; 3 | rows: number; 4 | fontFamily?: string; 5 | theme?: { 6 | background?: string; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "allowSyntheticDefaultImports": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "strict": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "moduleResolution": "node", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "noEmit": true, 14 | "jsx": "react" 15 | }, 16 | "include": ["src", "declaration.d.ts"] 17 | } -------------------------------------------------------------------------------- /webpack.config.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import webpack from "webpack"; 3 | 4 | const config: webpack.Configuration = { 5 | mode: 'development', 6 | entry: "./src/index.js", 7 | devtool: 'inline-source-map', 8 | target: 'electron-renderer', 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.(ts|js)x?$/, 13 | exclude: /node_modules/, 14 | use: { 15 | loader: "babel-loader", 16 | options: { 17 | presets: [ 18 | "@babel/preset-env", 19 | "@babel/preset-react", 20 | "@babel/preset-typescript", 21 | ], 22 | }, 23 | }, 24 | }, 25 | { 26 | test: [/\.s[ac]ss$/i, /\.css$/i], 27 | use: [ 28 | // Creates `style` nodes from JS strings 29 | 'style-loader', 30 | // Translates CSS into CommonJS 31 | 'css-loader', 32 | // Compiles Sass to CSS 33 | 'sass-loader', 34 | ], 35 | }, 36 | { 37 | test: [/\.png/, /\.svg/], 38 | type: 'asset/resource' 39 | } 40 | ], 41 | }, 42 | resolve: { 43 | extensions: [".tsx", ".jsx", ".ts", ".js"], 44 | }, 45 | output: { 46 | path: path.resolve(__dirname, "build"), 47 | filename: "bundle.js", 48 | }, 49 | devServer: { 50 | contentBase: path.join(__dirname, "build"), 51 | compress: true, 52 | port: 4000, 53 | }, 54 | }; 55 | 56 | export default config; --------------------------------------------------------------------------------