An easy-to-use platform for EEG experimentation in the classroom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

everything else

+136 -747
+1 -5
.dockerignore
··· 31 31 # OSX 32 32 .DS_Store 33 33 34 - # flow-typed 35 - flow-typed/npm/* 36 - !flow-typed/npm/module_vx.x.x.js 37 - 38 34 # App packaged 39 35 release 40 36 app/main.prod.js ··· 50 46 51 47 .idea 52 48 npm-debug.log.* 53 - .*.dockerfile 49 + .*.dockerfile
+7 -4
.eslintignore
··· 31 31 # OSX 32 32 .DS_Store 33 33 34 - # flow-typed 35 - flow-typed/npm/* 36 - !flow-typed/npm/module_vx.x.x.js 37 - 38 34 # App packaged 39 35 release 40 36 app/main.prod.js ··· 51 47 .idea 52 48 npm-debug.log.* 53 49 __snapshots__ 50 + 51 + # Package.json 52 + package.json 53 + .travis.yml 54 + *.css.d.ts 55 + *.sass.d.ts 56 + *.scss.d.ts
+8 -76
.eslintrc.js
··· 1 1 module.exports = { 2 - parser: 'babel-eslint', 3 - parserOptions: { 4 - sourceType: 'module', 5 - allowImportExportEverywhere: true, 6 - }, 7 - extends: ['airbnb', 'prettier'], 8 - env: { 9 - browser: true, 10 - node: true, 11 - }, 2 + extends: 'erb/typescript', 12 3 rules: { 13 - 'arrow-parens': ['off'], 14 - 'compat/compat': 'error', 15 - 'consistent-return': 'off', 16 - 'comma-dangle': 'off', 17 - 'generator-star-spacing': 'off', 18 - 'flowtype/object-type-delimiter': 'off', 19 - 'flowtype/no-weak-types': 'warn', 20 - 'import/no-unresolved': 'error', 21 - 'import/no-extraneous-dependencies': 'off', 22 - 'jsx-a11y/anchor-is-valid': 'off', 23 - 'no-console': 'off', 24 - 'no-use-before-define': 'off', 25 - 'no-multi-assign': 'off', 26 - 'no-plusplus': 'off', 27 - 'no-param-reassign': 'warn', 28 - 'promise/param-names': 'error', 29 - 'promise/always-return': 'error', 30 - 'promise/catch-or-return': 'error', 31 - 'promise/no-native': 'off', 32 - 'prefer-destructuring': 'off', 33 - 'react/no-will-update-set-state': 'warn', 34 - 'react/no-did-mount-set-state': 'warn', 35 - 'react/no-did-update-set-state': 'warn', 36 - 'react/sort-comp': [ 37 - 'error', 38 - { 39 - order: ['type-annotations', 'static-methods', 'lifecycle', 'everything-else', 'render'], 40 - }, 41 - ], 42 - 'react/jsx-no-bind': 'off', 43 - 'react/jsx-filename-extension': ['error', { extensions: ['.js', '.jsx'] }], 44 - 'react/prefer-stateless-function': 'off', 45 - 'linebreak-style': 'off', 46 - 'jsx-a11y/click-events-have-key-events': 'off', 47 - 'flowtype/boolean-style': ['error', 'boolean'], 48 - 'flowtype/define-flow-type': 'warn', 49 - 'flowtype/delimiter-dangle': 'off', 50 - 'flowtype/generic-spacing': ['error', 'never'], 51 - 'flowtype/no-primitive-constructor-types': 'error', 52 - 'flowtype/no-weak-types': 'warn', 53 - 'flowtype/object-type-delimiter': ['off'], 54 - 'flowtype/require-parameter-type': 'off', 55 - 'flowtype/require-return-type': 'off', 56 - 'flowtype/require-valid-file-annotation': 'off', 57 - 'flowtype/semi': ['error', 'always'], 58 - 'flowtype/space-after-type-colon': ['error', 'always'], 59 - 'flowtype/space-before-generic-bracket': ['error', 'never'], 60 - 'flowtype/space-before-type-colon': ['error', 'never'], 61 - 'flowtype/union-intersection-spacing': ['error', 'always'], 62 - 'flowtype/use-flow-type': 'error', 63 - 'flowtype/valid-syntax': 'error', 64 - 'react/no-will-update-set-state': 'warn', 65 - 'react/destructuring-assignment': 'off', 66 - 'react/jsx-props-no-spreading': 'warn', 67 - 'react/jsx-wrap-multilines': 'off', 68 - 'react/jsx-one-expression-per-line': 'off', 69 - 'import/order': 'off', 70 - 'max-classes-per-file': 'off', 71 - 'dot-notation': 'off', 72 - 'linebreak-style': 0, 73 - 'import/prefer-default-export': 0, 4 + // A temporary hack related to IDE not resolving correct package.json 5 + 'import/no-extraneous-dependencies': 'off' 74 6 }, 75 - plugins: ['flowtype', 'import', 'promise', 'compat', 'react'], 76 7 settings: { 77 8 'import/resolver': { 9 + // See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below 78 10 node: {}, 79 11 webpack: { 80 - config: require.resolve('./webpack.config.eslint.js'), 81 - }, 82 - }, 83 - }, 12 + config: require.resolve('./configs/webpack.config.eslint.js') 13 + } 14 + } 15 + } 84 16 };
+9 -52
.gitignore
··· 1 1 # Logs 2 2 logs 3 3 *.log 4 - npm-debug.log* 5 - yarn-debug.log* 6 - yarn-error.log* 7 - 8 - # Jupyter stuff 9 - .ipynb_checkpoints 10 - __pycache__ 11 - 12 4 13 5 # Runtime data 14 6 pids 15 7 *.pid 16 8 *.seed 17 - *.pid.lock 18 - 19 - # Auto-generated files 20 - #yarn.lock 21 - #package-lock.json 22 - 23 - # flow-typed 24 - flow-typed/npm 25 9 26 10 # Directory for instrumented libs generated by jscoverage/JSCover 27 11 lib-cov ··· 29 13 # Coverage directory used by tools like istanbul 30 14 coverage 31 15 32 - # nyc test coverage 33 - .nyc_output 34 - 35 16 # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 36 17 .grunt 37 18 38 - # Bower dependency directory (https://bower.io/) 39 - bower_components 40 - 41 19 # node-waf configuration 42 20 .lock-wscript 43 21 44 - # Compiled binary addons (https://nodejs.org/api/addons.html) 22 + # Compiled binary addons (http://nodejs.org/api/addons.html) 45 23 build/Release 46 - 47 - # Dependency directories 48 - node_modules/ 49 - jspm_packages/ 50 - app/utils/pyodide/src/ 51 - 52 - # TypeScript v1 declaration files 53 - typings/ 54 - 55 - # Optional npm cache directory 56 - .npm 57 - 58 - # Optional eslint cache 59 24 .eslintcache 60 25 61 - # Optional REPL history 62 - .node_repl_history 63 - 64 - # Output of 'npm pack' 65 - *.tgz 66 - 67 - # Yarn Integrity file 68 - .yarn-integrity 69 - 70 - # dotenv environment variables file 71 - .env 26 + # Dependency directory 27 + # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 28 + node_modules 72 29 73 - # next.js build output 74 - .next 30 + # OSX 31 + .DS_Store 75 32 76 33 # App packaged 77 34 release ··· 82 39 app/style.css 83 40 app/style.css.map 84 41 dist 85 - app/dist 86 42 dll 87 - dll/renderer.dev.dll.js 88 - dll/renderer.json 89 43 main.js 90 44 main.js.map 91 45 92 46 .idea 93 47 npm-debug.log.* 48 + *.css.d.ts 49 + *.sass.d.ts 50 + *.scss.d.ts 94 51 keys.js
-2
.npmrc
··· 1 - registry=http://registry.npmjs.org/ 2 - package-lock=true
-1
.nvmrc
··· 1 - v7
-9
.prettierrc.yaml
··· 1 - tabWidth: 2 2 - useTabs: false 3 - arrowParens: always 4 - bracketSpacing: true 5 - jsxSingleQuote: true 6 - printWidth: 100 7 - semi: true 8 - singleQuote: true 9 - trailingComma: es5
-3
.stylelintrc
··· 1 - { 2 - "extends": "stylelint-config-standard" 3 - }
-42
.travis.yml
··· 1 - sudo: true 2 - 3 - language: node_js 4 - 5 - node_js: 6 - - node 7 - - 9 8 - 9 - cache: 10 - yarn: true 11 - directories: 12 - - node_modules 13 - - app/node_modules 14 - 15 - addons: 16 - apt: 17 - sources: 18 - - ubuntu-toolchain-r-test 19 - packages: 20 - - g++-4.8 21 - - icnsutils 22 - - graphicsmagick 23 - - xz-utils 24 - - xorriso 25 - 26 - install: 27 - - export CXX="g++-4.8" 28 - - yarn 29 - - cd app && yarn && cd .. 30 - - '/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16' 31 - 32 - before_script: 33 - - export DISPLAY=:99.0 34 - - sh -e /etc/init.d/xvfb start & 35 - - sleep 3 36 - 37 - script: 38 - - node --version 39 - - yarn lint 40 - - yarn package 41 - - yarn test 42 - - yarn test-e2e
+62
babel.config.js
··· 1 + /* eslint global-require: off, import/no-extraneous-dependencies: off */ 2 + 3 + const developmentEnvironments = ['development', 'test']; 4 + 5 + const developmentPlugins = [require('react-hot-loader/babel')]; 6 + 7 + const productionPlugins = [ 8 + require('babel-plugin-dev-expression'), 9 + 10 + // babel-preset-react-optimize 11 + require('@babel/plugin-transform-react-constant-elements'), 12 + require('@babel/plugin-transform-react-inline-elements'), 13 + require('babel-plugin-transform-react-remove-prop-types') 14 + ]; 15 + 16 + module.exports = api => { 17 + // See docs about api at https://babeljs.io/docs/en/config-files#apicache 18 + 19 + const development = api.env(developmentEnvironments); 20 + 21 + return { 22 + presets: [ 23 + // @babel/preset-env will automatically target our browserslist targets 24 + require('@babel/preset-env'), 25 + require('@babel/preset-typescript'), 26 + [require('@babel/preset-react'), { development }] 27 + ], 28 + plugins: [ 29 + // Stage 0 30 + require('@babel/plugin-proposal-function-bind'), 31 + 32 + // Stage 1 33 + require('@babel/plugin-proposal-export-default-from'), 34 + require('@babel/plugin-proposal-logical-assignment-operators'), 35 + [require('@babel/plugin-proposal-optional-chaining'), { loose: false }], 36 + [ 37 + require('@babel/plugin-proposal-pipeline-operator'), 38 + { proposal: 'minimal' } 39 + ], 40 + [ 41 + require('@babel/plugin-proposal-nullish-coalescing-operator'), 42 + { loose: false } 43 + ], 44 + require('@babel/plugin-proposal-do-expressions'), 45 + 46 + // Stage 2 47 + [require('@babel/plugin-proposal-decorators'), { legacy: true }], 48 + require('@babel/plugin-proposal-function-sent'), 49 + require('@babel/plugin-proposal-export-namespace-from'), 50 + require('@babel/plugin-proposal-numeric-separator'), 51 + require('@babel/plugin-proposal-throw-expressions'), 52 + 53 + // Stage 3 54 + require('@babel/plugin-syntax-dynamic-import'), 55 + require('@babel/plugin-syntax-import-meta'), 56 + [require('@babel/plugin-proposal-class-properties'), { loose: true }], 57 + require('@babel/plugin-proposal-json-strings'), 58 + 59 + ...(development ? developmentPlugins : productionPlugins) 60 + ] 61 + }; 62 + };
-34
babel.config.json
··· 1 - { 2 - "presets": [ 3 - [ 4 - "@babel/preset-env", 5 - { 6 - "targets": { "node": 8 }, 7 - "useBuiltIns": false 8 - } 9 - ], 10 - "@babel/preset-react", 11 - ["@babel/preset-flow"] 12 - ], 13 - "plugins": [ 14 - "@babel/plugin-proposal-optional-catch-binding", 15 - ["@babel/plugin-proposal-decorators", { "legacy": true }], 16 - ["@babel/plugin-proposal-class-properties", { "loose": true }] 17 - ], 18 - "env": { 19 - "production": { 20 - "plugins": ["babel-plugin-dev-expression"] 21 - }, 22 - "development": { 23 - "plugins": [ 24 - [ 25 - "babel-plugin-flow-runtime", 26 - { 27 - "assert": true, 28 - "annotate": true 29 - } 30 - ] 31 - ] 32 - } 33 - } 34 - }
-3
flow-typed/module_vx.x.x.js
··· 1 - declare module 'module' { 2 - declare module.exports: any; 3 - }
+49 -17
package.json
··· 36 36 "test-watch": "yarn test --watch" 37 37 }, 38 38 "lint-staged": { 39 - "*.{js,jsx,ts,tsx}": ["cross-env NODE_ENV=development eslint --cache"], 39 + "*.{js,jsx,ts,tsx}": [ 40 + "cross-env NODE_ENV=development eslint --cache" 41 + ], 40 42 "{*.json,.{babelrc,eslintrc,prettierrc,stylelintrc}}": [ 41 43 "prettier --ignore-path .eslintignore --parser json --write" 42 44 ], ··· 74 76 ] 75 77 }, 76 78 "win": { 77 - "target": ["nsis", "msi"] 79 + "target": [ 80 + "nsis", 81 + "msi" 82 + ] 78 83 }, 79 84 "linux": { 80 - "target": ["deb", "rpm", "AppImage"], 85 + "target": [ 86 + "deb", 87 + "rpm", 88 + "AppImage" 89 + ], 81 90 "category": "Education" 82 91 }, 83 92 "directories": { ··· 134 143 "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/internals/mocks/fileMock.js", 135 144 "\\.(css|less|sass|scss)$": "identity-obj-proxy" 136 145 }, 137 - "moduleFileExtensions": ["js", "jsx", "ts", "tsx", "json"], 138 - "moduleDirectories": ["node_modules", "app/node_modules"], 139 - "setupFiles": ["./internals/scripts/CheckBuildsExist.js"] 146 + "moduleFileExtensions": [ 147 + "js", 148 + "jsx", 149 + "ts", 150 + "tsx", 151 + "json" 152 + ], 153 + "moduleDirectories": [ 154 + "node_modules", 155 + "app/node_modules" 156 + ], 157 + "setupFiles": [ 158 + "./internals/scripts/CheckBuildsExist.js" 159 + ] 140 160 }, 141 161 "devDependencies": { 142 162 "@babel/core": "^7.10.2", ··· 200 220 "enzyme": "^3.11.0", 201 221 "enzyme-adapter-react-16": "^1.15.2", 202 222 "enzyme-to-json": "^3.4.4", 203 - "eslint": "^7.2.0", 223 + "eslint": "7.2.0", 204 224 "eslint-config-airbnb-typescript": "^6.3.1", 205 225 "eslint-config-erb": "^0.3.0", 206 226 "eslint-config-prettier": "^6.11.0", ··· 251 271 "yarn": "^1.21.1" 252 272 }, 253 273 "dependencies": { 254 - "@babel/runtime-corejs2": "^7.10.2", 255 274 "@babel/runtime": "7.10.2", 275 + "@babel/runtime-corejs2": "^7.10.2", 256 276 "@fortawesome/fontawesome-free": "^5.13.0", 257 277 "@hot-loader/react-dom": "^16.13.0", 258 278 "@nteract/messaging": "^7.0.7", ··· 270 290 "history": "^5.0.0", 271 291 "kernelspecs": "^2.0.0", 272 292 "lab.js": "^20.0.1", 273 - "lodash.clonedeep": "^4.5.0", 274 293 "lodash": "^4.17.15", 294 + "lodash.clonedeep": "^4.5.0", 275 295 "mkdirp": "^1.0.4", 276 296 "moment": "^2.26.0", 277 297 "mousetrap": "^1.6.5", ··· 279 299 "papaparse": "^5.2.0", 280 300 "plotly.js": "^1.54.2", 281 301 "rc-slider": "^9.3.1", 302 + "react": "^16.13.1", 282 303 "react-dom": "^16.13.1", 283 304 "react-hot-loader": "^4.12.19", 284 305 "react-plotly.js": "^2.4.0", 285 306 "react-redux": "^7.2.0", 307 + "react-router": "^5.2.0", 286 308 "react-router-dom": "^5.2.0", 287 309 "react-router-redux": "^5.0.0-alpha.9", 288 - "react-router": "^5.2.0", 289 310 "react-toastify": "^6.0.5", 290 - "react": "^16.13.1", 291 311 "recursive-readdir": "^2.2.2", 292 - "redux-observable": "^1.2.0", 293 312 "redux": "^4.0.5", 294 - "rxjs-compat": "^6.5.5", 313 + "redux-observable": "^1.2.0", 295 314 "rxjs": "^6.5.5", 315 + "rxjs-compat": "^6.5.5", 296 316 "semantic-ui-css": "^2.4.1", 297 317 "semantic-ui-react": "^0.88.2", 298 318 "simple-statistics": "^7.1.0", ··· 306 326 "npm": ">=4.x", 307 327 "yarn": ">=0.21.3" 308 328 }, 309 - "browserslist": ["extends browserslist-config-erb"], 329 + "browserslist": [ 330 + "extends browserslist-config-erb" 331 + ], 310 332 "prettier": { 311 333 "overrides": [ 312 334 { 313 - "files": [".prettierrc", ".babelrc", ".eslintrc", ".stylelintrc"], 335 + "files": [ 336 + ".prettierrc", 337 + ".babelrc", 338 + ".eslintrc", 339 + ".stylelintrc" 340 + ], 314 341 "options": { 315 342 "parser": "json" 316 343 } ··· 319 346 "singleQuote": true 320 347 }, 321 348 "stylelint": { 322 - "extends": ["stylelint-config-standard", "stylelint-config-prettier"] 349 + "extends": [ 350 + "stylelint-config-standard", 351 + "stylelint-config-prettier" 352 + ] 323 353 }, 324 354 "renovate": { 325 - "extends": ["bliss"] 355 + "extends": [ 356 + "bliss" 357 + ] 326 358 }, 327 359 "husky": { 328 360 "hooks": {
-13
test/.eslintrc
··· 1 - { 2 - "env": { 3 - "jest/globals": true 4 - }, 5 - "plugins": [ 6 - "jest" 7 - ], 8 - "rules": { 9 - "jest/no-disabled-tests": "warn", 10 - "jest/no-focused-tests": "error", 11 - "jest/no-identical-title": "error" 12 - } 13 - }
-13
test/actions/__snapshots__/counter.spec.js.snap
··· 1 - // Jest Snapshot v1, https://goo.gl/fbAQLP 2 - 3 - exports[`actions should decrement should create decrement action 1`] = ` 4 - Object { 5 - "type": "DECREMENT_COUNTER", 6 - } 7 - `; 8 - 9 - exports[`actions should increment should create increment action 1`] = ` 10 - Object { 11 - "type": "INCREMENT_COUNTER", 12 - } 13 - `;
-13
test/actions/__snapshots__/counter.spec.ts.snap
··· 1 - // Jest Snapshot v1, https://goo.gl/fbAQLP 2 - 3 - exports[`actions should decrement should create decrement action 1`] = ` 4 - Object { 5 - "type": "DECREMENT_COUNTER", 6 - } 7 - `; 8 - 9 - exports[`actions should increment should create increment action 1`] = ` 10 - Object { 11 - "type": "INCREMENT_COUNTER", 12 - } 13 - `;
-41
test/actions/counter.spec.js
··· 1 - import { spy } from 'sinon'; 2 - import * as actions from '../../app/actions/counter'; 3 - 4 - describe('actions', () => { 5 - it('should increment should create increment action', () => { 6 - expect(actions.increment()).toMatchSnapshot(); 7 - }); 8 - 9 - it('should decrement should create decrement action', () => { 10 - expect(actions.decrement()).toMatchSnapshot(); 11 - }); 12 - 13 - it('should incrementIfOdd should create increment action', () => { 14 - const fn = actions.incrementIfOdd(); 15 - expect(fn).toBeInstanceOf(Function); 16 - const dispatch = spy(); 17 - const getState = () => ({ counter: 1 }); 18 - fn(dispatch, getState); 19 - expect(dispatch.calledWith({ type: actions.INCREMENT_COUNTER })).toBe(true); 20 - }); 21 - 22 - it('should incrementIfOdd shouldnt create increment action if counter is even', () => { 23 - const fn = actions.incrementIfOdd(); 24 - const dispatch = spy(); 25 - const getState = () => ({ counter: 2 }); 26 - fn(dispatch, getState); 27 - expect(dispatch.called).toBe(false); 28 - }); 29 - 30 - // There's no nice way to test this at the moment... 31 - it('should incrementAsync', (done) => { 32 - const fn = actions.incrementAsync(1); 33 - expect(fn).toBeInstanceOf(Function); 34 - const dispatch = spy(); 35 - fn(dispatch); 36 - setTimeout(() => { 37 - expect(dispatch.calledWith({ type: actions.INCREMENT_COUNTER })).toBe(true); 38 - done(); 39 - }, 5); 40 - }); 41 - });
-70
test/components/Counter.spec.js
··· 1 - import { spy } from 'sinon'; 2 - import React from 'react'; 3 - import Enzyme, { shallow } from 'enzyme'; 4 - import Adapter from 'enzyme-adapter-react-16'; 5 - import { BrowserRouter as Router } from 'react-router-dom'; 6 - import renderer from 'react-test-renderer'; 7 - import Counter from '../../app/components/Counter'; 8 - 9 - Enzyme.configure({ adapter: new Adapter() }); 10 - 11 - function setup() { 12 - const actions = { 13 - increment: spy(), 14 - incrementIfOdd: spy(), 15 - incrementAsync: spy(), 16 - decrement: spy(), 17 - }; 18 - const component = shallow(<Counter counter={1} {...actions} />); 19 - return { 20 - component, 21 - actions, 22 - buttons: component.find('button'), 23 - p: component.find('.counter'), 24 - }; 25 - } 26 - 27 - describe('Counter component', () => { 28 - it('should should display count', () => { 29 - const { p } = setup(); 30 - expect(p.text()).toMatch(/^1$/); 31 - }); 32 - 33 - it('should first button should call increment', () => { 34 - const { buttons, actions } = setup(); 35 - buttons.at(0).simulate('click'); 36 - expect(actions.increment.called).toBe(true); 37 - }); 38 - 39 - it('should match exact snapshot', () => { 40 - const { actions } = setup(); 41 - const counter = ( 42 - <div> 43 - <Router> 44 - <Counter counter={1} {...actions} /> 45 - </Router> 46 - </div> 47 - ); 48 - const tree = renderer.create(counter).toJSON(); 49 - 50 - expect(tree).toMatchSnapshot(); 51 - }); 52 - 53 - it('should second button should call decrement', () => { 54 - const { buttons, actions } = setup(); 55 - buttons.at(1).simulate('click'); 56 - expect(actions.decrement.called).toBe(true); 57 - }); 58 - 59 - it('should third button should call incrementIfOdd', () => { 60 - const { buttons, actions } = setup(); 61 - buttons.at(2).simulate('click'); 62 - expect(actions.incrementIfOdd.called).toBe(true); 63 - }); 64 - 65 - it('should fourth button should call incrementAsync', () => { 66 - const { buttons, actions } = setup(); 67 - buttons.at(3).simulate('click'); 68 - expect(actions.incrementAsync.called).toBe(true); 69 - }); 70 - });
-63
test/components/__snapshots__/Counter.spec.js.snap
··· 1 - // Jest Snapshot v1, https://goo.gl/fbAQLP 2 - 3 - exports[`Counter component should match exact snapshot 1`] = ` 4 - <div> 5 - <div> 6 - <div 7 - className="backButton" 8 - data-tid="backButton" 9 - > 10 - <a 11 - href="/" 12 - onClick={[Function]} 13 - > 14 - <i 15 - className="fa fa-arrow-left fa-3x" 16 - /> 17 - </a> 18 - </div> 19 - <div 20 - className="counter counter" 21 - data-tid="counter" 22 - > 23 - 1 24 - </div> 25 - <div 26 - className="btnGroup" 27 - > 28 - <button 29 - className="btn" 30 - data-tclass="btn" 31 - onClick={[Function]} 32 - > 33 - <i 34 - className="fa fa-plus" 35 - /> 36 - </button> 37 - <button 38 - className="btn" 39 - data-tclass="btn" 40 - onClick={[Function]} 41 - > 42 - <i 43 - className="fa fa-minus" 44 - /> 45 - </button> 46 - <button 47 - className="btn" 48 - data-tclass="btn" 49 - onClick={[Function]} 50 - > 51 - odd 52 - </button> 53 - <button 54 - className="btn" 55 - data-tclass="btn" 56 - onClick={[Function]} 57 - > 58 - async 59 - </button> 60 - </div> 61 - </div> 62 - </div> 63 - `;
-67
test/components/__snapshots__/Counter.spec.tsx.snap
··· 1 - // Jest Snapshot v1, https://goo.gl/fbAQLP 2 - 3 - exports[`Counter component should match exact snapshot 1`] = ` 4 - <div> 5 - <div> 6 - <div 7 - className="backButton" 8 - data-tid="backButton" 9 - > 10 - <a 11 - href="/" 12 - onClick={[Function]} 13 - > 14 - <i 15 - className="fa fa-arrow-left fa-3x" 16 - /> 17 - </a> 18 - </div> 19 - <div 20 - className="counter counter" 21 - data-tid="counter" 22 - > 23 - 1 24 - </div> 25 - <div 26 - className="btnGroup" 27 - > 28 - <button 29 - className="btn" 30 - data-tclass="btn" 31 - onClick={[Function]} 32 - type="button" 33 - > 34 - <i 35 - className="fa fa-plus" 36 - /> 37 - </button> 38 - <button 39 - className="btn" 40 - data-tclass="btn" 41 - onClick={[Function]} 42 - type="button" 43 - > 44 - <i 45 - className="fa fa-minus" 46 - /> 47 - </button> 48 - <button 49 - className="btn" 50 - data-tclass="btn" 51 - onClick={[Function]} 52 - type="button" 53 - > 54 - odd 55 - </button> 56 - <button 57 - className="btn" 58 - data-tclass="btn" 59 - onClick={[Function]} 60 - type="button" 61 - > 62 - async 63 - </button> 64 - </div> 65 - </div> 66 - </div> 67 - `;
-61
test/containers/CounterPage.spec.js
··· 1 - import React from 'react'; 2 - import Enzyme, { mount } from 'enzyme'; 3 - import Adapter from 'enzyme-adapter-react-16'; 4 - import { Provider } from 'react-redux'; 5 - import { createBrowserHistory } from 'history'; 6 - import { ConnectedRouter } from 'react-router-redux'; 7 - import CounterPage from '../../app/containers/CounterPage'; 8 - import { configureStore } from '../../app/store/configureStore'; 9 - 10 - Enzyme.configure({ adapter: new Adapter() }); 11 - 12 - function setup(initialState) { 13 - const store = configureStore(initialState); 14 - const history = createBrowserHistory(); 15 - const provider = ( 16 - <Provider store={store}> 17 - <ConnectedRouter history={history}> 18 - <CounterPage /> 19 - </ConnectedRouter> 20 - </Provider> 21 - ); 22 - const app = mount(provider); 23 - return { 24 - app, 25 - buttons: app.find('button'), 26 - p: app.find('.counter'), 27 - }; 28 - } 29 - 30 - describe('containers', () => { 31 - describe('App', () => { 32 - it('should display initial count', () => { 33 - const { p } = setup(); 34 - expect(p.text()).toMatch(/^0$/); 35 - }); 36 - 37 - it('should display updated count after increment button click', () => { 38 - const { buttons, p } = setup(); 39 - buttons.at(0).simulate('click'); 40 - expect(p.text()).toMatch(/^1$/); 41 - }); 42 - 43 - it('should display updated count after decrement button click', () => { 44 - const { buttons, p } = setup(); 45 - buttons.at(1).simulate('click'); 46 - expect(p.text()).toMatch(/^-1$/); 47 - }); 48 - 49 - it('shouldnt change if even and if odd button clicked', () => { 50 - const { buttons, p } = setup(); 51 - buttons.at(2).simulate('click'); 52 - expect(p.text()).toMatch(/^0$/); 53 - }); 54 - 55 - it('should change if odd and if odd button clicked', () => { 56 - const { buttons, p } = setup({ counter: 1 }); 57 - buttons.at(2).simulate('click'); 58 - expect(p.text()).toMatch(/^2$/); 59 - }); 60 - }); 61 - });
-113
test/e2e/e2e.spec.js
··· 1 - import { Application } from 'spectron'; 2 - import electronPath from 'electron'; 3 - import path from 'path'; 4 - 5 - jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000; 6 - 7 - const delay = (time) => new Promise((resolve) => setTimeout(resolve, time)); 8 - 9 - describe('main window', function spec() { 10 - beforeAll(async () => { 11 - this.app = new Application({ 12 - path: electronPath, 13 - args: [path.join(__dirname, '..', '..', 'app')], 14 - }); 15 - 16 - return this.app.start(); 17 - }); 18 - 19 - afterAll(() => { 20 - if (this.app && this.app.isRunning()) { 21 - return this.app.stop(); 22 - } 23 - }); 24 - 25 - const findCounter = () => this.app.client.element('[data-tid="counter"]'); 26 - 27 - const findButtons = async () => { 28 - const { value } = await this.app.client.elements('[data-tclass="btn"]'); 29 - return value.map((btn) => btn.ELEMENT); 30 - }; 31 - 32 - it('should open window', async () => { 33 - const { client, browserWindow } = this.app; 34 - 35 - await client.waitUntilWindowLoaded(); 36 - await delay(500); 37 - const title = await browserWindow.getTitle(); 38 - expect(title).toBe('Hello Electron React!'); 39 - }); 40 - 41 - it("should haven't any logs in console of main window", async () => { 42 - const { client } = this.app; 43 - const logs = await client.getRenderProcessLogs(); 44 - // Print renderer process logs 45 - logs.forEach((log) => { 46 - console.log(log.message); 47 - console.log(log.source); 48 - console.log(log.level); 49 - expect(log.level).not.toEqual('SEVERE'); 50 - }); 51 - // @NOTE: Temporarily have to disable this assertion because there are some warnings in 52 - // electron@2. Loading files from localhost in development uses http and this causes 53 - // electron to throw warnings 54 - // expect(logs).toHaveLength(0); 55 - }); 56 - 57 - it('should to Counter with click "to Counter" link', async () => { 58 - const { client } = this.app; 59 - 60 - await client.click('[data-tid=container] > a'); 61 - expect(await findCounter().getText()).toBe('0'); 62 - }); 63 - 64 - it('should display updated count after increment button click', async () => { 65 - const { client } = this.app; 66 - 67 - const buttons = await findButtons(); 68 - await client.elementIdClick(buttons[0]); // + 69 - expect(await findCounter().getText()).toBe('1'); 70 - }); 71 - 72 - it('should display updated count after descrement button click', async () => { 73 - const { client } = this.app; 74 - 75 - const buttons = await findButtons(); 76 - await client.elementIdClick(buttons[1]); // - 77 - expect(await findCounter().getText()).toBe('0'); 78 - }); 79 - 80 - it('shouldnt change if even and if odd button clicked', async () => { 81 - const { client } = this.app; 82 - 83 - const buttons = await findButtons(); 84 - await client.elementIdClick(buttons[2]); // odd 85 - expect(await findCounter().getText()).toBe('0'); 86 - }); 87 - 88 - it('should change if odd and if odd button clicked', async () => { 89 - const { client } = this.app; 90 - 91 - const buttons = await findButtons(); 92 - await client.elementIdClick(buttons[0]); // + 93 - await client.elementIdClick(buttons[2]); // odd 94 - expect(await findCounter().getText()).toBe('2'); 95 - }); 96 - 97 - it('should change if async button clicked and a second later', async () => { 98 - const { client } = this.app; 99 - 100 - const buttons = await findButtons(); 101 - await client.elementIdClick(buttons[3]); // async 102 - expect(await findCounter().getText()).toBe('2'); 103 - await delay(3000); 104 - expect(await findCounter().getText()).toBe('3'); 105 - }); 106 - 107 - it('should back to home if back button clicked', async () => { 108 - const { client } = this.app; 109 - await client.element('[data-tid="backButton"] > a').click(); 110 - 111 - expect(await client.isExisting('[data-tid="container"]')).toBe(true); 112 - }); 113 - });
-5
test/example.js
··· 1 - describe('description', () => { 2 - it('should have description', () => { 3 - expect(1 + 2).toBe(3); 4 - }); 5 - });
-9
test/reducers/__snapshots__/counter.spec.js.snap
··· 1 - // Jest Snapshot v1, https://goo.gl/fbAQLP 2 - 3 - exports[`reducers counter should handle DECREMENT_COUNTER 1`] = `0`; 4 - 5 - exports[`reducers counter should handle INCREMENT_COUNTER 1`] = `2`; 6 - 7 - exports[`reducers counter should handle initial state 1`] = `0`; 8 - 9 - exports[`reducers counter should handle unknown action type 1`] = `1`;
-9
test/reducers/__snapshots__/counter.spec.ts.snap
··· 1 - // Jest Snapshot v1, https://goo.gl/fbAQLP 2 - 3 - exports[`reducers counter should handle DECREMENT_COUNTER 1`] = `0`; 4 - 5 - exports[`reducers counter should handle INCREMENT_COUNTER 1`] = `2`; 6 - 7 - exports[`reducers counter should handle initial state 1`] = `0`; 8 - 9 - exports[`reducers counter should handle unknown action type 1`] = `1`;
-22
test/reducers/counter.spec.js
··· 1 - import counter from '../../app/reducers/counter'; 2 - import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../../app/actions/counter'; 3 - 4 - describe('reducers', () => { 5 - describe('counter', () => { 6 - it('should handle initial state', () => { 7 - expect(counter(undefined, {})).toMatchSnapshot(); 8 - }); 9 - 10 - it('should handle INCREMENT_COUNTER', () => { 11 - expect(counter(1, { type: INCREMENT_COUNTER })).toMatchSnapshot(); 12 - }); 13 - 14 - it('should handle DECREMENT_COUNTER', () => { 15 - expect(counter(1, { type: DECREMENT_COUNTER })).toMatchSnapshot(); 16 - }); 17 - 18 - it('should handle unknown action type', () => { 19 - expect(counter(1, { type: 'unknown' })).toMatchSnapshot(); 20 - }); 21 - }); 22 - });