diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..97e17131 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,15 @@ +{ + "extends": ["airbnb-typescript"], + "parserOptions": { + "project": "./tsconfig.json" + }, + "rules": { + "arrow-body-style": "off", + "no-plusplus": "off", + "no-param-reassign": "off" + }, + "env": { + "jest": true, + "browser": true + } +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 3a03d76c..43c0622e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ node_js: cache: directories: - node_modules -deplloy: +script: + - npm test +deploy: skip_cleanup: true - on: master + on: master \ No newline at end of file diff --git a/README.md b/README.md index acf6d330..f0a38775 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![](https://lh5.googleusercontent.com/5Gr2dZXHJdmIiASsPw9put-6mR20e4g1gOk-af4krREaJ7NqkZnqXLD5QgiotfNHYhGRh387HSqdhjRwxdwOvQzg9ChhfIrZz0FdxVu6gktBtG-sy1MX6Xq36Gmrzu_6G_K7LDQZ) -Spearmint helps developers easily create functional React/Redux/Endpoint tests without writing any code. It dynamically converts user inputs into executable Jest test code by using DOM query selectors provided by @testing-library. +Spearmint helps developers easily create functional React/Redux/Endpoint/Paint Timing tests without writing any code. It dynamically converts user inputs into executable Jest test code by using DOM query selectors provided by @testing-library. ## How to use @@ -22,6 +22,10 @@ To run Endpoint tests generated by spearmint, install the following in your dev npm i -D jest supertest +To run Puppeteer tests generated by spearmint, install the following in your dev dependencies. + + npm i -D jest puppeteer + ## How it works 1. On the initial screen, enter the URL of your project and load your application to start creating tests. @@ -30,23 +34,27 @@ To run Endpoint tests generated by spearmint, install the following in your dev 2. Utilize our auto-complete, drop-down options, and tooltips features to easily create arrangement, action, and assertion test statements for React; reducer, action creator, asynchronous action creator, and middleware test statements for Redux; and hooks, context, and endpoint test statements. -![](https://lh5.googleusercontent.com/5VYUlGG5VDdZxdZEh5aokuilhKRp8B5QyVmxvtW_abLYCAzYN-s-el1oV5WMtGuTzbEO2I6l8Ys_yK2gC0fCi8ISHwjh4LlgezsrPWd7mDEtLbPqBYf1J4pgkGmfIV4yq4I_dpQg) +![](/public/newReact.png?raw=true) 3. Refer to the browser view of your app that is displayed on the right to quickly identify values for your selectors and use the file directory to open up a code editor view to easily refer to your codebase for props information. 4. Spearmint will then convert user input to dynamically generate a test file that will be saved inside a **tests** folder, which you can use to run ‘npm test’ on. -![](https://lh4.googleusercontent.com/zE-ty31I22R7P9-ubFIb4ko6MOBb7r1-56cHX65h9AcF9IsE22RhPKMEdhyR0MJ3PbqNovj1uwxF2T5_klwZ2sWniXfCiXfaEysjQgH5NRskaDFNd-TOGce0oTMn2jPaPEGFHlEq) +![](/public/testfile.png?raw=true) ## Team > Alex [@apark0720](https://github.com/apark0720)  ·  +> Charlie [@charlie-maloney](https://github.com/charlie-maloney)  ·  > Chloe [@HeyItsChloe](https://github.com/HeyItsChloe)  ·  > Cornelius [@corneeltron](https://github.com/corneeltron)  ·  -> Dave [@davefranz](https://github.com/davefranz)  ·  -> Johnny [@johnny-lim](https://github.com/johnny-lim)
+> Dave [@davefranz](https://github.com/davefranz)
+> Johnny [@johnny-lim](https://github.com/johnny-lim)  ·  > Julie [@julicious100](https://github.com/julicious100)  ·  > Karen [@karenpinilla](https://github.com/karenpinilla)  ·  > Linda [@lcwish](https://github.com/lcwish)  ·  +> Mike [@mbcoker](https://github.com/mbcoker)
> Natlyn [@natlynp](https://github.com/natlynp)  ·  -> Rachel [@rachethecreator](https://github.com/rachethecreator) +> Rachel [@rachethecreator](https://github.com/rachethecreator)  ·  +> Sieun [@sieunjang](https://github.com/sieunjang)  ·  +> Tristen [@twastell](https://github.com/twastell) diff --git a/package.json b/package.json index e1da9c36..ca811c9e 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,16 @@ "homepage": "./", "private": true, "dependencies": { + "@types/jest": "^25.2.3", + "@types/react-beautiful-dnd": "^12.1.2", + "@types/react-dom": "^16.9.8", + "@types/react-modal": "^3.10.5", + "classnames": "^2.2.6", "concurrently": "^4.1.2", "cross-env": "^5.2.1", + "dotenv": "^8.2.0", "electron-is-dev": "^1.1.0", + "fibers": "^5.0.0", "js-beautify": "^1.10.0", "monaco-editor": "^0.17.0", "node-sass": "^4.12.0", @@ -30,23 +37,21 @@ "react-dom": "^16.8.6", "react-modal": "^3.8.1", "react-monaco-editor": "^0.25.1", - "react-scripts": "3.0.1", - "typescript": "^3.5.1", + "react-scripts": "3.4.1", + "sass": "^1.26.5", + "typescript": "^3.9.2", "wait-on": "^3.3.0" }, "scripts": { "react-start": "react-scripts start", - "react-build": "react-scripts build", + "react-build": "NODE_ENV=production react-scripts build", "test": "react-scripts test --env=jsdom", "test:watch": "jest --watch", "react-eject": "react-scripts eject", - "electron-build": "electron-builder -mwl", + "electron-build": "NODE_ENV=production electron-builder -mwl", "release": "npm run react-build && electron-builder --publish=always", - "build": "npm run react-build && npm run electron-build", - "start": "concurrently \"cross-env BROWSER=none npm run react-start\" \"wait-on http://localhost:3000 && electron .\"" - }, - "eslintConfig": { - "extends": "react-app" + "build": "NODE_ENV=production npm run react-build && npm run electron-build", + "start": "NODE_ENV=development concurrently \"cross-env BROWSER=none npm run react-start\" \"wait-on http://localhost:3000 && electron .\"" }, "browserslist": { "production": [ @@ -61,12 +66,22 @@ ] }, "devDependencies": { - "@testing-library/react": "^8.0.1", + "@testing-library/jest-dom": "^5.8.0", + "@testing-library/react": "^8.0.9", "@testing-library/react-hooks": "^3.2.1", + "@types/jest": "^25.2.3", + "@typescript-eslint/eslint-plugin": "^2.33.0", + "@typescript-eslint/parser": "^2.33.0", "electron": "^5.0.3", - "electron-builder": "^20.43.0", + "electron-builder": "^22.6.1", + "electron-devtools-installer": "^3.0.0", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.14.0", + "eslint-config-airbnb-typescript": "^7.2.1", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.20.0", + "eslint-plugin-react-hooks": "^2.5.1", "jest-dom": "^3.5.0", "react-test-renderer": "^16.12.0", "spectron": "^5.0.0", diff --git a/public/electron.js b/public/electron.js index 0d12b6b1..660ff62d 100644 --- a/public/electron.js +++ b/public/electron.js @@ -1,14 +1,22 @@ +require('dotenv').config() const { app, BrowserWindow } = require('electron'); const path = require('path'); const isDev = require('electron-is-dev'); - let mainWindow; -let testView; +if (process.env.NODE_ENV === 'development') { + const { default: installExtension, REACT_DEVELOPER_TOOLS } = require('electron-devtools-installer'); + function addDevTools() { + app.whenReady().then(() => { + installExtension(REACT_DEVELOPER_TOOLS) + .then((name) => console.log(`Added Extension: ${name}`)) + .catch((err) => console.log('An error occurred: ', err)); + }); + }; +} function createWindow() { mainWindow = new BrowserWindow({ - width: 1400, - minWidth: 1400, + width: 1550, height: 750, minHeight: 750, icon: path.join(__dirname, 'public/icon.png'), @@ -17,23 +25,24 @@ function createWindow() { webviewTag: true, }, }); - mainWindow.loadURL( isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}` ); mainWindow.on('closed', () => (mainWindow = null)); } -app.on('ready', createWindow); +if (process.env.NODE_ENV === 'development') { + app.on('ready', addDevTools); +} +app.on('ready', createWindow); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); - app.on('activate', () => { if (mainWindow === null) { createWindow(); } -}); +}); \ No newline at end of file diff --git a/public/index.html b/public/index.html index 48be9f3f..d8464cb2 100644 --- a/public/index.html +++ b/public/index.html @@ -9,6 +9,7 @@ manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> + + describe('Middlware', () => { + describe('Add Middleware', () => { + const action = { + type: 'ADD_MIDDLEWARE', + }; + + it('should add a middleware test case to reduxTestStatements', () => { + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].type).toEqual('middleware'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + + describe('Delete Middleware', () => { + const action = { + type: 'DELETE_MIDDLEWARE', + payload: 1, + }; + + it('should remove middleware test based on id from action payload', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 1, + type: 'middleware', + middlewaresFileName: '', + middlewaresFilePath: '', + queryType: '', + eventValue: null, + queryVariant: '', + querySelector: '', + queryValue: '', + queryFunction: '', + }); + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0]).toBe(undefined); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state) + }); + }); + + describe('Update Middleware', () => { + const action = { + type: 'UPDATE_MIDDLEWARE', + payload: { + id: 3, + queryType: 'queryType', + eventValue: 'eventValue', + queryVariant: 'queryVariant', + querySelector: 'querySelector', + queryValue: 'queryValue', + queryFunction: 'queryFunction', + suggestions: 'suggestions', + }, + }; + + it('updates the values of the middleware test based on action payload id and string values', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 3, + type: 'middleware', + queryType: '', + eventValue: null, + queryVariant: '', + querySelector: '', + queryValue: '', + queryFunction: '', + suggestions: '' + }); + + const {reduxStatements} = subject(state, action); + + expect(reduxStatements[0].id).toEqual(3); + expect(reduxStatements[0].type).toEqual('middleware'); + expect(reduxStatements[0].queryType).toEqual('queryType'); + expect(reduxStatements[0].eventValue).toEqual('eventValue'); + expect(reduxStatements[0].queryVariant).toEqual('queryVariant'); + expect(reduxStatements[0].querySelector).toEqual('querySelector'); + expect(reduxStatements[0].queryFunction).toEqual('queryFunction'); + expect(reduxStatements[0].suggestions).toEqual('suggestions'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + + describe('Update Middleware File Path', () => { + const action = { + type: 'UPDATE_MIDDLEWARES_FILEPATH', + payload: { + middlewaresFileName: 'Hello', +   middlewaresFilePath: 'World', + } + }; + + it("should update the middleware's file path", () => { + state = { + reduxTestStatement: '', + reduxStatements: [ + { + id: 3, + type: 'middleware', + middlewaresFileName: '', + middlewaresFilePath: '', + queryType: '', + eventValue: null, + queryVariant: '', + querySelector: '', + queryValue: '', + queryFunction: '', + } + ], + hasRedux: 1, + }; + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].middlewaresFileName).toEqual('Hello'); + expect(reduxStatements[0].middlewaresFilePath).toEqual('World'); + expect(reduxStatements[0].id).toEqual(3); + }); + }); + }); + + //------- Action Creator Test Statment Tests----------> + describe('Action Creator', () => { + describe('Add Action Creator', () => { + const action = { + type: 'ADD_ACTIONCREATOR', + }; + + it('should add a action creator test case to reduxTestStatements', () => { + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].type).toEqual('action-creator'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + + describe('Delete Action Creator', () => { + const action = { + type: 'DELETE_ACTIONCREATOR', + payload: 1, + }; + + it('should remove action creator test based on id from action payload', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 1, + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + type: 'action-creator', + actionCreatorFunc: '', + actionType: '', + payloadKey: null, + payloadType: null, + }); + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0]).toBe(undefined); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state) + }); + }); + + describe('Update Action Creator', () => { + const action = { + type: 'UPDATE_ACTIONCREATOR', + payload: { + id: 3, + actionsFile: 'actionsFile', + filePath: 'filePath', + typesFileName: 'typesFilename', + typesFilePath: 'typesFilePath', + actionCreatorFunc: 'actionCreatorFunc', + payloadKey: 'payloadKey', + payloadType: 'payloadType', + actionType: 'actionType', + }, + }; + + it('updates the values of the action creator test based on action payload id and string values', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 3, + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + type: 'action-creator', + actionCreatorFunc: '', + actionType: '', + payloadKey: null, + payloadType: null, + }); + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].id).toEqual(3); + expect(reduxStatements[0].type).toEqual('action-creator'); + expect(reduxStatements[0].actionsFile).toEqual('actionsFile'); + expect(reduxStatements[0].filePath).toEqual('filePath'); + expect(reduxStatements[0].typesFileName).toEqual('typesFilename'); + expect(reduxStatements[0].typesFilePath).toEqual('typesFilePath'); + expect(reduxStatements[0].actionCreatorFunc).toEqual('actionCreatorFunc'); + expect(reduxStatements[0].payloadKey).toEqual('payloadKey'); + expect(reduxStatements[0].payloadType).toEqual('payloadType'); + expect(reduxStatements[0].actionType).toEqual('actionType'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state) + }); + }); + + describe('Update Actions File Path', () => { + const action = { + type: 'UPDATE_ACTIONS_FILEPATH', + payload: { + actionsFileName: 'Hello', +   filePath: 'World', + id: 3, + } + }; + + it("should update the action's file path", () => { + state = { + reduxTestStatement: '', + reduxStatements: [ + { + id: 3, + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + type: 'action-creator', + actionCreatorFunc: '', + actionType: '', + payloadKey: null, + payloadType: null, + } + ], + hasRedux: 1, + }; + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].actionsFileName).toEqual('Hello'); + expect(reduxStatements[0].filePath).toEqual('World'); + expect(reduxStatements[0].id).toEqual(3); + }); + }); + }); + + //------- Reducer Test Statment Tests----------> + describe('Reducer', () => { + describe('Add Redcuer', () => { + const action = { + type: 'ADD_REDUCER', + }; + + it('should add a reducer test case to reduxTestStatements', () => { + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].type).toEqual('reducer'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + + describe('Delete Reducer', () => { + const action = { + type: 'DELETE_REDUCER', + payload: 1, + }; + + it('should remove reducer test based on id from action payload', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 1, + type: 'reducer', + typesFileName: '', + typesFilePath: '', + reducersFileName: '', + reducersFilePath: '', + reducerAction: '', + initialState: '', + reducerName: '', + expectedState: '', + }); + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0]).toBe(undefined); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + + describe('Update Reducer', () => { + const action = { + type: 'UPDATE_REDUCER', + payload: { + id: 3, + reducersFileName: 'reducersFileName', + reducersFilePath:'reducersFilePath', + typesFilePath: 'typesFilePath', + typesFileName: 'typesFileName', + reducerAction: 'reducerAction', + initialState: 'initalState', + reducerName: 'reducerName', + expectedState: 'expectedState', + }, + }; + + it('updates the values of the reducer test based on action payload id and string values', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 3, + type: 'reducer', + typesFileName: '', + typesFilePath: '', + reducersFileName: '', + reducersFilePath: '', + reducerAction: '', + initialState: '', + reducerName: '', + expectedState: '', + }); + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].id).toEqual(3); + expect(reduxStatements[0].type).toEqual('reducer'); + expect(reduxStatements[0].reducersFileName).toEqual('reducersFileName'); + expect(reduxStatements[0].reducersFilePath).toEqual('reducersFilePath'); + expect(reduxStatements[0].typesFilePath).toEqual('typesFilePath'); + expect(reduxStatements[0].typesFileName).toEqual('typesFileName'); + expect(reduxStatements[0].reducerAction).toEqual('reducerAction'); + expect(reduxStatements[0].initialState).toEqual('initalState'); + expect(reduxStatements[0].reducerName).toEqual('reducerName'); + expect(reduxStatements[0].expectedState).toEqual('expectedState'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state) + }); + }); + + describe('Update Reducers File Path', () => { + const action = { + type: 'UPDATE_REDUCERS_FILEPATH', + payload: { + reducersFileName: 'Hello', +   reducersFilePath: 'World', + } + }; + + it("should update the reducer's file path", () => { + state = { + reduxTestStatement: '', + reduxStatements: [ + { + id: 3, + type: 'reducer', + typesFileName: '', + typesFilePath: '', + reducersFileName: '', + reducersFilePath: '', + reducerAction: '', + initialState: '', + reducerName: '', + expectedState: '', + } + ], + hasRedux: 1, + }; + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].reducersFileName).toEqual('Hello'); + expect(reduxStatements[0].reducersFilePath).toEqual('World'); + }); + }); + }); + + //-------Async Test Statment Tests----------> + describe('Async', () => { + describe('Add Async', () => { + const action = { + type: 'ADD_ASYNC', + }; + + it('should add an async test case to reduxTestStatements', () => { + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].type).toEqual('async'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + + describe('Delete Async', () => { + const action = { + type: 'DELETE_ASYNC', + payload: 1, + }; + + it('should remove async test based on id from action payload', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 1, + type: 'async', + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + asyncFunction: '', + method: '', + route: '', + requestBody: '', + store: '', + matcher: '', + expectedResponse: '', + }); + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0]).toBe(undefined); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + + describe('Update Async', () => { + const action = { + type: 'UPDATE_ASYNC', + payload: { + id: 3, + actionsFile: 'actionsFile', + typesFileName: 'typesFileName', + typesFilePath: 'typesFilePath', + asyncFunction: 'asyncFunction', + method: 'method', + route: 'route', + requestBody: 'requestBody', + store: 'store', + matcher: 'matcher', + expectedResponse: 'expectedResponse', + }, + }; + + it('updates the values of the async/thunk test based on action payload id and string values', () => { + state = { + reduxTestStatement: '', + reduxStatements: [], + hasRedux: 1, + }; + + state.reduxStatements.push({ + id: 3, + type: 'async', + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + asyncFunction: '', + method: '', + route: '', + requestBody: '', + store: '', + matcher: '', + expectedResponse: '', + }); + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].id).toEqual(3); + expect(reduxStatements[0].type).toEqual('async'); + expect(reduxStatements[0].typesFileName).toEqual('typesFileName'); + expect(reduxStatements[0].typesFilePath).toEqual('typesFilePath'); + expect(reduxStatements[0].asyncFunction).toEqual('asyncFunction'); + expect(reduxStatements[0].method).toEqual('method'); + expect(reduxStatements[0].route).toEqual('route'); + expect(reduxStatements[0].requestBody).toEqual('requestBody'); + expect(reduxStatements[0].store).toEqual('store'); + expect(reduxStatements[0].matcher).toEqual('matcher'); + expect(reduxStatements[0].expectedResponse).toEqual('expectedResponse'); + }); + + it('should return copy of state object', () => { + expect(subject(state, action)).not.toBe(state); + }); + }); + }); + +//-----------Update Statments Order ------------> + describe('Update Statments Order', () => { + const action = { + type: 'UPDATE_STATEMENTS_ORDER', + payload: [ + { + id: 1, + type: 'reducer', + typesFileName: '', + typesFilePath: '', + reducersFileName: '', + reducersFilePath: '', + reducerAction: '', + initialState: '', + reducerName: '', + expectedState: '', + }, + { + id: 3, + type: 'async', + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + asyncFunction: '', + method: '', + route: '', + requestBody: '', + store: '', + matcher: '', + expectedResponse: '', + }, + ] + }; + + it('should return the reorderd redux test statments', () => { + state = { + reduxTestStatement: '', + reduxStatements: [ + { + id: 3, + type: 'async', + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + asyncFunction: '', + method: '', + route: '', + requestBody: '', + store: '', + matcher: '', + expectedResponse: '', + }, + { + id: 1, + type: 'reducer', + typesFileName: '', + typesFilePath: '', + reducersFileName: '', + reducersFilePath: '', + reducerAction: '', + initialState: '', + reducerName: '', + expectedState: '', + } + ], + hasRedux: 1, + }; + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].id).toEqual(1); + expect(reduxStatements[1].id).toEqual(3); + }); + }); +//----------- Update Types FilePath -------> + describe('Update Types File Path', () => { + const action = { + type: 'UPDATE_TYPES_FILEPATH', + payload: { + typesFileName: 'Hello', +   typesFilePath: 'World', + id: 3, + } + }; + + it("should update the types's file path", () => { + state = { + reduxTestStatement: '', + reduxStatements: [ + { + id: 3, + actionsFileName: '', + filePath: '', + typesFileName: '', + typesFilePath: '', + type: 'action-creator', + actionCreatorFunc: '', + actionType: '', + payloadKey: null, + payloadType: null, + } + ], + hasRedux: 1, + }; + + const { reduxStatements } = subject(state, action); + + expect(reduxStatements[0].typesFileName).toEqual('Hello'); + expect(reduxStatements[0].typesFilePath).toEqual('World'); + expect(reduxStatements[0].id).toEqual(3); + }); + }); +}); diff --git a/src/__tests__/spec.test.js b/src/__tests__/spec.test.js index 361c9b41..17e918eb 100644 --- a/src/__tests__/spec.test.js +++ b/src/__tests__/spec.test.js @@ -7,7 +7,7 @@ describe('Application launch', function() { beforeEach(() => { this.app = new Application({ path: electronPath, - args: [path.join(__dirname, '../../electron/main.js')], + args: [path.join(__dirname, '../../public/electron.js')], }); return this.app.start(); }); diff --git a/src/assets/icons/add-black-18dp.svg b/src/assets/icons/add-black-18dp.svg new file mode 100644 index 00000000..ca2fbd67 --- /dev/null +++ b/src/assets/icons/add-black-18dp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/Action/Action.jsx b/src/components/Action/Action.jsx new file mode 100644 index 00000000..1d0e9bda --- /dev/null +++ b/src/components/Action/Action.jsx @@ -0,0 +1,141 @@ +import React, { useContext } from 'react'; +import styles from '../Action/Action.module.scss'; +import { deleteAction, updateAction } from '../../context/actions/reactTestCaseActions'; +import AutoComplete from '../AutoComplete/AutoComplete'; +import AutoCompleteMockData from '../AutoComplete/AutoCompleteMockData'; +import ToolTip from '../ToolTip/ToolTip'; +import { MockDataContext } from '../../context/reducers/mockDataReducer'; +import { ReactTestCaseContext } from '../../context/reducers/reactTestCaseReducer'; +const questionIcon = require('../../assets/images/help-circle.png'); +const closeIcon = require('../../assets/images/close.png'); + +// Action box in middle panel (testCase.jsx) +const Action = ({ statement, statementId, describeId, itId }) => { + const [{ mockData }] = useContext(MockDataContext); + const [{}, dispatchToReactTestCase] = useContext(ReactTestCaseContext); + + const handleChangeActionFields = (e, field) => { + let updatedAction = { ...statement }; + updatedAction[field] = e.target.value; + dispatchToReactTestCase(updateAction(updatedAction)); + }; + + const handleClickDeleteAction = (e) => { + dispatchToReactTestCase(deleteAction(statement.id)); + }; + //conditional rendering for events with values + const needsEventValue = (eventType) => { + const eventsWithValues = [ + 'keyDown', + 'keyPress', + 'keyUp', + 'change', + 'input', + 'invalid', + 'submit', + ]; + return eventsWithValues.includes(eventType); + }; + + return ( +
+ close +
+

Action

+
+
+
+ + + +
+
+ {needsEventValue(statement.eventType) && mockData.length > 0 ? ( +
+ + +
+ ) : needsEventValue(statement.eventType) ? ( + + + handleChangeActionFields(e, 'eventValue')} + /> + + ) : null} +
+
+
+
+ +
+ + + help + + + + + + + + help + + + + +
+
+
+ + + handleChangeActionFields(e, 'queryValue')} + /> +
+
+
+ ); +}; + +export default Action; diff --git a/src/containers/LeftPanel/Action/Action.module.scss b/src/components/Action/Action.module.scss similarity index 83% rename from src/containers/LeftPanel/Action/Action.module.scss rename to src/components/Action/Action.module.scss index 5c993727..0a9fbc89 100644 --- a/src/containers/LeftPanel/Action/Action.module.scss +++ b/src/components/Action/Action.module.scss @@ -1,6 +1,6 @@ -@import '../../../assets/stylesheets/fonts.scss'; -@import '../../../assets/stylesheets/colors.scss'; -@import '../LeftPanel.module.scss'; +@import '../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/fonts.scss'; +@import '../../pages/LeftPanel/LeftPanel.module.scss'; #action { @include box-styling; @@ -56,11 +56,17 @@ } } +.eventValueMock { + input { + margin-top: 6px; + } +} + .eventValue { - // width: 50%; input { - width: 90%; + width: 185px; margin-top: 6px; + display: block; } } @@ -91,7 +97,7 @@ #query { input { - width: 148%; + width: 100%; } } diff --git a/src/containers/LeftPanel/Action/eventTypesList.js b/src/components/Action/eventTypesList.js similarity index 100% rename from src/containers/LeftPanel/Action/eventTypesList.js rename to src/components/Action/eventTypesList.js diff --git a/src/containers/LeftPanel/ActionCreator/ActionCreator.jsx b/src/components/ActionCreator/ActionCreator.jsx similarity index 73% rename from src/containers/LeftPanel/ActionCreator/ActionCreator.jsx rename to src/components/ActionCreator/ActionCreator.jsx index fd79c67a..4381d418 100644 --- a/src/containers/LeftPanel/ActionCreator/ActionCreator.jsx +++ b/src/components/ActionCreator/ActionCreator.jsx @@ -1,18 +1,19 @@ import React, { useContext } from 'react'; import styles from '../ActionCreator/ActionCreator.module.scss'; -import { GlobalContext } from '../../../context/globalReducer'; +import { GlobalContext } from '../../context/reducers/globalReducer'; import { deleteActionCreator, updateActionCreator, updateActionsFilePath, updateTypesFilePath, -} from '../../../context/reduxTestCaseActions'; +} from '../../context/actions/reduxTestCaseActions'; import { Draggable } from 'react-beautiful-dnd'; -const closeIcon = require('../../../assets/images/close.png'); -const dragIcon = require('../../../assets/images/drag-vertical.png'); +import SearchInput from '../SearchInput/SearchInput'; +const closeIcon = require('../../assets/images/close.png'); +const dragIcon = require('../../assets/images/drag-vertical.png'); const ActionCreator = ({ actionCreator, index, dispatchToReduxTestCase }) => { - const [{ filePathMap }, _] = useContext(GlobalContext); + const [{ filePathMap }] = useContext(GlobalContext); const handleChangeActionCreatorFields = (e, field) => { let updatedActionCreator = { ...actionCreator }; updatedActionCreator[field] = e.target.value; @@ -23,18 +24,6 @@ const ActionCreator = ({ actionCreator, index, dispatchToReduxTestCase }) => { dispatchToReduxTestCase(deleteActionCreator(actionCreator.id)); }; - const handleChangeActionsFileName = e => { - const actionsFileName = e.target.value; - const filePath = filePathMap[actionsFileName] || ''; - dispatchToReduxTestCase(updateActionsFilePath(actionsFileName, filePath)); - }; - - const handleChangeTypesFileName = e => { - const typesFileName = e.target.value; - const filePath = filePathMap[typesFileName] || ''; - dispatchToReduxTestCase(updateTypesFilePath(typesFileName, filePath)); - }; - return ( {provided => ( @@ -50,7 +39,6 @@ const ActionCreator = ({ actionCreator, index, dispatchToReduxTestCase }) => { alt='close' onClick={handleClickDeleteActionCreator} /> -
drag

Action Creator

@@ -59,24 +47,12 @@ const ActionCreator = ({ actionCreator, index, dispatchToReduxTestCase }) => {
- +
- +
diff --git a/src/containers/LeftPanel/ActionCreator/ActionCreator.module.scss b/src/components/ActionCreator/ActionCreator.module.scss similarity index 88% rename from src/containers/LeftPanel/ActionCreator/ActionCreator.module.scss rename to src/components/ActionCreator/ActionCreator.module.scss index a70b18c4..ab5e843f 100644 --- a/src/containers/LeftPanel/ActionCreator/ActionCreator.module.scss +++ b/src/components/ActionCreator/ActionCreator.module.scss @@ -1,6 +1,6 @@ -@import '../../../assets/stylesheets/fonts.scss'; -@import '../../../assets/stylesheets/colors.scss'; -@import '../LeftPanel.module.scss'; +@import '../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/fonts.scss'; +@import '../../pages/LeftPanel/LeftPanel.module.scss'; #actionCreator { @include box-styling; @@ -42,6 +42,7 @@ margin-top: 6px; width: 100%; } + position: relative; } #actionFlexBox { diff --git a/src/containers/LeftPanel/Assertion/LastAssertion.jsx b/src/components/Assertion/Assertion.jsx similarity index 75% rename from src/containers/LeftPanel/Assertion/LastAssertion.jsx rename to src/components/Assertion/Assertion.jsx index f7e2d59e..4fe29653 100644 --- a/src/containers/LeftPanel/Assertion/LastAssertion.jsx +++ b/src/components/Assertion/Assertion.jsx @@ -4,30 +4,33 @@ * - but for only the last assertion card? */ -import React from 'react'; +import React, { useContext } from 'react'; import styles from '../Assertion/Assertion.module.scss'; -import styles2 from '../AutoComplete/AutoCompleteMockData.module.scss'; -import { deleteAssertion, updateAssertion } from '../../../context/testCaseActions'; +import { deleteAssertion, updateAssertion } from '../../context/actions/reactTestCaseActions'; import ToolTip from '../ToolTip/ToolTip'; import ToolTipMatcher from '../ToolTip/ToolTipMatcher'; import AutoComplete from '../AutoComplete/AutoComplete'; import AutoCompleteMockData from '../AutoComplete/AutoCompleteMockData'; +import { ReactTestCaseContext } from '../../context/reducers/reactTestCaseReducer'; -const questionIcon = require('../../../assets/images/help-circle.png'); -const closeIcon = require('../../../assets/images/close.png'); -const dragIcon = require('../../../assets/images/drag-vertical.png'); -const LastAssertion = ({ assertion, dispatchToTestCase, isLast }) => { +const questionIcon = require('../../assets/images/help-circle.png'); +const closeIcon = require('../../assets/images/close.png'); +const dragIcon = require('../../assets/images/drag-vertical.png'); + +const Assertion = ({ statement, describeId, itId, statementId }) => { + const [{}, dispatchToReactTestCase] = useContext(ReactTestCaseContext); + const handleChangeAssertionFields = (e, field) => { - let updatedAssertion = { ...assertion }; + let updatedAssertion = { ...statement }; field === 'isNot' ? (updatedAssertion[field] = !updatedAssertion.isNot) : (updatedAssertion[field] = e.target.value); - dispatchToTestCase(updateAssertion(updatedAssertion)); + dispatchToReactTestCase(updateAssertion(updatedAssertion)); }; const handleClickDelete = e => { - dispatchToTestCase(deleteAssertion(assertion.id)); + dispatchToReactTestCase(deleteAssertion(statementId)); }; const needsMatcherValue = matcherType => { @@ -52,9 +55,8 @@ const LastAssertion = ({ assertion, dispatchToTestCase, isLast }) => { return (
- {!isLast && close} + close
- {!isLast && drag}

Assertion

@@ -65,7 +67,7 @@ const LastAssertion = ({ assertion, dispatchToTestCase, isLast }) => {
handleChangeAssertionFields(e, 'querySelector')} >
@@ -111,13 +113,16 @@ const LastAssertion = ({ assertion, dispatchToTestCase, isLast }) => { Query
+
+
+
@@ -126,42 +131,43 @@ const LastAssertion = ({ assertion, dispatchToTestCase, isLast }) => { Not? handleChangeAssertionFields(e, 'isNot')} />
-
-
-
+
help - + +
- {needsMatcherValue(assertion.matcherType) && ( + {needsMatcherValue(statement.matcherType) && ( +
- handleChangeAssertionFields(e, 'matcherValue')} + placeholder='Value' /> +
)}
-
+
); }; -export default LastAssertion; +export default Assertion; diff --git a/src/containers/LeftPanel/Assertion/Assertion.module.scss b/src/components/Assertion/Assertion.module.scss similarity index 68% rename from src/containers/LeftPanel/Assertion/Assertion.module.scss rename to src/components/Assertion/Assertion.module.scss index 7734b05c..5413b3e4 100644 --- a/src/containers/LeftPanel/Assertion/Assertion.module.scss +++ b/src/components/Assertion/Assertion.module.scss @@ -1,6 +1,6 @@ -@import '../../../assets/stylesheets/fonts.scss'; -@import '../../../assets/stylesheets/colors.scss'; -@import '../LeftPanel.module.scss'; +@import '../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/fonts.scss'; +@import '../../pages/LeftPanel/LeftPanel.module.scss'; #assertion { @include box-styling; @@ -91,16 +91,39 @@ align-items: center; margin-bottom: 8px; } + +#valueFlexBox { + display: flex; + div { + font-size: 12px; + } + justify-content: space-between; + width: 185px; + align-items: center; + margin-bottom: 8px; +} + #matcherFlexBox { display: flex; + div { + font-size: 12px; + } justify-content: space-between; - // width%; + width: 250px; + align-items: flex-end; + margin-bottom: 8px; + padding-top: -2rem; + +} +#autoTool { + display: flex; align-items: center; - margin-right: 182px; + justify-content: space-between; } #matcherLeft { display: flex; align-items: center; + flex-direction: column; } #matcherAuto { margin-right: 15%; @@ -115,6 +138,20 @@ } #matcherVal { - display: inline-block; - padding-left: 2.1rem; + display: flex; + div { + font-size: 12px; + } + margin-left: 78px; + justify-content: space-between; + width: 185px; + align-items: center; + + + input { + width: 185px; + display: block; + margin-top: 6px; + + } } diff --git a/src/containers/LeftPanel/Assertion/matcherTypesList.js b/src/components/Assertion/matcherTypesList.js similarity index 100% rename from src/containers/LeftPanel/Assertion/matcherTypesList.js rename to src/components/Assertion/matcherTypesList.js diff --git a/src/containers/LeftPanel/AutoComplete/AutoComplete.jsx b/src/components/AutoComplete/AutoComplete.jsx similarity index 97% rename from src/containers/LeftPanel/AutoComplete/AutoComplete.jsx rename to src/components/AutoComplete/AutoComplete.jsx index b5c4c280..88ae601d 100644 --- a/src/containers/LeftPanel/AutoComplete/AutoComplete.jsx +++ b/src/components/AutoComplete/AutoComplete.jsx @@ -1,6 +1,6 @@ import React from 'react'; import styles from './AutoComplete.module.scss'; -import { updateAction, updateAssertion } from '../../../context/testCaseActions'; +import { updateAction, updateAssertion } from '../../context/actions/reactTestCaseActions'; import { eventTypesList } from '../Action/eventTypesList'; import { matcherTypesList } from '../Assertion/matcherTypesList'; import AutoSuggest from 'react-autosuggest'; diff --git a/src/containers/LeftPanel/AutoComplete/AutoComplete.module.scss b/src/components/AutoComplete/AutoComplete.module.scss similarity index 84% rename from src/containers/LeftPanel/AutoComplete/AutoComplete.module.scss rename to src/components/AutoComplete/AutoComplete.module.scss index e3761e06..9f8e8aa6 100644 --- a/src/containers/LeftPanel/AutoComplete/AutoComplete.module.scss +++ b/src/components/AutoComplete/AutoComplete.module.scss @@ -1,5 +1,5 @@ -@import '../../../assets/stylesheets/fonts.scss'; -@import '../../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/fonts.scss'; .container { position: relative; diff --git a/src/containers/LeftPanel/AutoComplete/AutoCompleteMockData.jsx b/src/components/AutoComplete/AutoCompleteMockData.jsx similarity index 80% rename from src/containers/LeftPanel/AutoComplete/AutoCompleteMockData.jsx rename to src/components/AutoComplete/AutoCompleteMockData.jsx index dcfec2ec..a365d5a3 100644 --- a/src/containers/LeftPanel/AutoComplete/AutoCompleteMockData.jsx +++ b/src/components/AutoComplete/AutoCompleteMockData.jsx @@ -1,8 +1,8 @@ import React, { useContext, useState } from 'react'; import styles from '../AutoComplete/AutoCompleteMockData.module.scss'; import AutoSuggest from 'react-autosuggest'; -import { updateAction, updateAssertion, updateRenderProp } from '../../../context/testCaseActions'; -import { MockDataContext } from '../../../context/mockDataReducer'; +import { updateAction, updateAssertion, updateProp } from '../../context/actions/reactTestCaseActions'; +import { MockDataContext } from '../../context/reducers/mockDataReducer'; const AutoCompleteMockData = ({ statement, @@ -16,7 +16,7 @@ const AutoCompleteMockData = ({ let updatedAction = { ...statement }; let updatedAssertion = { ...statement }; - const [{ mockData }, _] = useContext(MockDataContext); + const [{ mockData }] = useContext(MockDataContext); const [mockDataValue, setMockDataValue] = useState(''); const [mockDataSuggestions, setMockDataSuggestions] = useState([]); const mockOptionsList = []; @@ -30,16 +30,17 @@ const AutoCompleteMockData = ({ updatedAssertion.queryValue = newValue; dispatchToTestCase(updateAssertion(updatedAssertion)); } else if (propType === 'prop') { - dispatchToTestCase(updateRenderProp(renderId, propId, propKey, newValue)); + dispatchToTestCase(updateProp(renderId, propId, propKey, newValue)); } }; mockData.forEach(mockDatum => { + let name = mockDatum.name.charAt(0).toUpperCase() + mockDatum.name.slice(1) mockDatum.fieldKeys.forEach(key => { - mockOptionsList.push({ value: `mock${mockDatum.name}.${key.fieldKey}` }); + mockOptionsList.push({ value: `mock${name}.${key.fieldKey}` }); }); - mockOptionsList.push({ value: `[mock${mockDatum.name}]` }); - mockOptionsList.push({ value: `{mock${mockDatum.name}}` }); + mockOptionsList.push({ value: `[mock${name}]` }); + mockOptionsList.push({ value: `{mock${name}}` }); }); const getSuggestions = mockDataValue => { diff --git a/src/containers/LeftPanel/AutoComplete/AutoCompleteMockData.module.scss b/src/components/AutoComplete/AutoCompleteMockData.module.scss similarity index 83% rename from src/containers/LeftPanel/AutoComplete/AutoCompleteMockData.module.scss rename to src/components/AutoComplete/AutoCompleteMockData.module.scss index 6ce0cf1a..e61a2398 100644 --- a/src/containers/LeftPanel/AutoComplete/AutoCompleteMockData.module.scss +++ b/src/components/AutoComplete/AutoCompleteMockData.module.scss @@ -1,5 +1,5 @@ -@import '../../../assets/stylesheets/fonts.scss'; -@import '../../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/fonts.scss'; .container { position: relative; @@ -7,12 +7,13 @@ .input { // width: 185px; - width: 130%; + width: 185px; padding: '10px 20px'; font-family: $oxygen; font-weight: 300; font-size: 12; letter-spacing: 0.5px; + background-color: red($color: #ed0909); border: '1px solid #aaa'; } @@ -33,7 +34,7 @@ display: block; position: absolute; top: 26px; - width: 100%; + width: 185px; border: 1px solid $light-gray; background-color: #fff; font-family: $oxygen; diff --git a/src/containers/RightPanel/BrowserView/BrowserView.jsx b/src/components/BrowserView/BrowserView.jsx similarity index 66% rename from src/containers/RightPanel/BrowserView/BrowserView.jsx rename to src/components/BrowserView/BrowserView.jsx index df148590..787f7933 100644 --- a/src/containers/RightPanel/BrowserView/BrowserView.jsx +++ b/src/components/BrowserView/BrowserView.jsx @@ -1,9 +1,9 @@ import React, { useContext } from 'react'; import styles from './BrowserView.module.scss'; -import { GlobalContext } from '../../../context/globalReducer'; +import { GlobalContext } from '../../context/reducers/globalReducer'; const BrowserView = () => { - const [{ url }, _] = useContext(GlobalContext); + const [{ url }] = useContext(GlobalContext); return ( <> diff --git a/src/containers/RightPanel/BrowserView/BrowserView.module.scss b/src/components/BrowserView/BrowserView.module.scss similarity index 84% rename from src/containers/RightPanel/BrowserView/BrowserView.module.scss rename to src/components/BrowserView/BrowserView.module.scss index b733c102..d18af211 100644 --- a/src/containers/RightPanel/BrowserView/BrowserView.module.scss +++ b/src/components/BrowserView/BrowserView.module.scss @@ -1,5 +1,5 @@ -@import '../../../assets/stylesheets/fonts.scss'; -@import '../../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/fonts.scss'; #browserView { height: 100vh; diff --git a/src/components/Context/Context.jsx b/src/components/Context/Context.jsx new file mode 100644 index 00000000..fce3a498 --- /dev/null +++ b/src/components/Context/Context.jsx @@ -0,0 +1,157 @@ +import React, { useContext } from 'react'; +import styles from '../Context/Context.module.scss'; +import { GlobalContext } from '../../context/reducers/globalReducer'; +import { + deleteContexts, + updateContexts, + updateContextFilePath, +} from '../../context/actions/hooksTestCaseActions'; +import { Draggable } from 'react-beautiful-dnd'; +import SearchInput from '../SearchInput/SearchInput'; +const closeIcon = require('../../assets/images/close.png'); +const dragIcon = require('../../assets/images/drag-vertical.png'); + +const Context = ({ context, index, dispatchToHooksTestCase }) => { + const [{ filePathMap }] = useContext(GlobalContext); + + const handleChangeContextFields = (e, field) => { + let updatedContext = { ...context }; + updatedContext[field] = e.target.value; + dispatchToHooksTestCase(updateContexts(updatedContext)); + }; + + const handleClickDeleteContext = () => { + dispatchToHooksTestCase(deleteContexts(context.id)); + }; + + return ( + + {provided => ( +
+ close + +
+ drag +

Context

+
+ +
+
+
+ + +
+ +
+ {/* drop downs */} +
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+ {/* input boxes */} +
+ + handleChangeContextFields(e, 'consumerComponent')} + /> +
+ +
+ + handleChangeContextFields(e, 'providerComponent')} + /> +
+
+ +
+
+ + handleChangeContextFields(e, 'context')} + /> +
+ +
+ + handleChangeContextFields(e, 'values')} + /> +
+
+
+
+
+ )} +
+ ); +}; + +export default Context; diff --git a/src/containers/LeftPanel/Context/Context.module.scss b/src/components/Context/Context.module.scss similarity index 90% rename from src/containers/LeftPanel/Context/Context.module.scss rename to src/components/Context/Context.module.scss index 611c18a8..f59134a6 100644 --- a/src/containers/LeftPanel/Context/Context.module.scss +++ b/src/components/Context/Context.module.scss @@ -1,6 +1,7 @@ -@import '../../../assets/stylesheets/fonts.scss'; -@import '../../../assets/stylesheets/colors.scss'; -@import '../LeftPanel.module.scss'; +@import '../../assets/stylesheets/colors.scss'; +@import '../../assets/stylesheets/fonts.scss'; +@import '../../pages/LeftPanel/LeftPanel.module.scss'; + #context { @@ -87,6 +88,7 @@ display: flex; align-items: center; width: 111%; + margin-top: 1rem; } #query { @@ -110,13 +112,11 @@ #contextBox { width: 50%; margin-right: 7%; - // margin-bottom: 5px; input { margin-top: 1px; width: 100%; - margin-bottom: 7% - } + position: relative; } #contextDrop { diff --git a/src/components/CustomInput/CustomInput.jsx b/src/components/CustomInput/CustomInput.jsx new file mode 100644 index 00000000..2ce5cfa8 --- /dev/null +++ b/src/components/CustomInput/CustomInput.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import styles from './CustomInput.module.scss'; +import cn from 'classnames'; + +const CustomInput = ({ id, label, placeholder, handleChange, value, bold }) => { + + return ( +
+ + +
+ ); +}; + +export default CustomInput; diff --git a/src/components/CustomInput/CustomInput.module.scss b/src/components/CustomInput/CustomInput.module.scss new file mode 100644 index 00000000..5eefd771 --- /dev/null +++ b/src/components/CustomInput/CustomInput.module.scss @@ -0,0 +1,34 @@ +@import '../../assets/stylesheets/fonts.scss'; +@import '../../assets/stylesheets/colors.scss'; + +.customInputContainer { + width: 90%; + margin: 1rem; + box-sizing: border-box; + + .customInput { + width: 100%; + padding: 0.1rem; + padding-left: 0.4rem; + font-size: 0.75rem; + font-family: $openSans; + border: none; + border-bottom: 1px solid $mint; + background-color: rgba(0,0,0,0); + + &:focus { + outline: none; + border-bottom: 1.5px solid $mint; + } + + } + + .label { + margin-bottom: 2rem; + } + + .bold { + font-weight: bold; + font-size: 1.1rem; + } +} diff --git a/src/components/DescribeRenderer/DescribeRenderer.jsx b/src/components/DescribeRenderer/DescribeRenderer.jsx new file mode 100644 index 00000000..52bd3c9e --- /dev/null +++ b/src/components/DescribeRenderer/DescribeRenderer.jsx @@ -0,0 +1,109 @@ +import React from 'react'; +import ItRenderer from '../ItRenderer/ItRenderer'; +import styles from './DescribeRenderer.module.scss'; +import { deleteDescribeBlock, addItstatement } from '../../context/actions/reactTestCaseActions'; +import cn from 'classnames'; +import { Draggable } from 'react-beautiful-dnd'; + +const DescribeRenderer = ({ + dispatcher, + describeBlocks, + itStatements, + statements, + draggableStatements, + handleChangeDescribeText, + handleChangeItStatementText, + type, +}) => { + const deleteDescribeBlockHandleClick = (e) => { + e.stopPropagation() + const describeId = e.target.id; + dispatcher(deleteDescribeBlock(describeId)); + }; + + const addItStatementHandleClick = (e) => { + const describeId = e.target.id; + dispatcher(addItstatement(describeId)); + }; + + return draggableStatements.map((id, i) => { + return ( +
+ + + +
+ +
+ +
+
+ ); + }); +}; + +export default DescribeRenderer; + +{/* + {(provided) => ( +
+ + + +
+ +
+ +
+
+ )} +
*/} diff --git a/src/components/DescribeRenderer/DescribeRenderer.module.scss b/src/components/DescribeRenderer/DescribeRenderer.module.scss new file mode 100644 index 00000000..3c268da6 --- /dev/null +++ b/src/components/DescribeRenderer/DescribeRenderer.module.scss @@ -0,0 +1,85 @@ +@import '../../assets/stylesheets/fonts.scss'; +@import '../../assets/stylesheets/colors.scss'; + +#describeBlock { + position: relative; + background-color: white; + border-radius: 3px; + padding: 1rem; + margin-top: 10px; + box-shadow: 1px 1px 5px gray; + display: flex; + flex-direction: column; + z-index: 3; + margin-top: 1rem; + + .describeClose { + position: absolute; + top: 5px; + right: 5px; + font-size: 1.25rem; + z-index: 3; + transition: 250ms; + + &:hover { + color: red; + cursor: pointer; + font-size: 1.50rem; + font-weight: bold; + } + } + + .separator { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 65px; + // background-color: rgba(128, 128, 128, 0.20); + background-color: #02c3c33f; + border-bottom: 2px solid gray; + opacity: 100%; + z-index: 0; + } + + .describeLabel { + font-weight: bold; + font-size: 0.9rem; + z-index: 3; + font-family: $oxygen; + + } + + .describeInput { + border: none; + // border-bottom: 1px solid $mint; + background-color: rgba(0, 0, 0, 0); + margin-top: 0.3rem; + font-size: 0.90rem; + z-index: 3; + + } + + .buttonContainer { + display: flex; + justify-content: center; + align-items: center; + height: 30px; + margin-top: 1rem; + + .addIt { + height: auto; + color: white; + padding: 0.5rem; + border-radius: 5px; + background-color: $mint; + + &:hover { + background-color: white; + color: $mint; + } + } + } + + +} \ No newline at end of file diff --git a/src/containers/RightPanel/EditorView/EditorView.jsx b/src/components/EditorView/EditorView.jsx similarity index 83% rename from src/containers/RightPanel/EditorView/EditorView.jsx rename to src/components/EditorView/EditorView.jsx index e0d00f02..d8791713 100644 --- a/src/containers/RightPanel/EditorView/EditorView.jsx +++ b/src/components/EditorView/EditorView.jsx @@ -1,10 +1,10 @@ import React, { useContext } from 'react'; import MonacoEditor from 'react-monaco-editor'; -import { GlobalContext } from '../../../context/globalReducer'; +import { GlobalContext } from '../../context/reducers/globalReducer'; import { editor } from 'monaco-editor'; const Editor = () => { - const [{ displayedFileCode }, _] = useContext(GlobalContext); + const [{ displayedFileCode }] = useContext(GlobalContext); const options = { selectOnLineNumbers: true, @@ -23,7 +23,7 @@ const Editor = () => { return (
{ - const [{ filePathMap }, _] = useContext(GlobalContext); + const [{ filePathMap }] = useContext(GlobalContext); const handleChangeEndpointFields = (e, field) => { let updatedEndpoint = { ...endpoint }; @@ -23,12 +24,6 @@ const Endpoint = ({ endpoint, index, dispatchToEndpointTestCase }) => { dispatchToEndpointTestCase(deleteEndpoint(endpoint.id)); }; - const handleChangeServerFileName = e => { - const serverFileName = e.target.value; - const filePath = filePathMap[serverFileName] || ''; - dispatchToEndpointTestCase(updateServerFilePath(serverFileName, filePath)); - }; - return ( {provided => ( @@ -49,14 +44,8 @@ const Endpoint = ({ endpoint, index, dispatchToEndpointTestCase }) => {
-
- +
+
@@ -109,8 +98,6 @@ const Endpoint = ({ endpoint, index, dispatchToEndpointTestCase }) => {
- {/* toBe */} -