You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by sh...@apache.org on 2022/05/02 21:19:04 UTC
[trafficcontrol] branch master updated: Add e2e tests for TPv2 Servers table (#6773)
This is an automated email from the ASF dual-hosted git repository.
shamrick pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new 96b8efb03f Add e2e tests for TPv2 Servers table (#6773)
96b8efb03f is described below
commit 96b8efb03f4e69566785ebc95ef5b798718c8317
Author: ocket8888 <oc...@apache.org>
AuthorDate: Mon May 2 15:18:59 2022 -0600
Add e2e tests for TPv2 Servers table (#6773)
* Fix ESLint not properly detecting valid uses of `this`
* Add global definition of a test suite type
* Add generic table methods
* Add servers table page object and tests
* Remove unused function
* Fix incorrect servers page selector
* Add filtering test assertion
* Simplify users page object and tests with new typings
* Simplify login tests with new typings
* Stop cachebusting in all tpv2 workflows
* Move running steps back to action
* Set window size explicitly
* Fix clicking at the wrong time
* Add pause to servers table
* Fix test that couldn't possibly work
* Fix import order
* Rename workflow
* Remove unused dependency
* Upload JUNIT output
* Move configuration change to configuration file
* Skip npm install when cache is valid
* Use npm clean install
---
.github/actions/tpv2-integration-tests/README.md | 16 --
.github/actions/tpv2-integration-tests/action.yml | 19 ---
.github/actions/tpv2-integration-tests/cdn.json | 10 +-
.../actions/tpv2-integration-tests/entrypoint.sh | 97 ++---------
.github/workflows/tpv2.integration.tests.yml | 115 -------------
.github/workflows/tpv2.yml | 178 ++++++++++++++++++++-
experimental/traffic-portal/.eslintrc.json | 13 +-
.../traffic-portal/nightwatch/globals/globals.ts | 10 +-
.../nightwatch/globals/{globals.ts => index.ts} | 26 +--
.../nightwatch/globals/tables/index.ts | 99 ++++++++++++
.../traffic-portal/nightwatch/nightwatch.conf.js | 3 +-
.../nightwatch/page_objects/servers.ts | 55 +++++++
.../nightwatch/page_objects/users.ts | 36 +----
.../traffic-portal/nightwatch/tests/login.spec.ts | 19 ++-
.../nightwatch/tests/servers.spec.ts | 34 ++++
.../traffic-portal/nightwatch/tests/users.spec.ts | 25 +--
16 files changed, 415 insertions(+), 340 deletions(-)
diff --git a/.github/actions/tpv2-integration-tests/README.md b/.github/actions/tpv2-integration-tests/README.md
index 3df1b87c57..2575893da1 100644
--- a/.github/actions/tpv2-integration-tests/README.md
+++ b/.github/actions/tpv2-integration-tests/README.md
@@ -19,22 +19,9 @@
# tp-integration-tests javascript action
this action runs the traffic portal integration tests
-- requires an smtp service (see `smtp_address` input)
## inputs
-### `smtp_address`
-**required** the address of an smtp server for use by traffic ops.
-
-### `smtp_port`
-**required** the address of an smtp server for use by traffic ops. required but defaults to `25`.
-
-### `smtp_user`
-**optional** the user to authenticate with for the smtp server.
-
-### `smtp_password`
-**optional** the password to authenticate with for the smtp server.
-
## outputs
### `exit-code`
@@ -90,7 +77,4 @@ jobs:
uses: ./.github/actions/todb-init
- name: Run TP
uses: ./.github/actions/tpv2-integration-tests
- with:
- smtp_address: 172.17.0.1
-
```
diff --git a/.github/actions/tpv2-integration-tests/action.yml b/.github/actions/tpv2-integration-tests/action.yml
index 67d2ccc669..043a3317a0 100644
--- a/.github/actions/tpv2-integration-tests/action.yml
+++ b/.github/actions/tpv2-integration-tests/action.yml
@@ -17,27 +17,8 @@
name: 'tpv2-integration-tests'
description: 'Runs Traffic Portalv2 Integration tests'
-inputs:
- smtp_address:
- description: 'Address of an SMTP server to use for the Traffic Ops API tests'
- required: true
- smtp_port:
- description: 'Port of an SMTP server to use for the Traffic Ops API tests'
- required: true
- default: '25'
- smtp_user:
- description: 'The user to authenticate with for the SMTP server.'
- required: false
- smtp_password:
- description: 'The user to authenticate with for the SMTP server.'
- required: false
runs:
using: composite
steps:
- run: ${{ github.action_path }}/entrypoint.sh
shell: bash
- env:
- INPUT_SMTP_USER: ${{ inputs.smtp_user }}
- INPUT_SMTP_PORT: ${{ inputs.smtp_port }}
- INPUT_SMTP_ADDRESS: ${{ inputs.smtp_address }}
- INPUT_SMTP_PASSWORD: ${{ inputs.smtp_password }}
diff --git a/.github/actions/tpv2-integration-tests/cdn.json b/.github/actions/tpv2-integration-tests/cdn.json
index fa6d2895a9..c4f60a624f 100644
--- a/.github/actions/tpv2-integration-tests/cdn.json
+++ b/.github/actions/tpv2-integration-tests/cdn.json
@@ -1,7 +1,7 @@
{
"hypnotoad": {
"listen": [
- "https://not-a-real-host.test:1?cert=$PWD/localhost.crt&key=$PWD/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED"
+ "https://not-a-real-host.test:1?cert=$GITHUB_WORKSPACE/traffic_ops/traffic_ops_golang/localhost.crt&key=$GITHUB_WORKSPACE/traffic_ops/traffic_ops_golang/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED"
],
"user": "trafops",
"group": "trafops",
@@ -35,7 +35,7 @@
"max_connections": 500,
"max_idle_connections": 30,
"query_timeout_seconds": 10,
- "aes_key_location": "/aes.key"
+ "aes_key_location": "$GITHUB_WORKSPACE/aes.key"
},
"supported_ds_metrics": [ "kbps", "tps_total", "tps_2xx", "tps_3xx", "tps_4xx", "tps_5xx" ]
},
@@ -59,9 +59,9 @@
"inactivity_timeout": 60,
"smtp": {
"enabled": true,
- "user": "$INPUT_SMTP_USER",
- "password": "$INPUT_SMTP_PASSWORD",
- "address": "${INPUT_SMTP_ADDRESS}:${INPUT_SMTP_PORT}"
+ "user": "",
+ "password": "",
+ "address": "172.17.0.1:25"
},
"InfluxEnabled": false
}
diff --git a/.github/actions/tpv2-integration-tests/entrypoint.sh b/.github/actions/tpv2-integration-tests/entrypoint.sh
index 2765ca400e..b7f03aa004 100755
--- a/.github/actions/tpv2-integration-tests/entrypoint.sh
+++ b/.github/actions/tpv2-integration-tests/entrypoint.sh
@@ -16,97 +16,22 @@
# specific language governing permissions and limitations
# under the License.
-onFail() {
- echo "Error on line ${1} of ${2}" >&2;
- cd "${REPO_DIR}/experimental/traffic-portal"
- if ! [[ -d Reports ]]; then
- mkdir Reports;
- fi
- if [[ -d nightwatch/junit ]]; then
- mv nightwatch/junit Reports
- fi
- if [[ -d nightwatch/screens ]]; then
- mv nightwatch/screens Reports
- fi
- if [[ -d logs ]]; then
- mv logs Reports
- fi
- if [[ -f "${REPO_DIR}/traffic_ops/traffic_ops_golang" ]]; then
- cp "${REPO_DIR}/traffic_ops/traffic_ops_golang" Reports/to.log;
- fi
- echo "Detailed logs produced info Reports artifact"
- exit 1
-}
+set -ex
-trap 'onFail "${LINENO}" "${0}"' ERR
-set -o errexit -o nounset -o pipefail
-
-to_fqdn="https://localhost:6443"
-tp_fqdn="http://localhost:4200"
-
-export PGUSER="traffic_ops"
-export PGPASSWORD="twelve"
-export PGHOST="localhost"
-export PGDATABASE="traffic_ops"
-export PGPORT="5432"
-
-to_admin_username="admin"
-to_admin_password="twelve12"
-password_hash="$(<<PYTHON_COMMANDS PYTHONPATH="${GITHUB_WORKSPACE}/traffic_ops/install/bin" python
-import _postinstall
-print(_postinstall.hash_pass('${to_admin_password}'))
-PYTHON_COMMANDS
-)"
-<<QUERY psql
-INSERT INTO tm_user (username, role, tenant_id, local_passwd)
- VALUES ('${to_admin_username}', 1, 1,
- '${password_hash}'
- );
-QUERY
-
-sudo useradd trafops
-
-ciab_dir="${GITHUB_WORKSPACE}/infrastructure/cdn-in-a-box";
-openssl rand 32 | base64 | sudo tee /aes.key
-
-sudo apt-get install -y --no-install-recommends gettext curl
-
-export GOPATH="${HOME}/go"
-readonly ORG_DIR="$GOPATH/src/github.com/apache"
-readonly REPO_DIR="${ORG_DIR}/trafficcontrol"
-resources="$(dirname "$0")"
-if [[ ! -e "$REPO_DIR" ]]; then
- mkdir -p "$ORG_DIR"
- cd
- mv "${GITHUB_WORKSPACE}" "${REPO_DIR}/"
- ln -s "$REPO_DIR" "${GITHUB_WORKSPACE}"
-fi
-
-pushd "${REPO_DIR}/traffic_ops/traffic_ops_golang"
-if [[ ! -d "${GITHUB_WORKSPACE}/vendor/golang.org" ]]; then
- go mod vendor
-fi
-go build .
-
-openssl req -new -x509 -nodes -newkey rsa:4096 -out localhost.crt -keyout localhost.key -subj "/CN=tptests";
-
-envsubst <"${resources}/cdn.json" >cdn.conf
-cp "${resources}/database.json" database.conf
+cd "${GITHUB_WORKSPACE}/traffic_ops/traffic_ops_golang"
truncate -s0 out.log
-./traffic_ops_golang --cfg ./cdn.conf --dbcfg ./database.conf >out.log 2>&1 &
-popd
+envsubst <../../.github/actions/tpv2-integration-tests/cdn.json >./cdn.conf
+
+./traffic_ops_golang --cfg ./cdn.conf --dbcfg ../../.github/actions/tpv2-integration-tests/database.json > out.log 2>&1 &
-cd "${REPO_DIR}/experimental/traffic-portal"
-npm ci
+cd "${GITHUB_WORKSPACE}/experimental/traffic-portal"
npx ng serve &
-# Wait for tp/to build
timeout 15m bash <<TMOUT
- while ! curl -Lvsk "${tp_fqdn}/api/4.0/ping" >/dev/null 2>&1; do
- echo "waiting for TP/TO server to start on '${tp_fqdn}'"
- sleep 30
- done
+ while ! curl -k "http://localhost:4200/api/4.0/ping" >/dev/null 2>&1; do
+ echo "waiting for TP dev server to proxy TO API"
+ sleep 5
+ done
TMOUT
-
-npm run e2e:ci
+timeout 15m npm run e2e:ci
diff --git a/.github/workflows/tpv2.integration.tests.yml b/.github/workflows/tpv2.integration.tests.yml
deleted file mode 100644
index 19c367e7ad..0000000000
--- a/.github/workflows/tpv2.integration.tests.yml
+++ /dev/null
@@ -1,115 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-name: TPv2 Integration Tests
-
-env:
- # alpine:3.13
- ALPINE_VERSION: sha256:08d6ca16c60fe7490c03d10dc339d9fd8ea67c6466dea8d558526b1330a85930
-
-on:
- push:
- paths:
- - .github/actions/tpv2-integration-tests/**
- - .github/workflows/tpv2.integration.tests.yml
- - experimental/traffic-portal/**
- # Uncomment these when TPv2 is no longer experimental
- # - .github/actions/todb-init/**
- # - .github/actions/tvdb-init/**
- # - GO_VERSION
- # - infrastructure/cdn-in-a-box/optional/traffic_vault/**
- # - traffic_ops/*client/**.go
- # - traffic_ops/testing/api/**.go
- #- traffic_ops/traffic_ops_golang/**.go
- create:
- pull_request:
- paths:
- - .github/actions/tpv2-integration-tests/**
- - .github/workflows/tpv2.integration.tests.yml
- - experimental/traffic-portal/**
- types: [ opened, reopened, ready_for_review, synchronize ]
-
-jobs:
- TP_Integration_tests:
- if: github.event.pull_request.draft == false
- runs-on: ubuntu-latest
- services:
- postgres:
- image: postgres:11
- env:
- POSTGRES_USER: traffic_ops
- POSTGRES_PASSWORD: twelve
- POSTGRES_DB: traffic_ops
- ports:
- - 5432:5432
- options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
- smtp:
- image: maildev/maildev:2.0.0-beta3
- ports:
- - 25:25
- options: >-
- --entrypoint=bin/maildev
- --user=root
- --health-cmd="sh -c \"[[ \$(wget -qO- http://smtp/healthz) == true ]]\""
- --
- maildev/maildev:2.0.0-beta3
- --smtp=25
- --hide-extensions=STARTTLS
- --web=80
-
- steps:
- - name: Checkout
- uses: actions/checkout@master
- - name: Cache Alpine Docker image
- uses: actions/cache@v2
- with:
- path: ${{ github.workspace }}/docker-images
- key: docker-images/alpine@${{ env.ALPINE_VERSION }}.tar.gz
- - name: Import cached Alpine Docker image
- run: .github/actions/save-alpine-tar/entrypoint.sh load ${{ env.ALPINE_VERSION }}
- - name: Cache node modules
- uses: actions/cache@v2
- with:
- path: ./experimental/traffic-portal/node_modules
- key: ${{ runner.os }}-node-${{ hashFiles('./experimental/traffic-portal/package-lock.json') }}
- restore-keys: |
- ${{ runner.os }}-node-modules-
- - name: Initialize Traffic Ops Database
- id: todb
- uses: ./.github/actions/todb-init
- - name: Initialize Traffic Vault Database
- id: tvdb
- uses: ./.github/actions/tvdb-init
- - name: Check Go Version
- run: echo "::set-output name=value::$(cat GO_VERSION)"
- id: go-version
- - name: Install Go
- uses: actions/setup-go@v2
- with:
- go-version: ${{ steps.go-version.outputs.value }}
- - name: Run TP
- uses: ./.github/actions/tpv2-integration-tests
- with:
- smtp_address: 172.17.0.1
- - name: Upload Report
- uses: actions/upload-artifact@v2
- if: always()
- with:
- name: ${{ github.job }}
- path: ${{ github.workspace }}/expirimental/traffic-portal/Reports
- - name: Save Alpine Docker image
- run: .github/actions/save-alpine-tar/entrypoint.sh save ${{ env.ALPINE_VERSION }}
diff --git a/.github/workflows/tpv2.yml b/.github/workflows/tpv2.yml
index 70e93a450b..066f55a944 100644
--- a/.github/workflows/tpv2.yml
+++ b/.github/workflows/tpv2.yml
@@ -14,25 +14,32 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
-name: Lint and Test Experimental Traffic Portal
+name: Experimental Traffic Portal v2
+
+env:
+ # alpine:3.13
+ ALPINE_VERSION: sha256:08d6ca16c60fe7490c03d10dc339d9fd8ea67c6466dea8d558526b1330a85930
on:
pull_request:
paths:
- experimental/traffic-portal/**
- .github/workflows/tpv2.yml
- types: [opened, reopened, edited, synchronize]
+ - .github/actions/tpv2-integration-tests
+ types: [opened, reopened, ready_for_review, synchronize]
jobs:
build:
+ if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v1
+ uses: actions/checkout@v3
- name: Cache node modules
- uses: actions/cache@v1
+ id: restore-npm-cache
+ uses: actions/cache@v3
with:
path: ./experimental/traffic-portal/node_modules
key: ${{ runner.os }}-node-${{ hashFiles('./experimental/traffic-portal/package-lock.json') }}
@@ -40,14 +47,12 @@ jobs:
${{ runner.os }}-node-
- name: Node 16
- uses: actions/setup-node@v1
+ uses: actions/setup-node@v3
with:
node-version: 16.x
- - name: Install latest Chrome
- run: sudo apt-get update && sudo apt-get install google-chrome-stable
-
- name: NPM install
+ if: steps.restore-npm-cache.cache-hit != 'true'
run: |
cd experimental/traffic-portal/
npm ci
@@ -56,13 +61,170 @@ jobs:
run: |
cd experimental/traffic-portal/
npm run build:ssr
+ lint:
+ if: github.event.pull_request.draft == false
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Cache node modules
+ id: restore-npm-cache
+ uses: actions/cache@v3
+ with:
+ path: ./experimental/traffic-portal/node_modules
+ key: ${{ runner.os }}-node-${{ hashFiles('./experimental/traffic-portal/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-
+
+ - name: Node 16
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16.x
+
+ - name: NPM install
+ if: steps.restore-npm-cache.cache-hit != 'true'
+ run: |
+ cd experimental/traffic-portal/
+ npm ci
- name: Lint
run: |
cd experimental/traffic-portal/
npm run lint
+ unit-tests:
+ if: github.event.pull_request.draft == false
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Cache node modules
+ id: restore-npm-cache
+ uses: actions/cache@v3
+ with:
+ path: ./experimental/traffic-portal/node_modules
+ key: ${{ runner.os }}-node-${{ hashFiles('./experimental/traffic-portal/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-
+
+ - name: Node 16
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16.x
+
+ - name: Install latest Chrome
+ run: sudo apt-get update && sudo apt-get install google-chrome-stable
+
+ - name: NPM install
+ if: steps.restore-npm-cache.cache-hit != 'true'
+ run: |
+ cd experimental/traffic-portal/
+ npm ci
- name: Test
run: |
cd experimental/traffic-portal/
npm run test:ci
+ end-to-end-tests:
+ if: github.event.pull_request.draft == false
+ runs-on: ubuntu-latest
+ env:
+ PGUSER: traffic_ops
+ PGPASSWORD: twelve
+ PGHOST: localhost
+ PGDATABASE: traffic_ops
+ PGPORT: 5432
+ services:
+ postgres:
+ image: postgres:13
+ env:
+ POSTGRES_USER: traffic_ops
+ POSTGRES_PASSWORD: twelve
+ POSTGRES_DB: traffic_ops
+ ports:
+ - 5432:5432
+ options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
+ smtp:
+ image: maildev/maildev:2.0.0-beta3
+ ports:
+ - 25:25
+ options: >-
+ --entrypoint=bin/maildev
+ --user=root
+ --health-cmd="sh -c \"[[ \$(wget -qO- http://smtp/healthz) == true ]]\""
+ --
+ maildev/maildev:2.0.0-beta3
+ --smtp=25
+ --hide-extensions=STARTTLS
+ --web=80
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Cache Alpine Docker image
+ uses: actions/cache@v3
+ with:
+ path: ${{ github.workspace }}/docker-images
+ key: docker-images/alpine@${{ env.ALPINE_VERSION }}.tar.gz
+ - name: Import cached Alpine Docker image
+ run: .github/actions/save-alpine-tar/entrypoint.sh load ${{ env.ALPINE_VERSION }}
+ - name: Cache node modules
+ id: restore-npm-cache
+ uses: actions/cache@v3
+ with:
+ path: ./experimental/traffic-portal/node_modules
+ key: ${{ runner.os }}-node-${{ hashFiles('./experimental/traffic-portal/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-modules-
+ - name: Initialize Traffic Ops Database
+ id: todb
+ uses: ./.github/actions/todb-init
+ - name: Initialize Traffic Vault Database
+ id: tvdb
+ uses: ./.github/actions/tvdb-init
+ - name: Check Go Version
+ run: echo "::set-output name=value::$(cat GO_VERSION)"
+ id: go-version
+ - name: Install Go
+ uses: actions/setup-go@v3
+ with:
+ go-version: ${{ steps.go-version.outputs.value }}
+ - name: Build Traffic Ops
+ run: |
+ cd "${GITHUB_WORKSPACE}/traffic_ops/traffic_ops_golang"
+ go build .
+
+ # Setup
+ - name: Install dependencies
+ run: sudo apt-get update && sudo apt-get install postgresql-client gettext-base
+ - name: Create admin user
+ run: |
+ psql -c "INSERT INTO tm_user (username, role, tenant_id, local_passwd) VALUES ('admin', 1, 1, 'SCRYPT:16384:8:1:p0Bppp/6IBeYxSwdLuYddsdMLBU/BNSlLY6fSIF7H1XW4eTbNVeMPVm7TuTEG4FM8PbqLlVwi8sPy8ZJznAlaQ==:sRcHWGe43mm/uEmXTIw37GcLEQZTlWAdf4vJqK8f0MDh8P+8gXoNx+nxWyb3r/0Bh+yyg0g/dUvti/ePZJL+Jw==');"
+ - name: Create SSL Certificates and AES key
+ run: |
+ openssl rand 32 | base64 | tee "${GITHUB_WORKSPACE}/aes.key"
+ openssl req -new -x509 -nodes -newkey rsa:4096 -out traffic_ops/traffic_ops_golang/localhost.crt -keyout traffic_ops/traffic_ops_golang/localhost.key -subj "/CN=tptests"
+ - name: NPM install
+ if: steps.restore-npm-cache.cache-hit != 'true'
+ run: |
+ cd experimental/traffic-portal
+ npm ci
+ - name: Run everything and test
+ uses: ./.github/actions/tpv2-integration-tests
+ - name: Upload Report
+ uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: ${{ github.job }}
+ path: |
+ traffic_ops/traffic_ops_golang/out.log
+ experimental/traffic-portal/logs
+ experimental/traffic-portal/nightwatch/junit
+ experimental/traffic-portal/nightwatch/screens
+ experimental/traffic-portal/tests_output
+
+ - name: Save Alpine Docker image
+ run: .github/actions/save-alpine-tar/entrypoint.sh save ${{ env.ALPINE_VERSION }}
diff --git a/experimental/traffic-portal/.eslintrc.json b/experimental/traffic-portal/.eslintrc.json
index 9e49372860..8ff5ffa0c1 100644
--- a/experimental/traffic-portal/.eslintrc.json
+++ b/experimental/traffic-portal/.eslintrc.json
@@ -177,6 +177,12 @@
"ignoreParameters": true
}
],
+ "@typescript-eslint/no-invalid-this": [
+ "error",
+ {
+ "capIsConstructor": false
+ }
+ ],
"@typescript-eslint/no-invalid-void-type": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-misused-promises": "error",
@@ -308,12 +314,7 @@
"no-else-return": "error",
"no-empty": "error",
"no-extra-bind": "error",
- "no-invalid-this": [
- "error",
- {
- "capIsConstructor": false
- }
- ],
+ "no-invalid-this": "off",
"no-multiple-empty-lines": [
"error",
{
diff --git a/experimental/traffic-portal/nightwatch/globals/globals.ts b/experimental/traffic-portal/nightwatch/globals/globals.ts
index d1ed9e379a..a624e86707 100644
--- a/experimental/traffic-portal/nightwatch/globals/globals.ts
+++ b/experimental/traffic-portal/nightwatch/globals/globals.ts
@@ -23,13 +23,9 @@ export interface GlobalConfig extends NightwatchGlobals {
trafficOpsURL: string;
}
const config = {
- chrome_headless: {},
- default: {
- adminPass: "twelve12",
- adminUser: "admin",
- trafficOpsURL: "https://localhost:6443"
- }
+ adminPass: "twelve12",
+ adminUser: "admin",
+ trafficOpsURL: "https://localhost:6443"
};
-config.chrome_headless = config.default;
module.exports = config;
diff --git a/experimental/traffic-portal/nightwatch/globals/globals.ts b/experimental/traffic-portal/nightwatch/globals/index.ts
similarity index 55%
copy from experimental/traffic-portal/nightwatch/globals/globals.ts
copy to experimental/traffic-portal/nightwatch/globals/index.ts
index d1ed9e379a..cf939cab87 100644
--- a/experimental/traffic-portal/nightwatch/globals/globals.ts
+++ b/experimental/traffic-portal/nightwatch/globals/index.ts
@@ -1,5 +1,4 @@
/*
-*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -12,24 +11,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {type NightwatchGlobals} from "nightwatch";
+
+import type { NightwatchBrowser } from "nightwatch";
+
+import type { GlobalConfig } from "./globals";
/**
- * Defines the configuration used for the testing environment
+ * A test suite is a mapping of test descriptions to the functions that
+ * implement the thereby described test.
*/
-export interface GlobalConfig extends NightwatchGlobals {
- adminPass: string;
- adminUser: string;
- trafficOpsURL: string;
+export interface TestSuite {
+ [description: string]: (browser: NightwatchBrowser & {globals: GlobalConfig}) => (void | Promise<void>);
}
-const config = {
- chrome_headless: {},
- default: {
- adminPass: "twelve12",
- adminUser: "admin",
- trafficOpsURL: "https://localhost:6443"
- }
-};
-config.chrome_headless = config.default;
-
-module.exports = config;
diff --git a/experimental/traffic-portal/nightwatch/globals/tables/index.ts b/experimental/traffic-portal/nightwatch/globals/tables/index.ts
new file mode 100644
index 0000000000..d48af8f7b9
--- /dev/null
+++ b/experimental/traffic-portal/nightwatch/globals/tables/index.ts
@@ -0,0 +1,99 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import type { EnhancedElementInstance, EnhancedPageObject, EnhancedSectionInstance } from "nightwatch";
+
+/**
+ * TableSectionCommands is the base type for page object sections representing
+ * pages containing AG-Grid generic tables.
+ */
+export interface TableSectionCommands extends EnhancedSectionInstance, EnhancedElementInstance<EnhancedPageObject> {
+ getColumnState(column: string): Promise<boolean>;
+ searchText<T extends this>(text: string): T;
+ toggleColumn<T extends this>(column: string): T;
+}
+
+/**
+ * A CSS selector for an AG-Grid generic table's column visibility dropdown
+ * menu.
+ */
+export const columnMenuSelector = "button.dropdown-toggle";
+
+/**
+ * A CSS selector for an AG-Grid generic table's "Fuzzy Search" input text box.
+ */
+export const searchboxSelector = "input[name='fuzzControl']";
+
+/**
+ * Gets the state of an AG-Grid column by checking whether or not it's checked
+ * in the column visibility menu (doesn't actually verify that this means the
+ * column is visible).
+ *
+ * @param this Special parameter that tells the compiler what `this` is in a
+ * valid context for this function.
+ * @param column The name of the column being retrieved.
+ * @returns The state of the column named `column`. Behavior is undefined if
+ * multiple columns exist with the same given name.
+ */
+export async function getColumnState(this: TableSectionCommands, column: string): Promise<boolean> {
+ return new Promise((resolve, reject) => {
+ this.click(columnMenuSelector).getElementProperty(`input[name='column-${column}']`, "checked",
+ result => {
+ if (typeof result.value !== "boolean") {
+ console.error("incorrect type for 'checked' DOM property:", result.value);
+ reject(new Error(`incorrect type for 'checked' DOM property: ${typeof result.value}`));
+ return;
+ }
+ this.click(columnMenuSelector);
+ resolve(result.value);
+ }
+ );
+ });
+}
+
+/**
+ * Sets the text of the table's "Fuzzy Search" searchbox.
+ *
+ * @param this Special parameter that tells the compiler what `this` is in a
+ * valid context for this function.
+ * @param text The text to set in the search input.
+ * @returns The calling command section for call-chaining the way Nightwatch
+ * likes to do.
+ */
+export function searchText<T extends TableSectionCommands>(this: T, text: string): T {
+ return this.setValue(searchboxSelector, text);
+}
+
+/**
+ * Toggles the presence of a given column.
+ *
+ * @param this Special parameter that tells the compiler what `this` is in a
+ * valid context for this function.
+ * @param column The name of the column to be toggled.
+ * @returns The calling command section for call-chaining the way Nightwatch
+ * likes to do.
+ */
+export function toggleColumn<T extends TableSectionCommands>(this: T, column: string): T {
+ return this.click(columnMenuSelector).click(`input[name='${column}']`).click(columnMenuSelector);
+}
+
+/**
+ * This is meant to be mixed-in to generic table page object command sections,
+ * to most easily provide all the functionality of a table.
+ */
+export const TABLE_COMMANDS = {
+ getColumnState,
+ searchText,
+ toggleColumn
+};
diff --git a/experimental/traffic-portal/nightwatch/nightwatch.conf.js b/experimental/traffic-portal/nightwatch/nightwatch.conf.js
index a17707d4c4..eb6cf1d1fe 100644
--- a/experimental/traffic-portal/nightwatch/nightwatch.conf.js
+++ b/experimental/traffic-portal/nightwatch/nightwatch.conf.js
@@ -62,7 +62,8 @@ module.exports = {
desiredCapabilities: {
"goog:chromeOptions": {
args: [
- "--headless"
+ "--headless",
+ "--window-size=1920,1080"
]
}
},
diff --git a/experimental/traffic-portal/nightwatch/page_objects/servers.ts b/experimental/traffic-portal/nightwatch/page_objects/servers.ts
new file mode 100644
index 0000000000..79e8bf5246
--- /dev/null
+++ b/experimental/traffic-portal/nightwatch/page_objects/servers.ts
@@ -0,0 +1,55 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+import {
+ EnhancedPageObject,
+ EnhancedSectionInstance,
+ NightwatchAPI
+} from "nightwatch";
+
+import { TableSectionCommands, TABLE_COMMANDS } from "../globals/tables";
+
+/**
+ * Defines the commands for the servers table section.
+ */
+type ServersTableSectionCommands = TableSectionCommands;
+
+const serversPageObject = {
+ api: {} as NightwatchAPI,
+ sections: {
+ serversTable: {
+ commands: {
+ ...TABLE_COMMANDS
+ } as ServersTableSectionCommands,
+ elements: {
+ },
+ selector: "servers-table main"
+ }
+ },
+ url(): string {
+ return `${this.api.launchUrl}/core/servers`;
+ }
+};
+
+/**
+ * Defines the servers table section.
+ */
+type ServersTableSection = EnhancedSectionInstance<ServersTableSectionCommands, typeof serversPageObject.sections.serversTable.elements>;
+
+/**
+ * The type of the servers table page object as provided by the Nightwatch API at
+ * runtime.
+ */
+export type ServersPageObject = EnhancedPageObject<{}, {}, { serversTable: ServersTableSection }>;
+
+export default serversPageObject;
diff --git a/experimental/traffic-portal/nightwatch/page_objects/users.ts b/experimental/traffic-portal/nightwatch/page_objects/users.ts
index b5fd50e380..02ca591aaa 100644
--- a/experimental/traffic-portal/nightwatch/page_objects/users.ts
+++ b/experimental/traffic-portal/nightwatch/page_objects/users.ts
@@ -12,54 +12,26 @@
* limitations under the License.
*/
import {
- EnhancedElementInstance,
EnhancedPageObject,
EnhancedSectionInstance,
NightwatchAPI
} from "nightwatch";
+import { TableSectionCommands, TABLE_COMMANDS } from "../globals/tables";
+
/**
* Defines the commands for the users table section.
*/
-interface UsersTableSectionCommands extends EnhancedSectionInstance, EnhancedElementInstance<EnhancedPageObject> {
- getColumnState(column: string): Promise<boolean>;
- searchText(text: string): this;
- toggleColumn(column: string): this;
-}
+type UsersTableSectionCommands = TableSectionCommands;
const usersPageObject = {
api: {} as NightwatchAPI,
sections: {
usersTable: {
commands: {
- async getColumnState(column: string): Promise<boolean> {
- return new Promise((resolve, reject) => {
- this.click("@columnMenu").getElementProperty(`input[name='column-${column}']`, "checked",
- result => {
- if (typeof result.value !== "boolean") {
- console.error("incorrect type for 'checked' DOM property:", result.value);
- reject(new Error(`incorrect type for 'checked' DOM property: ${typeof result.value}`));
- return;
- }
- resolve(result.value);
- }
- ).click("@columnMenu");
- });
- },
- searchText(text: string): UsersTableSectionCommands {
- return this.setValue("@searchbox", text);
- },
- toggleColumn(column: string): UsersTableSectionCommands {
- return this.click("@columnMenu").click(`input[name='${column}']`).click("@columnMenu");
- },
+ ...TABLE_COMMANDS
} as UsersTableSectionCommands,
elements: {
- columnMenu: {
- selector: "button.dropdown-toggle"
- },
- searchbox: {
- selector: "input[name='fuzzControl']"
- },
},
selector: "main > main"
}
diff --git a/experimental/traffic-portal/nightwatch/tests/login.spec.ts b/experimental/traffic-portal/nightwatch/tests/login.spec.ts
index 0f8e928258..ec92912df0 100644
--- a/experimental/traffic-portal/nightwatch/tests/login.spec.ts
+++ b/experimental/traffic-portal/nightwatch/tests/login.spec.ts
@@ -11,13 +11,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {type NightwatchBrowser} from "nightwatch";
+import type { TestSuite } from "../globals";
+import type { LoginPageObject } from "../page_objects/login";
-import {type GlobalConfig} from "../globals/globals";
-import {type LoginPageObject} from "../page_objects/login";
-
-module.exports = {
- "Clear form test": (browser: NightwatchBrowser): void => {
+const suite: TestSuite = {
+ "Clear form test": browser => {
const page: LoginPageObject = browser.page.login();
page.navigate()
.section.loginForm
@@ -27,7 +25,7 @@ module.exports = {
.assert.containsText("@passwordTxt", "")
.end();
},
- "Incorrect password test": (browser: NightwatchBrowser): void => {
+ "Incorrect password test": browser => {
const page: LoginPageObject = browser.page.login();
page.navigate()
.section.loginForm
@@ -38,14 +36,15 @@ module.exports = {
.assert.containsText("@snackbarEle", "Invalid")
.end();
},
- "Login test": (browser: NightwatchBrowser): void => {
+ "Login test": browser => {
const page: LoginPageObject = browser.page.login();
- const globals = browser.globals as GlobalConfig;
page.navigate()
.section.loginForm
- .login(globals.adminUser, globals.adminPass)
+ .login(browser.globals.adminUser, browser.globals.adminPass)
.parent
.assert.containsText("@snackbarEle", "Success")
.end();
}
};
+
+export default suite;
diff --git a/experimental/traffic-portal/nightwatch/tests/servers.spec.ts b/experimental/traffic-portal/nightwatch/tests/servers.spec.ts
new file mode 100644
index 0000000000..301683b01e
--- /dev/null
+++ b/experimental/traffic-portal/nightwatch/tests/servers.spec.ts
@@ -0,0 +1,34 @@
+/*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+import type { TestSuite } from "../globals";
+import type { LoginPageObject } from "../page_objects/login";
+import type { ServersPageObject } from "../page_objects/servers";
+
+const suite: TestSuite = {
+ "Filter by hostname": async browser => {
+ const username = browser.globals.adminUser;
+ const password = browser.globals.adminPass;
+
+ const loginPage: LoginPageObject = browser.page.login();
+ loginPage.navigate().section.loginForm.login(username, password);
+
+ const page: ServersPageObject = browser.waitForElementPresent("main").page.servers().navigate();
+ page.pause(4000);
+ let tbl = page.waitForElementPresent("input[name=fuzzControl]").section.serversTable;
+ tbl = tbl.searchText("edge");
+ tbl.parent.assert.urlContains("search=edge").end();
+ }
+};
+
+export default suite;
diff --git a/experimental/traffic-portal/nightwatch/tests/users.spec.ts b/experimental/traffic-portal/nightwatch/tests/users.spec.ts
index 31630f563c..a74ee7f00b 100644
--- a/experimental/traffic-portal/nightwatch/tests/users.spec.ts
+++ b/experimental/traffic-portal/nightwatch/tests/users.spec.ts
@@ -11,24 +11,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import type { NightwatchBrowser } from "nightwatch";
-import { LoginPageObject } from "nightwatch/page_objects/login";
-
-import type { GlobalConfig } from "../globals/globals";
+import type { TestSuite } from "../globals";
+import { LoginPageObject } from "../page_objects/login";
import type { UsersPageObject } from "../page_objects/users";
-/**
- * A test suite is a mapping of test descriptions to the functions that
- * implement the thereby described test.
- */
-interface TestSuite {
- [description: string]: (browser: NightwatchBrowser) => (void | Promise<void>);
-}
-
const suite: TestSuite = {
"Filter by username": async browser => {
- const username = (browser.globals as GlobalConfig).adminUser;
- const password = (browser.globals as GlobalConfig).adminPass;
+ const username = browser.globals.adminUser;
+ const password = browser.globals.adminPass;
const loginPage: LoginPageObject = browser.page.login();
loginPage.navigate().section.loginForm.login(username, password);
@@ -48,14 +38,15 @@ const suite: TestSuite = {
browser.assert.equal(true, false, `failed to select ag-grid rows: ${result.value.message}`);
return;
}
- browser.assert.equal(result.value.length, 1);
+ browser.assert.equal(result.value.length, 1)
+ .end();
}
);
},
// Uncomment when user details page exists
// "View user details": browser => {
- // const username = (browser.globals as GlobalConfig).adminUser;
- // const password = (browser.globals as GlobalConfig).adminPass;
+ // const username = browser.globals.adminUser;
+ // const password = browser.globals.adminPass;
// const loginPage: LoginPageObject = browser.page.login();
// loginPage.navigate().section.loginForm.login(username, password);