diff --git a/open_xdmod/modules/xdmod/automated_tests/.eslintrc.json b/open_xdmod/modules/xdmod/automated_tests/.eslintrc.json new file mode 100644 index 0000000000..845881951c --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "env": { + "mocha": true, + "node": true, + "es6": true + }, + "globals": { + "require": false, + "expect": false, + "browser": false, + "testHelpers": false, + "$": false + }, + "rules": { + "class-methods-use-this": [0], + "no-underscore-dangle": [0] + } +} diff --git a/open_xdmod/modules/xdmod/automated_tests/.gitignore b/open_xdmod/modules/xdmod/automated_tests/.gitignore new file mode 100644 index 0000000000..bae8c22473 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/.gitignore @@ -0,0 +1,4 @@ +# Screenshots +/xdmod +/xdmod.tar.gz +/errorShots diff --git a/open_xdmod/modules/xdmod/automated_tests/package-lock.json b/open_xdmod/modules/xdmod/automated_tests/package-lock.json new file mode 100644 index 0000000000..bdbcb70b58 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/package-lock.json @@ -0,0 +1,2316 @@ +{ + "name": "selenium-tests", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "adm-zip": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", + "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "dev": true + }, + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + } + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=" + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "archiver": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-1.3.0.tgz", + "integrity": "sha1-TyGU1tj5nfP1MeaIHxTxXVX6ryI=", + "requires": { + "archiver-utils": "1.3.0", + "async": "2.5.0", + "buffer-crc32": "0.2.13", + "glob": "7.1.2", + "lodash": "4.17.4", + "readable-stream": "2.3.3", + "tar-stream": "1.5.4", + "walkdir": "0.0.11", + "zip-stream": "1.2.0" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.7" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "archiver-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", + "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "requires": { + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "lazystream": "1.0.0", + "lodash": "4.17.4", + "normalize-path": "2.1.1", + "readable-stream": "2.3.3" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.7" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=" + }, + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "requires": { + "lodash": "4.17.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + } + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/atob/-/atob-1.1.3.tgz", + "integrity": "sha1-lfE2KbEsOlGl0hWr3OKqnzL4B3M=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "babel-runtime": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", + "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs=", + "requires": { + "core-js": "2.4.1", + "regenerator-runtime": "0.10.5" + } + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "bl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "requires": { + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "requires": { + "assertion-error": "1.0.2", + "deep-eql": "0.1.3", + "type-detect": "1.0.0" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.2", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "cheerio": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", + "integrity": "sha1-dy5wFfLuKZZQltcepBdbdas1SSU=", + "requires": { + "css-select": "1.0.0", + "dom-serializer": "0.1.0", + "entities": "1.1.1", + "htmlparser2": "3.8.3", + "lodash": "3.10.1" + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", + "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=" + }, + "compress-commons": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.0.tgz", + "integrity": "sha1-WFhwku8g03y1i68AARLJJ4/3O58=", + "requires": { + "buffer-crc32": "0.2.13", + "crc32-stream": "2.0.0", + "normalize-path": "2.1.1", + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "core-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", + "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "crc": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz", + "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms=" + }, + "crc32-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", + "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "requires": { + "crc": "3.4.4", + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.10.1" + } + }, + "css": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.1.tgz", + "integrity": "sha1-c6TIHehdtmTU7mdPfUcIXjstVdw=", + "requires": { + "inherits": "2.0.3", + "source-map": "0.1.43", + "source-map-resolve": "0.3.1", + "urix": "0.1.0" + } + }, + "css-parse": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz", + "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=", + "requires": { + "css": "2.2.1" + } + }, + "css-select": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz", + "integrity": "sha1-sRIcpRhI3SZOIkTQWM7iVN7rRLA=", + "requires": { + "boolbase": "1.0.0", + "css-what": "1.0.0", + "domutils": "1.4.3", + "nth-check": "1.0.1" + } + }, + "css-value": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", + "integrity": "sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo=" + }, + "css-what": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", + "integrity": "sha1-18wt9FGAZm+Z0rFEYmOUaeAPc2w=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "requires": { + "type-detect": "0.1.1" + }, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=" + } + } + }, + "deepmerge": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.3.2.tgz", + "integrity": "sha1-FmNpFinU2/42T6EqKk8KqGqjoFA=" + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=" + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" + } + } + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "requires": { + "domelementtype": "1.3.0" + } + }, + "domutils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz", + "integrity": "sha1-CGVRN5bGswYDGFDhdVFrr4C3Km8=", + "requires": { + "domelementtype": "1.3.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "ejs": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.6.tgz", + "integrity": "sha1-R5Y2v6P+Ox3r1SCH8KyyBLTxnIg=" + }, + "end-of-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", + "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", + "requires": { + "once": "1.4.0" + } + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=" + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "external-editor": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz", + "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=", + "requires": { + "iconv-lite": "0.4.18", + "jschardet": "1.5.0", + "tmp": "0.0.31" + } + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "1.2.0" + } + }, + "fibers": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/fibers/-/fibers-1.0.15.tgz", + "integrity": "sha1-IvA5yPGLhWGQ+75N7PBWFUwerpw=" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + } + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.15" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=" + }, + "gaze": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "requires": { + "globule": "1.2.0" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "requires": { + "inherits": "2.0.3", + "minimatch": "0.3.0" + } + }, + "globule": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", + "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", + "requires": { + "glob": "7.1.2", + "lodash": "4.17.4", + "minimatch": "3.0.4" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.7" + } + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.0.0", + "readable-stream": "1.1.14" + }, + "dependencies": { + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "requires": { + "dom-serializer": "0.1.0", + "domelementtype": "1.3.0" + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" + } + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.0" + } + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.2.0", + "extend": "3.0.1" + } + }, + "iconv-lite": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", + "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "inquirer": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", + "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", + "requires": { + "ansi-escapes": "1.4.0", + "chalk": "1.1.3", + "cli-cursor": "2.1.0", + "cli-width": "2.1.0", + "external-editor": "2.0.4", + "figures": "2.0.0", + "lodash": "4.17.4", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx": "4.1.0", + "string-width": "2.1.0", + "strip-ansi": "3.0.1", + "through": "2.3.8" + }, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + } + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-my-json-valid": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jade": { + "version": "0.26.3", + "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, + "dependencies": { + "commander": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=" + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=" + } + } + }, + "jodid25519": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", + "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "jschardet": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.0.tgz", + "integrity": "sha512-+Q8JsoEQbrdE+a/gg1F9XO92gcKXgpE5UACqr0sIubjDmBEkd+OOWPGzQeMrWSLxd73r4dHxBeRW7edHu5LmJQ==" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "optional": true + } + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "optional": true + } + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=" + }, + "mime-db": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "requires": { + "mime-db": "1.27.0" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" + }, + "minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "requires": { + "lru-cache": "2.7.3", + "sigmund": "1.0.1" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "1.0.2" + } + }, + "npm-install-package": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/npm-install-package/-/npm-install-package-2.1.0.tgz", + "integrity": "sha1-1+/jz816sAYUuJbqUxGdyaslkSU=" + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "requires": { + "boolbase": "1.0.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.0", + "object-keys": "1.0.11" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "q": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", + "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + }, + "remove-trailing-separator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", + "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=" + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "requires": { + "aws-sign2": "0.6.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.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.0.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.0.1" + } + }, + "require-dir": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/require-dir/-/require-dir-0.3.2.tgz", + "integrity": "sha1-wdXHXp+//eny5rM+OD209ZS1pqk=" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rgb2hex": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/rgb2hex/-/rgb2hex-0.1.0.tgz", + "integrity": "sha1-zNVfhgrgxcTqN1BLlY5ELY0SMls=" + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, + "requires": { + "glob": "7.1.2" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.7" + } + } + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + } + }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=" + }, + "safe-buffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", + "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" + }, + "sauce-connect-launcher": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/sauce-connect-launcher/-/sauce-connect-launcher-1.2.2.tgz", + "integrity": "sha1-c0bMj73EQxkTI0ObBzNFH181IfI=", + "dev": true, + "requires": { + "adm-zip": "0.4.7", + "async": "2.5.0", + "https-proxy-agent": "1.0.0", + "lodash": "4.17.4", + "rimraf": "2.6.1" + }, + "dependencies": { + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "selenium-standalone": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/selenium-standalone/-/selenium-standalone-6.5.0.tgz", + "integrity": "sha1-Xsr/3LFXmf5plU5hQ3kaOL+I39E=", + "dev": true, + "requires": { + "async": "2.5.0", + "commander": "2.11.0", + "cross-spawn": "5.1.0", + "debug": "2.6.8", + "lodash": "4.17.4", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "progress": "1.1.8", + "request": "2.79.0", + "tar-stream": "1.5.2", + "urijs": "1.18.10", + "which": "1.2.14", + "yauzl": "2.8.0" + }, + "dependencies": { + "async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "bl": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.1.tgz", + "integrity": "sha1-ysMo977kVzDUBLaSID/LWQ4XLV4=", + "dev": true, + "requires": { + "readable-stream": "2.3.3" + } + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.2.14" + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.11.0", + "is-my-json-valid": "2.16.0", + "pinkie-promise": "2.0.1" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.15", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.4.3", + "uuid": "3.0.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tar-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.2.tgz", + "integrity": "sha1-+8bG6DwaGdTLSMfZYXH8JI7/x78=", + "dev": true, + "requires": { + "bl": "1.2.1", + "end-of-stream": "1.4.0", + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + } + } + }, + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.16.3" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "requires": { + "amdefine": "1.0.1" + } + }, + "source-map-resolve": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.3.1.tgz", + "integrity": "sha1-YQ9hIqRFuN1RU1oqcbeD38Ekh2E=", + "requires": { + "atob": "1.1.3", + "resolve-url": "0.2.1", + "source-map-url": "0.3.0", + "urix": "0.1.0" + } + }, + "source-map-url": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.3.0.tgz", + "integrity": "sha1-fsrxO1e80J2opAxdJp2zN5nUqvk=" + }, + "sshpk": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz", + "integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jodid25519": "1.0.2", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "string-width": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", + "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=" + }, + "tar-stream": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.4.tgz", + "integrity": "sha1-NlSc8E7RrumyowwBQyUiONr5QBY=", + "requires": { + "bl": "1.2.1", + "end-of-stream": "1.4.0", + "readable-stream": "2.3.3", + "xtend": "4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-iso-string": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=" + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=" + }, + "urijs": { + "version": "1.18.10", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.18.10.tgz", + "integrity": "sha1-uURj6rpZoaeWA2pGe7YzxmfyIas=", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=" + }, + "validator": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-7.0.0.tgz", + "integrity": "sha1-x03rgGNRL6w1VHk45vCxUEooL9I=" + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "requires": { + "extsprintf": "1.0.2" + } + }, + "walkdir": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.0.11.tgz", + "integrity": "sha1-oW0CXrkxvQO1LzCMrtD0D86+lTI=" + }, + "wdio-dot-reporter": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/wdio-dot-reporter/-/wdio-dot-reporter-0.0.8.tgz", + "integrity": "sha1-NhlVdtoNmYIQxxlIy7ZfW/Eb/GU=" + }, + "wdio-mocha-framework": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/wdio-mocha-framework/-/wdio-mocha-framework-0.5.10.tgz", + "integrity": "sha1-0fa1sRKahF8nNnLZsq0MS083y6E=", + "requires": { + "babel-runtime": "6.23.0", + "mocha": "2.5.3", + "wdio-sync": "0.6.14" + } + }, + "wdio-sauce-service": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/wdio-sauce-service/-/wdio-sauce-service-0.4.0.tgz", + "integrity": "sha1-OtXc7e4MXNGRGMooe6meYZgs+kk=", + "dev": true, + "requires": { + "request": "2.81.0", + "sauce-connect-launcher": "1.2.2" + } + }, + "wdio-selenium-standalone-service": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/wdio-selenium-standalone-service/-/wdio-selenium-standalone-service-0.0.9.tgz", + "integrity": "sha1-yA1P9Il0TVoLkdUYl2SRbUwMhWQ=", + "dev": true, + "requires": { + "fs-extra": "0.30.0", + "selenium-standalone": "6.5.0" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + } + } + }, + "wdio-sync": { + "version": "0.6.14", + "resolved": "https://registry.npmjs.org/wdio-sync/-/wdio-sync-0.6.14.tgz", + "integrity": "sha1-odzVkHuh0EFUquYXbGItkQw8qbM=", + "requires": { + "babel-runtime": "6.23.0", + "fibers": "1.0.15", + "object.assign": "4.0.4" + } + }, + "webdriverio": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-4.8.0.tgz", + "integrity": "sha1-1Skpt0kID4mWf24WFAUcvIFy0TI=", + "requires": { + "archiver": "1.3.0", + "babel-runtime": "6.23.0", + "css-parse": "2.0.0", + "css-value": "0.0.1", + "deepmerge": "1.3.2", + "ejs": "2.5.6", + "gaze": "1.1.2", + "glob": "7.1.2", + "inquirer": "3.0.6", + "json-stringify-safe": "5.0.1", + "mkdirp": "0.5.1", + "npm-install-package": "2.1.0", + "optimist": "0.6.1", + "q": "1.5.0", + "request": "2.81.0", + "rgb2hex": "0.1.0", + "safe-buffer": "5.0.1", + "supports-color": "3.2.3", + "url": "0.11.0", + "validator": "7.0.0", + "wdio-dot-reporter": "0.0.8", + "wgxpath": "1.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.7" + } + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "wgxpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wgxpath/-/wgxpath-1.0.0.tgz", + "integrity": "sha1-7vikudVYzEla06mit1FZfs2a9pA=" + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yauzl": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.8.0.tgz", + "integrity": "sha1-eUUK/yKyqcWkHvVOAtuQfM+/nuI=", + "dev": true, + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } + }, + "zip-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", + "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", + "requires": { + "archiver-utils": "1.3.0", + "compress-commons": "1.2.0", + "lodash": "4.17.4", + "readable-stream": "2.3.3" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + } + } + } + } +} diff --git a/open_xdmod/modules/xdmod/automated_tests/package.json b/open_xdmod/modules/xdmod/automated_tests/package.json new file mode 100644 index 0000000000..ca3b41352f --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/package.json @@ -0,0 +1,25 @@ +{ + "name": "selenium-tests", + "version": "1.0.0", + "description": "Selenium Tests for XDMod", + "main": "index.js", + "scripts": { + "test": "wdio wdio.conf.js", + "test-sauce": "wdio wdio-sauce.conf.js" + }, + "author": "Ben Plessinger", + "license": "GPL-3.0", + "dependencies": { + "chai": "^3.4.1", + "cheerio": "^0.19.0", + "mocha": "^2.3.4", + "require-dir": "^0.3.0", + "wdio-mocha-framework": "^0.5.10", + "webdriverio": "^4.8.0" + }, + "repository": "https://github.com/ubccr/xdmod", + "devDependencies": { + "wdio-sauce-service": "^0.4.0", + "wdio-selenium-standalone-service": "0.0.9" + } +} diff --git a/open_xdmod/modules/xdmod/automated_tests/readme.md b/open_xdmod/modules/xdmod/automated_tests/readme.md new file mode 100644 index 0000000000..5725d14a61 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/readme.md @@ -0,0 +1,106 @@ +# Automated Regression tests for the XDMoD Frontend + +Based on [webdriver.io][wd] + +## Setup + +```bash +npm install +``` + +This will not work with a "clean" reference database yet. + +You will need to perform the following steps + +1. Login as the user you want the tests to run as +2. Goto the Metric Explorer +3. Add Data + + 1. Jobs + 2. CPU Hours: Total + 3. Group By None (if using Metric Catalog) + +4. Save + +5. Save Changes + +6. Check Available For Report + +7. Switch to the Report Generator Tab +8. Click new +9. Drag untitled query 1 from the Available Charts to Included Charts +10. Click Save + +### wdio.conf.js/wdio-sauce.conf.js + +#### host + +Change the baseUrl to point to the environment you want it pointed to. + +By default this uses the "reference" database set up on . + +```javascript + // Set a base URL in order to shorten url command calls. If your url parameter starts + // with "/", the base url gets prepended. + baseUrl: "https://tas-reference-dbs.ccr.xdmod.org", +``` + +#### browser Options + +Change the browser to run the tests in by changing the list of browsers in the capabilities array. + +``` +InternetExplorer +FireFox +Chrome +Safari +PhantomJS +``` + +By default the tests run only in Chrome. + +```javascript +capabilities: [ + Chrome +], +``` + +##### SauceLabs + +Choose/add another browser to `wdio-sauce.conf.js`, use the [Platform Configurator](https://wiki.saucelabs.com/display/DOCS/Platform+Configurator#/) and add specifications using the same syntax of the `Chrome` and `FireFox` browsers. + +#### Other Options + +In `mochaOpts`, set the `timeout` to desired time length. + +Set `maxInstances` to the desired number of concurrent tests to run at a time. + +_Note:_ The XDMoD SauceLabs account allows for a max of 5 concurrent tests at a time. + +If running tests through SauceLabs, enter the correct `key` for the `xdmod-sauce` account. + +#### template.secrets.json + +```bash +cp template.secrets.json .secrets.json +``` + +modify .secrets.json to have correct username, password, and display name for user being tested. + +## Run + +### run tests locally + +```bash +npm test +``` + +### run tests through sauce labs + +```bash +npm run test-sauce +``` + +and see the fun that is automated ui testing. + +[wd]: http://webdriver.io/ diff --git a/open_xdmod/modules/xdmod/automated_tests/template.secrets.json b/open_xdmod/modules/xdmod/automated_tests/template.secrets.json new file mode 100644 index 0000000000..82d3f98795 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/template.secrets.json @@ -0,0 +1,9 @@ +{ + "role": { + "centerdirector": { + "username": "USERNAME", + "password": "PASSWORD", + "display": "DISPAY NAME" + } + } +} diff --git a/open_xdmod/modules/xdmod/automated_tests/test/helpers/auth.js b/open_xdmod/modules/xdmod/automated_tests/test/helpers/auth.js new file mode 100644 index 0000000000..883adf8ab7 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/helpers/auth.js @@ -0,0 +1,7 @@ +'use strict'; + +var roles = require('./../../.secrets.json').role; + +module.exports = { + roles: roles +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/test/helpers/index.js b/open_xdmod/modules/xdmod/automated_tests/test/helpers/index.js new file mode 100644 index 0000000000..f7c749d520 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/helpers/index.js @@ -0,0 +1 @@ +module.exports = require('require-dir')(); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/helpers/instructions.js b/open_xdmod/modules/xdmod/automated_tests/test/helpers/instructions.js new file mode 100644 index 0000000000..abf42397aa --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/helpers/instructions.js @@ -0,0 +1,10 @@ +// TODO: Look into moving these to files... +var sections = { + metricExplorer: { + instructions: '
No data is available for viewing

Please refer to the instructions below:



For more information, please refer to the User Manual
' + } +}; + +module.exports = function instructions(browser, section, selector) { + expect(browser.getHTML(selector + ' .x-grid-empty')).to.equal(sections[section].instructions); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/test/helpers/metricExplorer.js b/open_xdmod/modules/xdmod/automated_tests/test/helpers/metricExplorer.js new file mode 100644 index 0000000000..7096775fe1 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/helpers/metricExplorer.js @@ -0,0 +1,88 @@ +module.exports = { + tab: '#main_tab_panel__metric_explorer', + metricCatalogEntryByName: function (name) { + return '//div[@id="metric_explorer"]//ul[@class="x-tree-root-ct x-tree-arrows"]//a[@class="x-tree-node-anchor"]//span[contains(text(), "' + name + '")]'; + }, + metricCatalogEntryExpanderByName: function (name) { + return '//div[@id="metric_explorer"]//ul[@class="x-tree-root-ct x-tree-arrows"]//span[contains(text(), "' + name + '")]/ancestor::li//img[@class="x-tree-ec-icon x-tree-elbow-end-plus"]'; + }, + metricContextEntryByName: function (name) { + return '//div[@class="x-menu x-menu-floating x-layer x-menu-nosep"]//span[contains(text(), "' + name + '")]'; + }, + title: "//*[local-name()='svg']/*[local-name()='text' and @class='highcharts-title']/*[local-name()='tspan']", + contextMenuItemByText: function (text) { + return '//div[@class="x-menu x-menu-floating x-layer x-menu-nosep"]//span[contains(text(), "' + text + '")]'; + }, + resizableWindowByTitle: function (title) { + return '//div[contains(@class, "x-window") and contains(@class, "x-resizable-pinned") and contains(@style, "visibility: visible")]//span[@class="x-window-header-text" and text()[contains(.,"' + title + '")]]'; + }, + rawDataEntryByIndex: function (index) { + var thisIndex = (index !== undefined) ? index : 1; + return "(//div[contains(@class, 'x-window') and contains(@style, 'visibility: visible')]//div[contains(@class, 'x-grid3-body')]//div[contains(@class, 'x-grid3-cell-inner') and contains(@class, 'x-grid3-col-local_job_id')])[" + thisIndex + ']'; + }, + startDate: '#metric_explorer input[id^=start_field_ext]', + endDate: '#metric_explorer input[id^=end_field_ext]', + container: '#metric_explorer', + load: { + button: function meLoadButtonId() { + return 'button=Load Chart'; + }, + firstSaved: '.x-menu-floating:not(.x-hide-offsets) .x-grid3-body .x-grid3-row-first', + // This will return the id for the chart number specified in a zero based manner. + // This does not take into account the selected item + chartNum: function meChartByIndex(number) { + var thisNumber = number + 1; + return '.x-menu-floating:not(.x-hide-offsets) .x-grid3-body > div:nth-child(' + thisNumber + ')'; + } + }, + addData: { + button: '.x-btn-text.add_data', + secondLevel: '.x-menu-floating:not(.x-hide-offsets):not(.x-menu-nosep)' + }, + data: { + button: 'button=Data', + container: '', + modal: { + updateButton: 'button=Update', + groupBy: { + input: 'input[name=dimension]' + } + } + }, + deleteChart: '', + undo: function meUndoButtonId() { + // eslint-disable-next-line no-undef + return '#' + $container('button.x-btn-text-icon') + .closest('table') + .attr('id'); + }, + options: { + aggregate: '#aggregate_cb', + button: '#metric_explorer button.chartoptions', + trendLine: '#me_trend_line', + swap: '#me_chart_swap_xy', + title: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] #me_chart_title' + }, + chart: { + svg: '#metric_explorer > div > .x-panel-body-noborder > .x-panel-noborder svg', + title: '#hc-panelmetric_explorer svg .undefinedtitle', + titleInput: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] input[type=text]', + titleOkButton: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] table.x-btn.x-btn-noicon.x-box-item:first-child button', + titleCancelButton: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] table.x-btn.x-btn-noicon.x-box-item:last-child button', + contextMenu: { + container: '#metric-explorer-chartoptions-context-menu', + legend: '#metric-explorer-chartoptions-legend', + addData: '#metric-explorer-chartoptions-add-data', + addFilter: '#metric-explorer-chartoptions-add-filter' + + }, + axis: '#metric_explorer .highcharts-xaxis-labels' + }, + catalog: { + container: '#metric_explorer > div > .x-panel-body-noborder > .x-border-panel:not(.x-panel-noborder)', + tree: '#metric_explorer > div > .x-panel-body-noborder > .x-border-panel:not(.x-panel-noborder) .x-tree-root-ct' + }, + buttonMenu: { + firstLevel: '.x-menu-floating:not(.x-hide-offsets)' + } +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/about.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/about.js new file mode 100644 index 0000000000..9010a5a7fd --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/about.js @@ -0,0 +1,100 @@ +var logIn = require('./loginPage.page.js'); +var loginName = testHelpers.auth.roles.centerdirector.username; +var loginPassword = testHelpers.auth.roles.centerdirector.password; +var displayName = testHelpers.auth.roles.centerdirector.display; +var Abt = require('./about.page.js'); + +describe('About', function about() { + logIn.login('Open XDMoD', '/', loginName, loginPassword, displayName); + describe('Logged In Test', function loggedInTests() { + it('Verify About is the Last Tab', function aboutIsTheLastTab() { + browser.waitForVisible(Abt.tab, 30000); + expect(browser.getText(Abt.last_tab)).to.equal('About'); + }); + + it('Select Tab', function selectTab() { + browser.waitForLoadedThenClick(Abt.tab, 50000); + browser.waitForVisible(Abt.container, 20000); + }); + describe('Check Nav Entries', function checkNavEntries() { + it('XDMoD', function checkNavEntryXDMoD() { + Abt.checkTab('XDMoD'); + }); + it('Open XDMoD', function checkNavEntryXDMoD() { + Abt.checkTab('Open XDMoD'); + }); + it('SUPReMM', function checkNavEntrySUPReMM() { + Abt.checkTab('SUPReMM'); + }); + it('Roadmap', function checkNavEntryXDMoD() { + Abt.checkRoadmap(); + }); + it('Team', function checkNavEntryXDMoD() { + Abt.checkTab('Team'); + }); + it('Publications', function checkNavEntryXDMoD() { + Abt.checkTab('Publications'); + }); + it('Presentations', function checkNavEntryXDMoD() { + Abt.checkTab('Presentations'); + }); + it('Links', function checkNavEntryXDMoD() { + Abt.checkTab('Links'); + }); + it('Release Notes', function checkNavEntryXDMoD() { + Abt.checkTab('Release Notes'); + }); + }); + }); + + describe('Logged Out Tests', function loggedInTests() { + it('Click the logout link', function clickLogout() { + browser.waitForLoadedThenClick('#logout_link', 50000); + }); + it('Display Logged out State', function clickLogout() { + browser.waitUntilNotExist('.ext-el-mask-msg'); + $('a[href*=actionLogin]').waitForExist(); + }); + + it('Verify About is the Last Tab', function aboutIsTheLastTab() { + browser.waitForVisible(Abt.tab, 30000); + expect(browser.getText(Abt.last_tab)).to.equal('About'); + }); + + it('Select Tab', function selectTab() { + browser.waitForLoadedThenClick(Abt.tab, 50000); + browser.waitForVisible(Abt.container, 20000); + }); + describe('Check Nav Entries', function checkNavEntries() { + it('XDMoD', function checkNavEntryXDMoD() { + Abt.checkTab('XDMoD'); + }); + it('Open XDMoD', function checkNavEntryXDMoD() { + Abt.checkTab('Open XDMoD'); + }); + it('SUPReMM', function checkNavEntrySUPReMM() { + Abt.checkTab('SUPReMM'); + }); + it('Roadmap', function checkNavEntryXDMoD() { + Abt.checkRoadmap(); + }); + it('Team', function checkNavEntryXDMoD() { + Abt.checkTab('Team'); + }); + it('Publications', function checkNavEntryXDMoD() { + Abt.checkTab('Publications'); + }); + it('Presentations', function checkNavEntryXDMoD() { + Abt.checkTab('Presentations'); + }); + it('Links', function checkNavEntryXDMoD() { + Abt.checkTab('Links'); + }); + it('Release Notes', function checkNavEntryXDMoD() { + Abt.checkTab('Release Notes'); + }); + }); + }); + logIn.login('Open XDMoD', '/', loginName, loginPassword, displayName); + logIn.logout(); +}); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/about.page.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/about.page.js new file mode 100644 index 0000000000..6e351bab78 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/about.page.js @@ -0,0 +1,33 @@ +class About { + constructor() { + this.tab = '//ul[contains(@class, "x-tab-strip")]//span[text()="About"]'; + this.container = '//div[@id="about_xdmod"]'; + this.center = '//div[@id="about_xdmod"]//div[contains(@class, "x-panel-body") and contains(@class, "x-border-layout-ct")]/div[contains(@class,"x-panel") and contains(@class,"x-panel-reset") and contains(@class,"x-border-panel")]'; + this.last_tab = '//ul[contains(@class, "x-tab-strip")]//li[contains(@class, "tab-strip")][last()]'; + } + + navEntry(name) { + return '//div[@class="x-tree-root-node"]//div[contains(@class,"x-tree-node-el")]//span[contains(text(),"' + name + '")]'; + } + + checkTab(name) { + browser.waitForLoadedThenClick(this.navEntry(name), 50000); + $(this.container).waitForText(50000); + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(name.replace(' ',''), this.center, "xdmod"); + } + + checkRoadmap() { + browser.waitForLoadedThenClick(this.navEntry('Roadmap')); + browser.waitForExist('iframe#about_roadmap', 30000); + browser.frame('about_roadmap', function (err, result) { + expect(err).to.be.a('undefined'); + expect(result).to.not.be.a('null'); + }); + browser.waitForExist('.trello-lists', 30000); + browser.waitForText('.trello-lists', 30000); + browser.frameParent(); + } + +} +module.exports = new About(); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/loginPage.page.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/loginPage.page.js new file mode 100644 index 0000000000..0394214664 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/loginPage.page.js @@ -0,0 +1,53 @@ +class LoginPage { + login(title, theUrl, loginName, loginPassword, displayName) { + describe('General', function () { + it('Verify Logo and Title', function () { + browser.url(theUrl); + expect(browser.getTitle()).to.equal(title); + // $(this.logo).waitForVisible(2000); + $('#logo').waitForVisible(2000); + var logoSize = browser.getElementSize('#logo'); + expect(logoSize.width).to.equal(93); + expect(logoSize.height).to.equal(32); + }); + }); + describe('Login', function login() { + it('Click the login link', function clickLogin() { + browser.waitUntilNotExist('.ext-el-mask-msg'); + $('a[href*=actionLogin]').click(); + }); + it('Should Login', function doLogin() { + $('.x-window-header-text=Welcome To XDMoD').waitForExist(20000); + $('#wnd_login iframe').waitForExist(20000); + browser.frame($('#wnd_login iframe').value); + $('#txt_login_username input').setValue(loginName); + $('#txt_login_password input').setValue(loginPassword); + $('#btn_sign_in .x-btn-mc').click(); + }); + it('Display Logged in Users Name', function () { + $('#welcome_message').waitForExist(60000); + expect($('#welcome_message').getText()).to.equal(displayName); + }); + }); + } + logout() { + describe('Logout', function logout() { + it('Click the logout link', function clickLogout() { + browser.pause(1000); + $('#logout_link').waitForVisible(); + $('#logout_link').click(); + }); + it('Display Logged out State', function clickLogout() { + browser.waitUntilNotExist('.ext-el-mask-msg'); + $('a[href*=actionLogin]').waitForExist(); + }); + }); +/* + describe("Update Screenshot Repository", function screenshots() { + it("Should upload screenshots", function screenshotsSync() { + //return browser.sync(); + }); + });*/ + } +} +module.exports = new LoginPage(); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/mainToolbar.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/mainToolbar.js new file mode 100644 index 0000000000..d932a214c4 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/mainToolbar.js @@ -0,0 +1,42 @@ +var logIn = require('./loginPage.page.js'); +var loginName = testHelpers.auth.roles.centerdirector.username; +var loginPassword = testHelpers.auth.roles.centerdirector.password; +var displayName = testHelpers.auth.roles.centerdirector.display; +var mTb = require('./mainToolbar.page.js'); +var mainTab; + +describe('Main Toolbar', function () { + logIn.login('Open XDMoD', '/', loginName, loginPassword, displayName); + describe('Check Tab', function xdmod() { + it('Get Browser Tab ID', function () { + mainTab = browser.getCurrentTabId(); + }); + it("About should change 'Tabs'", function () { + mTb.checkAbout(); + }); + }); + describe('Contact Us', function () { + for (var type in mTb.contactTypes) { + if (mTb.contactTypes.hasOwnProperty(type)) { + // TODO: Fix this with Page Objects? + // eslint-disable-next-line no-loop-func + it(type, function () { + mTb.contactFunc(type); + }); + } + } + }); + describe('Help', function () { + for (var type in mTb.helpTypes) { + if (mTb.helpTypes.hasOwnProperty(type)) { + // TODO: Fix this with Page Objects? + // eslint-disable-next-line no-loop-func + it(type, function () { + mTb.helpFunc(type, mainTab); + browser.pause(1500); + }); + } + } + }); + logIn.logout(); +}); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/mainToolbar.page.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/mainToolbar.page.js new file mode 100644 index 0000000000..a34803d0b3 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/mainToolbar.page.js @@ -0,0 +1,57 @@ +class MainToolbar { + constructor() { + this.helpTypes = { + Manual: '#global-toolbar-help-user-manual', + 'You Tube': '#global-toolbar-help-youtube' + }; + this.contactTypes = { + 'Submit Support Request': '#global-toolbar-contact-us-submit-support-request', + 'Send Message': '#global-toolbar-contact-us-send-message', + 'Request Feature': '#global-toolbar-contact-us-request-feature' + }; + this.toolbarClose = '.x-window .x-tool-close'; + this.toolbarAbout = '#global-toolbar-about'; + this.contactus = '#global-toolbar-contact-us'; + this.help = '#help_button'; + this.about = '#about_xdmod'; + this.container = '.x-window'; + this.header = '.x-window .x-window-header .x-window-header-text'; + this.floatlayer = 'div.x-menu.x-menu-floating.x-layer'; + this.note = '.x-window.x-notification'; + } + helpFunc(type, mainTab) { + $(this.help).click(); + browser.waitForExist(this.floatlayer); + browser.waitForExist(this.helpTypes[type]); + browser.click(this.helpTypes[type]); + var ids = browser.windowHandles().value; + var id = ids.length; + expect(id).to.equal(2); + while (id--) { + if (ids[id] !== mainTab) { + browser.window(ids[id]); + browser.close(); + } + } + browser.window(mainTab); + } + contactFunc(type) { + browser.waitUntilNotExist(this.note); + $(this.contactus).click(); + browser.waitForExist(this.floatlayer); + browser.waitForExist(this.contactTypes[type]); + browser.click(this.contactTypes[type]); + browser.waitForExist(this.container); + expect(browser.getText(this.header)).to.be.equal(type); + browser.pause(500); + browser.waitForExist(this.toolbarClose); + browser.click(this.toolbarClose); + } + checkAbout() { + browser.waitForExist(this.toolbarAbout); + browser.pause(5000); + browser.click(this.toolbarAbout); + browser.waitForExist(this.about); + } +} +module.exports = new MainToolbar(); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/metricExplorer.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/metricExplorer.js new file mode 100644 index 0000000000..48d7a7fd0c --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/metricExplorer.js @@ -0,0 +1,460 @@ +var logIn = require('./loginPage.page.js'); +var me = require('./metricExplorer.page.js'); +var cheerio = require('cheerio'); +describe('Metric Explorer', function metricExplorer() { + var baselineDate = { + start: '2016-12-22', + end: '2017-01-01' + }; + var $container; + var actions = { + chart: { + load: function (chartNumber) { + var mychartNumber = chartNumber || 0; + it('Load Chart', function () { + me.actionLoadChart(mychartNumber); + }); + }, + contextMenu: { + open: function chartContextMenuOpen() { + it('Open Chart Context Menu', function () { + // TODO: Find a better way to open this. Currently there is a chance + // that the click will open the dataseries menu + browser.waitAndClick('#hc-panelmetric_explorer', 10000); + }); + }, + addData: function () { + it('Should Display', function () { + browser.waitAndClick('#hc-panelmetric_explorer', 10000); + browser.waitAndClick(me.selectors.chart.contextMenu.addData, 10000); + browser.waitForVisible('#metric-explorer-chartoptions-add-data-menu', 10000); + browser.click('#logo'); + }); + }, + addFilter: function () { + it('Should Display', function () { + browser.waitAndClick('#hc-panelmetric_explorer', 10000); + browser.waitAndClick(me.selectors.chart.contextMenu.addFilter, 10000); + browser.waitForVisible('#metric-explorer-chartoptions-add-filter-menu', 10000); + browser.click('#logo'); + }); + }, + legend: function () { + it('Click Legend', function selectLegend() { + browser.waitAndClick(me.selectors.chart.contextMenu.legend, 10000); + }); + }, + setLegendPosition: function chartContextMenuLegendPosition(position) { + describe('Set Legend ' + position, function setLegend() { + actions.chart.contextMenu.open(); + actions.chart.contextMenu.legend(); + it('Click ' + position, function selectLegendPosition() { + var posId = me.selectors.chart.contextMenu.legend + '-' + + position.toLowerCase().replace(/ /g, '-'); + browser.waitAndClick(posId); + browser.waitForChart(); + }); + }); + } + } + } + }; + var loginName = testHelpers.auth.roles.centerdirector.username; + var loginPassword = testHelpers.auth.roles.centerdirector.password; + var displayName = testHelpers.auth.roles.centerdirector.display; + logIn.login('Open XDMoD', '/', loginName, loginPassword, displayName); + describe('Select Tab', function xdmod() { + it('Selected', function meSelect() { + browser.waitForLoadedThenClick(me.selectors.tab); + browser.waitForVisible(me.selectors.container, 3000); + $container = cheerio.load(browser.getHTML(me.selectors.container)); + }); + }); + describe('Basic Scenarios', function basicScenarios() { + it('Has Instructions', function meConfirmInstructions() { + testHelpers.instructions(browser, 'metricExplorer', me.selectors.container); + }); + it('Instructions look the same as previous run', function () { + browser.waitForVisible(me.selectors.catalog.container, 10000); + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "instructions") + }); + it('Has three toolbars', function meConfirmToolbars() { + expect($container('.x-toolbar').length).to.equal(3); + }); + it('Has one canned Date Picker', function meConfirmDatePicker() { + // TODO: Make Datepicker have a unique name + expect($container('table[id^=canned_dates]').length).to.equal(1); + }); + + it('Set a known start date', function meSetStartEnd() { + browser.waitForVisible(me.selectors.startDate, 10000); + browser.click(me.selectors.startDate); + browser.setValue(me.selectors.startDate, baselineDate.start); + }); + + it('Set a known end date', function meSetStartEnd() { + browser.waitForVisible(me.selectors.endDate, 10000); + browser.click(me.selectors.endDate); + browser.setValue(me.selectors.endDate, baselineDate.end); + }); + it("'Add Data' via toolbar", function meAddData1() { + // click on CPU Hours: Total + me.addDataViaMenu('.ext-el-mask-msg', '3'); + browser.waitAndClick('#adp_submit_button'); + }); + it('Scratchpad looks the same as previous run', function () { + browser.waitForChart(); + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "scratchpad.01.source") + // browser.pause(5000); + }); + + it("'Add Data' again via toolbar", function meAddData2() { + me.addDataViaToolbar(); + }); + it('Chart looks the same as previous run', function () { + browser.waitForChart(); + // browser.takeScreenshot(moduleName, me.selectors.container, "scratchpad.02.sources") + }); + it('Switch to aggregate chart (expect incompatible metric error)', function () { + me.switchToAggregate(); + // browser.takeScreenshot(moduleName, me.selectors.container, "scratchpad.02.aggregate") + }); + it('Undo Scratch Pad switch to aggregate', function () { + me.undoAggregateOrTrendLine($container); + }); + it('Chart looks the same as previous run', function () { + browser.waitForChart(); + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "scratchpad.undo.02.aggregate") + // browser.pause(3000); + }); + it('Undo Scratch Pad second source', function meUndoScratchPad() { + browser.waitAndClick(me.undo($container)); + // The mouse stays and causes a hover, lets move the mouse somewhere else + browser.waitAndClick('.xtb-text.logo93'); + }); + it('Chart looks the same as previous run', function () { + browser.waitForChart(); + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "scratchpad.undo.02.source") + // browser.pause(3000); + }); + /* + it("Swap the X and Y axis", function(){ + me.axisSwap() + }); + */ + it('Attempt Delete Scratchpad Chart', function meDeleteScratchPad() { + me.attemptDeleteScratchpad(cheerio); + }); + it('Chart looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "scratchpad.delete.confirm") + // browser.pause(1000); + }); + it('Delete Scratchpad Chart', function meValidateDeletedScratchPad() { + browser.waitAndClick(me.selectors.deleteChart); + }); + it('Chart looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "scratchpad.delete.complete") + // browser.pause(1000); + }); + it('Open load chart dialog', function meLoadChart() { + browser.click(me.selectors.load.button()); + }); + it('Load chart dialog looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "load.dialog") + // browser.pause(1000); + }); + it('Open chart from load dialog', function meOpenChart() { + // TODO: Need to make sure to select the same chart every time, not just the first for screenshots + browser.waitAndClick(me.selectors.load.chartNum(0)); + browser.waitForChart(); + }); + it('Loaded chart looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "load.chart") + // browser.pause(1000); + }); + it('Open Chart Options', function meChartOptions() { + browser.waitAndClick(me.selectors.options.button); + }); + it('Chart options looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "chart.options") + // browser.pause(1000); + }); + it('Show Trend Line via Chart Options', function meAddTrendLine() { + browser.waitAndClick(me.selectors.options.trendLine); + browser.waitAndClick(me.selectors.options.button); + }); + it('Trend Line looks the same as previous run', function () { + browser.waitForChart(); + // browser.takeScreenshot(moduleName, me.selectors.container, "chart.trendline") + browser.pause(3000); + }); + it('Undo Trend Line', function meUndoTrendLine() { + me.undoAggregateOrTrendLine($container); + browser.waitForChart(); + }); + it('Undo Trend Line looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "saved.chart.undo.trendline") + // browser.pause(2000); + }); + }); + describe('Context Menu', function contextMenu() { + it('Start with scratchpad', function () { + browser.refresh(); + browser.pause(10000); + me.clear(); + browser.pause(2000); + }); + + it('Attempt Delete Scratchpad Chart', function meDeleteScratchPad() { + me.attemptDeleteScratchpad(cheerio); + }); + it('Delete Scratchpad Chart', function meValidateDeletedScratchPad() { + browser.waitAndClick(me.selectors.deleteChart); + }); + + it('Set a known start date', function meSetStartEnd() { + browser.waitForVisible('#metric_explorer input[id^=start_field_ext]', 10000); + browser.setValue('#metric_explorer input[id^=start_field_ext]', baselineDate.start); + }); + + it('Set a known end date', function meSetStartEnd() { + browser.waitForVisible('#metric_explorer input[id^=end_field_ext]', 10000); + browser.setValue('#metric_explorer input[id^=end_field_ext]', baselineDate.end); + }); + + it('Wait For Metric Catalog', function () { + browser.pause(3000); + browser.waitUntilNotExist('.ext-el-mask-msg'); + browser.waitForVisible(me.selectors.catalog.container, 10000); + }); + it('Generic Starting Point', function () { + me.genericStartingPoint(); + }); + + describe('Add Data Menu', function () { + actions.chart.contextMenu.addData(); + }); + describe('Add Filter Menu', function () { + actions.chart.contextMenu.addFilter(); + }); + describe('Legend Menus', function () { + actions.chart.contextMenu.setLegendPosition('Top Left'); + actions.chart.contextMenu.setLegendPosition('Top Right'); + browser.pause(5000); + describe('Verify after load', function () { + actions.chart.load(1); + actions.chart.contextMenu.open(); + actions.chart.contextMenu.legend(); + it('legend Items set Properly', function () { + browser.waitForVisible('#metric-explorer-chartoptions-legend-options', 2000); + var legendText = browser.getText('#metric-explorer-chartoptions-legend-options .x-menu-item-checked'); + expect(legendText).to.equal('Bottom Center (Default)', 'Loaded chart has non default legend'); + }); + }); + }); + }); + describe('Pie Charts', function pieCharts() { + describe("Can't use timeseries data", function noTimeSeries() { + it('Start with scratchpad', function () { + me.clear(); + }); + it("Add Data via the 'Add Data' Menu", function addData() { + // 'Add Data' via the 'Add Data' menu: + // 'Add Data' -> Jobs -> CPU Hours: Total -> 'Add' + // wait for the global mask to disapear + me.addDataViaMenu('.ext-el-mask-msg', '2'); + }); + it("Set 'Group By' to resource", function findGroupBy() { + me.setGroupByToResource(); + }); + it("'Add' data", function add() { + browser.waitAndClick('#adp_submit_button'); + browser.waitUntilNotExist('.ext-el-mask'); + }); + it('Verify that the chart has been rendered', function chartRendered() { + // Attempt to ascertain if the HighChartPanel ( the panel that contains the chart contents ) is hidden or not. + // Pause so we can determine if the chart was actually loaded. + browser.waitForVisible('#hc-panelmetric_explorer', 3000); + // If the chart was successfully loaded / rendered this should return false. + var execReturn = browser.execute('return CCR.xdmod.ui.metricExplorer.chartViewPanel.items.get(0).hidden;').value; + expect(execReturn).to.equal(false); + }); + it('Chart looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "pie.loaded"); + }); + it("Select the 'Data' toolbar button", function selectData() { + browser.click(me.selectors.data.button); + }); + it('Click the First Row', function jobsRow() { + browser.waitForVisible('.x-menu-floating:not(.x-hide-offsets)'); + browser.execute('return CCR.xdmod.ui.metricExplorer.datasetsGridPanel.getView().getRow(0)').doubleClick(); + }); + it("Set 'Display Type' to 'Pie'", function clickDisplayType() { + me.setToPie(); + }); + it('Verify error message', function checkErrorMessage() { + me.verifyError(); + }); + }); + describe('Aggregate data', function useAggregateData() { + it('Start with scratchpad', function freshChart() { + me.clear(); + }); + }); // Aggregate data + }); // Pie Charts + describe('Chart Interactions', function chartInteractions() { + it('Should start with a new chart', function newChart() { + me.clear(); + }); + describe('Should start start with a dataset', function dataset() { + it("Add Data via the 'Add Data' Menu", function addData() { + // 'Add Data' via the 'Add Data' menu: + // 'Add Data' -> Jobs -> CPU Hours: Total -> 'Add' + // wait for the global mask to disapear + me.addDataViaMenu('div.x-panel.x-masked-relative.x-masked', '2'); + }); + it("Set 'Group By' to resource", function findGroupBy() { + me.setGroupByToResource(); + }); + it("'Add' data", function add() { + browser.waitAndClick('#adp_submit_button'); + browser.waitUntilNotExist('.ext-el-mask'); + }); + it('Verify that the chart has been rendered', function chartRendered() { + // Attempt to ascertain if the HighChartPanel ( the panel that contains the chart contents ) is hidden or not. + // Pause so we can determine if the chart was actually loaded. + browser.waitForChart(); + browser.pause(750); + // If the chart was successfully loaded / rendered this should return false. + var execReturn = browser.execute('return CCR.xdmod.ui.metricExplorer.chartViewPanel.items.get(0).hidden;'); + expect(execReturn.value).to.equal(false); + }); + it('Chart looks the same as previous run', function () { + // TODO: Determine Pass case for this without using screenshot + // browser.takeScreenshot(moduleName, me.selectors.container, "highcharts.loaded") + }); + }); // Should start with a dataset. + + describe('Chart Titles', function chartTitle() { + describe('Update the Chart Title with a value that contains html entities', function editChartTitleDialog() { + it('Click the Chart Title element', function clickChartTitleElement() { + browser.waitAndClick(me.selectors.chart.title); + browser.waitForVisible(me.selectors.chart.titleInput, 3000); + }); + + it('Update the Chart Title input element', function editChartTitle() { + browser.pause(2000); + browser.clearElement(me.selectors.chart.titleInput); + browser.setValue(me.selectors.chart.titleInput, me.newTitle); + }); + + it('Click the Ok element', function clickOkElement() { + browser.pause(2000); + browser.waitAndClick(me.selectors.chart.titleOkButton); + }); + + it('Chart Title element should be updated', function checkChartTitle() { + browser.pause(2500); + me.verifyHighChartsTitle(me.newTitle); + }); + + it('Chart Title in Chart Options should be updated', function verifyChartOptions() { + me.chartTitleInOptionsUpdated(); + }); + }); + + describe('Set the title to a value that does not include html entities', function noHtmlEntities() { + it('click the Chart Title', function clickChartTitle() { + browser.waitForVisible(me.selectors.chart.title, 3000); + browser.click(me.selectors.chart.title); + browser.waitForVisible(me.selectors.chart.titleInput, 3000); + }); + + it('clear the title field', function clearTitleField() { + browser.clearElement(me.selectors.chart.titleInput); + }); + + it('set the title field to a value that does not contain html entities.', function setWithNoEntities() { + browser.pause(500); + browser.setValue(me.selectors.chart.titleInput, me.originalTitle); + browser.pause(2000); + }); + + it("click 'ok' to confirm the change", function confirmTheChange() { + browser.click(me.selectors.chart.titleOkButton); + browser.waitForVisible(me.selectors.chart.title, 3000); + }); + + it('get the new value from the chart title to verify that it has in fact changed', function checkNewValue() { + browser.pause(500); + var execReturn = browser.execute('return document.querySelector("' + me.selectors.chart.title + '").textContent;'); + expect(execReturn.value).to.be.a('string'); + expect(execReturn.value).to.equal(me.originalTitle); + }); + }); + + describe('Arrow Keys', function () { + it('Arrow keys can be used in chart options title', function () { + me.arrowKeys(); + }); + }); + describe('Accept html entity input via the Chart Options -> Chart Title element.', function editChartTitleChartOptions() { + it('set the Chart Options -> Chart Title value with html entities', function setTitleWithHtmlEntities() { + browser.pause(2000); + me.setTitleWithOptionsMenu(me.newTitle); + browser.pause(2000); + }); + it('click the Chart Options button again', function clickChartOptions() { + browser.waitForChart(); + browser.waitAndClick(me.selectors.options.button); + browser.waitForChart(); + browser.pause(3000); + }); + it('verify that the HighCharts chart title has the new value', function highChartsTitle() { + me.verifyHighChartsTitle(me.newTitle); + }); + it('verify that the Edit Chart Title Modal has the new value', function chartTitleModal() { + me.verifyEditChartTitle(); + }); + }); + + describe('Providing an empty title value', function shouldAcceptEmptyTitle() { + it('Set the chart title to an empty value', function setTitleEmpty() { + me.setChartTitleViaChart(''); + }); + + it('Get the new chart title and confirm that no svg element was generated', function confirmEmptyChartTitle() { + browser.pause(500); + var titleChange = browser.execute('return document.querySelector("' + me.selectors.chart.title + '");'); + // expect(titleChange.state).to.equal('success'); + expect(titleChange._status).to.equal(0); + expect(titleChange.value).to.equal(null); + }); + }); + + describe('Providing an exceptionally large title should be ok', function shouldNotAcceptLargeTitle() { + var largeTitle = me.generateTitle(900); + it('Set the chart title to an exceptionally large value (' + largeTitle.length + ')', function setALargeTitle() { + me.setTitleWithOptionsMenu(largeTitle); + browser.waitAndClick(me.selectors.options.button); + }); + + it('Confirm that the chart title has been changed', function confirmTheTitleWasSet() { + me.confirmChartTitleChange(largeTitle); + }); + }); + }); + }); + logIn.logout(); +}); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/metricExplorer.page.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/metricExplorer.page.js new file mode 100644 index 0000000000..7ef9e6982e --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/metricExplorer.page.js @@ -0,0 +1,263 @@ +class MetricExplorer { + constructor() { + this.meselectors = testHelpers.metricExplorer; + this.originalTitle = '(untitled query 2)'; + this.newTitle = '"& (untitled query) 2 &"'; + this.possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + this.selectors = { + tab: '#main_tab_panel__metric_explorer', + startDate: '#metric_explorer input[id^=start_field_ext]', + endDate: '#metric_explorer input[id^=end_field_ext]', + container: '#metric_explorer', + load: { + button: function meLoadButtonId() { + return 'button=Load Chart'; + }, + firstSaved: '.x-menu-floating:not(.x-hide-offsets) .x-grid3-body .x-grid3-row-first', + chartNum: function meChartByIndex(number) { + var mynumber = number + 1; + return '.x-menu-floating:not(.x-hide-offsets) .x-grid3-body > div:nth-child(' + mynumber + ')'; + } + }, + addData: { + button: '.x-btn-text.add_data', + secondLevel: '.x-menu-floating:not(.x-hide-offsets):not(.x-menu-nosep)' + }, + data: { + button: 'button=Data', + container: '', + modal: { + updateButton: 'button=Update', + groupBy: { + input: 'input[name=dimension]' + } + } + }, + deleteChart: '', + options: { + aggregate: '#aggregate_cb', + button: '#metric_explorer button.chartoptions', + trendLine: '#me_trend_line', + swap: '#me_chart_swap_xy', + title: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] #me_chart_title' + }, + chart: { + svg: '#metric_explorer > div > .x-panel-body-noborder > .x-panel-noborder svg', + title: '#hc-panelmetric_explorer svg .undefinedtitle', + titleInput: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] input[type=text]', + titleOkButton: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] table.x-btn.x-btn-noicon.x-box-item:first-child button', + titleCancelButton: 'div.x-menu.x-menu-floating.x-layer.x-menu-nosep[style*="visibility: visible"] table.x-btn.x-btn-noicon.x-box-item:last-child button', + contextMenu: { + container: '#metric-explorer-chartoptions-context-menu', + legend: '#metric-explorer-chartoptions-legend', + addData: '#metric-explorer-chartoptions-add-data', + addFilter: '#metric-explorer-chartoptions-add-filter' + + }, + axis: '#metric_explorer .highcharts-yaxis-labels' + }, + catalog: { + container: '#metric_explorer > div > .x-panel-body-noborder > .x-border-panel:not(.x-panel-noborder)', + tree: '#metric_explorer > div > .x-panel-body-noborder > .x-border-panel:not(.x-panel-noborder) .x-tree-root-ct' + }, + buttonMenu: { + firstLevel: '.x-menu-floating:not(.x-hide-offsets)' + } + }; + } + undo($container) { + return '#' + $container('button.x-btn-text-icon') + .closest('table') + .attr('id'); + } + clear() { + browser.refresh(); + browser.waitForVisible('#logout_link', 3000); + } + generateTitle(size) { + var result = ''; + for (var i = 0; i < size; i++) { + result += this.possible.charAt(Math.floor(Math.random() * this.possible.length)); + } + return result; + } + setToPie() { + browser.execute("return document.getElementsByName('display_type')[0];").click(); + browser.execute("return document.querySelector('div.x-layer.x-combo-list[style*=\"visibility: visible\"] div.x-combo-list-inner div.x-combo-list-item:last-child');").click(); + } + + verifyError() { + var invalidChart = browser.execute("return document.querySelectorAll('div.x-window.x-window-plain.x-window-dlg[style*=\"visibility: visible\"] span.x-window-header-text')[0];").getText(); + expect(invalidChart).to.equal('Invalid Chart Display Type'); + var errorText = browser.execute("return document.querySelectorAll('div.x-window.x-window-plain.x-window-dlg[style*=\"visibility: visible\"] span.ext-mb-text')[0];").getText(); + expect(errorText).to.contain('You cannot display timeseries data in a pie chart.'); + expect(errorText).to.contain('Please change the dataset or display type.'); + } + + arrowKeys() { + browser.waitForChart(); + browser.waitForLoadedThenClick(this.selectors.options.button); + browser.waitForLoadedThenClick(this.selectors.options.title); + var cursorPosition = browser.execute('return document.getElementById("me_chart_title").selectionStart;'); + expect(cursorPosition._status).to.equal(0); + expect(cursorPosition.value).to.equal(this.originalTitle.length, 'Cursor Position not at end'); + browser.keys('Arrow_Up'); + var newPosition = browser.execute('return document.getElementById("me_chart_title").selectionStart;'); + expect(newPosition._status).to.equal(0); + expect(newPosition.value).to.equal(0, 'Cursor Position not at begining'); + browser.waitAndClick(this.selectors.options.button); + } + addDataViaMenu(maskName, n) { + browser.waitUntilNotExist(maskName); + browser.waitForVisible(this.selectors.catalog.container, 5000); + browser.waitAndClick(this.selectors.addData.button); + browser.waitAndClick(this.selectors.buttonMenu.firstLevel + ' ul li:nth-child(3)'); + browser.waitAndClick(this.selectors.addData.secondLevel + ' ul li:nth-child(' + n + ')'); + } + setTitleWithOptionsMenu(title) { + browser.waitForChart(); + browser.waitAndClick(this.selectors.options.button); + browser.waitForVisible(this.selectors.options.title, 5000); + browser.clearElement(this.selectors.options.title); + browser.pause(500); + browser.setValue(this.selectors.options.title, title); + } + verifyHighChartsTitle(title) { + var execReturn = browser.execute('return Ext.util.Format.htmlDecode(document.querySelector("' + this.selectors.chart.title + '").textContent);'); + expect(execReturn._status).to.equal(0); + expect(execReturn.value).to.be.a('string'); + expect(execReturn.value).to.equal(title); + } + verifyEditChartTitle() { + browser.waitAndClick(this.selectors.chart.title); + browser.waitForVisible(this.selectors.chart.titleInput); + var titleValue = browser.getValue(this.selectors.chart.titleInput); + expect(titleValue).to.be.a('string'); + expect(titleValue).to.equal(this.newTitle); + browser.waitAndClick(this.selectors.chart.titleOkButton); + browser.waitForChart(); + } + setChartTitleViaChart(title) { + browser.waitForChart(); + browser.waitAndClick(this.selectors.chart.title); + browser.waitForVisible(this.selectors.chart.titleInput); + browser.clearElement(this.selectors.chart.titleInput); + browser.setValue(this.selectors.chart.titleInput, title); + browser.pause(500); + browser.waitAndClick(this.selectors.chart.titleOkButton); + } + setGroupByToResource() { + browser.click(this.selectors.data.modal.groupBy.input); + browser.pause(1000); + browser.execute("return document.querySelectorAll('div.x-layer.x-combo-list[style*=\"visibility: visible\"] .x-combo-list-item:nth-child(10)')[0];").click(); + } + axisSwap() { + var axisFirstChildText = ''; + var axisSecondChildText = ''; + axisFirstChildText = browser.getText(this.selectors.chart.axis + ' text'); + browser.waitAndClick(this.selectors.options.button); + browser.waitAndClick(this.selectors.options.swap); + // browser.pause(1000); + axisSecondChildText = browser.getText(this.selectors.chart.axis + ' text'); + // browser.waitForChart(); + browser.pause(1000); + browser.waitAndClick(this.selectors.options.button); + // browser.pause(1000); + expect(axisFirstChildText[1]).to.not.equal(axisSecondChildText[1]); + browser.pause(10000); + } + chartTitleInOptionsUpdated() { + browser.waitForChart(); + browser.waitAndClick(this.selectors.options.button); + browser.waitForVisible(this.selectors.options.title, 3000); + var res1 = browser.getValue(this.selectors.options.title); + expect(res1).to.be.a('string'); + var res2 = browser.execute(function (text) { + // TODO: Fix this withOut having to use EXT if Possible + // eslint-disable-next-line no-undef + return Ext.util.Format.htmlDecode(text); + }, res1); + expect(res2.value).to.equal(this.newTitle); + browser.waitForChart(); + browser.waitAndClick(this.selectors.options.button); + } + attemptDeleteScratchpad(cheerio) { + browser.waitAndClick('.x-btn-text.delete2'); + // this gets the buttons, however, not able to get just the yes button + // $$(".x-window-dlg .x-toolbar-cell:not(.x-hide-offsets) table"); + browser.waitForVisible('.x-window-dlg .x-toolbar-cell:not(.x-hide-offsets) table'); + var $yesButton = cheerio.load(browser.getHTML('.x-window-dlg .x-toolbar-cell:not(.x-hide-offsets) table')[0]); + this.selectors.deleteChart = '#' + $yesButton('table').attr('id'); + } + actionLoadChart(chartNumber) { + browser.pause(3000); + browser.waitAndClick(this.selectors.load.button(), 2000); + browser.waitAndClick(this.selectors.load.chartNum(chartNumber), 2000); + browser.waitForChart(); + } + addDataViaToolbar() { + browser.click(this.selectors.addData.button); + // Click on Jobs + browser.waitAndClick(this.selectors.buttonMenu.firstLevel + ' ul li:nth-child(3)'); + // click on CPU Hours: Per Job + browser.waitAndClick(this.selectors.addData.secondLevel + ' ul li:nth-child(2)'); + browser.waitAndClick('#adp_submit_button'); + } + genericStartingPoint() { + browser.waitAndClick(this.selectors.addData.button); + // Click on Jobs (5 on original site) + browser.waitAndClick(this.selectors.buttonMenu.firstLevel + ' ul li:nth-child(3)'); + // click on CPU Hours: Total + browser.waitAndClick(this.selectors.addData.secondLevel + ' ul li:nth-child(3)', 1000); + // browser.waitAndClick("#adp_submit_button", 4000) + browser.click('#adp_submit_button'); + } + confirmChartTitleChange(largeTitle) { + browser.waitForChart(); + browser.pause(2000); + var titleChange = browser.execute('return document.querySelector("' + this.selectors.chart.title + '").textContent;'); + // expect(titleChange.state).to.equal('success'); + expect(titleChange._status).to.equal(0); + expect(titleChange.value).to.be.a('string'); + expect(titleChange.value).to.equal(largeTitle); + } + + switchToAggregate() { + browser.pause(3000); + browser.waitAndClick(this.selectors.options.button); + browser.waitAndClick(this.selectors.options.aggregate); + browser.waitForChart(); + } + + undoAggregateOrTrendLine($container) { + browser.pause(3000); + browser.waitAndClick(this.undo($container)); + browser.pause(3000); + // The mouse stays and causes a hover, lets move the mouse somewhere else + browser.waitAndClick('.xtb-text.logo93'); + } + + clickFirstDataPoint() { + var seriesIndex = 0; + var pointIndex = 0; + browser.moveToObject('#hc-panelmetric_explorer', 0, 0); + var pointLocation = browser.getChartSeriesPointLocation('hc-panelmetric_explorer', seriesIndex, pointIndex).value; + expect(pointLocation.left).to.be.a('number'); + expect(pointLocation.top).to.be.a('number'); + browser.moveTo(null, pointLocation.left, pointLocation.top); + browser.buttonDown(); + browser.buttonUp(); + browser.execute('return document.querySelectorAll("svg g.highcharts-series-group g.highcharts-markers.highcharts-tracker path")[' + seriesIndex + '];').click(); + browser.pause(10000); + } + saveChartTitle() { + browser.pause(5000); + browser.waitForLoadedThenClick(this.meselectors.options.button); + browser.waitForVisible(this.meselectors.options.title, 30000); + expect(browser.getValue(this.meselectors.options.title)).to.be.a('string'); + var chartTitle = browser.getValue(this.meselectors.options.title); + return (chartTitle); + } +} + +module.exports = new MetricExplorer(); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/reportGenerator.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/reportGenerator.js new file mode 100644 index 0000000000..ca42a81200 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/reportGenerator.js @@ -0,0 +1,107 @@ +var logIn = require('./loginPage.page.js'); +var rg = require('./reportGenerator.page.js'); + +describe('Report Generator', function reportGenerator() { + var loginName = testHelpers.auth.roles.centerdirector.username; + var loginPassword = testHelpers.auth.roles.centerdirector.password; + var displayName = testHelpers.auth.roles.centerdirector.display; + logIn.login('Open XDMoD', '/', loginName, loginPassword, displayName); + var columnIndex = 1; + var reportName = 'TAS Report 1'; + var startDate = '2016-12-20'; + var endDate = '2017-01-01'; + var currentSchedule; + describe('Report Generator', function xdmod() { + it('Click on the Report Generator Tab', function clickTab() { + browser.waitForVisible(rg.mask, 50000, true); + browser.waitAndClick(rg.tabForName(rg.name)); + browser.waitAndClick(rg.tabForName(rg.name)); + }); + + it('Open the report to test', function selectReport() { + browser.waitForVisible(rg.tableRowForColumnText(columnIndex, reportName), 30000); + browser.doubleClick(rg.tableRowForColumnText(columnIndex, reportName)); + }); + + it('Edit the timeframe for the selected report', function editTimeFrame() { + browser.waitAndClick(rg.editDateForRowByIndex(1)); + }); + + it('Wait for Date Editor to be visible', function waitForEditorVisibility() { + browser.waitForVisible(rg.dateEditorcmp, 30000); + }); + + it("Select 'Specific' for the timeframe type", function setTimeFrameType() { + browser.click(rg.radioButton(rg.radial.specific)); + }); + + it('Clear start and end date', function clearStartAndEndDate() { + browser.setValue(rg.startDateField(), ''); + browser.setValue(rg.endDateField(), ''); + }); + + it('Press the update button, expect error about start date', function pressUpdateButton() { + rg.pressUpdateExpectError('start date'); + }); + + it('Set a start date', function setStartDate() { + browser.click(rg.startDateField()); + browser.setValue(rg.startDateField(), startDate); + }); + + it('Press the update button, expect error about end date', function pressUpdateButton() { + rg.pressUpdateExpectError('end date'); + }); + + it('Set an end date', function setEndDate() { + browser.click(rg.startDateField()); + browser.setValue(rg.endDateField(), endDate); + }); + + it('Press the update button', function pressUpdateButton() { + rg.pressUpdate(); + }); + + it('Verify that the date has been changed', function verifyDateChange() { + rg.verifyDateChange(startDate, endDate); + }); + + it('Save the Report', function saveTheReport() { + rg.saveTheReport(); + }); + + it('Close the report', function closeReport() { + browser.click(rg.returnToMyReportsButton()); + browser.waitForVisible(rg.tableRowForColumnText(columnIndex, reportName), 30000); + }); + + it('Open the report', function openReportAgain() { + browser.doubleClick(rg.tableRowForColumnText(columnIndex, reportName)); + }); + + it('Get the current Report Schedule', function getCurrentReportSchedule() { + browser.waitForVisible(rg.cmp(), 30000); + currentSchedule = browser.getValue(rg.cmp()); + }); + + it('Change the Report Schedule', function changeReportSchedule() { + browser.click(rg.cmp()); + browser.click(rg.selectionByName(rg.nextValue(currentSchedule))); + }); + + it('Save the Report', function saveTheReport() { + rg.saveTheReport(); + browser.waitForVisible(rg.chartUpdateInProgressByIndex(1), 50000, true); + }); + + it('Close the report', function closeReport() { + browser.click(rg.returnToMyReportsButton()); + browser.waitForVisible(rg.tableRowForColumnText(columnIndex, reportName), 30000); + }); + + it('Validate that the Schedule has been changed', function validateScheduleChange() { + browser.isExisting(rg.tableRowForColumnText(3, rg.nextValue(currentSchedule))); + }); + logIn.logout(); + }); +}); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/reportGenerator.page.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/reportGenerator.page.js new file mode 100644 index 0000000000..6af2340dbf --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/reportGenerator.page.js @@ -0,0 +1,128 @@ +class ReportGenerator { + constructor() { + this.name = 'Report Generator'; + this.contents = "//div[@id='report_generator']"; + this.dateEditorcmp = "//div[contains(@class, 'chart_date_editor')]"; + this.radial = { + periodic: 'Periodic', + specific: 'Specific' + }; + this.items = [ + 'Once', + 'Daily', + 'Weekly', + 'Monthly', + 'Quarterly', + 'Semi-annually', + 'Annually' + ]; + this.mask = "//div[contains(@class, 'ext-el-mask')]"; + } + + radioButton(value) { + return this.dateEditorcmp + "//input[@type='radio' and contains(@class, 'x-form-radio') and @value='" + value + "']"; + } + + startDateField() { + return this.dateEditorcmp + "//input[@type='text' and @id='report_generator_edit_date_start_date_field']"; + } + + endDateField() { + return this.dateEditorcmp + "//input[@type='text' and @id='report_generator_edit_date_end_date_field']"; + } + + updateButton() { + return this.dateEditorcmp + "//button[contains(@class, 'chart_date_editor_update_button')]"; + } + + errorMessageContains(message) { + return this.dateEditorcmp + "//div[contains(@class, 'overlay_message') and text()[contains(., '" + message + "')]]"; + } + + cmp() { + return this.contents + "//input[@type='text' and @id='report_generator_report_schedule']"; + } + + selectionByName(name) { + return "//div[contains(@class, 'x-combo-list') and contains(@style, 'visibility: visible')]//div[contains(@class, 'x-combo-list-item') and text()[contains(.,'" + name + "')]]"; + } + + nextValue(value) { + var values = this.items; + var index = values.indexOf(value) + 1; + if (index === values.length) { + index = 0; + } + return values[index]; + } + + tabForName(name) { + return "//div[contains(@class, 'x-tab-panel-header')]//span[contains(@class, 'x-tab-strip-text') and text()[contains(., '" + name + "')]]"; + } + + tableRowForColumnText(columnIndex, text) { + return this.contents + "//div[contains(@class, 'x-grid3-row')]//table[contains(@class, 'x-grid3-row-table')]//div[contains(@class, 'x-grid3-cell-inner') and contains(@class, x-grid3-col-" + columnIndex + ") and text()[contains(., '" + text + "')]]"; + } + + tableRowByRowIndex(rowIndex) { + var myrowIndex; + if (typeof rowIndex !== 'number') { + myrowIndex = 1; + } else if (rowIndex < 1) { + myrowIndex = 1; + } else { + myrowIndex = rowIndex; + } + return '(' + this.contents + "//div[@id='CurrentNewchartbaseTab_queueGrid']//div[contains(@class, 'x-grid3-row')])[" + myrowIndex + ']'; + } + + editDateForRowByIndex(rowIndex, byImage) { + var newbyImage = byImage !== undefined ? byImage : false; + if (newbyImage === true) { + return this.tableRowByRowIndex(rowIndex) + "//a[@id='report_generator_timeframe_selector_img']"; + } + return this.tableRowByRowIndex(rowIndex) + "//a[@id='report_generator_timeframe_selector']"; + } + + chartUpdateInProgressByIndex(rowIndex) { + return this.tableRowByRowIndex(rowIndex) + "//img[contains(@src, 'report_gen_thumbnail_progress')]"; + } + + saveReportButton() { + return this.contents + "//button[contains(@class, 'btn_save') and text()[contains(.,'Save')]]"; + } + + saveReportMessage() { + return "//div[contains(@class, 'x-window') and @id='report_generator_message' and contains(@style, 'visibility: visible')]"; + } + + returnToMyReportsButton() { + return this.contents + "//button[contains(@class, 'btn_return_to_overview')]"; + } + + saveTheReport() { + browser.click(this.saveReportButton()); + browser.waitForVisible(this.saveReportMessage(), 50000); + browser.waitForVisible(this.saveReportMessage(), 50000, true); + } + pressUpdate() { + browser.pause(4000); + browser.click(this.updateButton()); + browser.pause(4000); + browser.waitForVisible(this.dateEditorcmp, 50000, true); + browser.waitForVisible(this.chartUpdateInProgressByIndex(1), 50000, true); + } + verifyDateChange(startDate, endDate) { + var dateChange = browser.getText(this.editDateForRowByIndex(1)); + var hasStartDate = dateChange.indexOf(startDate) >= 0; + var hasEndDate = dateChange.indexOf(endDate) >= 0; + expect(hasStartDate).to.equal(true); + expect(hasEndDate).to.equal(true); + } + pressUpdateExpectError(error) { + browser.click(this.updateButton()); + browser.waitForVisible(this.errorMessageContains(error), 60000); + browser.waitForVisible(this.errorMessageContains(error), 60000, true); + } +} +module.exports = new ReportGenerator(); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/usageTab.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/usageTab.js new file mode 100644 index 0000000000..86e2f3a295 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/usageTab.js @@ -0,0 +1,29 @@ +var logIn = require('./loginPage.page.js'); +var usg = require('./usageTab.page.js'); + +describe('Usage', function () { + var loginName = testHelpers.auth.roles.centerdirector.username; + var loginPassword = testHelpers.auth.roles.centerdirector.password; + var displayName = testHelpers.auth.roles.centerdirector.display; + logIn.login('Open XDMoD', '/', loginName, loginPassword, displayName); + var baselineDate = { + start: '2016-12-25', + end: '2017-01-02' + }; + describe('Usage Tab', function xdmod() { + it('Selected', function () { + browser.waitForLoadedThenClick(usg.tab).call(); + }); + it('Set a known start and end date', function meSetStartEnd() { + browser.setValue(usg.startField, baselineDate.start); + browser.setValue(usg.endField, baselineDate.end); + }); + it('Select Job Size Min', function () { + browser.waitForLoadedThenClick(usg.jobSizeMin); + }); + it('Legend Text is Correct', function () { + usg.checkLegendText('Screwdriver'); + }); + }); + logIn.logout(); +}); diff --git a/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/usageTab.page.js b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/usageTab.page.js new file mode 100644 index 0000000000..f02ad6c7f4 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/test/specs/xdmod/usageTab.page.js @@ -0,0 +1,18 @@ +class Usage { + constructor() { + this.tab = '#main_tab_panel__tg_usage'; + this.startField = '#tg_usage input[id^=start_field_ext]'; + this.endField = '#tg_usage input[id^=end_field_ext]'; + this.jobSizeMin = '.x-tree-root-node > li:nth-child(1) > ul:nth-child(2) > li:nth-child(5)'; + this.legendText = 'g.highcharts-legend-item'; + } + + checkLegendText(text) { + browser.waitForChart(); + browser.pause(2500); + browser.waitForExist(this.legendText, 50000); + expect(browser.getText(this.legendText)).to.equal(text); + } + +} +module.exports = new Usage(); diff --git a/open_xdmod/modules/xdmod/automated_tests/wdio-sauce.conf.js b/open_xdmod/modules/xdmod/automated_tests/wdio-sauce.conf.js new file mode 100644 index 0000000000..e8ff87154d --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/wdio-sauce.conf.js @@ -0,0 +1,218 @@ +// eslint-disable-next-line no-unused-vars +var InternetExplorer = { + browserName: 'internet explorer', + platform: 'Windows 10', + version: '11.103', + screenResolution: '1280x1024' +}; +// eslint-disable-next-line no-unused-vars +var FireFox = { + browserName: 'firefox', + platform: 'Windows 10', + version: '45.0', + screenResolution: '2560x1600' +}; + +var Chrome = { + browserName: 'chrome', + platform: 'Windows 10', + version: '48.0', + screenResolution: '2560x1600', + chromeOptions: { + args: [ + 'incognito', + 'disable-extensions', + 'start-maximized', + 'window-size=2560,1600' + ] + } +}; +// eslint-disable-next-line no-unused-vars +var Safari = { + browserName: 'safari', + platform: 'macOS 10.12', + version: '10', + screenResolution: '1024x768' +}; +// eslint-disable-next-line no-unused-vars +var PhantomJS = { + browserName: 'phantomjs', + 'phantomjs.cli.args': [ + '--ignore-ssl-errors=true', + '--web-security=false', + '--debug=false' + ] +}; + +exports.config = { + // Sauce Labs Login, comment out user and key to run tests locally + user: 'xdmod-sauce', + key: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', // enter key before running + // + // ================== + // Specify Test Files + // ================== + // Define which test specs should run. The pattern is relative to the directory + // from which `wdio` was called. Notice that, if you are calling `wdio` from an + // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working + // directory is where your package.json resides, so `wdio` will be called from there. + // + specs: [ + './test/specs/**/*.js' + ], + + // Patterns to exclude. + exclude: [ + // pageObject files should always be excluded + './test/**/*.page.js' + ], + // + // ============ + // Capabilities + // ============ + // Define your capabilities here. WebdriverIO can run multiple capabilties at the same + // time. Depending on the number of capabilities, WebdriverIO launches several test + // sessions. Within your capabilities you can overwrite the spec and exclude option in + // order to group specific specs to a specific capability. + // + // If you have trouble getting all important capabilities together, check out the + // Sauce Labs platform configurator - a great tool to configure your capabilities: + // https://docs.saucelabs.com/reference/platforms-configurator + // + // **NOTE** if no browserName is specified webdriverio defaults to firefox + // Webdriver.io has the ability to run multiple browsers at once + // uncomment the different objects to enable each browser + // uncomment multiple objects to enable multiple at the same time + // Please bear in mind that if the tests are manipulating saved state on the server + // then running multiple logins concurrently could cause problems. + + // Define how many instances should be started at the same time. Let's + // say you have 3 different capabilities (Chrome, Firefox, and Safari) + // and you have set maxInstances to 1, wdio will spawn 3 processes. + // Therefore, if you have 10 spec files and you set maxInstances to 10; + // all spec files will get tested at the same time and 30 processes will + // get spawned. The property handles how many capabilities from the same + // test should run tests. + // The XDMoD SauceLabs account has a limit of 5 concurrent sessions. + maxInstances: 1, + + capabilities: [ + FireFox, + Chrome + ], + // + // =================== + // Test Configurations + // =================== + // Define all options that are relevant for the WebdriverIO instance here + // + + // By default WebdriverIO commands are executed in a synchronous way using + // the wdio-sync package. If you still want to run your tests in an async way + // e.g. using promises you can set the sync option to false. + sync: true, + + // Level of logging verbosity. + logLevel: 'silent', + // + // Enables colors for log output. + coloredLogs: true, + // + // Saves a screenshot to a given path if a command fails. + // Comment out to disable feature. + // screenshotPath: './errorShots/', + // + // Set a base URL in order to shorten url command calls. If your url parameter starts + // with '/', the base url gets prepended. + baseUrl: 'https://tas-reference-dbs.ccr.xdmod.org', + // + // Default timeout for all waitForXXX commands. + waitforTimeout: 10000, + // + // Initialize the browser instance with a WebdriverIO plugin. The object should have the + // plugin name as key and the desired plugin options as property. Make sure you have + // the plugin installed before running any tests. The following plugins are currently + // available: + // WebdriverCSS: https://github.com/webdriverio/webdrivercss + // WebdriverRTC: https://github.com/webdriverio/webdriverrtc + // Browserevent: https://github.com/webdriverio/browserevent + // plugins: { + // webdrivercss: { + // screenshotRoot: 'my-shots', + // failedComparisonsRoot: 'diffs', + // misMatchTolerance: 0.05, + // screenWidth: [320,480,640,1024] + // }, + // webdriverrtc: {}, + // browserevent: {} + // }, + // + services: [ + 'sauce' + ], + // Framework you want to run your specs with. + // The following are supported: mocha, jasmine and cucumber + // see also: http://webdriver.io/guide/testrunner/frameworks.html + // + // Make sure you have the node package for the specific framework installed before running + // any tests. If not please install the following package: + // Mocha: `$ npm install mocha` + // Jasmine: `$ npm install jasmine` + // Cucumber: `$ npm install cucumber` + framework: 'mocha', + // + // Test reporter for stdout. + // The following are supported: dot (default), spec and xunit + // see also: http://webdriver.io/guide/testrunner/reporters.html + reporter: 'spec', + // + // Options to be passed to Mocha. + // See the full list at http://mochajs.org/ + mochaOpts: { + ui: 'bdd', + timeout: 100000 + }, + // + // ===== + // Hooks + // ===== + // Run functions before or after the test. If one of them returns with a promise, WebdriverIO + // will wait until that promise got resolved to continue. + // + // Gets executed before all workers get launched. + onPrepare: function onPrepare() { + // do something + }, + // + // Gets executed before test execution begins. At this point you will have access to all global + // variables like `browser`. It is the perfect place to define custom commands. + before: function before() { + // eslint-disable-next-line global-require + global.testHelpers = require('./test/helpers'); + // eslint-disable-next-line global-require + var webdriverHelpers = require('./webdriverHelpers'); + for (var extension in webdriverHelpers) { + if (webdriverHelpers.hasOwnProperty(extension) && typeof webdriverHelpers[extension] === 'function') { + browser.addCommand(extension, webdriverHelpers[extension].bind(browser)); + } else { + console.warning('Not Adding: ', extension, typeof webdriverHelpers[extension]); + } + } + // eslint-disable-next-line global-require + var chai = require('chai'); + // eslint-disable-next-line no-global-assign + expect = chai.expect; + }, + // + // Gets executed after all tests are done. You still have access to all global variables from + // the test. + after: function after(/* failures, pid */) { + // do something + }, + // + // Gets executed after all workers got shut down and the process is about to exit. It is not + // possible to defer the end of the process using a promise. + onComplete: function onComplete() { + // do something + } +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/wdio.conf.js b/open_xdmod/modules/xdmod/automated_tests/wdio.conf.js new file mode 100644 index 0000000000..833ba3aab8 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/wdio.conf.js @@ -0,0 +1,211 @@ +// eslint-disable-next-line no-unused-vars +var InternetExplorer = { + browserName: 'internet explorer', + platform: 'Windows 10', + version: '11.103', + screenResolution: '1280x1024' +}; +// eslint-disable-next-line no-unused-vars +var FireFox = { + browserName: 'firefox', + platform: 'Windows 10', + version: '45.0', + screenResolution: '2560x1600' +}; + +var Chrome = { + browserName: 'chrome', + platform: 'Windows 10', + version: '48.0', + screenResolution: '2560x1600', + chromeOptions: { + args: [ + 'incognito', + 'disable-extensions', + 'start-maximized', + 'window-size=2560,1600' + ] + } +}; +// eslint-disable-next-line no-unused-vars +var Safari = { + browserName: 'safari', + platform: 'macOS 10.12', + version: '10', + screenResolution: '1024x768' +}; +// eslint-disable-next-line no-unused-vars +var PhantomJS = { + browserName: 'phantomjs', + 'phantomjs.cli.args': [ + '--ignore-ssl-errors=true', + '--web-security=false', + '--debug=false' + ] +}; + +exports.config = { + // ================== + // Specify Test Files + // ================== + // Define which test specs should run. The pattern is relative to the directory + // from which `wdio` was called. Notice that, if you are calling `wdio` from an + // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working + // directory is where your package.json resides, so `wdio` will be called from there. + // + specs: [ + './test/specs/**/*.js' + ], + + // Patterns to exclude. + exclude: [ + // pageObject files should always be excluded + './test/**/*.page.js' + ], + // + // ============ + // Capabilities + // ============ + // Define your capabilities here. WebdriverIO can run multiple capabilties at the same + // time. Depending on the number of capabilities, WebdriverIO launches several test + // sessions. Within your capabilities you can overwrite the spec and exclude option in + // order to group specific specs to a specific capability. + // + // If you have trouble getting all important capabilities together, check out the + // Sauce Labs platform configurator - a great tool to configure your capabilities: + // https://docs.saucelabs.com/reference/platforms-configurator + // + // **NOTE** if no browserName is specified webdriverio defaults to firefox + // Webdriver.io has the ability to run multiple browsers at once + // uncomment the different objects to enable each browser + // uncomment multiple objects to enable multiple at the same time + // Please bear in mind that if the tests are manipulating saved state on the server + // then running multiple logins concurrently could cause problems. + + // Define how many instances should be started at the same time. Let's + // say you have 3 different capabilities (Chrome, Firefox, and Safari) + // and you have set maxInstances to 1, wdio will spawn 3 processes. + // Therefore, if you have 10 spec files and you set maxInstances to 10; + // all spec files will get tested at the same time and 30 processes will + // get spawned. The property handles how many capabilities from the same + // test should run tests. + maxInstances: 1, + + capabilities: [ + Chrome + ], + // + // =================== + // Test Configurations + // =================== + // Define all options that are relevant for the WebdriverIO instance here + // + + // By default WebdriverIO commands are executed in a synchronous way using + // the wdio-sync package. If you still want to run your tests in an async way + // e.g. using promises you can set the sync option to false. + sync: true, + // Level of logging verbosity. + logLevel: 'silent', + // + // Enables colors for log output. + coloredLogs: true, + // + // Saves a screenshot to a given path if a command fails. + // Comment out to disable feature. + // screenshotPath: './errorShots/', + // + // Set a base URL in order to shorten url command calls. If your url parameter starts + // with '/', the base url gets prepended. + baseUrl: 'https://tas-reference-dbs.ccr.xdmod.org', + // + // Default timeout for all waitForXXX commands. + waitforTimeout: 10000, + // + // Initialize the browser instance with a WebdriverIO plugin. The object should have the + // plugin name as key and the desired plugin options as property. Make sure you have + // the plugin installed before running any tests. The following plugins are currently + // available: + // WebdriverCSS: https://github.com/webdriverio/webdrivercss + // WebdriverRTC: https://github.com/webdriverio/webdriverrtc + // Browserevent: https://github.com/webdriverio/browserevent + // plugins: { + // webdrivercss: { + // screenshotRoot: 'my-shots', + // failedComparisonsRoot: 'diffs', + // misMatchTolerance: 0.05, + // screenWidth: [320,480,640,1024] + // }, + // webdriverrtc: {}, + // browserevent: {} + // }, + // + services: [ + 'selenium-standalone' + ], + // Framework you want to run your specs with. + // The following are supported: mocha, jasmine and cucumber + // see also: http://webdriver.io/guide/testrunner/frameworks.html + // + // Make sure you have the node package for the specific framework installed before running + // any tests. If not please install the following package: + // Mocha: `$ npm install mocha` + // Jasmine: `$ npm install jasmine` + // Cucumber: `$ npm install cucumber` + framework: 'mocha', + // + // Test reporter for stdout. + // The following are supported: dot (default), spec and xunit + // see also: http://webdriver.io/guide/testrunner/reporters.html + reporter: 'spec', + // + // Options to be passed to Mocha. + // See the full list at http://mochajs.org/ + mochaOpts: { + ui: 'bdd', + timeout: 100000 + }, + // + // ===== + // Hooks + // ===== + // Run functions before or after the test. If one of them returns with a promise, WebdriverIO + // will wait until that promise got resolved to continue. + // + // Gets executed before all workers get launched. + onPrepare: function onPrepare() { + // do something + }, + // + // Gets executed before test execution begins. At this point you will have access to all global + // variables like `browser`. It is the perfect place to define custom commands. + before: function before() { + // eslint-disable-next-line global-require + global.testHelpers = require('./test/helpers'); + // eslint-disable-next-line global-require + var webdriverHelpers = require('./webdriverHelpers'); + for (var extension in webdriverHelpers) { + if (webdriverHelpers.hasOwnProperty(extension) && typeof webdriverHelpers[extension] === 'function') { + browser.addCommand(extension, webdriverHelpers[extension].bind(browser)); + } else { + console.warning('Not Adding: ', extension, typeof webdriverHelpers[extension]); + } + } + // eslint-disable-next-line global-require + var chai = require('chai'); + // eslint-disable-next-line no-global-assign + expect = chai.expect; + }, + // + // Gets executed after all tests are done. You still have access to all global variables from + // the test. + after: function after(/* failures, pid */) { + // do something + }, + // + // Gets executed after all workers got shut down and the process is about to exit. It is not + // possible to defer the end of the process using a promise. + onComplete: function onComplete() { + // do something + } +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/getChartSeriesPointLocation.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/getChartSeriesPointLocation.js new file mode 100644 index 0000000000..9af80b4c21 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/getChartSeriesPointLocation.js @@ -0,0 +1,39 @@ +/** + * Attempt to retrieve the location ( top, left ) relative to the provided + * containerId of the point in the series ( pointIndex, seriesIndex ). A top + * and left offset can also be supplied. + * + * @param {String} containerId - the 'id' property of the container that + * contains the Highcharts instance. + * NOTE: this is an Ext id so no '#'. + * @param {Number} [seriesIndex=0] - the index of the series that contains + * the point to be located. + * @param {Number} [pointIndex=0] - the index of the point to be located. + * + * @return {Object} in the form: + * { + * top: , + * left: + * } + **/ +module.exports = function getChartSeriesPointLocation(containerId, seriesIndex, pointIndex) { + var thisSeriesIndex = (seriesIndex !== undefined) ? seriesIndex : 0; + var thisPointIndex = (pointIndex !== undefined) ? pointIndex : 0; + return this.execute(function (innerContainerId, innerSeriesIndex, innerPointIndex) { + // TODO: Fix this withOut having to use EXT if Possible + // eslint-disable-next-line no-undef + var cmp = Ext.getCmp(innerContainerId); + var axes = cmp.chart.axes; + var xAxis = axes[0]; + var yAxis = axes[1]; + var series = cmp.chart.series[innerSeriesIndex]; + var point = series.data[innerPointIndex]; + var top = yAxis.toPixels(point.options.y); + var left = xAxis.toPixels(point.options.x); + + return { + top: Number(top.toFixed(0)), + left: Number(left.toFixed(0)) + }; + }, containerId, thisSeriesIndex, thisPointIndex); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/index.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/index.js new file mode 100644 index 0000000000..f7c749d520 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/index.js @@ -0,0 +1 @@ +module.exports = require('require-dir')(); diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitAndClick.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitAndClick.js new file mode 100644 index 0000000000..978e5b2af0 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitAndClick.js @@ -0,0 +1,14 @@ +/* + * Wait for selector to be visible then click on it + * + * @param {string} selector - element to click on + * @param {Number} [ms=5000] - Milliseconds to wait for element to be visible + * + * @uses commands/waitForVisible, commands/click + */ +module.exports = function waitAndClick(selector, ms) { + var thisMs = ms || 5000; + + this.waitForVisible(selector, thisMs); + return this.click(selector); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitAndSet.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitAndSet.js new file mode 100644 index 0000000000..e111730a36 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitAndSet.js @@ -0,0 +1,52 @@ +/** + * Wait for the element identified by the provided selector to be visible and + * then set it's value to the provided value. To more accurately simulate a user + * setting a value the click argument defaults to true. Also, as a simple sanity + * check, validate is also defaulted to true with a default validate function + * that just checks that the value that the selector was set to is what is + * retrieved via a getValue. + * + * @param {String} selector - will be used to identify the element. + * @param {*} value - the value to use while performing a setValue + * on the now visible element. + * @param {Number} [ms=5000] - the amount of time to wait for the selector + * to become visible. + * @param {Boolean} [click=true] - A value of true indicates that a click + * event will be executed before the setValue + * for the provided selector. A value of false + * indicates that the click event should be + * skipped. + * @param {Boolean} [validate=true] - validate that the value the selector + * is set to matches the value that is + * retrieved after the setValue is + * performed. + * @param {Function} [validateFunc=function(expected, actual){ + * expect(actual).to.be.equal(expected); + * } + * ] - The function that will be used to validate the value retrieved + * from the selector if the validate argument is true. + **/ +// eslint-disable-next-line consistent-return +module.exports = function waitAndSet(selector, value, ms, click, validate) { + var timeOut = ms || 5000; + var thisClick = click !== undefined ? click : true; + var thisValidate = validate !== undefined ? validate : true; + + if (thisClick === true && thisValidate === true) { + this.waitForVisible(selector, timeOut); + this.click(selector); + this.setValue(selector, value); + return this.getValue(selector); + } else if (thisClick === true && thisValidate === false) { + this.waitForVisible(selector, timeOut); + this.click(selector); + return this.setValue(selector, value); + } else if (thisClick === false && thisValidate === true) { + this.waitForVisible(selector, timeOut); + this.setValue(selector, value); + return this.getValue(selector); + } else if (thisClick === false && thisValidate === false) { + this.waitForVisible(selector, timeOut); + return this.setValue(selector, value); + } +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForChart.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForChart.js new file mode 100644 index 0000000000..ea911858eb --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForChart.js @@ -0,0 +1,14 @@ +/* + * Wait for chart to load + * TODO: Find a better way to determine if chart is rendered + * + * @param {Number} [ms=9000] - Milliseconds to wait for chat to be visible + * + * @uses commands/waitForVisible, protocol/pause + */ + +module.exports = function waitForChart(ms) { + var timeOut = ms || 9000; + + return this.waitForVisible('.ext-el-mask-msg', timeOut, true); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForInvisible.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForInvisible.js new file mode 100644 index 0000000000..ac41338edb --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForInvisible.js @@ -0,0 +1,13 @@ +/* + * Wait for selector to be invisible + * + * @param {string} selector - element to check + * @param {Number} [ms=1000] - Milliseconds to wait for element to be invisible + * + * @uses commands/waitForVisible + */ + +module.exports = function waitForInvisible(selector, ms) { + var timeOut = ms || 1000; + return this.waitForVisible(selector, timeOut, true); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForLoadedThenClick.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForLoadedThenClick.js new file mode 100644 index 0000000000..117b8f7779 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitForLoadedThenClick.js @@ -0,0 +1,13 @@ +/* + * Wait for loadingMask to not exist and selector to exist then click on selector + * + * @param {string} selector - element to click on + * @param {Number} [maskMs=500] - Milliseconds to wait for mask to not exist + * + * @uses commands/waitForVisible, helpers/waitAndClick + */ +module.exports = function waitForLoadedThenClick(selector, maskMs) { + var maskTimeOut = maskMs || 9000; + browser.waitForVisible('.ext-el-mask-msg', maskTimeOut, true); + return browser.click(selector); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilAnimEnd.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilAnimEnd.js new file mode 100644 index 0000000000..4603d65646 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilAnimEnd.js @@ -0,0 +1,29 @@ +/* + * Wait for selector to stop animating, where animation is defined + * as moving in the view. + * + * @param {string} selector - element to click on + * @param {Number} [ms=9000] - Milliseconds to wait for element to be visible + * @param {Number} [interval=250] - interval between element location checks + * + * @uses commands/waitUntil commands/getLocationInView + */ + +module.exports = function waitUntilAnimEnd(selector, ms, interval) { + var timeOut = ms || 9000; + var checkInterval = interval || 250; + + var initialLoc = { x: -1, y: -1 }; + + this.waitForVisible(selector, timeOut); + return this.waitUntil(function () { + var loc = this.getLocationInView(selector); + if (loc.x === initialLoc.x && loc.y === initialLoc.y) { + return true; + } + + initialLoc = loc; + + return false; + }, timeOut, checkInterval); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilAnimEndAndClick.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilAnimEndAndClick.js new file mode 100644 index 0000000000..0e38270a39 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilAnimEndAndClick.js @@ -0,0 +1,19 @@ +/* + * Wait for selector to stop animating then click on it + * + * @param {string} selector - element to click on + * @param {string} [button=left] which mouse key to use ["left", "middle", "right"] + * @param {Number} [ms=9000] - Milliseconds to wait for element to stop moving + * @param {Number} [interval=250] - interval between element location checks + * + * @uses waitUntilAnimEnd commands/buttonPress + */ + +module.exports = function waitUntilAnimEndAndClick(selector, button, ms, interval) { + var clickButton = button || 'left'; + var timeOut = ms || 9000; + var checkInterval = interval || 250; + this.waitUntilAnimEnd(selector, timeOut, checkInterval); + this.moveToObject(selector); + return this.buttonPress(clickButton); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilChartLoadsBySeries.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilChartLoadsBySeries.js new file mode 100644 index 0000000000..1b151b2ae3 --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilChartLoadsBySeries.js @@ -0,0 +1,14 @@ +/** + * Wait for the Highchart that contains the provided series to load. + * + * @param {String} series - name of the series to be used to further + * identify the Highcharts instance. + * @param {Number} [ms=9000] - Milliseconds to wait for the element to + **/ +module.exports = function waitUntilChartLoadsBySeries(series, ms) { + var timeOut = ms || 9000; + return this.waitForVisible( + "//*[local-name() = 'svg']//*[local-name() = 'g' and contains(@class, 'highcharts-axis')]//*[local-name() = 'tspan' and text()[contains(., '" + series + "')]]", + timeOut + ); +}; diff --git a/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilNotExist.js b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilNotExist.js new file mode 100644 index 0000000000..1ecb98629c --- /dev/null +++ b/open_xdmod/modules/xdmod/automated_tests/webdriverHelpers/waitUntilNotExist.js @@ -0,0 +1,13 @@ +/* + * Wait for selector to be visible then click on it + * + * @param {string} selector - element to click on + * @param {Number} [ms=9000] - Milliseconds to wait for element to be visible + * + * @uses commands/waitForExist + */ + +module.exports = function waitUntilNotExist(selector, ms) { + var timeOut = ms || 9000; + return this.waitForExist(selector, timeOut, true); +};