Initial commit adding integration tests. (#1557)
* Initial commit adding integration tests. * Fix test name. * Adding package-lock. * Some updates. * More updates. * Extend page comparison max to 9.99% * Removed node assert statement. * Updated baseline images and tests. * Added docs, fixed docker configuration file. * Updates. * Update docker compose. * Fix json error. * Add comment to Dockerfile. * Comment to trigger CI. * Moved dependencies to allow for docker image build. * Add restore command. * Fix restore command. * Change docker image. * Add checkout command. * Add java. * Add node version install. * Trying machine executor. * Fix typo.: * Remove old docker command. * EVERYTHING IN ONE SHELL. * Trying nvm. * Fix typo. * Fix node version... * Fix typo. * More node stuff. * Updates to docker compose. * Add chown to circleci config. * Fix docker login error. * Change exec command user. * Add screenshots for debugging. * Try fixing js command. * Try fixing js command again. * Change screenshot path * Add mkdir for error shots. * Trying something for postgres. * Updates. * Fix lint error. * Try fixing errorshots. * Updates before rebase. * Updated baseline for new homepage. * Remove baseline image save. * Trying a change for errorshots. * Update test.
This commit is contained in:
Родитель
d252cc2a29
Коммит
b19eff6d4a
|
@ -49,6 +49,28 @@ jobs:
|
|||
name: Test Code
|
||||
command: docker run blurts-server npm run lint
|
||||
|
||||
integration-test:
|
||||
machine:
|
||||
image: ubuntu-1604:201903-01
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Build and run tests.
|
||||
command: |
|
||||
export NVM_DIR="/opt/circleci/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
nvm use 10
|
||||
node -v
|
||||
cp .env-dist .env
|
||||
npm install
|
||||
npm install --only=dev
|
||||
sudo chown -R $USER:$USER .
|
||||
mkdir ./tests/integration/errorShots
|
||||
docker-compose -f tests/integration/docker-compose.yml up --build -d
|
||||
docker-compose -f tests/integration/docker-compose.yml exec --user root firefox npm run test:integration
|
||||
- store_artifacts:
|
||||
path: ./tests/integration/errorShots/
|
||||
|
||||
deploy:
|
||||
docker:
|
||||
- image: docker:18.02.0-ce
|
||||
|
@ -98,7 +120,6 @@ workflows:
|
|||
filters:
|
||||
tags:
|
||||
only: /.*/
|
||||
|
||||
- deploy:
|
||||
requires:
|
||||
- build
|
||||
|
@ -111,3 +132,7 @@ workflows:
|
|||
filters:
|
||||
branches:
|
||||
only: master
|
||||
- integration-test:
|
||||
requires:
|
||||
- build
|
||||
|
||||
|
|
|
@ -41,19 +41,20 @@ BASKET_NEWSLETTER=mozilla-and-you
|
|||
# leave FXA_ENABLED empty to disable FXA
|
||||
FXA_ENABLED=
|
||||
FXA_SETTINGS_URL="https://stable.dev.lcip.org/settings"
|
||||
OAUTH_CLIENT_ID=cb1bef9d06bb9bc9
|
||||
OAUTH_CLIENT_SECRET=f5fb99de6e0af18ab17e013ac1d439903179a97a1c510fc10bc3bd50bbce089b
|
||||
OAUTH_CLIENT_ID=edd29a80019d61a1
|
||||
OAUTH_CLIENT_SECRET=a80feaad77c847275d39ac989ee12a873ef6b54cbc184128f86f2afecdf003b5
|
||||
OAUTH_AUTHORIZATION_URI="https://oauth-stable.dev.lcip.org/v1/authorization"
|
||||
OAUTH_PROFILE_URI="https://stable.dev.lcip.org/profile/v1/profile"
|
||||
OAUTH_TOKEN_URI="https://oauth-stable.dev.lcip.org/v1/token"
|
||||
|
||||
# HIBP API for breach data
|
||||
HIBP_API_ROOT="https://stage.haveibeenpwned.com/api/v2/"
|
||||
# How many seconds to wait before refreshing upstream breach data from HIBP
|
||||
HIBP_RELOAD_BREACHES_TIMER=600
|
||||
# HIBP API for range search and subscription
|
||||
HIBP_KANON_API_ROOT="https://api.haveibeenpwned.com"
|
||||
HIBP_KANON_API_TOKEN=""
|
||||
HIBP_KANON_API_TOKEN=
|
||||
HIBP_API_ROOT="https://haveibeenpwned.com/api/v2"
|
||||
HIBP_API_TOKEN=
|
||||
# How many milliseconds to wait before retrying an HIBP request
|
||||
HIBP_THROTTLE_DELAY=2000
|
||||
# Max number of times to try an HIBP request before throwing error
|
||||
|
|
12
.eslintrc.js
12
.eslintrc.js
|
@ -35,7 +35,17 @@ module.exports = {
|
|||
],
|
||||
env: {
|
||||
jest: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
'tests/integration/**/*.js',
|
||||
],
|
||||
globals: {
|
||||
"$": "readonly",
|
||||
"$$": "readonly",
|
||||
"browser": "readonly",
|
||||
},
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
|
|
|
@ -12,7 +12,7 @@ USER app
|
|||
COPY package.json package.json
|
||||
COPY package-lock.json package-lock.json
|
||||
|
||||
RUN npm install && rm -rf ~app/.npm /tmp/*
|
||||
RUN npm install --production && rm -rf ~app/.npm /tmp/*
|
||||
|
||||
COPY --chown=app:app . /app
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
23
package.json
23
package.json
|
@ -10,9 +10,12 @@
|
|||
"@sentry/node": "^4.2.3",
|
||||
"arg": "^2.0.0",
|
||||
"basic-auth": "^2.0.0",
|
||||
"babel-minify": "^0.4.3",
|
||||
"body-parser": "^1.18.3",
|
||||
"clean-css-cli": "^4.2.1",
|
||||
"client-oauth2": "^4.2.1",
|
||||
"client-sessions": "^0.8.0",
|
||||
"concat": "^1.0.3",
|
||||
"cpr": "^3.0.1",
|
||||
"csurf": "^1.9.0",
|
||||
"dotenv": "^5.0.1",
|
||||
|
@ -33,14 +36,22 @@
|
|||
"mozlog": "^2.2.0",
|
||||
"nodemailer": "^4.6.4",
|
||||
"nodemailer-express-handlebars": "^3.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pg": "^7.4.3",
|
||||
"sns-validator": "^0.3.4",
|
||||
"uuid": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-minify": "^0.4.3",
|
||||
"@wdio/cli": "^5.18.6",
|
||||
"@wdio/dot-reporter": "^5.18.6",
|
||||
"@wdio/firefox-profile-service": "^5.16.11",
|
||||
"@wdio/local-runner": "^5.18.6",
|
||||
"@wdio/mocha-framework": "^5.18.6",
|
||||
"@wdio/selenium-standalone-service": "^5.16.10",
|
||||
"@wdio/spec-reporter": "^5.18.6",
|
||||
"@wdio/sync": "^5.18.5",
|
||||
"chai": "^4.2.0",
|
||||
"clean-css-cli": "^4.2.1",
|
||||
"concat": "^1.0.3",
|
||||
"coveralls": "^3.0.1",
|
||||
"eslint": "^4.18.1",
|
||||
"eslint-plugin-node": "^6.0.1",
|
||||
|
@ -51,12 +62,13 @@
|
|||
"node-mocks-http": "^1.7.0",
|
||||
"nodemon": "^1.18.7",
|
||||
"npm-audit-ci-wrapper": "^2.4.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"onchange": "^6.1.0",
|
||||
"postcss-cli": "^6.1.2",
|
||||
"stylelint": "^9.10.1",
|
||||
"stylelint-config-standard": "^18.2.0",
|
||||
"uglify-js": "^3.4.9"
|
||||
"uglify-js": "^3.4.9",
|
||||
"wdio-docker-service": "^2.2.0",
|
||||
"wdio-image-comparison-service": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "10"
|
||||
|
@ -116,6 +128,9 @@
|
|||
"test:db:migrate": "NODE_ENV=tests knex migrate:latest --knexfile db/knexfile.js --env tests",
|
||||
"test:tests": "NODE_ENV=tests HIBP_THROTTLE_DELAY=1000 HIBP_THROTTLE_MAX_TRIES=3 jest --runInBand --coverage tests/",
|
||||
"test:coveralls": "cat ./coverage/lcov.info | coveralls",
|
||||
"test:integration": "wdio tests/integration/wdio.conf.js",
|
||||
"test:integration-headless": "MOZ_HEADLESS=1 wdio tests/integration/wdio.conf.js",
|
||||
"test:integration-docker": "MOZ_HEADLESS=1 wdio tests/integration/wdio.docker.js",
|
||||
"test": "run-s test:db:migrate test:tests test:coveralls"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env bash
|
||||
# Use this script to test if a given TCP host/port are available
|
||||
|
||||
WAITFORIT_cmdname=${0##*/}
|
||||
|
||||
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
|
||||
|
||||
usage()
|
||||
{
|
||||
cat << USAGE >&2
|
||||
Usage:
|
||||
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
|
||||
-h HOST | --host=HOST Host or IP under test
|
||||
-p PORT | --port=PORT TCP port under test
|
||||
Alternatively, you specify the host and port as host:port
|
||||
-s | --strict Only execute subcommand if the test succeeds
|
||||
-q | --quiet Don't output any status messages
|
||||
-t TIMEOUT | --timeout=TIMEOUT
|
||||
Timeout in seconds, zero for no timeout
|
||||
-- COMMAND ARGS Execute command with args after the test finishes
|
||||
USAGE
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_for()
|
||||
{
|
||||
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
|
||||
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
|
||||
else
|
||||
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
|
||||
fi
|
||||
WAITFORIT_start_ts=$(date +%s)
|
||||
while :
|
||||
do
|
||||
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
|
||||
nc -z $WAITFORIT_HOST $WAITFORIT_PORT
|
||||
WAITFORIT_result=$?
|
||||
else
|
||||
(echo > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
|
||||
WAITFORIT_result=$?
|
||||
fi
|
||||
if [[ $WAITFORIT_result -eq 0 ]]; then
|
||||
WAITFORIT_end_ts=$(date +%s)
|
||||
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
return $WAITFORIT_result
|
||||
}
|
||||
|
||||
wait_for_wrapper()
|
||||
{
|
||||
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
|
||||
if [[ $WAITFORIT_QUIET -eq 1 ]]; then
|
||||
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
|
||||
else
|
||||
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
|
||||
fi
|
||||
WAITFORIT_PID=$!
|
||||
trap "kill -INT -$WAITFORIT_PID" INT
|
||||
wait $WAITFORIT_PID
|
||||
WAITFORIT_RESULT=$?
|
||||
if [[ $WAITFORIT_RESULT -ne 0 ]]; then
|
||||
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
|
||||
fi
|
||||
return $WAITFORIT_RESULT
|
||||
}
|
||||
|
||||
# process arguments
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
*:* )
|
||||
WAITFORIT_hostport=(${1//:/ })
|
||||
WAITFORIT_HOST=${WAITFORIT_hostport[0]}
|
||||
WAITFORIT_PORT=${WAITFORIT_hostport[1]}
|
||||
shift 1
|
||||
;;
|
||||
--child)
|
||||
WAITFORIT_CHILD=1
|
||||
shift 1
|
||||
;;
|
||||
-q | --quiet)
|
||||
WAITFORIT_QUIET=1
|
||||
shift 1
|
||||
;;
|
||||
-s | --strict)
|
||||
WAITFORIT_STRICT=1
|
||||
shift 1
|
||||
;;
|
||||
-h)
|
||||
WAITFORIT_HOST="$2"
|
||||
if [[ $WAITFORIT_HOST == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--host=*)
|
||||
WAITFORIT_HOST="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
-p)
|
||||
WAITFORIT_PORT="$2"
|
||||
if [[ $WAITFORIT_PORT == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--port=*)
|
||||
WAITFORIT_PORT="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
-t)
|
||||
WAITFORIT_TIMEOUT="$2"
|
||||
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--timeout=*)
|
||||
WAITFORIT_TIMEOUT="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
WAITFORIT_CLI=("$@")
|
||||
break
|
||||
;;
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echoerr "Unknown argument: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
|
||||
echoerr "Error: you need to provide a host and port to test."
|
||||
usage
|
||||
fi
|
||||
|
||||
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
|
||||
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
|
||||
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
|
||||
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
|
||||
|
||||
# Check to see if timeout is from busybox?
|
||||
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
|
||||
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
|
||||
|
||||
WAITFORIT_BUSYTIMEFLAG=""
|
||||
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
|
||||
WAITFORIT_ISBUSY=1
|
||||
# Check if busybox timeout uses -t flag
|
||||
# (recent Alpine versions don't support -t anymore)
|
||||
if timeout &>/dev/stdout | grep -q -e '-t '; then
|
||||
WAITFORIT_BUSYTIMEFLAG="-t"
|
||||
fi
|
||||
else
|
||||
WAITFORIT_ISBUSY=0
|
||||
fi
|
||||
|
||||
if [[ $WAITFORIT_CHILD -gt 0 ]]; then
|
||||
wait_for
|
||||
WAITFORIT_RESULT=$?
|
||||
exit $WAITFORIT_RESULT
|
||||
else
|
||||
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
|
||||
wait_for_wrapper
|
||||
WAITFORIT_RESULT=$?
|
||||
else
|
||||
wait_for
|
||||
WAITFORIT_RESULT=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $WAITFORIT_CLI != "" ]]; then
|
||||
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
|
||||
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
|
||||
exit $WAITFORIT_RESULT
|
||||
fi
|
||||
exec "${WAITFORIT_CLI[@]}"
|
||||
else
|
||||
exit $WAITFORIT_RESULT
|
||||
fi
|
|
@ -0,0 +1,26 @@
|
|||
# Build app for integration tests
|
||||
FROM node:10
|
||||
|
||||
RUN useradd -d /app -u 1001 -g 1000 app
|
||||
|
||||
RUN npm update -g
|
||||
RUN rm -rf /tmp/*
|
||||
|
||||
# RUN apk add --no-cache bash
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN chown app /app
|
||||
|
||||
USER app
|
||||
|
||||
COPY package.json package.json
|
||||
COPY package-lock.json package-lock.json
|
||||
|
||||
RUN npm install && rm -rf ~app/.npm /tmp/*
|
||||
|
||||
COPY --chown=app:root . /app
|
||||
|
||||
RUN npm run build:all
|
||||
|
||||
CMD NODE_ICU_DATA=./node_modules/full-icu node server.js
|
|
@ -0,0 +1,22 @@
|
|||
# Firefox Monitor Integration tests
|
||||
|
||||
### Prerequisites
|
||||
- Docker
|
||||
- Docker-Compose
|
||||
- [geckodriver]
|
||||
- [npm]
|
||||
- [nodejs]
|
||||
|
||||
## Firefox Setup
|
||||
|
||||
Make sure Firefox is in your system path if you want to watch the tests run inside your browser.
|
||||
|
||||
1. Follow setup instructions [here](https://github.com/mozilla/blurts-server#install).
|
||||
2. Set appropriate ENV variables, HIBP_API_TOKEN, HIBP_KANON_API_TOKEN, MAILINATOR_PASSWORD
|
||||
2. Build and start the containers: ```docker-compose -f tests/integration/docker-compose.yml up --build -d```.
|
||||
3. Run the tests: ```npm run test:integration```.
|
||||
They can also be run headlessly: ```npm run test:integration-headless```, and inside docker: ```npm run test:integration-docker```.
|
||||
|
||||
[geckodriver]: https://github.com/mozilla/geckodriver/releases
|
||||
[npm]: https://docs.npmjs.com/
|
||||
[nodejs]: https://nodejs.org/en/
|
|
@ -0,0 +1,55 @@
|
|||
# Integration test docker-compose
|
||||
version: "3.7"
|
||||
services:
|
||||
server:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: tests/integration/Dockerfile.integration-test.yml
|
||||
ports:
|
||||
- ${PORT}:${PORT}
|
||||
depends_on:
|
||||
- postgres
|
||||
environment:
|
||||
- HIBP_KANON_API_TOKEN
|
||||
- HIBP_API_TOKEN
|
||||
- FXA_ENABLED=1
|
||||
- LOGOS_ORIGIN=null
|
||||
- BREACH_RESOLUTION_ENABLED=false
|
||||
- MONITOR_FXA_PASSWORD
|
||||
- DATABASE_URL=postgres://postgres@postgres:5432/blurts
|
||||
links:
|
||||
- postgres
|
||||
postgres:
|
||||
image: postgres
|
||||
restart: always
|
||||
environment:
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_DB=blurts
|
||||
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||
expose:
|
||||
- "5432"
|
||||
ports:
|
||||
- "5432:5432"
|
||||
migration:
|
||||
image: integration_server:latest
|
||||
command: bash -c "chmod +x ./scripts/wait-for-it.sh && ./scripts/wait-for-it.sh postgres:5432 -- npm run db:migrate"
|
||||
environment:
|
||||
- DATABASE_URL=postgres://postgres@postgres:5432/blurts
|
||||
links:
|
||||
- postgres
|
||||
depends_on:
|
||||
- postgres
|
||||
firefox:
|
||||
image: b4handjr/selenium-firefox:python3-latest
|
||||
env_file: ../../.env
|
||||
environment:
|
||||
- MOZ_HEADLESS=1
|
||||
- MONITOR_FXA_PASSWORD
|
||||
volumes:
|
||||
- ../../:/code
|
||||
expose:
|
||||
- "4444"
|
||||
ports:
|
||||
- "5900:5900"
|
||||
shm_size: 2g
|
||||
network_mode: host
|
|
@ -0,0 +1,21 @@
|
|||
"use strict";
|
||||
|
||||
class UserDashboardPage {
|
||||
|
||||
waitForPageToLoad() {
|
||||
$("#dashboard").waitForExist(5000);
|
||||
return this;
|
||||
}
|
||||
|
||||
get addEmailBox() { return $("#email-add"); }
|
||||
get verificationLink() { return $("#email-add-submit"); }
|
||||
manageEmailAddresses() {
|
||||
const UserPreferencesPage = require("./userPreferences.page");
|
||||
|
||||
$(".manage-emails").waitForExist(5000);
|
||||
$(".manage-emails").click();
|
||||
return UserPreferencesPage.waitForPageToLoad();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new UserDashboardPage();
|
|
@ -0,0 +1,29 @@
|
|||
"use strict";
|
||||
|
||||
class HomePage {
|
||||
/* Represents the Home page */
|
||||
|
||||
waitForPageToLoad() {
|
||||
this.monitorLogo.waitForExist(5000);
|
||||
return this;
|
||||
}
|
||||
|
||||
get monitorLogo() { return $(".fx-monitor-logotype"); }
|
||||
get breachCard() { return new BreachCard(); }
|
||||
get breachEmailAddress() { return $("#scan-email"); }
|
||||
get checkBreachesButton() {
|
||||
$(".input-group-button > input:nth-child(1)").click();
|
||||
const ScanResultsPage = require("./scanResults.page");
|
||||
|
||||
return ScanResultsPage.waitForPageToLoad();
|
||||
}
|
||||
}
|
||||
|
||||
class BreachCard {
|
||||
/* Represents the Breach card region */
|
||||
|
||||
get latestBreachCard() { return $(".latest-breach"); }
|
||||
|
||||
}
|
||||
|
||||
module.exports = new HomePage();
|
|
@ -0,0 +1,19 @@
|
|||
/* global $$ */
|
||||
/* global $ */
|
||||
|
||||
"use strict";
|
||||
|
||||
class ScanResultsPage {
|
||||
|
||||
waitForPageToLoad() {
|
||||
$(".scan-results").waitForExist(5000);
|
||||
return this;
|
||||
}
|
||||
|
||||
get numberOfBreaches() {
|
||||
return $(".headline > span:nth-child(1)").getText();
|
||||
}
|
||||
get breachCards() { return $$(".breach-card"); }
|
||||
}
|
||||
|
||||
module.exports = new ScanResultsPage();
|
|
@ -0,0 +1,13 @@
|
|||
/* global $ */
|
||||
|
||||
"use strict";
|
||||
|
||||
class UserPreferencesPage {
|
||||
|
||||
waitForPageToLoad() {
|
||||
$(".preferences").waitForExist(5000);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new UserPreferencesPage();
|
|
@ -0,0 +1,9 @@
|
|||
"use strict";
|
||||
|
||||
class NavBar {
|
||||
/* Represents the navbar */
|
||||
|
||||
get signIn() { return $("#sign-in-btn"); }
|
||||
}
|
||||
|
||||
module.exports = new NavBar();
|
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Breaches_Page-1920x1080.png
Normal file
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Breaches_Page-1920x1080.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 173 KiB |
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Breaches_Page-headless-1920x1080.png
Normal file
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Breaches_Page-headless-1920x1080.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 99 KiB |
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Home_Page-1920x1080.png
Normal file
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Home_Page-1920x1080.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 695 KiB |
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Home_Page-headless-1920x1080.png
Normal file
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/Home_Page-headless-1920x1080.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 414 KiB |
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/SecurityTips_Page-1920x1080.png
Normal file
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/SecurityTips_Page-1920x1080.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 5.2 MiB |
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/SecurityTips_Page-headless-1920x1080.png
Normal file
Двоичные данные
tests/integration/tests/Visual_Baseline/desktop_firefox/SecurityTips_Page-headless-1920x1080.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.0 MiB |
|
@ -0,0 +1,17 @@
|
|||
"use strict";
|
||||
|
||||
describe("Firefox Monitor Breaches Page", function() {
|
||||
this.retries(2);
|
||||
|
||||
beforeEach(function() {
|
||||
browser.url("/breaches");
|
||||
});
|
||||
|
||||
it("should look like normal", function() {
|
||||
expect(browser.checkFullPageScreen("Breaches_Page", {
|
||||
hideElements: [
|
||||
$$(".breach-info-wrapper"),
|
||||
],
|
||||
})).to.be.within(0, 9.99);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,81 @@
|
|||
/* eslint-disable no-console */
|
||||
"use strict";
|
||||
|
||||
const HomePage = require("../pages/desktop/home.page");
|
||||
const NavBar = require("../regions/navbar.region");
|
||||
const UserDashboardPage = require("../pages/desktop/dashboard.page");
|
||||
|
||||
describe("Firefox Monitor homepage", function() {
|
||||
/* this.retries(2); */
|
||||
|
||||
beforeEach(function() {
|
||||
browser.url("/");
|
||||
});
|
||||
|
||||
it("should load the latest breach card", function() {
|
||||
const homePage = HomePage;
|
||||
|
||||
homePage.waitForPageToLoad();
|
||||
expect(homePage.breachCard.latestBreachCard.isDisplayed()).to.be.true;
|
||||
});
|
||||
|
||||
it("should look like normal", function() {
|
||||
expect(browser.checkFullPageScreen("Home_Page", {
|
||||
hideElements: [
|
||||
$$(".breach-info-wrapper"),
|
||||
],
|
||||
})).to.be.within(0, 9.99);
|
||||
});
|
||||
|
||||
it("should load correct number of breaches from an email input", function() {
|
||||
const homePage = HomePage;
|
||||
|
||||
homePage.waitForPageToLoad();
|
||||
homePage.breachEmailAddress.setValue(global.primaryEmail);
|
||||
const scanResults = homePage.checkBreachesButton;
|
||||
expect(scanResults.breachCards.length)
|
||||
.to
|
||||
.equal(Number(scanResults.numberOfBreaches));
|
||||
});
|
||||
|
||||
it("should allow secondary email to be added", function() {
|
||||
const homePage = HomePage;
|
||||
const navBar = NavBar;
|
||||
|
||||
homePage.waitForPageToLoad();
|
||||
navBar.signIn.click();
|
||||
// FxA login
|
||||
// Check if fxa email is needed, if error, just continue
|
||||
try {
|
||||
$(".email").waitForExist(5000);
|
||||
$(".email").click();
|
||||
$(".email").setValue(global.primaryEmail);
|
||||
$("#submit-btn").click();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
// FxA password login
|
||||
$("#password").waitForExist(5000);
|
||||
$("#password").click();
|
||||
$("#password").setValue(global.monitorFxaPassword);
|
||||
$("#submit-btn").click();
|
||||
|
||||
// Begin navigiation in monitor
|
||||
const dashboard = UserDashboardPage.waitForPageToLoad();
|
||||
dashboard.addEmailBox.setValue(global.secondaryEmail);
|
||||
dashboard.verificationLink.click();
|
||||
// Wait for dashboard to reload
|
||||
try {
|
||||
dashboard.waitForPageToLoad();
|
||||
dashboard.manageEmailAddresses();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const email = $$(".e-address")[1];
|
||||
// Check email
|
||||
expect(email.getText()).to.equal(global.secondaryEmail);
|
||||
$(".remove-email-submit").click();
|
||||
browser.refresh();
|
||||
expect(email.getText()).to.equal(global.primaryEmail);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
"use strict";
|
||||
|
||||
describe("Firefox Monitor Security Tips Page", function() {
|
||||
this.retries(2);
|
||||
|
||||
beforeEach(function() {
|
||||
browser.url("/security-tips");
|
||||
});
|
||||
|
||||
it("should look like normal", function() {
|
||||
expect(browser.checkFullPageScreen("SecurityTips_Page", {})).to.be.within(0, 5);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
This file is used to create a baseline image for a webpage.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
describe("Firefox Monitor homepage", function() {
|
||||
this.retries(2);
|
||||
|
||||
beforeEach(function() {
|
||||
browser.url("/");
|
||||
});
|
||||
|
||||
it("should look like normal", function() {
|
||||
browser.saveFullPageScreen("Home_Page", {
|
||||
hideElements: [
|
||||
$$(".breach-info-wrapper"),
|
||||
],
|
||||
});
|
||||
expect(browser.checkFullPageScreen("Home_Page", {
|
||||
hideElements: [
|
||||
$$(".breach-info-wrapper"),
|
||||
],
|
||||
})).to.equal(0);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,278 @@
|
|||
/* eslint-disable no-process-env */
|
||||
/* eslint-disable no-undef */
|
||||
/* eslint-disable strict */
|
||||
|
||||
const { join } = require("path");
|
||||
require("dotenv").config();
|
||||
|
||||
exports.config = {
|
||||
//
|
||||
// ====================
|
||||
// Runner Configuration
|
||||
// ====================
|
||||
//
|
||||
// WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
|
||||
// on a remote machine).
|
||||
runner: "local",
|
||||
//
|
||||
// Override default path ('/wd/hub') for chromedriver service.
|
||||
// path: '/wd/hub',
|
||||
//
|
||||
// ==================
|
||||
// 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: [
|
||||
"./tests/integration/tests/**/test-*-page.js",
|
||||
],
|
||||
// Patterns to exclude.
|
||||
exclude: [
|
||||
// 'path/to/excluded/files'
|
||||
],
|
||||
//
|
||||
// ============
|
||||
// Capabilities
|
||||
// ============
|
||||
// Define your capabilities here. WebdriverIO can run multiple capabilities 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 options in
|
||||
// order to group specific specs to a specific capability.
|
||||
//
|
||||
// First, you can 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,
|
||||
//
|
||||
// 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
|
||||
//
|
||||
capabilities: [{
|
||||
browserName: "firefox",
|
||||
"moz:firefoxOptions": {
|
||||
log: { level: "trace" },
|
||||
prefs: {},
|
||||
},
|
||||
}],
|
||||
//
|
||||
// ===================
|
||||
// Test Configurations
|
||||
// ===================
|
||||
// Define all options that are relevant for the WebdriverIO instance here
|
||||
//
|
||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||
logLevel: "error",
|
||||
//
|
||||
// Set specific log levels per logger
|
||||
// loggers:
|
||||
// - webdriver, webdriverio
|
||||
// - @wdio/applitools-service, @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
|
||||
// - @wdio/mocha-framework, @wdio/jasmine-framework
|
||||
// - @wdio/local-runner, @wdio/lambda-runner
|
||||
// - @wdio/sumologic-reporter
|
||||
// - @wdio/cli, @wdio/config, @wdio/sync, @wdio/utils
|
||||
// Level of logging verbosity: trace | debug | info | warn | error | silent
|
||||
// logLevels: {
|
||||
// webdriver: 'info',
|
||||
// '@wdio/applitools-service': 'info'
|
||||
// },
|
||||
//
|
||||
// If you only want to run your tests until a specific amount of tests have failed use
|
||||
// bail (default is 0 - don't bail, run all tests).
|
||||
bail: 0,
|
||||
//
|
||||
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
|
||||
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
|
||||
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
|
||||
// gets prepended directly.
|
||||
baseUrl: process.env.SERVER_URL,
|
||||
//
|
||||
// Default timeout for all waitFor* commands.
|
||||
waitforTimeout: 10000,
|
||||
//
|
||||
// Default timeout in milliseconds for request
|
||||
// if browser driver or grid doesn't send response
|
||||
connectionRetryTimeout: 90000,
|
||||
//
|
||||
// Default request retries count
|
||||
connectionRetryCount: 3,
|
||||
//
|
||||
// Test runner services
|
||||
// Services take over a specific job you don't want to take care of. They enhance
|
||||
// your test setup with almost no effort. Unlike plugins, they don't add new
|
||||
// commands. Instead, they hook themselves up into the test process.
|
||||
services: [
|
||||
"firefox-profile", "selenium-standalone", ["image-comparison", {
|
||||
baselineFolder: join(process.cwd(), "./tests/integration/tests/Visual_Baseline/"),
|
||||
formatImageName: process.env.MOZ_HEADLESS ? "{tag}-headless-{width}x{height}" : "{tag}-{width}x{height}",
|
||||
screenshotPath: join(process.cwd(), ".tmp/"),
|
||||
savePerInstance: true,
|
||||
// autoSaveBaseline: true,
|
||||
}],
|
||||
],
|
||||
|
||||
// Framework you want to run your specs with.
|
||||
// The following are supported: Mocha, Jasmine, and Cucumber
|
||||
// see also: https://webdriver.io/docs/frameworks.html
|
||||
//
|
||||
// Make sure you have the wdio adapter package for the specific framework installed
|
||||
// before running any tests.
|
||||
framework: "mocha",
|
||||
//
|
||||
// The number of times to retry the entire specfile when it fails as a whole
|
||||
// specFileRetries: 1,
|
||||
//
|
||||
// Test reporter for stdout.
|
||||
// The only one supported by default is 'dot'
|
||||
// see also: https://webdriver.io/docs/dot-reporter.html
|
||||
reporters: ["dot", "spec"],
|
||||
|
||||
//
|
||||
// Options to be passed to Mocha.
|
||||
// See the full list at http://mochajs.org/
|
||||
mochaOpts: {
|
||||
ui: "bdd",
|
||||
timeout: 120000,
|
||||
},
|
||||
//
|
||||
// =====
|
||||
// Hooks
|
||||
// =====
|
||||
// WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
|
||||
// it and to build services around it. You can either apply a single function or an array of
|
||||
// methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
|
||||
// resolved to continue.
|
||||
/**
|
||||
* Gets executed once before all workers get launched.
|
||||
* @param {Object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
*/
|
||||
// onPrepare: function (config, capabilities) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed just before initialising the webdriver session and test framework. It allows you
|
||||
* to manipulate configurations depending on the capability or spec.
|
||||
* @param {Object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that are to be run
|
||||
*/
|
||||
//beforeSession: function (config, capabilities, specs) {
|
||||
//},
|
||||
/**
|
||||
* Gets executed before test execution begins. At this point you can access to all global
|
||||
* variables like `browser`. It is the perfect place to define custom commands.
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that are to be run
|
||||
*/
|
||||
before: function (capabilities, specs) {
|
||||
const chai = require("chai");
|
||||
|
||||
global.expect = chai.expect;
|
||||
chai.Should();
|
||||
|
||||
global.primaryEmail = "test@mailinator.com";
|
||||
global.secondaryEmail = "test" + Math.random() + "@mailinator.com";
|
||||
global.monitorFxaPassword = process.env.MONITOR_FXA_PASSWORD || "a_secure_password ;)";
|
||||
browser.setWindowSize(1920, 1080);
|
||||
|
||||
},
|
||||
/**
|
||||
* Runs before a WebdriverIO command gets executed.
|
||||
* @param {String} commandName hook command name
|
||||
* @param {Array} args arguments that command would receive
|
||||
*/
|
||||
// beforeCommand: function (commandName, args) {
|
||||
// },
|
||||
/**
|
||||
* Hook that gets executed before the suite starts
|
||||
* @param {Object} suite suite details
|
||||
*/
|
||||
// beforeSuite: function (suite) {
|
||||
// },
|
||||
/**
|
||||
* Function to be executed before a test (in Mocha/Jasmine) starts.
|
||||
*/
|
||||
// beforeTest: function (test, context) {
|
||||
// },
|
||||
/**
|
||||
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
|
||||
* beforeEach in Mocha)
|
||||
*/
|
||||
// beforeHook: function (test, context) {
|
||||
// },
|
||||
/**
|
||||
* Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
|
||||
* afterEach in Mocha)
|
||||
*/
|
||||
// afterHook: function (test, context, { error, result, duration, passed, retries }) {
|
||||
// },
|
||||
/**
|
||||
* Function to be executed after a test (in Mocha/Jasmine).
|
||||
*/
|
||||
afterTest: function(test, context, { error, result, duration, passed, retries }) {
|
||||
/* Take screenshots for debugging on circleci */
|
||||
if ("CIRCLECI" in process.env) {
|
||||
const path = join(process.cwd(), "./tests/integration/errorShots/error-"+Date.now()+".png");
|
||||
browser.saveScreenshot(path);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Hook that gets executed after the suite has ended
|
||||
* @param {Object} suite suite details
|
||||
*/
|
||||
// afterSuite: function (suite) {
|
||||
// },
|
||||
/**
|
||||
* Runs after a WebdriverIO command gets executed
|
||||
* @param {String} commandName hook command name
|
||||
* @param {Array} args arguments that command would receive
|
||||
* @param {Number} result 0 - command success, 1 - command error
|
||||
* @param {Object} error error object if any
|
||||
*/
|
||||
// afterCommand: function (commandName, args, result, error) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed after all tests are done. You still have access to all global variables from
|
||||
* the test.
|
||||
* @param {Number} result 0 - test pass, 1 - test fail
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that ran
|
||||
*/
|
||||
// after: function (result, capabilities, specs) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed right after terminating the webdriver session.
|
||||
* @param {Object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {Array.<String>} specs List of spec file paths that ran
|
||||
*/
|
||||
// afterSession: function (config, capabilities, specs) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed after all workers got shut down and the process is about to exit. An error
|
||||
* thrown in the onComplete hook will result in the test run failing.
|
||||
* @param {Object} exitCode 0 - success, 1 - fail
|
||||
* @param {Object} config wdio configuration object
|
||||
* @param {Array.<Object>} capabilities list of capabilities details
|
||||
* @param {<Object>} results object containing test results
|
||||
*/
|
||||
// onComplete: function(exitCode, config, capabilities, results) {
|
||||
// },
|
||||
/**
|
||||
* Gets executed when a refresh happens.
|
||||
* @param {String} oldSessionId session ID of the old session
|
||||
* @param {String} newSessionId session ID of the new session
|
||||
*/
|
||||
//onReload: function(oldSessionId, newSessionId) {
|
||||
//}
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
/* eslint-disable no-process-env */
|
||||
"use strict";
|
||||
|
||||
const common = require("./wdio.conf.js");
|
||||
const { join } = require("path");
|
||||
|
||||
exports.config = Object.assign({}, common.config, {
|
||||
baseUrl: "http://localhost:6060",
|
||||
maxInstances: 3,
|
||||
services: ["docker", "firefox-profile", "selenium-standalone", ["image-comparison", {
|
||||
baselineFolder: join(process.cwd(), "./tests/integration/tests/Visual_Baseline/"),
|
||||
formatImageName: process.env.MOZ_HEADLESS ? "{tag}-headless-{width}x{height}" : "{tag}-{width}x{height}",
|
||||
screenshotPath: join(process.cwd(), ".tmp/"),
|
||||
savePerInstance: true,
|
||||
}]],
|
||||
dockerOptions: {
|
||||
image: "selenium/standalone-firefox",
|
||||
healthCheck: {
|
||||
url: "http://localhost:4444",
|
||||
maxRetries: 3,
|
||||
inspectInterval: 1000,
|
||||
startDelay: 2000,
|
||||
},
|
||||
options: {
|
||||
e: ["MOZ_HEADLESS=1",
|
||||
"MONITOR_FXA_PASSWORD=${MONITOR_FXA_PASSWORD}",
|
||||
"HIBP_KANON_API_TOKEN=${HIBP_KANON_API_TOKEN}",
|
||||
"HIBP_API_TOKEN=${HIBP_API_TOKEN}",
|
||||
],
|
||||
p: ["4444:4444", "5900:5900"],
|
||||
v: "/dev/shm:/dev/shm",
|
||||
shmSize: "2g",
|
||||
network: "host",
|
||||
},
|
||||
dockerLogs: "docker-logs/",
|
||||
},
|
||||
});
|
Загрузка…
Ссылка в новой задаче