diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 3083681..0000000 --- a/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "plugins": ["react-hot-loader/babel", "transform-decorators-legacy", "transform-runtime"], - "presets": ["es2015", "react", "stage-0"] -} diff --git a/.eslintrc b/.eslintrc index f5f85f2..2c6e96e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,50 +1,41 @@ { "env": { "browser": true, + "cypress/globals": true, "es6": true, - "jquery": true, + "jest": true, "node": true }, "plugins": [ - "react" + "react", + "cypress", + "prettier" ], - "ecmaFeatures": { - "modules": true, - "jsx": true + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true + } }, "parser": "babel-eslint", "rules": { - "camelcase": [2, {"properties": "never"}], - "eqeqeq": 2, - "global-strict": 0, - "indent": [2, 2], - "jsx-quotes": [2, "prefer-double"], - "max-params": [2, 3], - "no-console": 0, - "no-shadow": 1, - "no-undef": 1, - "no-underscore-dangle": 0, - "no-use-before-define": 1, - "no-var": 2, - "quotes": [2, "single", "avoid-escape"], - "object-shorthand": [2, "always"], - "semi": 1, - "strict": [1, "function"], - "react/display-name": 0, - "react/jsx-no-undef": 1, - "react/jsx-uses-react": 1, - "react/jsx-uses-vars": 1, - "react/no-did-mount-set-state": 1, - "react/no-did-update-set-state": 1, - "react/no-multi-comp": 1, - "react/no-unknown-property": 1, - "react/prop-types": 1, - "react/react-in-jsx-scope": 1, - "react/self-closing-comp": 1, - "react/wrap-multilines": 1 + "camelcase": ["warn", {"properties": "never"}], + "curly": ["warn", "all"], + "eqeqeq": ["warn", "always"], + "max-params": ["warn", 3], + "no-shadow": "warn", + "no-undef": "warn", + "no-var": "warn", + "object-shorthand": ["error", "always"], + "react/jsx-no-undef": ["warn", { "allowGlobals": true }], + "react/no-multi-comp": ["warn", { "ignoreStateless": true }], + "react/react-in-jsx-scope": "warn", + "react/self-closing-comp": "warn", + "prettier/prettier": "error" } } diff --git a/.gitignore b/.gitignore index 43a827b..915c3d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ ########## App ########## +/config/config.js /dist/ /log/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..5edc02d --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +coverage +dist +node_modules +package.json +package-lock.json diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..d6e2c6e --- /dev/null +++ b/babel.config.js @@ -0,0 +1,51 @@ +module.exports = function(api) { + const isTest = String(api.env()) === "test"; + + const plugins = [ + "react-hot-loader/babel", + + // stage 0 + "@babel/plugin-proposal-function-bind", + + // stage 1 + "@babel/plugin-proposal-export-default-from", + "@babel/plugin-proposal-logical-assignment-operators", + ["@babel/plugin-proposal-optional-chaining", { loose: false }], + ["@babel/plugin-proposal-pipeline-operator", { proposal: "minimal" }], + ["@babel/plugin-proposal-nullish-coalescing-operator", { loose: false }], + "@babel/plugin-proposal-do-expressions", + + // stage 2 + ["@babel/plugin-proposal-decorators", { legacy: true }], + "@babel/plugin-proposal-function-sent", + "@babel/plugin-proposal-export-namespace-from", + "@babel/plugin-proposal-numeric-separator", + "@babel/plugin-proposal-throw-expressions", + + // stage 3 + "@babel/plugin-syntax-dynamic-import", + "@babel/plugin-syntax-import-meta", + ["@babel/plugin-proposal-class-properties", { loose: false }], + "@babel/plugin-proposal-json-strings", + + // jest + isTest ? "babel-plugin-dynamic-import-node" : null + ].filter(Boolean); + + const presets = [ + [ + "@babel/preset-env", + { + debug: false, + modules: isTest ? "commonjs" : false, + useBuiltIns: "usage" + } + ], + "@babel/preset-react" + ]; + + return { + plugins, + presets + }; +}; diff --git a/cypress.json b/cypress.json new file mode 100644 index 0000000..87e4a1a --- /dev/null +++ b/cypress.json @@ -0,0 +1,4 @@ +{ + "baseUrl": "http://localhost:3000/", + "integrationFolder": "cypress/e2e" +} diff --git a/cypress/e2e/app.js b/cypress/e2e/app.js new file mode 100644 index 0000000..49dd016 --- /dev/null +++ b/cypress/e2e/app.js @@ -0,0 +1,7 @@ +describe('app', () => { + it('can visit the app', () => { + cy.visit('/') + .getByText('Home') + .click() + }) +}) diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 0000000..02e4254 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/cypress/fixtures/profile.json b/cypress/fixtures/profile.json new file mode 100644 index 0000000..a95e88f --- /dev/null +++ b/cypress/fixtures/profile.json @@ -0,0 +1,5 @@ +{ + "id": 8739, + "name": "Jane", + "email": "jane@example.com" +} diff --git a/cypress/fixtures/users.json b/cypress/fixtures/users.json new file mode 100644 index 0000000..82a0056 --- /dev/null +++ b/cypress/fixtures/users.json @@ -0,0 +1,232 @@ +[ + { + "id": 1, + "name": "Leanne Graham", + "username": "Bret", + "email": "Sincere@april.biz", + "address": { + "street": "Kulas Light", + "suite": "Apt. 556", + "city": "Gwenborough", + "zipcode": "92998-3874", + "geo": { + "lat": "-37.3159", + "lng": "81.1496" + } + }, + "phone": "1-770-736-8031 x56442", + "website": "hildegard.org", + "company": { + "name": "Romaguera-Crona", + "catchPhrase": "Multi-layered client-server neural-net", + "bs": "harness real-time e-markets" + } + }, + { + "id": 2, + "name": "Ervin Howell", + "username": "Antonette", + "email": "Shanna@melissa.tv", + "address": { + "street": "Victor Plains", + "suite": "Suite 879", + "city": "Wisokyburgh", + "zipcode": "90566-7771", + "geo": { + "lat": "-43.9509", + "lng": "-34.4618" + } + }, + "phone": "010-692-6593 x09125", + "website": "anastasia.net", + "company": { + "name": "Deckow-Crist", + "catchPhrase": "Proactive didactic contingency", + "bs": "synergize scalable supply-chains" + } + }, + { + "id": 3, + "name": "Clementine Bauch", + "username": "Samantha", + "email": "Nathan@yesenia.net", + "address": { + "street": "Douglas Extension", + "suite": "Suite 847", + "city": "McKenziehaven", + "zipcode": "59590-4157", + "geo": { + "lat": "-68.6102", + "lng": "-47.0653" + } + }, + "phone": "1-463-123-4447", + "website": "ramiro.info", + "company": { + "name": "Romaguera-Jacobson", + "catchPhrase": "Face to face bifurcated interface", + "bs": "e-enable strategic applications" + } + }, + { + "id": 4, + "name": "Patricia Lebsack", + "username": "Karianne", + "email": "Julianne.OConner@kory.org", + "address": { + "street": "Hoeger Mall", + "suite": "Apt. 692", + "city": "South Elvis", + "zipcode": "53919-4257", + "geo": { + "lat": "29.4572", + "lng": "-164.2990" + } + }, + "phone": "493-170-9623 x156", + "website": "kale.biz", + "company": { + "name": "Robel-Corkery", + "catchPhrase": "Multi-tiered zero tolerance productivity", + "bs": "transition cutting-edge web services" + } + }, + { + "id": 5, + "name": "Chelsey Dietrich", + "username": "Kamren", + "email": "Lucio_Hettinger@annie.ca", + "address": { + "street": "Skiles Walks", + "suite": "Suite 351", + "city": "Roscoeview", + "zipcode": "33263", + "geo": { + "lat": "-31.8129", + "lng": "62.5342" + } + }, + "phone": "(254)954-1289", + "website": "demarco.info", + "company": { + "name": "Keebler LLC", + "catchPhrase": "User-centric fault-tolerant solution", + "bs": "revolutionize end-to-end systems" + } + }, + { + "id": 6, + "name": "Mrs. Dennis Schulist", + "username": "Leopoldo_Corkery", + "email": "Karley_Dach@jasper.info", + "address": { + "street": "Norberto Crossing", + "suite": "Apt. 950", + "city": "South Christy", + "zipcode": "23505-1337", + "geo": { + "lat": "-71.4197", + "lng": "71.7478" + } + }, + "phone": "1-477-935-8478 x6430", + "website": "ola.org", + "company": { + "name": "Considine-Lockman", + "catchPhrase": "Synchronised bottom-line interface", + "bs": "e-enable innovative applications" + } + }, + { + "id": 7, + "name": "Kurtis Weissnat", + "username": "Elwyn.Skiles", + "email": "Telly.Hoeger@billy.biz", + "address": { + "street": "Rex Trail", + "suite": "Suite 280", + "city": "Howemouth", + "zipcode": "58804-1099", + "geo": { + "lat": "24.8918", + "lng": "21.8984" + } + }, + "phone": "210.067.6132", + "website": "elvis.io", + "company": { + "name": "Johns Group", + "catchPhrase": "Configurable multimedia task-force", + "bs": "generate enterprise e-tailers" + } + }, + { + "id": 8, + "name": "Nicholas Runolfsdottir V", + "username": "Maxime_Nienow", + "email": "Sherwood@rosamond.me", + "address": { + "street": "Ellsworth Summit", + "suite": "Suite 729", + "city": "Aliyaview", + "zipcode": "45169", + "geo": { + "lat": "-14.3990", + "lng": "-120.7677" + } + }, + "phone": "586.493.6943 x140", + "website": "jacynthe.com", + "company": { + "name": "Abernathy Group", + "catchPhrase": "Implemented secondary concept", + "bs": "e-enable extensible e-tailers" + } + }, + { + "id": 9, + "name": "Glenna Reichert", + "username": "Delphine", + "email": "Chaim_McDermott@dana.io", + "address": { + "street": "Dayna Park", + "suite": "Suite 449", + "city": "Bartholomebury", + "zipcode": "76495-3109", + "geo": { + "lat": "24.6463", + "lng": "-168.8889" + } + }, + "phone": "(775)976-6794 x41206", + "website": "conrad.com", + "company": { + "name": "Yost and Sons", + "catchPhrase": "Switchable contextually-based project", + "bs": "aggregate real-time technologies" + } + }, + { + "id": 10, + "name": "Clementina DuBuque", + "username": "Moriah.Stanton", + "email": "Rey.Padberg@karina.biz", + "address": { + "street": "Kattie Turnpike", + "suite": "Suite 198", + "city": "Lebsackbury", + "zipcode": "31428-2261", + "geo": { + "lat": "-38.2386", + "lng": "57.2232" + } + }, + "phone": "024-648-3804", + "website": "ambrose.net", + "company": { + "name": "Hoeger LLC", + "catchPhrase": "Centralized empowering task-force", + "bs": "target end-to-end models" + } + } +] diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 0000000..fd170fb --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,17 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config +} diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 0000000..c1f5a77 --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This is will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/cypress/support/index.js b/cypress/support/index.js new file mode 100644 index 0000000..9f06be5 --- /dev/null +++ b/cypress/support/index.js @@ -0,0 +1,21 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' +import 'cypress-testing-library/add-commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/index.html b/index.html index c050ba6..06c89a8 100644 --- a/index.html +++ b/index.html @@ -7,6 +7,6 @@
- +