From 999762b702394576fe995e71ae6e25756b3a8f6f Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Mon, 5 Aug 2019 13:38:57 -0700 Subject: [PATCH 01/13] Add JS functional test harness Commenting out other stages in travis.yml for now. This just has all the wiring to get a functional test running in TravisCI using Selenium Webdriver, the latest release version of Firefox and the Mocha test framework. --- .travis.yml | 80 +++++---- package-lock.json | 350 ++++++++++++++++++++++++++++++++++++++- package.json | 4 +- test/.eslintrc.yml | 2 + test/functional_test.mjs | 35 ++++ 5 files changed, 435 insertions(+), 36 deletions(-) create mode 100644 test/functional_test.mjs diff --git a/.travis.yml b/.travis.yml index 888a34ff..8935dd8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,44 +1,58 @@ jobs: include: + # TODO: move into "Javascript tests" stage - stage: test - name: "Javascript tests" + name: "Javascript functional tests" language: node_js node_js: - node + env: + - MOZ_HEADLESS=1 addons: - apt: - packages: - - python-virtualenv - after_success: - - "npm run coveralls" - - stage: test - name: "Python 3.6 tests" - language: python - python: - - "3.6" - install: - - pip install -e cli/ - script: - - pytest cli/fathom_web/test - - stage: test - name: "Python 3.7 tests" - dist: bionic - language: python - python: - - "3.7" - install: - - pip install -e cli/ + firefox: latest script: - - pytest cli/fathom_web/test - - stage: deploy - name: "Docs deployment" - script: skip - deploy: - provider: script - script: docs/tooling/travis-deploy-docs - on: - branch: master - skip_cleanup: true + - make all + - export PATH=$PATH:$TRAVIS_BUILD_DIR/node_modules/geckodriver/bin + - yarn mocha --timeout 15000 test/functional_test.js + # - stage: test + # name: "Javascript tests" + # language: node_js + # node_js: + # - node + # addons: + # apt: + # packages: + # - python-virtualenv + # after_success: + # - "npm run coveralls" + # - stage: test + # name: "Python 3.6 tests" + # language: python + # python: + # - "3.6" + # install: + # - pip install -e cli/ + # script: + # - pytest cli/fathom_web/test + # - stage: test + # name: "Python 3.7 tests" + # dist: bionic + # language: python + # python: + # - "3.7" + # install: + # - pip install -e cli/ + # script: + # - pytest cli/fathom_web/test + # - stage: deploy + # name: "Docs deployment" + # script: skip + # deploy: + # provider: script + # script: docs/tooling/travis-deploy-docs + # on: + # branch: master + # skip_cleanup: true notifications: email: diff --git a/package-lock.json b/package-lock.json index b9e2abe9..4a88c355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,6 +251,21 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" }, + "adm-zip": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.11.tgz", + "integrity": "sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, "ajv": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", @@ -713,6 +728,12 @@ "dev": true, "optional": true }, + "bluebird": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz", + "integrity": "sha1-AdqNgh2HgT0ViWfnQ9X+bGLPjA8=", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -773,6 +794,12 @@ "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", "dev": true }, + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -829,6 +856,12 @@ "readdirp": "^2.0.0" } }, + "chownr": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.2.tgz", + "integrity": "sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==", + "dev": true + }, "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", @@ -952,6 +985,15 @@ "request": "^2.86.0" } }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, "cssom": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", @@ -1097,6 +1139,15 @@ "webidl-conversions": "^4.0.2" } }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1176,6 +1227,21 @@ "event-emitter": "~0.3.5" } }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -1603,6 +1669,15 @@ "mime-types": "^2.1.12" } }, + "fs-minipass": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz", + "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, "fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -2169,6 +2244,19 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "geckodriver": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-1.16.2.tgz", + "integrity": "sha512-kXZP4QferAv57Ru4Fx2WYuu//ErKJP4hPEkJm4mSETo42jsdYFwdNxwQ4vCGhf14gsCdxU9YrwNupJ8gr1GxPg==", + "dev": true, + "requires": { + "adm-zip": "0.4.11", + "bluebird": "3.4.6", + "got": "5.6.0", + "https-proxy-agent": "2.2.1", + "tar": "4.4.2" + } + }, "generate-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", @@ -2253,6 +2341,30 @@ "pinkie-promise": "^2.0.0" } }, + "got": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-5.6.0.tgz", + "integrity": "sha1-ux1+4WO3gIK7yOuDbz85UATqb78=", + "dev": true, + "requires": { + "create-error-class": "^3.0.1", + "duplexer2": "^0.1.4", + "is-plain-obj": "^1.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "node-status-codes": "^1.0.0", + "object-assign": "^4.0.1", + "parse-json": "^2.1.0", + "pinkie-promise": "^2.0.0", + "read-all-stream": "^3.0.0", + "readable-stream": "^2.0.5", + "timed-out": "^2.0.0", + "unzip-response": "^1.0.0", + "url-parse-lax": "^1.0.0" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -2361,6 +2473,33 @@ "sshpk": "^1.7.0" } }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2375,6 +2514,12 @@ "integrity": "sha512-pUh+xUQQhQzevjRHHFqqcTy0/dP/kS9I8HSrUydhihjuD09W6ldVWFtIrwhXdUJHis3i2rZNqEHpZH/cbinFbg==", "dev": true }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2586,6 +2731,12 @@ "path-is-inside": "^1.0.1" } }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, "is-posix-bracket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", @@ -2606,6 +2757,12 @@ "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", "dev": true }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -2621,6 +2778,18 @@ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -2938,6 +3107,18 @@ "verror": "1.10.0" } }, + "jszip": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.2.tgz", + "integrity": "sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -2974,6 +3155,15 @@ "type-check": "~0.3.2" } }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, "load-json-file": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", @@ -3021,6 +3211,12 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, "magic-string": { "version": "0.22.5", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", @@ -3087,6 +3283,25 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "dev": true, + "requires": { + "minipass": "^2.2.1" + } + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -3186,6 +3401,12 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, + "node-status-codes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", + "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=", + "dev": true + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -3396,6 +3617,12 @@ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", @@ -3513,6 +3740,12 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", @@ -3581,6 +3814,16 @@ } } }, + "read-all-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", + "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0", + "readable-stream": "^2.0.0" + } + }, "read-pkg": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", @@ -3862,6 +4105,43 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, + "selenium-webdriver": { + "version": "4.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.4.tgz", + "integrity": "sha512-etJt20d8qInkxMAHIm5SEpPBSS+CdxVcybnxzSIB/GlWErb8pIWrArz/VA6VfUW0/6tIcokepXQ5ufvdzqqk1A==", + "dev": true, + "requires": { + "jszip": "^3.1.5", + "rimraf": "^2.6.3", + "tmp": "0.0.30", + "xml2js": "^0.4.19" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -3872,8 +4152,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true, - "optional": true + "dev": true }, "shelljs": { "version": "0.7.8", @@ -4088,6 +4367,21 @@ } } }, + "tar": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.2.tgz", + "integrity": "sha512-BfkE9CciGGgDsATqkikUHrQrraBCO+ke/1f6SFAEMnxyyfN9lxC+nW1NFWMpqH865DhHIy9vQi682gk1X7friw==", + "dev": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -4100,6 +4394,21 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "timed-out": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", + "integrity": "sha1-84sK6B03R9YoAB9B2vxlKs5nHAo=", + "dev": true + }, + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + }, "to-fast-properties": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", @@ -4189,6 +4498,12 @@ } } }, + "unzip-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", + "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", + "dev": true + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -4197,6 +4512,15 @@ "punycode": "^2.1.0" } }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, "user-home": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", @@ -4343,11 +4667,33 @@ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true } } } diff --git a/package.json b/package.json index 6189d866..75fb1a7e 100644 --- a/package.json +++ b/package.json @@ -20,12 +20,14 @@ "eslint": "^3.7.1", "eslint-plugin-import": "^2.18.1", "eslint-plugin-node": "^2.1.2", + "geckodriver": "^1.16.2", "istanbul": "^1.1.0-alpha.1", "leven": "^2.1.0", "mocha": "^5.2.0", "rollup": "^0.50.0", "rollup-plugin-commonjs": "^8.2.4", - "rollup-plugin-node-resolve": "^3.4.0" + "rollup-plugin-node-resolve": "^3.4.0", + "selenium-webdriver": "^4.0.0-alpha.4" }, "engines": { "node": ">= 6.0.0" diff --git a/test/.eslintrc.yml b/test/.eslintrc.yml index 9808c3b2..9a16c85b 100644 --- a/test/.eslintrc.yml +++ b/test/.eslintrc.yml @@ -1,2 +1,4 @@ env: mocha: true +parserOptions: + ecmaVersion: 8 diff --git a/test/functional_test.mjs b/test/functional_test.mjs new file mode 100644 index 00000000..dc07ea42 --- /dev/null +++ b/test/functional_test.mjs @@ -0,0 +1,35 @@ +const { expect } = require('chai'); +const firefox = require('selenium-webdriver/firefox'); +const webdriver = require('selenium-webdriver'), + By = webdriver.By, + until = webdriver.until, + Key = webdriver.Key; + +describe('isVisible', () => { + const options = new firefox.Options(); + // TODO: also add options.setBinary('path/to/binary'); get from englehardt + options.headless(); + + const driver = new webdriver.Builder() + // TODO: can set version and platform in forBrowser + .forBrowser('firefox') + // .setFirefoxOptions(options) + .build(); + describe('Unprivileged', () => { + it('should return false when...TODO', async () => { + // TODO: put actual checks here + await driver.get('https://developer.mozilla.org/'); + await driver.findElement(By.id('home-q')).sendKeys('testing', Key.RETURN); + await driver.wait(until.titleIs('Search Results for "testing" | MDN')); + await driver.wait(async () => { + const readyState = await driver.executeScript('return document.readyState'); + return readyState === 'complete'; + }); + const input = 2; + const expected = 2; + expect(input).to.deep.equal(expected); + }); + }); + + after(async () => driver.quit()); +}); From 43e4a30aa3ec077e9c37579ec3a89f302cc004ee Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Mon, 5 Aug 2019 15:44:16 -0700 Subject: [PATCH 02/13] Test Fathom's isVisible method on a page --- test/functional_test.mjs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/test/functional_test.mjs b/test/functional_test.mjs index dc07ea42..c2b882a8 100644 --- a/test/functional_test.mjs +++ b/test/functional_test.mjs @@ -1,33 +1,34 @@ const { expect } = require('chai'); const firefox = require('selenium-webdriver/firefox'); -const webdriver = require('selenium-webdriver'), - By = webdriver.By, - until = webdriver.until, - Key = webdriver.Key; +const webdriver = require('selenium-webdriver'); +const { ancestors, isDomElement, isVisible, toDomElement } = require('../utilsForFrontend'); describe('isVisible', () => { const options = new firefox.Options(); - // TODO: also add options.setBinary('path/to/binary'); get from englehardt options.headless(); const driver = new webdriver.Builder() - // TODO: can set version and platform in forBrowser .forBrowser('firefox') - // .setFirefoxOptions(options) + .setFirefoxOptions(options) .build(); describe('Unprivileged', () => { - it('should return false when...TODO', async () => { + it('should return true when an element is visible', async () => { // TODO: put actual checks here await driver.get('https://developer.mozilla.org/'); - await driver.findElement(By.id('home-q')).sendKeys('testing', Key.RETURN); - await driver.wait(until.titleIs('Search Results for "testing" | MDN')); await driver.wait(async () => { const readyState = await driver.executeScript('return document.readyState'); return readyState === 'complete'; }); - const input = 2; - const expected = 2; - expect(input).to.deep.equal(expected); + const isElementVisible = await driver.wait(async () => { + return driver.executeScript(` + ${ancestors} + ${isDomElement} + ${toDomElement} + return (${isVisible}(document.getElementById("home-q"))); + `); + }); + const expected = true; + expect(isElementVisible).to.deep.equal(expected); }); }); From e01f13f651577ba008749054085050c095bcc088 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Thu, 8 Aug 2019 16:43:43 -0700 Subject: [PATCH 03/13] Add locally hosted test page Travis now runs a local HTTP server[1] in a background process, and the functional test opens a locally hosted test page. I also moved all functional test files to a new directory: test/functional Finally, since test scripts are never going to be imported as ES6 modules, I made the test a .js file rather than a .jsm. Note: if I were to leave it as a .jsm, I would have wanted to change the 'require' statements to 'import' statements to keep consistent with the other .mjs files. These .mjs files get transpiled via Babel into CommonJS .js files (i.e. using 'require' statements) as a build step. [1]: I did quite a lot of deliberation about whether an HTTP server would be sufficient (compared to an HTTPS server) and determined it was. Ultimately, I adhered to one of the principles of extreme programming (thanks Daniel): don't add functionality until it's necessary. Here is my reasoning (I spoke with a Mozilla security engineer who works on certificates): * TravisCI's default environment runs each build on a [single machine](https://docs.travis-ci.com/user/reference/trusty/#using-trusty) * This means we are running the server on the loopback interface, and there shouldn't be much risk -- particularly since we don't have any secrets. * The only downside is there are some [DOM APIs that only work in secure contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts/features_restricted_to_secure_contexts) -- none of which we are using currently. But Firefox is working on enabling these APIs in this case where everything is on the same machine. --- .gitignore | 1 + .travis.yml | 4 +++- test/functional/functional_test.html | 14 ++++++++++++ .../functional_test.js} | 6 ++--- test/functional/setup_http_server.js | 22 +++++++++++++++++++ 5 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 test/functional/functional_test.html rename test/{functional_test.mjs => functional/functional_test.js} (91%) create mode 100644 test/functional/setup_http_server.js diff --git a/.gitignore b/.gitignore index 0b6bdcc0..e3133653 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ **/*.js !/rollup.config.js !/trainees.js +!/test/functional/* /cli/build /cli/dist diff --git a/.travis.yml b/.travis.yml index 8935dd8b..45cd94a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,9 @@ jobs: script: - make all - export PATH=$PATH:$TRAVIS_BUILD_DIR/node_modules/geckodriver/bin - - yarn mocha --timeout 15000 test/functional_test.js + - node test/functional/setup_http_server & + - yarn mocha --timeout 60000 test/functional/functional_test.js + - kill %1 # - stage: test # name: "Javascript tests" # language: node_js diff --git a/test/functional/functional_test.html b/test/functional/functional_test.html new file mode 100644 index 00000000..a2fbfc3e --- /dev/null +++ b/test/functional/functional_test.html @@ -0,0 +1,14 @@ + + + + + + + + +

Functional Testing Page - isVisible

+ + + + diff --git a/test/functional_test.mjs b/test/functional/functional_test.js similarity index 91% rename from test/functional_test.mjs rename to test/functional/functional_test.js index c2b882a8..bf1f0184 100644 --- a/test/functional_test.mjs +++ b/test/functional/functional_test.js @@ -1,7 +1,7 @@ const { expect } = require('chai'); const firefox = require('selenium-webdriver/firefox'); const webdriver = require('selenium-webdriver'); -const { ancestors, isDomElement, isVisible, toDomElement } = require('../utilsForFrontend'); +const { ancestors, isDomElement, isVisible, toDomElement } = require('../../utilsForFrontend'); describe('isVisible', () => { const options = new firefox.Options(); @@ -14,7 +14,7 @@ describe('isVisible', () => { describe('Unprivileged', () => { it('should return true when an element is visible', async () => { // TODO: put actual checks here - await driver.get('https://developer.mozilla.org/'); + await driver.get('http://localhost:8000/functional_test.html'); await driver.wait(async () => { const readyState = await driver.executeScript('return document.readyState'); return readyState === 'complete'; @@ -24,7 +24,7 @@ describe('isVisible', () => { ${ancestors} ${isDomElement} ${toDomElement} - return (${isVisible}(document.getElementById("home-q"))); + return (${isVisible}(document.getElementById("image"))); `); }); const expected = true; diff --git a/test/functional/setup_http_server.js b/test/functional/setup_http_server.js new file mode 100644 index 00000000..698a1e09 --- /dev/null +++ b/test/functional/setup_http_server.js @@ -0,0 +1,22 @@ +const http = require('http'); +const fs = require('fs'); +const url = require('url'); + +const PORT = 8000; + +const server = http.createServer((request, response) => { + const path = url.parse(request.url).pathname; + fs.readFile(__dirname + path, 'utf8', (error, data) => { + if (error) { + response.writeHead(404); + response.write(`There was an error: ${error.errno}, ${error.code}`); + response.end(); + } else { + response.writeHead(200, {'Content-Type': 'text/html'}); + response.write(data); + response.end(); + } + }); +}); +server.listen(PORT); +console.log(`Serving from ${__dirname} at http://localhost:${PORT}...`); From 938234ef9219eaa1206b4d35f6f8cde70bbf8f73 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Fri, 9 Aug 2019 21:15:59 -0700 Subject: [PATCH 04/13] Update test cases --- test/functional/functional_test.html | 83 ++++++++++++++++++++++++++-- test/functional/functional_test.js | 40 ++++++++++---- 2 files changed, 108 insertions(+), 15 deletions(-) diff --git a/test/functional/functional_test.html b/test/functional/functional_test.html index a2fbfc3e..b5b73015 100644 --- a/test/functional/functional_test.html +++ b/test/functional/functional_test.html @@ -3,12 +3,85 @@ - + isVisible functional test + -

Functional Testing Page - isVisible

- - +

isVisible functional test

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/functional/functional_test.js b/test/functional/functional_test.js index bf1f0184..81528cb4 100644 --- a/test/functional/functional_test.js +++ b/test/functional/functional_test.js @@ -3,6 +3,9 @@ const firefox = require('selenium-webdriver/firefox'); const webdriver = require('selenium-webdriver'); const { ancestors, isDomElement, isVisible, toDomElement } = require('../../utilsForFrontend'); +const WAIT_MS = 10000; +const TEST_PAGE_URL = 'http://localhost:8000/functional_test.html'; + describe('isVisible', () => { const options = new firefox.Options(); options.headless(); @@ -11,24 +14,41 @@ describe('isVisible', () => { .forBrowser('firefox') .setFirefoxOptions(options) .build(); + describe('Unprivileged', () => { - it('should return true when an element is visible', async () => { - // TODO: put actual checks here - await driver.get('http://localhost:8000/functional_test.html'); + it('Should return false when an element is hidden', async () => { + const hiddenElementIds = [ + 'not-visible-1', + 'not-visible-2', + 'not-visible-3', + 'not-visible-4', + 'not-visible-5', + 'not-visible-6', + 'not-visible-7', + 'not-visible-8', + 'not-visible-9', + 'not-visible-10', + 'not-visible-11', + 'not-visible-12', + ]; + await driver.get(TEST_PAGE_URL); await driver.wait(async () => { const readyState = await driver.executeScript('return document.readyState'); return readyState === 'complete'; - }); - const isElementVisible = await driver.wait(async () => { - return driver.executeScript(` + }, WAIT_MS, `Page did not finish loading after ${WAIT_MS} ms`); + + for (const id of hiddenElementIds) { + const isElementVisible = await driver.executeScript(` ${ancestors} ${isDomElement} ${toDomElement} - return (${isVisible}(document.getElementById("image"))); + return ${isVisible}(document.getElementById('${id}')); `); - }); - const expected = true; - expect(isElementVisible).to.deep.equal(expected); + expect( + isElementVisible, + `isVisible should return false for element with id '${id}'.` + ).to.be.false; + } }); }); From 8c4d931336be7452b34e9e8073b5c65287026499 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Fri, 9 Aug 2019 21:21:52 -0700 Subject: [PATCH 05/13] Rename functional test and test page --- .travis.yml | 2 +- test/functional/{functional_test.html => isVisible.html} | 0 test/functional/{functional_test.js => isVisible.js} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename test/functional/{functional_test.html => isVisible.html} (100%) rename test/functional/{functional_test.js => isVisible.js} (96%) diff --git a/.travis.yml b/.travis.yml index 45cd94a1..fba108c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ jobs: - make all - export PATH=$PATH:$TRAVIS_BUILD_DIR/node_modules/geckodriver/bin - node test/functional/setup_http_server & - - yarn mocha --timeout 60000 test/functional/functional_test.js + - yarn mocha --timeout 60000 test/functional/isVisible.js - kill %1 # - stage: test # name: "Javascript tests" diff --git a/test/functional/functional_test.html b/test/functional/isVisible.html similarity index 100% rename from test/functional/functional_test.html rename to test/functional/isVisible.html diff --git a/test/functional/functional_test.js b/test/functional/isVisible.js similarity index 96% rename from test/functional/functional_test.js rename to test/functional/isVisible.js index 81528cb4..3f80af1f 100644 --- a/test/functional/functional_test.js +++ b/test/functional/isVisible.js @@ -4,7 +4,7 @@ const webdriver = require('selenium-webdriver'); const { ancestors, isDomElement, isVisible, toDomElement } = require('../../utilsForFrontend'); const WAIT_MS = 10000; -const TEST_PAGE_URL = 'http://localhost:8000/functional_test.html'; +const TEST_PAGE_URL = 'http://localhost:8000/isVisible.html'; describe('isVisible', () => { const options = new firefox.Options(); From 0b326d9108d5bf940c53c814116a597619f699e9 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Fri, 9 Aug 2019 21:42:30 -0700 Subject: [PATCH 06/13] Move JS functional tests into existing 'JavaScript tests' stage Also replace chai's expect with assert for consistency with existing JS tests. For some reason, in the Makefile, make coverage was using node_modules/.bin/_mocha. The isVisible functional test fails unless I replace '_mocha' with 'mocha'. --- .travis.yml | 80 +++++++++---------- Makefile | 4 +- test/functional/isVisible.js | 74 ++++++++--------- ...setup_http_server.js => setup_http_server} | 2 + 4 files changed, 78 insertions(+), 82 deletions(-) rename test/functional/{setup_http_server.js => setup_http_server} (97%) mode change 100644 => 100755 diff --git a/.travis.yml b/.travis.yml index fba108c2..854dec73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,60 +1,52 @@ jobs: include: - # TODO: move into "Javascript tests" stage - stage: test - name: "Javascript functional tests" + name: "Javascript tests" language: node_js node_js: - node env: - MOZ_HEADLESS=1 addons: + apt: + packages: + - python-virtualenv firefox: latest script: - - make all - export PATH=$PATH:$TRAVIS_BUILD_DIR/node_modules/geckodriver/bin - - node test/functional/setup_http_server & - - yarn mocha --timeout 60000 test/functional/isVisible.js + - test/functional/setup_http_server & + - npm test - kill %1 - # - stage: test - # name: "Javascript tests" - # language: node_js - # node_js: - # - node - # addons: - # apt: - # packages: - # - python-virtualenv - # after_success: - # - "npm run coveralls" - # - stage: test - # name: "Python 3.6 tests" - # language: python - # python: - # - "3.6" - # install: - # - pip install -e cli/ - # script: - # - pytest cli/fathom_web/test - # - stage: test - # name: "Python 3.7 tests" - # dist: bionic - # language: python - # python: - # - "3.7" - # install: - # - pip install -e cli/ - # script: - # - pytest cli/fathom_web/test - # - stage: deploy - # name: "Docs deployment" - # script: skip - # deploy: - # provider: script - # script: docs/tooling/travis-deploy-docs - # on: - # branch: master - # skip_cleanup: true + after_success: + - "npm run coveralls" + - stage: test + name: "Python 3.6 tests" + language: python + python: + - "3.6" + install: + - pip install -e cli/ + script: + - pytest cli/fathom_web/test + - stage: test + name: "Python 3.7 tests" + dist: bionic + language: python + python: + - "3.7" + install: + - pip install -e cli/ + script: + - pytest cli/fathom_web/test + - stage: deploy + name: "Docs deployment" + script: skip + deploy: + provider: script + script: docs/tooling/travis-deploy-docs + on: + branch: master + skip_cleanup: true notifications: email: diff --git a/Makefile b/Makefile index 2489d5fa..e7bd5d04 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,11 @@ lint: @node_modules/.bin/eslint --ext mjs . test: $(JS) - @node_modules/.bin/mocha + @node_modules/.bin/mocha --recursive pytest cli/fathom_web/test coverage: $(JS) - @node_modules/.bin/istanbul cover node_modules/.bin/_mocha + @node_modules/.bin/istanbul cover node_modules/.bin/mocha -- --recursive debugtest: $(JS) # This is known to work on node 7.6.0. diff --git a/test/functional/isVisible.js b/test/functional/isVisible.js index 3f80af1f..d470c44a 100644 --- a/test/functional/isVisible.js +++ b/test/functional/isVisible.js @@ -1,8 +1,10 @@ -const { expect } = require('chai'); +const { assert } = require('chai'); const firefox = require('selenium-webdriver/firefox'); const webdriver = require('selenium-webdriver'); const { ancestors, isDomElement, isVisible, toDomElement } = require('../../utilsForFrontend'); +const { until, By } = webdriver; + const WAIT_MS = 10000; const TEST_PAGE_URL = 'http://localhost:8000/isVisible.html'; @@ -15,42 +17,42 @@ describe('isVisible', () => { .setFirefoxOptions(options) .build(); - describe('Unprivileged', () => { - it('Should return false when an element is hidden', async () => { - const hiddenElementIds = [ - 'not-visible-1', - 'not-visible-2', - 'not-visible-3', - 'not-visible-4', - 'not-visible-5', - 'not-visible-6', - 'not-visible-7', - 'not-visible-8', - 'not-visible-9', - 'not-visible-10', - 'not-visible-11', - 'not-visible-12', - ]; - await driver.get(TEST_PAGE_URL); - await driver.wait(async () => { - const readyState = await driver.executeScript('return document.readyState'); - return readyState === 'complete'; - }, WAIT_MS, `Page did not finish loading after ${WAIT_MS} ms`); + it('Should return false when an element is hidden', async () => { + const hiddenElementIds = [ + 'not-visible-1', + 'not-visible-2', + 'not-visible-3', + 'not-visible-4', + 'not-visible-5', + 'not-visible-6', + 'not-visible-7', + 'not-visible-8', + 'not-visible-9', + 'not-visible-10', + 'not-visible-11', + 'not-visible-12', + ]; + await driver.get(TEST_PAGE_URL); + // await driver.wait(async () => { + // const readyState = await driver.executeScript('return document.readyState'); + // return readyState === 'complete'; + // }, WAIT_MS, `Page did not finish loading after ${WAIT_MS} ms`); - for (const id of hiddenElementIds) { - const isElementVisible = await driver.executeScript(` - ${ancestors} - ${isDomElement} - ${toDomElement} - return ${isVisible}(document.getElementById('${id}')); - `); - expect( - isElementVisible, - `isVisible should return false for element with id '${id}'.` - ).to.be.false; - } - }); - }); + for (const id of hiddenElementIds) { + await driver.wait(until.elementLocated(By.id(id)), WAIT_MS); + const isElementVisible = await driver.executeScript(` + ${ancestors} + ${isDomElement} + ${toDomElement} + return ${isVisible}(document.getElementById('${id}')); + `); + assert.equal( + isElementVisible, + false, + `isVisible should return false for element with id '${id}'.` + ); + } + }).timeout(60000); after(async () => driver.quit()); }); diff --git a/test/functional/setup_http_server.js b/test/functional/setup_http_server old mode 100644 new mode 100755 similarity index 97% rename from test/functional/setup_http_server.js rename to test/functional/setup_http_server index 698a1e09..5e445f01 --- a/test/functional/setup_http_server.js +++ b/test/functional/setup_http_server @@ -1,3 +1,5 @@ +#!/usr/bin/env node + const http = require('http'); const fs = require('fs'); const url = require('url'); From 210644cd9856711413676e98cfca7817bc5fd992 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Tue, 13 Aug 2019 19:28:25 -0700 Subject: [PATCH 07/13] Incorporate initial feedback --- .eslintrc.yml | 5 +- .travis.yml | 2 +- Makefile | 1 + test/.eslintrc.yml | 4 - test/functional/isVisible.html | 88 ++++++------------- test/functional/isVisible.js | 71 +++++++-------- .../{setup_http_server => start_http_server} | 4 +- 7 files changed, 71 insertions(+), 104 deletions(-) delete mode 100644 test/.eslintrc.yml rename test/functional/{setup_http_server => start_http_server} (79%) diff --git a/.eslintrc.yml b/.eslintrc.yml index 33c8cf09..a1c48177 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -1,10 +1,11 @@ env: es6: true node: true + mocha: true parserOptions: sourceType: module - ecmaVersion: 7 + ecmaVersion: 8 extends: - eslint:recommended @@ -17,6 +18,7 @@ plugins: root: true rules: + array-bracket-spacing: [error, never] eqeqeq: error generator-star-spacing: [warn, {before: true, after: false}] guard-for-in: warn # There's nothing wrong with for..in if you know what you're doing. This is here just to keep me from accidentally saying "for..in" when I mean "for..of". Delete this and come up with a better solution if we ever need to use "for..in". @@ -36,6 +38,7 @@ rules: no-useless-escape: error no-var: warn no-warning-comments: [warn, {terms: [xxx, fixme, hack], location: start}] + object-curly-spacing: [error, never] object-shorthand: [error, properties] prefer-const: off quotes: [error, single, {avoidEscape: true, allowTemplateLiterals: true}] diff --git a/.travis.yml b/.travis.yml index 854dec73..3dd4d17d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ jobs: firefox: latest script: - export PATH=$PATH:$TRAVIS_BUILD_DIR/node_modules/geckodriver/bin - - test/functional/setup_http_server & + - test/functional/start_http_server & - npm test - kill %1 after_success: diff --git a/Makefile b/Makefile index e7bd5d04..264286bf 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ all: $(JS) lint: @node_modules/.bin/eslint --ext mjs . + @node_modules/.bin/eslint test/functional test: $(JS) @node_modules/.bin/mocha --recursive diff --git a/test/.eslintrc.yml b/test/.eslintrc.yml deleted file mode 100644 index 9a16c85b..00000000 --- a/test/.eslintrc.yml +++ /dev/null @@ -1,4 +0,0 @@ -env: - mocha: true -parserOptions: - ecmaVersion: 8 diff --git a/test/functional/isVisible.html b/test/functional/isVisible.html index b5b73015..80d3f190 100644 --- a/test/functional/isVisible.html +++ b/test/functional/isVisible.html @@ -2,86 +2,54 @@ - + isVisible functional test

isVisible functional test

-
-
-
-
+
+
+ + + -
-
+
+ +
-
-
+ +
+
+
+ +
+
-
-
+ +
+ +
+ +
+ +
+
+ +
+
-
-
-
-
diff --git a/test/functional/isVisible.js b/test/functional/isVisible.js index d470c44a..328a9d37 100644 --- a/test/functional/isVisible.js +++ b/test/functional/isVisible.js @@ -1,9 +1,9 @@ -const { assert } = require('chai'); +const {assert} = require('chai'); const firefox = require('selenium-webdriver/firefox'); const webdriver = require('selenium-webdriver'); -const { ancestors, isDomElement, isVisible, toDomElement } = require('../../utilsForFrontend'); +const {ancestors, isDomElement, isVisible, toDomElement} = require('../../utilsForFrontend'); -const { until, By } = webdriver; +const {Builder, until, By} = webdriver; const WAIT_MS = 10000; const TEST_PAGE_URL = 'http://localhost:8000/isVisible.html'; @@ -12,45 +12,46 @@ describe('isVisible', () => { const options = new firefox.Options(); options.headless(); - const driver = new webdriver.Builder() + const driver = new Builder() .forBrowser('firefox') .setFirefoxOptions(options) .build(); - it('Should return false when an element is hidden', async () => { - const hiddenElementIds = [ - 'not-visible-1', - 'not-visible-2', - 'not-visible-3', - 'not-visible-4', - 'not-visible-5', - 'not-visible-6', - 'not-visible-7', - 'not-visible-8', - 'not-visible-9', - 'not-visible-10', - 'not-visible-11', - 'not-visible-12', - ]; + async function checkVisibility(id, expected) { + await driver.wait(until.elementLocated(By.id(id)), WAIT_MS); + const isElementVisible = await driver.executeScript(` + ${ancestors} + ${isDomElement} + ${toDomElement} + return ${isVisible}(document.getElementById('${id}')); + `); + assert.equal( + isElementVisible, + expected, + `isVisible should return false for element with id '${id}'.` + ); + } + + it('should return false when an element is hidden', async () => { + const hiddenElementIds = await driver.executeScript(` + return [].slice.call(document.querySelectorAll('[id^="not-visible-"]')).map((element) => element.id); + `); + await driver.get(TEST_PAGE_URL); - // await driver.wait(async () => { - // const readyState = await driver.executeScript('return document.readyState'); - // return readyState === 'complete'; - // }, WAIT_MS, `Page did not finish loading after ${WAIT_MS} ms`); for (const id of hiddenElementIds) { - await driver.wait(until.elementLocated(By.id(id)), WAIT_MS); - const isElementVisible = await driver.executeScript(` - ${ancestors} - ${isDomElement} - ${toDomElement} - return ${isVisible}(document.getElementById('${id}')); - `); - assert.equal( - isElementVisible, - false, - `isVisible should return false for element with id '${id}'.` - ); + await checkVisibility(id, false); + } + }).timeout(60000); + + it('should return true when an element is visible', async () => { + const visibleElementIds = await driver.executeScript(` + return [].slice.call(document.querySelectorAll('[id^="visible-"]')).map((element) => element.id); + `); + await driver.get(TEST_PAGE_URL); + + for (const id of visibleElementIds) { + await checkVisibility(id, true); } }).timeout(60000); diff --git a/test/functional/setup_http_server b/test/functional/start_http_server similarity index 79% rename from test/functional/setup_http_server rename to test/functional/start_http_server index 5e445f01..8aa3337a 100755 --- a/test/functional/setup_http_server +++ b/test/functional/start_http_server @@ -10,9 +10,7 @@ const server = http.createServer((request, response) => { const path = url.parse(request.url).pathname; fs.readFile(__dirname + path, 'utf8', (error, data) => { if (error) { - response.writeHead(404); - response.write(`There was an error: ${error.errno}, ${error.code}`); - response.end(); + console.error(`There was a ${error.code} error fetching the resource at ${path}.`); } else { response.writeHead(200, {'Content-Type': 'text/html'}); response.write(data); From 68b791b1a1fe5c024090ab892bbdae0ad7c24b3a Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Tue, 13 Aug 2019 21:10:18 -0700 Subject: [PATCH 08/13] Ignore node/no-missing-require eslint error Now that we are actually linting the isVisible.js functional test, eslint reports an error: ``` /home/travis/build/mozilla/fathom/test/functional/isVisible.js 4:68 error "../../utilsForFrontend" is not found node/no-missing-require ``` I believe this is because 'require' is relative to the directory in which the script is found, while eslint is checking relative to the current working directory. This could be resolved by: * Ignoring the error (easiest) * Updating 'eslint-plugin-node' to >= v5.1.0 in which we can apply the 'resolvePaths' setting. * This requires also updating 'eslint', as otherwise 'make lint' fails * Updating 'eslint' updates default rules, for which there are then dozens of new violations throughout the source code to address * I vote that considering updating eslint be a follow-up issue, rather than part of fixing #122 In light of these options, I chose the best, easiest one, since it doesn't blow up everything else. --- test/functional/isVisible.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/isVisible.js b/test/functional/isVisible.js index 328a9d37..c06d5972 100644 --- a/test/functional/isVisible.js +++ b/test/functional/isVisible.js @@ -1,7 +1,7 @@ const {assert} = require('chai'); const firefox = require('selenium-webdriver/firefox'); const webdriver = require('selenium-webdriver'); -const {ancestors, isDomElement, isVisible, toDomElement} = require('../../utilsForFrontend'); +const {ancestors, isDomElement, isVisible, toDomElement} = require('../../utilsForFrontend'); // eslint-disable-line node/no-missing-require const {Builder, until, By} = webdriver; From 8d87435625f267362d66b95e0efa4b96390d1b46 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Mon, 19 Aug 2019 11:38:44 -0700 Subject: [PATCH 09/13] Fix mocha timeout issue Added a timeout to the 'after all' hook, as it is possible this can take longer than two seconds. Also made the callbacks into 'it' regular functions instead of arrow functions for consistency with the 'after all' hook. * With arrow functions, the 'this' binding for 'this.timeout' does not point to the desired target, and the 'after' hook threw an error if I tried to use the original approach I had with the 'it' blocks. --- test/functional/isVisible.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/test/functional/isVisible.js b/test/functional/isVisible.js index c06d5972..214a9f95 100644 --- a/test/functional/isVisible.js +++ b/test/functional/isVisible.js @@ -32,7 +32,8 @@ describe('isVisible', () => { ); } - it('should return false when an element is hidden', async () => { + it('should return false when an element is hidden', async function () { + this.timeout(WAIT_MS); const hiddenElementIds = await driver.executeScript(` return [].slice.call(document.querySelectorAll('[id^="not-visible-"]')).map((element) => element.id); `); @@ -41,10 +42,12 @@ describe('isVisible', () => { for (const id of hiddenElementIds) { await checkVisibility(id, false); + } - }).timeout(60000); + }); - it('should return true when an element is visible', async () => { + it('should return true when an element is visible', async function () { + this.timeout(WAIT_MS); const visibleElementIds = await driver.executeScript(` return [].slice.call(document.querySelectorAll('[id^="visible-"]')).map((element) => element.id); `); @@ -53,7 +56,10 @@ describe('isVisible', () => { for (const id of visibleElementIds) { await checkVisibility(id, true); } - }).timeout(60000); + }); - after(async () => driver.quit()); + after(async function () { + this.timeout(WAIT_MS); + return driver.quit(); + }); }); From c8f2ee2dd001e5b5ae462a966362609d0d01bef5 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Mon, 19 Aug 2019 17:04:52 -0700 Subject: [PATCH 10/13] Exclude 'isVisible' and its called functions from coverage Add '/* istanbul ignore next */' to stop trying to cover the following methods, since they are executed in the 'isVisible.html' test page, and that scope does not have coverage variables defined. * ancestors * isDomElement * isVisible * toDomElement This allows coverage to continue to work (ignoring these functions) and keeps the JS functional tests in the same stage as the rest of the JavaScript tests in TravisCI. It should be noted that none of these functions previously had test coverage, which is part of why this approach is feasible. --- Makefile | 2 +- utilsForFrontend.mjs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 264286bf..a11a8167 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ test: $(JS) pytest cli/fathom_web/test coverage: $(JS) - @node_modules/.bin/istanbul cover node_modules/.bin/mocha -- --recursive + @node_modules/.bin/istanbul cover node_modules/.bin/_mocha -- --recursive debugtest: $(JS) # This is known to work on node 7.6.0. diff --git a/utilsForFrontend.mjs b/utilsForFrontend.mjs index 08774d24..27b2e50e 100644 --- a/utilsForFrontend.mjs +++ b/utilsForFrontend.mjs @@ -389,6 +389,7 @@ export function domSort(fnodes) { /** * @return whether a thing appears to be a DOM element. */ +/* istanbul ignore next */ export function isDomElement(thing) { return thing.nodeName !== undefined; } @@ -399,6 +400,7 @@ export function isDomElement(thing) { * * @arg fnodeOrElement {Node|Fnode} */ +/* istanbul ignore next */ export function toDomElement(fnodeOrElement) { return isDomElement(fnodeOrElement) ? fnodeOrElement : fnodeOrElement.element; } @@ -436,6 +438,7 @@ export function attributesMatch(element, predicate, attrs = []) { /** * Yield an element and each of its ancestors. */ +/* istanbul ignore next */ export function *ancestors(element) { yield element; let parent; @@ -461,6 +464,7 @@ export function sigmoid(x) { * Return whether an element is practically visible, considering things like 0 * size or opacity, ``visibility: hidden`` and ``overflow: hidden``. */ +/* istanbul ignore next */ export function isVisible(fnodeOrElement) { // This could be 5x more efficient if https://github.com/w3c/csswg-drafts/issues/4122 happens. const element = toDomElement(fnodeOrElement); From ed8e087e49c5f3df56671749e969ff8f4f9c252e Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Mon, 19 Aug 2019 18:41:28 -0700 Subject: [PATCH 11/13] Make 'npm test' work both locally and in CI Move the set up and tear down commands inside of 'npm test' instead of just in '.travis.yml'. --- .travis.yml | 3 --- package.json | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3dd4d17d..19f72e83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,10 +13,7 @@ jobs: - python-virtualenv firefox: latest script: - - export PATH=$PATH:$TRAVIS_BUILD_DIR/node_modules/geckodriver/bin - - test/functional/start_http_server & - npm test - - kill %1 after_success: - "npm run coveralls" - stage: test diff --git a/package.json b/package.json index 75fb1a7e..233e0572 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,13 @@ "url": "https://github.com/mozilla/fathom.git" }, "scripts": { + "add-geckodriver-to-path": "export PATH=$PATH:$PWD/node_modules/geckodriver/bin", "coveralls": "cat ./coverage/lcov.info | coveralls", "lint": "make lint", + "init-server": "./test/functional/start_http_server & echo $! > pid", "pretest": "npm run lint", - "test": "make coverage" + "test": "npm run add-geckodriver-to-path && npm run init-server && make coverage && npm run uninit-server", + "uninit-server": "kill $(cat pid) && rm pid" }, "main": "index" } From 9e2ab8ec4a3984fcf22657fb4dd2bcd7ac154c4b Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Mon, 19 Aug 2019 20:17:00 -0700 Subject: [PATCH 12/13] Rename 'test/functional' to 'test/browser' --- .gitignore | 2 +- Makefile | 2 +- package.json | 2 +- test/{functional => browser}/isVisible.html | 0 test/{functional => browser}/isVisible.js | 0 test/{functional => browser}/start_http_server | 0 6 files changed, 3 insertions(+), 3 deletions(-) rename test/{functional => browser}/isVisible.html (100%) rename test/{functional => browser}/isVisible.js (100%) rename test/{functional => browser}/start_http_server (100%) diff --git a/.gitignore b/.gitignore index e3133653..f96705dd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,6 @@ **/*.js !/rollup.config.js !/trainees.js -!/test/functional/* +!/test/browser/* /cli/build /cli/dist diff --git a/Makefile b/Makefile index a11a8167..b50eaaa0 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ all: $(JS) lint: @node_modules/.bin/eslint --ext mjs . - @node_modules/.bin/eslint test/functional + @node_modules/.bin/eslint test/browser test: $(JS) @node_modules/.bin/mocha --recursive diff --git a/package.json b/package.json index 233e0572..bb879398 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "add-geckodriver-to-path": "export PATH=$PATH:$PWD/node_modules/geckodriver/bin", "coveralls": "cat ./coverage/lcov.info | coveralls", "lint": "make lint", - "init-server": "./test/functional/start_http_server & echo $! > pid", + "init-server": "./test/browser/start_http_server & echo $! > pid", "pretest": "npm run lint", "test": "npm run add-geckodriver-to-path && npm run init-server && make coverage && npm run uninit-server", "uninit-server": "kill $(cat pid) && rm pid" diff --git a/test/functional/isVisible.html b/test/browser/isVisible.html similarity index 100% rename from test/functional/isVisible.html rename to test/browser/isVisible.html diff --git a/test/functional/isVisible.js b/test/browser/isVisible.js similarity index 100% rename from test/functional/isVisible.js rename to test/browser/isVisible.js diff --git a/test/functional/start_http_server b/test/browser/start_http_server similarity index 100% rename from test/functional/start_http_server rename to test/browser/start_http_server From b04d519e9828dcde74ac99215af80d9274c5f2b5 Mon Sep 17 00:00:00 2001 From: Bianca Danforth Date: Mon, 19 Aug 2019 21:13:39 -0700 Subject: [PATCH 13/13] Incorporate other review feedback --- test/browser/isVisible.html | 3 ++- test/browser/isVisible.js | 32 +++++++++++++------------------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/test/browser/isVisible.html b/test/browser/isVisible.html index 80d3f190..569e860e 100644 --- a/test/browser/isVisible.html +++ b/test/browser/isVisible.html @@ -2,7 +2,8 @@ - + + isVisible functional test