diff --git a/.babelrc b/.babelrc
index e812394..9404bc9 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,6 +1,7 @@
{
"presets": [
["env", { "modules": false }],
- "stage-3"
+ "stage-3",
+ "es2015"
]
}
diff --git a/.travis.yml b/.travis.yml
index d3b9f6c..62c7d05 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,6 +12,7 @@ cache:
script:
- npm run lint
- npm run production
+ - npm run test
notifications:
email: false
diff --git a/README.md b/README.md
index 9660b51..6353b73 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,8 @@
The purpose of this repository is to consume API, provide by [a Laravel Application](https://github.com/guillaumebriday/todolist-backend), with the [Vue.js](https://vuejs.org) JavaScript front-end framework.
+![Screenshot](https://raw.githubusercontent.com/guillaumebriday/todolist-frontend/master/screenshot.png)
+
## Some of the tools used in this project
- [Vue.js](https://vuejs.org)
@@ -30,8 +32,8 @@ Setting up your development environment on your local machine :
```
$ git clone https://github.com/guillaumebriday/todolist-frontend.git
$ cd todolist-frontend
-$ docker-compose run node npm install
-$ docker-compose run --service-ports node npm run hot
+$ docker-compose run --rm node npm install
+$ docker-compose run --service-ports --rm node npm run hot
```
## Useful commands
@@ -53,6 +55,11 @@ Running ESLint :
$ docker-compose run --rm node npm run lint
```
+Running tests :
+```bash
+$ docker-compose run --rm node npm run test
+```
+
## More details
More details are available on my blog post : [https://guillaumebriday.fr/laravel-vuejs-faire-une-todo-list-partie-1-presentation-et-objectifs](https://guillaumebriday.fr/laravel-vuejs-faire-une-todo-list-partie-1-presentation-et-objectifs) (French).
diff --git a/index.html b/index.html
index 27eb3bb..0356ab6 100644
--- a/index.html
+++ b/index.html
@@ -4,8 +4,9 @@
-
-
Todolist-frontend
+
+
+ Todolist
diff --git a/package-lock.json b/package-lock.json
index 547cebd..847e4a5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -105,6 +105,12 @@
}
}
},
+ "@types/node": {
+ "version": "4.0.35",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-4.0.35.tgz",
+ "integrity": "sha512-p+bI8MK0GCGwDkxF9iXM6RsSZbCYNWzdwduiYKo/30UReZumhkrqqgOqHSk4f5bjdOftOcCG+e7BqfEOd9pBaA==",
+ "dev": true
+ },
"JSONStream": {
"version": "0.8.4",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz",
@@ -114,6 +120,12 @@
"through": "2.3.8"
}
},
+ "abab": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
+ "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=",
+ "dev": true
+ },
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -152,6 +164,15 @@
}
}
},
+ "acorn-globals": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz",
+ "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==",
+ "dev": true,
+ "requires": {
+ "acorn": "5.3.0"
+ }
+ },
"acorn-jsx": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
@@ -291,6 +312,12 @@
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
"integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE="
},
+ "array-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+ "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
+ "dev": true
+ },
"array-find-index": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@@ -1186,6 +1213,38 @@
}
}
},
+ "babel-preset-es2015": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
+ "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-check-es2015-constants": "6.22.0",
+ "babel-plugin-transform-es2015-arrow-functions": "6.22.0",
+ "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0",
+ "babel-plugin-transform-es2015-block-scoping": "6.26.0",
+ "babel-plugin-transform-es2015-classes": "6.24.1",
+ "babel-plugin-transform-es2015-computed-properties": "6.24.1",
+ "babel-plugin-transform-es2015-destructuring": "6.23.0",
+ "babel-plugin-transform-es2015-duplicate-keys": "6.24.1",
+ "babel-plugin-transform-es2015-for-of": "6.23.0",
+ "babel-plugin-transform-es2015-function-name": "6.24.1",
+ "babel-plugin-transform-es2015-literals": "6.22.0",
+ "babel-plugin-transform-es2015-modules-amd": "6.24.1",
+ "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
+ "babel-plugin-transform-es2015-modules-systemjs": "6.24.1",
+ "babel-plugin-transform-es2015-modules-umd": "6.24.1",
+ "babel-plugin-transform-es2015-object-super": "6.24.1",
+ "babel-plugin-transform-es2015-parameters": "6.24.1",
+ "babel-plugin-transform-es2015-shorthand-properties": "6.24.1",
+ "babel-plugin-transform-es2015-spread": "6.22.0",
+ "babel-plugin-transform-es2015-sticky-regex": "6.24.1",
+ "babel-plugin-transform-es2015-template-literals": "6.22.0",
+ "babel-plugin-transform-es2015-typeof-symbol": "6.23.0",
+ "babel-plugin-transform-es2015-unicode-regex": "6.24.1",
+ "babel-plugin-transform-regenerator": "6.26.0"
+ }
+ },
"babel-preset-stage-3": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz",
@@ -1444,6 +1503,18 @@
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
"dev": true
},
+ "browser-process-hrtime": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz",
+ "integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44=",
+ "dev": true
+ },
+ "browser-stdout": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz",
+ "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=",
+ "dev": true
+ },
"browserify-aes": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz",
@@ -1776,6 +1847,15 @@
}
}
},
+ "clean-webpack-plugin": {
+ "version": "0.1.17",
+ "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-0.1.17.tgz",
+ "integrity": "sha512-Bts/V725v8Ijosp4K1cqppQXgXcrohxoMsg0CV2xL4y/vua1G5pAfHEW/eJIiKF+GNNG72mdjbipxMRFEms7yg==",
+ "dev": true,
+ "requires": {
+ "rimraf": "2.6.2"
+ }
+ },
"cli-boxes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
@@ -2193,6 +2273,12 @@
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"dev": true
},
+ "content-type-parser": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz",
+ "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==",
+ "dev": true
+ },
"convert-source-map": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
@@ -2706,6 +2792,21 @@
}
}
},
+ "cssom": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz",
+ "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=",
+ "dev": true
+ },
+ "cssstyle": {
+ "version": "0.2.37",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
+ "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
+ "dev": true,
+ "requires": {
+ "cssom": "0.3.2"
+ }
+ },
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@@ -3112,6 +3213,12 @@
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
"dev": true
},
+ "domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.0.tgz",
+ "integrity": "sha512-WpwuBlZ2lQRFa4H/4w49deb9rJLot9KmqrKKjMc9qBl7CID+DdC2swoa34ccRl+anL2B6bLp6TjFdIdnzekMBQ==",
+ "dev": true
+ },
"domhandler": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",
@@ -3398,6 +3505,34 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
+ "escodegen": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz",
+ "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==",
+ "dev": true,
+ "requires": {
+ "esprima": "3.1.3",
+ "estraverse": "4.2.0",
+ "esutils": "2.0.2",
+ "optionator": "0.8.2",
+ "source-map": "0.5.7"
+ },
+ "dependencies": {
+ "esprima": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
+ "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+ "dev": true
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
"escope": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
@@ -3837,6 +3972,20 @@
"fill-range": "2.2.3"
}
},
+ "expect": {
+ "version": "22.0.3",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-22.0.3.tgz",
+ "integrity": "sha512-QapzeQkcA3jCx4pDnD07I4SPPxScKbey8TD/WwrnzmpHmL5q0dUtXfUt5OIFOjVBCg+C4zn4Y1zK9Rb9SIDL1g==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "3.2.0",
+ "jest-diff": "22.0.3",
+ "jest-get-type": "22.0.3",
+ "jest-matcher-utils": "22.0.3",
+ "jest-message-util": "22.0.3",
+ "jest-regex-util": "22.0.3"
+ }
+ },
"express": {
"version": "4.16.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
@@ -5331,12 +5480,24 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
+ "growl": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
+ "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
+ "dev": true
+ },
"handle-thing": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz",
"integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=",
"dev": true
},
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true
+ },
"har-validator": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
@@ -5519,6 +5680,15 @@
"integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=",
"dev": true
},
+ "html-encoding-sniffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
+ "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+ "dev": true,
+ "requires": {
+ "whatwg-encoding": "1.0.3"
+ }
+ },
"html-entities": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
@@ -6145,6 +6315,67 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
},
+ "jest-diff": {
+ "version": "22.0.3",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.0.3.tgz",
+ "integrity": "sha512-Y7xN9Lc/NgFvR14lvjrJXB6x2x1LLe5NnMyzLvilBSSOyjy9uAVnR2Bt1YgzdfRrfaxsx7xFUVcqXLUnPkrJcA==",
+ "dev": true,
+ "requires": {
+ "chalk": "2.3.0",
+ "diff": "3.4.0",
+ "jest-get-type": "22.0.3",
+ "pretty-format": "22.0.3"
+ }
+ },
+ "jest-get-type": {
+ "version": "22.0.3",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.0.3.tgz",
+ "integrity": "sha512-TaJnc/lnJQ3jwry+NUWkqaJmKrM/Ut3XdK89HfiqdI3DMRLd6Zb4wyKjwuNP37MEQqlNg0YWH4sbBR8D4exjCA==",
+ "dev": true
+ },
+ "jest-matcher-utils": {
+ "version": "22.0.3",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.0.3.tgz",
+ "integrity": "sha512-FJbKpCR3K7YYE/Pnvy5OrLFgPEswpYWIfVtdwT2NC6pBARbYGX39KF3bTxS9yg2mv0YL2zHe3UbwzFsi9nFpVA==",
+ "dev": true,
+ "requires": {
+ "chalk": "2.3.0",
+ "jest-get-type": "22.0.3",
+ "pretty-format": "22.0.3"
+ }
+ },
+ "jest-message-util": {
+ "version": "22.0.3",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.0.3.tgz",
+ "integrity": "sha512-AVBdCx7Oj5wBpMOH089lx7Zgwpdz9HbReA82HuVAlIT4kEQRvCy6Sl9yVWDGJwHTgB/OYQGkgmbv/P/K8TkWNw==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "7.0.0-beta.36",
+ "chalk": "2.3.0",
+ "micromatch": "2.3.11",
+ "slash": "1.0.0",
+ "stack-utils": "1.0.1"
+ },
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.0.0-beta.36",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.36.tgz",
+ "integrity": "sha512-sW77BFwJ48YvQp3Gzz5xtAUiXuYOL2aMJKDwiaY3OcvdqBFurtYfOpSa4QrNyDxmOGRFSYzUpabU2m9QrlWE7w==",
+ "dev": true,
+ "requires": {
+ "chalk": "2.3.0",
+ "esutils": "2.0.2",
+ "js-tokens": "3.0.2"
+ }
+ }
+ }
+ },
+ "jest-regex-util": {
+ "version": "22.0.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.0.3.tgz",
+ "integrity": "sha512-mplC9chiAotES3ClzNhy0SJcfHB2DivooKJZW+2hDdvP8LLB+OUI+D6bJd7sncbKUsyFcmblEvpm/zz/hef7HA==",
+ "dev": true
+ },
"js-base64": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.0.tgz",
@@ -6172,6 +6403,197 @@
"dev": true,
"optional": true
},
+ "jsdom": {
+ "version": "11.5.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.5.1.tgz",
+ "integrity": "sha512-89ztIZ03aYK9f1uUrLXLsZndRge/JnZjzjpaN+lrse3coqz+8PR/dX4WLHpbF5fIKTXhDjFODOJw2328lPJ90g==",
+ "dev": true,
+ "requires": {
+ "abab": "1.0.4",
+ "acorn": "5.3.0",
+ "acorn-globals": "4.1.0",
+ "array-equal": "1.0.0",
+ "browser-process-hrtime": "0.1.2",
+ "content-type-parser": "1.0.2",
+ "cssom": "0.3.2",
+ "cssstyle": "0.2.37",
+ "domexception": "1.0.0",
+ "escodegen": "1.9.0",
+ "html-encoding-sniffer": "1.0.2",
+ "left-pad": "1.2.0",
+ "nwmatcher": "1.4.3",
+ "parse5": "3.0.3",
+ "pn": "1.1.0",
+ "request": "2.83.0",
+ "request-promise-native": "1.0.5",
+ "sax": "1.2.4",
+ "symbol-tree": "3.2.2",
+ "tough-cookie": "2.3.3",
+ "webidl-conversions": "4.0.2",
+ "whatwg-encoding": "1.0.3",
+ "whatwg-url": "6.4.0",
+ "xml-name-validator": "2.0.1"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true
+ },
+ "boom": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
+ "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
+ "dev": true,
+ "requires": {
+ "hoek": "4.2.0"
+ }
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "cryptiles": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
+ "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
+ "dev": true,
+ "requires": {
+ "boom": "5.2.0"
+ },
+ "dependencies": {
+ "boom": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
+ "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
+ "dev": true,
+ "requires": {
+ "hoek": "4.2.0"
+ }
+ }
+ }
+ },
+ "form-data": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
+ "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
+ "dev": true,
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.5",
+ "mime-types": "2.1.17"
+ }
+ },
+ "har-validator": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
+ "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
+ "dev": true,
+ "requires": {
+ "ajv": "5.5.2",
+ "har-schema": "2.0.0"
+ }
+ },
+ "hawk": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
+ "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
+ "dev": true,
+ "requires": {
+ "boom": "4.3.1",
+ "cryptiles": "3.1.2",
+ "hoek": "4.2.0",
+ "sntp": "2.1.0"
+ }
+ },
+ "hoek": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
+ "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==",
+ "dev": true
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "jsprim": "1.4.1",
+ "sshpk": "1.13.1"
+ }
+ },
+ "qs": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+ "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
+ "dev": true
+ },
+ "request": {
+ "version": "2.83.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
+ "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
+ "dev": true,
+ "requires": {
+ "aws-sign2": "0.7.0",
+ "aws4": "1.6.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.5",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.3.1",
+ "har-validator": "5.0.3",
+ "hawk": "6.0.2",
+ "http-signature": "1.2.0",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.17",
+ "oauth-sign": "0.8.2",
+ "performance-now": "2.1.0",
+ "qs": "6.5.1",
+ "safe-buffer": "5.1.1",
+ "stringstream": "0.0.5",
+ "tough-cookie": "2.3.3",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.1.0"
+ }
+ },
+ "sntp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
+ "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
+ "dev": true,
+ "requires": {
+ "hoek": "4.2.0"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
+ }
+ }
+ },
+ "jsdom-global": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz",
+ "integrity": "sha1-a9KZwTsMRiay2iwDk81DhdYGrLk=",
+ "dev": true
+ },
"jsesc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
@@ -6350,6 +6772,12 @@
"through2": "0.6.5"
}
},
+ "left-pad": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.2.0.tgz",
+ "integrity": "sha1-0wpzxrggHY99jnlWupYWCHpo4O4=",
+ "dev": true
+ },
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@@ -6487,6 +6915,12 @@
"integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=",
"dev": true
},
+ "lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
+ "dev": true
+ },
"lodash.tail": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz",
@@ -6820,6 +7254,183 @@
}
}
},
+ "mocha": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz",
+ "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==",
+ "dev": true,
+ "requires": {
+ "browser-stdout": "1.3.0",
+ "commander": "2.11.0",
+ "debug": "3.1.0",
+ "diff": "3.3.1",
+ "escape-string-regexp": "1.0.5",
+ "glob": "7.1.2",
+ "growl": "1.10.3",
+ "he": "1.1.1",
+ "mkdirp": "0.5.1",
+ "supports-color": "4.4.0"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
+ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
+ "dev": true
+ },
+ "diff": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz",
+ "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
+ "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "2.0.0"
+ }
+ }
+ }
+ },
+ "mocha-webpack": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mocha-webpack/-/mocha-webpack-1.0.1.tgz",
+ "integrity": "sha512-E/gGw0knbee7/8OWnjoD3VwUXSKLc1wYXsWgpMeLtM60JjR6k24j0J8UCAqRK5/iFrRBoKWDJWuuZ+E32/nUwQ==",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "chalk": "1.1.3",
+ "chokidar": "1.7.0",
+ "glob-parent": "2.0.0",
+ "globby": "6.1.0",
+ "interpret": "1.1.0",
+ "is-glob": "2.0.1",
+ "loader-utils": "1.1.0",
+ "lodash": "4.17.4",
+ "memory-fs": "0.4.1",
+ "nodent-runtime": "3.2.0",
+ "normalize-path": "2.1.1",
+ "progress": "1.1.8",
+ "source-map-support": "0.4.18",
+ "toposort": "1.0.6",
+ "yargs": "4.8.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
+ "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "2.2.1",
+ "escape-string-regexp": "1.0.5",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.1",
+ "supports-color": "2.0.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
+ },
+ "progress": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
+ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
+ "dev": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "dev": true,
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ },
+ "window-size": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz",
+ "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=",
+ "dev": true
+ },
+ "yargs": {
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz",
+ "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=",
+ "dev": true,
+ "requires": {
+ "cliui": "3.2.0",
+ "decamelize": "1.2.0",
+ "get-caller-file": "1.0.2",
+ "lodash.assign": "4.2.0",
+ "os-locale": "1.4.0",
+ "read-pkg-up": "1.0.1",
+ "require-directory": "2.1.1",
+ "require-main-filename": "1.0.1",
+ "set-blocking": "2.0.0",
+ "string-width": "1.0.2",
+ "which-module": "1.0.0",
+ "window-size": "0.2.0",
+ "y18n": "3.2.1",
+ "yargs-parser": "2.4.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz",
+ "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=",
+ "dev": true,
+ "requires": {
+ "camelcase": "3.0.0",
+ "lodash.assign": "4.2.0"
+ }
+ }
+ }
+ },
"moment": {
"version": "2.20.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
@@ -7088,6 +7699,12 @@
}
}
},
+ "nodent-runtime": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/nodent-runtime/-/nodent-runtime-3.2.0.tgz",
+ "integrity": "sha512-vpc9vNZmLiTgQO/0ecoX0rogUSikHRj6hPTCO4pW0cJQiozdhhfxsb3TfNi9pzrpNVG71c7oXWRocbfdvkuhWw==",
+ "dev": true
+ },
"nopt": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
@@ -7176,6 +7793,12 @@
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
+ "nwmatcher": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.3.tgz",
+ "integrity": "sha512-IKdSTiDWCarf2JTS5e9e2+5tPZGdkRJ79XjYV0pzK8Q9BpsFyBq1RGKxzs7Q8UBushGw7m6TzVKz6fcY99iSWw==",
+ "dev": true
+ },
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
@@ -7414,6 +8037,15 @@
"error-ex": "1.3.1"
}
},
+ "parse5": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
+ "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "4.0.35"
+ }
+ },
"parseurl": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
@@ -7499,6 +8131,12 @@
"sha.js": "2.4.9"
}
},
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@@ -7560,6 +8198,12 @@
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
"dev": true
},
+ "pn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
+ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
+ "dev": true
+ },
"portfinder": {
"version": "1.0.13",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz",
@@ -10181,6 +10825,16 @@
"utila": "0.4.0"
}
},
+ "pretty-format": {
+ "version": "22.0.3",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.0.3.tgz",
+ "integrity": "sha512-qXbDFJ2/Kk3HFIaLdOblbsCKQ09kZu4MKbXB+m/EaqD7PZ/wXe2XcRREmQleMh4wmerxlma6eJTh3nxCXYUmmA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "3.0.0",
+ "ansi-styles": "3.2.0"
+ }
+ },
"private": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
@@ -10880,6 +11534,26 @@
"uuid": "3.1.0"
}
},
+ "request-promise-core": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
+ "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
+ "dev": true,
+ "requires": {
+ "lodash": "4.17.4"
+ }
+ },
+ "request-promise-native": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz",
+ "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=",
+ "dev": true,
+ "requires": {
+ "request-promise-core": "1.1.1",
+ "stealthy-require": "1.1.1",
+ "tough-cookie": "2.3.3"
+ }
+ },
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -11585,6 +12259,12 @@
}
}
},
+ "stack-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz",
+ "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=",
+ "dev": true
+ },
"statuses": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
@@ -11605,6 +12285,12 @@
"readable-stream": "2.3.3"
}
},
+ "stealthy-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
+ "dev": true
+ },
"stream-browserify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
@@ -12217,6 +12903,12 @@
}
}
},
+ "symbol-tree": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
+ "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
+ "dev": true
+ },
"synesthesia": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/synesthesia/-/synesthesia-1.0.1.tgz",
@@ -12397,6 +13089,23 @@
"punycode": "1.4.1"
}
},
+ "tr46": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
+ "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+ "dev": true,
+ "requires": {
+ "punycode": "2.1.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz",
+ "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=",
+ "dev": true
+ }
+ }
+ },
"trim-newlines": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
@@ -12871,6 +13580,12 @@
"minimalistic-assert": "1.0.0"
}
},
+ "webidl-conversions": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
+ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+ "dev": true
+ },
"webpack": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz",
@@ -13188,6 +13903,26 @@
"integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
"dev": true
},
+ "whatwg-encoding": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz",
+ "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==",
+ "dev": true,
+ "requires": {
+ "iconv-lite": "0.4.19"
+ }
+ },
+ "whatwg-url": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz",
+ "integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==",
+ "dev": true,
+ "requires": {
+ "lodash.sortby": "4.7.0",
+ "tr46": "1.0.1",
+ "webidl-conversions": "4.0.2"
+ }
+ },
"whet.extend": {
"version": "0.9.9",
"resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
@@ -13354,6 +14089,12 @@
"integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=",
"dev": true
},
+ "xml-name-validator": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
+ "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
+ "dev": true
+ },
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
diff --git a/package.json b/package.json
index 0db3192..d30099f 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,8 @@
"watch": "npm run development -- --watch",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production webpack --no-progress --hide-modules",
- "lint": "eslint --ext .js,.vue src"
+ "lint": "eslint --ext .js,.vue src",
+ "test": "mocha-webpack --webpack-config webpack.config.js --require tests/setup.js tests/*.spec.js"
},
"dependencies": {
"axios": "^0.17.1",
@@ -34,7 +35,9 @@
"babel-eslint": "^8.1.2",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
+ "babel-preset-es2015": "^6.24.1",
"babel-preset-stage-3": "^6.24.1",
+ "clean-webpack-plugin": "^0.1.17",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"eslint": "^4.14.0",
@@ -45,10 +48,15 @@
"eslint-plugin-node": "^5.2.1",
"eslint-plugin-promise": "^3.6.0",
"eslint-plugin-standard": "^3.0.1",
+ "expect": "^22.0.3",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.6",
"glob-all": "^3.1.0",
"html-webpack-plugin": "^2.30.1",
+ "jsdom": "^11.5.1",
+ "jsdom-global": "^3.0.2",
+ "mocha": "^4.1.0",
+ "mocha-webpack": "^1.0.1",
"node-sass": "^4.7.2",
"postcss-loader": "^2.0.9",
"purify-css": "^1.2.5",
@@ -56,7 +64,7 @@
"sass-loader": "^6.0.6",
"style-loader": "^0.19.1",
"vue-loader": "^13.0.5",
- "vue-template-compiler": "^2.4.4",
+ "vue-template-compiler": "^2.5.13",
"vue-test-utils": "^1.0.0-beta.9",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
diff --git a/screenshot.png b/screenshot.png
new file mode 100644
index 0000000..3449138
Binary files /dev/null and b/screenshot.png differ
diff --git a/src/js/app.js b/src/js/app.js
index c042e9b..718b283 100644
--- a/src/js/app.js
+++ b/src/js/app.js
@@ -3,11 +3,13 @@ import './bootstrap'
import Vue from 'vue'
import App from './components/App'
import router from './router'
+import store from './store'
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
+ store,
template: ' ',
components: { App }
})
diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js
index fbb72f0..6c06957 100644
--- a/src/js/bootstrap.js
+++ b/src/js/bootstrap.js
@@ -1,12 +1,18 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import axios from 'axios'
+import Navbar from './components/Navbar'
+
+const API_URL = process.env.API_URL || 'http://localhost/api/v1/'
window.Vue = Vue
Vue.config.productionTip = false
Vue.use(VueRouter)
+Vue.component('Navbar', Navbar)
window.axios = axios
-window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'
+axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'
+axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.token
+axios.defaults.baseURL = API_URL
diff --git a/src/js/components/App.vue b/src/js/components/App.vue
index e0a364b..a8b66ed 100644
--- a/src/js/components/App.vue
+++ b/src/js/components/App.vue
@@ -1,6 +1,6 @@
- Home
+
diff --git a/src/js/components/Home.vue b/src/js/components/Home.vue
index f34f397..c908ef3 100644
--- a/src/js/components/Home.vue
+++ b/src/js/components/Home.vue
@@ -1,6 +1,6 @@
-
{{ message }}
+ {{ message }}
@@ -9,7 +9,7 @@ export default {
name: 'Home',
data () {
return {
- message: 'Home'
+ message: 'Tasks'
}
}
}
diff --git a/src/js/components/Login.vue b/src/js/components/Login.vue
new file mode 100644
index 0000000..b8d69e6
--- /dev/null
+++ b/src/js/components/Login.vue
@@ -0,0 +1,88 @@
+
+
+
+
Todolist
+
+
+ Incorrect username or password.
+
+
+
+
+ Source code available on GitHub .
+
+
+
+
+
+
+
diff --git a/src/js/components/Navbar.vue b/src/js/components/Navbar.vue
new file mode 100644
index 0000000..17c15b1
--- /dev/null
+++ b/src/js/components/Navbar.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ Todolist
+
+
+
+
+ Logout
+
+
+
+
+
+
+
+
diff --git a/src/js/router/index.js b/src/js/router/index.js
index f45ad5c..2a79c07 100644
--- a/src/js/router/index.js
+++ b/src/js/router/index.js
@@ -1,12 +1,40 @@
import VueRouter from 'vue-router'
+import store from '../store'
import Home from '../components/Home'
+import Login from '../components/Login'
-export default new VueRouter({
+let router = new VueRouter({
+ mode: 'history',
routes: [
{
path: '/',
name: 'Home',
- component: Home
+ component: Home,
+ meta: {auth: true}
+ },
+ {
+ path: '/login',
+ name: 'Login',
+ component: Login,
+ meta: {auth: false}
+ },
+ {
+ path: '*',
+ redirect: '/'
}
]
})
+
+router.beforeEach((to, from, next) => {
+ if (!store.getters.isLogged && to.meta.auth) {
+ return next('/login')
+ }
+
+ if (store.getters.isLogged && to.name === 'Login') {
+ return next('/')
+ }
+
+ next()
+})
+
+export default router
diff --git a/src/js/store/auth.js b/src/js/store/auth.js
new file mode 100644
index 0000000..75b15bb
--- /dev/null
+++ b/src/js/store/auth.js
@@ -0,0 +1,47 @@
+import router from '../router'
+
+const types = {
+ LOGIN: 'LOGIN',
+ LOGOUT: 'LOGOUT'
+}
+
+const state = {
+ logged: !!localStorage.getItem('token')
+}
+
+const mutations = {
+ [types.LOGIN] (state) {
+ state.logged = true
+ },
+
+ [types.LOGOUT] (state) {
+ state.logged = false
+ }
+}
+
+const getters = {
+ isLogged: state => state.logged
+}
+
+const actions = {
+ login ({ commit }, token) {
+ commit(types.LOGIN)
+ localStorage.setItem('token', token)
+
+ router.push({name: 'Home'})
+ },
+
+ logout ({ commit }) {
+ commit(types.LOGOUT)
+ localStorage.removeItem('token')
+
+ router.push({name: 'Login'})
+ }
+}
+
+export default {
+ state,
+ mutations,
+ getters,
+ actions
+}
diff --git a/src/js/store/index.js b/src/js/store/index.js
new file mode 100644
index 0000000..d92a6f1
--- /dev/null
+++ b/src/js/store/index.js
@@ -0,0 +1,12 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+import auth from './auth'
+
+Vue.use(Vuex)
+
+export default new Vuex.Store({
+ modules: {
+ auth
+ }
+})
diff --git a/tests/login.spec.js b/tests/login.spec.js
new file mode 100644
index 0000000..8782b0c
--- /dev/null
+++ b/tests/login.spec.js
@@ -0,0 +1,33 @@
+import { mount } from 'vue-test-utils'
+import Login from '../src/js/components/Login.vue'
+import expect from 'expect'
+
+/* eslint-disable no-undef */
+describe('Login', () => {
+ let wrapper
+
+ beforeEach(() => {
+ wrapper = mount(Login)
+ })
+
+ it('does not contain error alert', () => {
+ expect(wrapper.html()).not.toContain('Incorrect username or password.')
+ })
+
+ it('enables the sign in button', () => {
+ wrapper.setData({
+ email: 'frodo@baggins.sh',
+ password: 'my_precious'
+ })
+
+ let button = wrapper.find('button')
+
+ expect(button.attributes().disabled).not.toBe('disabled')
+ })
+
+ it('disables the sign in button', () => {
+ let button = wrapper.find('button')
+
+ expect(button.attributes().disabled).toBe('disabled')
+ })
+})
diff --git a/tests/setup.js b/tests/setup.js
new file mode 100644
index 0000000..bbd0e63
--- /dev/null
+++ b/tests/setup.js
@@ -0,0 +1 @@
+require('jsdom-global')()
diff --git a/webpack.config.js b/webpack.config.js
index 0ea2901..18aba90 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,6 +4,7 @@ var webpack = require('webpack')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var PurifyCSSPlugin = require('purifycss-webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
+var CleanWebpackPlugin = require('clean-webpack-plugin')
var inProduction = (process.env.NODE_ENV === 'production')
module.exports = {
@@ -97,7 +98,8 @@ if (inProduction) {
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
- NODE_ENV: '"production"'
+ NODE_ENV: '"production"',
+ API_URL: '"http://localhost/api/v1/"'
}
}),
new webpack.optimize.UglifyJsPlugin({
@@ -114,6 +116,7 @@ if (inProduction) {
]),
minimize: true
}),
+ new CleanWebpackPlugin(['dist']),
new webpack.LoaderOptionsPlugin({
minimize: true
}),