mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-06 03:13:42 -05:00
Add support for E2E (end-to-end) tests (#625)
This changeset lays the foundation for supporting E2E (end-to-end) integration tests for US Notify. It brings in the Playwright testing framework along with the Playwright pytest plugin to make this possible, and includes the following adjustments: - A new test session fixture for ensuring that Playwright authenticates with the sites that are currently behind HTTP Auth (requies env-var config) - A new end_to_end test directory specifically for E2E tests - Updates to the Makefile that make sure E2E tests are not run as a part of the normal test routine but can be run separately - A new command in the Makefile to run E2E tests that will run in Chromium, Firefox, and Webkit headless browsers Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
This commit is contained in:
8
.github/workflows/checks.yml
vendored
8
.github/workflows/checks.yml
vendored
@@ -41,7 +41,13 @@ jobs:
|
||||
- name: Run js tests
|
||||
run: npm test
|
||||
- name: Run py tests with coverage
|
||||
run: pipenv run coverage run --omit=*/notifications_utils/* -m pytest --maxfail=10
|
||||
run: pipenv run coverage run --omit=*/notifications_utils/* -m pytest --maxfail=10 --ignore=tests/end_to_end tests/
|
||||
- name: Run E2E tests
|
||||
run: pipenv run pytest -v --browser chromium --browser firefox --browser webkit tests/end_to_end
|
||||
env:
|
||||
NOTIFY_STAGING_HTTP_AUTH_PASSWORD: ${{ secrets.NOTIFY_STAGING_HTTP_AUTH_PASSWORD }}
|
||||
NOTIFY_STAGING_HTTP_AUTH_USER: ${{ secrets.NOTIFY_STAGING_HTTP_AUTH_USER }}
|
||||
NOTIFY_STAGING_URI: ${{ secrets.NOTIFY_STAGING_URI }}
|
||||
- name: Check coverage threshold
|
||||
run: pipenv run coverage report --fail-under=90
|
||||
|
||||
|
||||
8
Makefile
8
Makefile
@@ -16,6 +16,7 @@ NVMSH := $(shell [ -f "$(HOME)/.nvm/nvm.sh" ] && echo "$(HOME)/.nvm/nvm.sh" || e
|
||||
.PHONY: bootstrap
|
||||
bootstrap: generate-version-file ## Set up everything to run the app
|
||||
pipenv install --dev
|
||||
pipenv run playwright install --with-deps
|
||||
source $(NVMSH) --no-use && nvm install && npm ci --no-audit
|
||||
source $(NVMSH) && npm run build
|
||||
|
||||
@@ -54,10 +55,15 @@ py-lint: ## Run python linting scanners
|
||||
.PHONY: py-test
|
||||
py-test: export NEW_RELIC_ENVIRONMENT=test
|
||||
py-test: ## Run python unit tests
|
||||
pipenv run coverage run --omit=*/notifications_utils/* -m pytest --maxfail=10 tests/
|
||||
pipenv run coverage run --omit=*/notifications_utils/* -m pytest --maxfail=10 --ignore=tests/end_to_end tests/
|
||||
pipenv run coverage report --fail-under=90
|
||||
pipenv run coverage html -d .coverage_cache
|
||||
|
||||
.PHONY: e2e-test
|
||||
e2e-test: export NEW_RELIC_ENVIRONMENT=test
|
||||
e2e-test: ## Run end-to-end integration tests
|
||||
pipenv run pytest -v --browser chromium --browser firefox --browser webkit tests/end_to_end
|
||||
|
||||
.PHONY: js-lint
|
||||
js-lint: ## Run javascript linting scanners
|
||||
source $(NVMSH) && npm run lint
|
||||
|
||||
1
Pipfile
1
Pipfile
@@ -37,6 +37,7 @@ newrelic = "*"
|
||||
flask-talisman = "*"
|
||||
notifications-utils = {editable = true, ref = "main", git = "https://github.com/GSA/notifications-utils.git"}
|
||||
coverage = "*"
|
||||
pytest-playwright = "*"
|
||||
|
||||
[dev-packages]
|
||||
isort = "==5.12.0"
|
||||
|
||||
127
Pipfile.lock
generated
127
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "7d90c44fa5dd863a7ebab1ec4fa02b8d5dc11050235d7bad87ee6cfde791720e"
|
||||
"sha256": "e6e49305bdee7cdd4605b8f6f7d0135cfe91e0c038abe6efdfa1784194ce3cdd"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@@ -50,19 +50,19 @@
|
||||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:cfcb20d5784428f31d89889e68b26efeda90f231c3119eef4af8b25ad405c55f",
|
||||
"sha256:d5ac6599951fdd519ed26c6fe15c41a7aa4021cb9adce33167344f8ce5cdb07b"
|
||||
"sha256:b2d178c8a56fe3e4c9b123dccdff20e9555d12a597b72627fa659aa6295e238a",
|
||||
"sha256:db6443fd2c65d9f35f671b03bacb0592b62d06884395ed65d75922ccddc34c2e"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.28.12"
|
||||
"version": "==1.28.13"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:7e5db466c762a071bb58c9a39d070f1333ce4f4ba6fdf9820ba21e87bd4c7e29",
|
||||
"sha256:86380672151866b5e425636e3ebad74f2b83e7163e36ef5d38d11a04b9cba33b"
|
||||
"sha256:78b96afbd88b8bd4c0967611a4cedddd9ea33d8601309dc351f81cbb5479d976",
|
||||
"sha256:9a5080ea2a444f0447a7a1a79f64252ae2a1417b6c13a54656ee991cb610dd4e"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.31.12"
|
||||
"version": "==1.31.13"
|
||||
},
|
||||
"cachetools": {
|
||||
"hashes": [
|
||||
@@ -235,7 +235,7 @@
|
||||
"sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac",
|
||||
"sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==3.2.0"
|
||||
},
|
||||
"click": {
|
||||
@@ -556,6 +556,14 @@
|
||||
"markers": "python_version < '3.10'",
|
||||
"version": "==6.8.0"
|
||||
},
|
||||
"iniconfig": {
|
||||
"hashes": [
|
||||
"sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3",
|
||||
"sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
|
||||
@@ -826,6 +834,14 @@
|
||||
],
|
||||
"version": "==2.0.3"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
|
||||
"sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==23.1"
|
||||
},
|
||||
"phonenumbers": {
|
||||
"hashes": [
|
||||
"sha256:89671217c706cbaa3ced101deefafa779836feac3e059434d886ac31f09f32c0",
|
||||
@@ -833,6 +849,27 @@
|
||||
],
|
||||
"version": "==8.13.17"
|
||||
},
|
||||
"playwright": {
|
||||
"hashes": [
|
||||
"sha256:428a719a6c7e40781c19860ed813840ac2d63678f7587abe12e800ea030d4b7e",
|
||||
"sha256:4e396853034742b76654cdab27422155d238f46e4dc6369ea75854fafb935586",
|
||||
"sha256:72e80076e595f5fcd8ebd89bf6635ad78e4bafa633119faed8b2568d17dbd398",
|
||||
"sha256:84213339f179fd2a70f77ea7faea0616d74871349d556c53a1ecb7dd5097973c",
|
||||
"sha256:89ca2261bb00b67d3dff97691cf18f4347ee0529a11e431e47df67b703d4d8fa",
|
||||
"sha256:b7c6ddfca2b141b0385387cc56c125b14ea867902c39e3fc650ddd6c429b17da",
|
||||
"sha256:ffbb927679b62fad5071439d5fe0840af46ad1844bc44bf80e1a0ad706140c98"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.36.0"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849",
|
||||
"sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"prometheus-client": {
|
||||
"hashes": [
|
||||
"sha256:21e674f39831ae3f8acde238afd9a27a37d0d2fb5a28ea094f0ce25d2cbf2091",
|
||||
@@ -848,6 +885,13 @@
|
||||
],
|
||||
"version": "==2.21"
|
||||
},
|
||||
"pyee": {
|
||||
"hashes": [
|
||||
"sha256:2770c4928abc721f46b705e6a72b0c59480c4a69c9a83ca0b00bb994f1ea4b32",
|
||||
"sha256:9f066570130c554e9cc12de5a9d86f57c7ee47fece163bbdaa3e9c933cfbdfa5"
|
||||
],
|
||||
"version": "==9.0.4"
|
||||
},
|
||||
"pyexcel": {
|
||||
"hashes": [
|
||||
"sha256:ddc6904512bfa2ecda509fb3b58229bb30db14498632fd9e7a5ba7bbfb02ed1b",
|
||||
@@ -942,6 +986,30 @@
|
||||
"index": "pypi",
|
||||
"version": "==3.6.0"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32",
|
||||
"sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==7.4.0"
|
||||
},
|
||||
"pytest-base-url": {
|
||||
"hashes": [
|
||||
"sha256:e1e88a4fd221941572ccdcf3bf6c051392d2f8b6cef3e0bc7da95abec4b5346e",
|
||||
"sha256:ed36fd632c32af9f1c08f2c2835dcf42ca8fcd097d6ed44a09f253d365ad8297"
|
||||
],
|
||||
"markers": "python_version >= '3.7' and python_version < '4.0'",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"pytest-playwright": {
|
||||
"hashes": [
|
||||
"sha256:83a896b1b28bfaa081ca9ea27229a06a114e106e2e62fb3d5f06544748fbc1fe",
|
||||
"sha256:9bf79c633c97dd1405308b8d3600e6c8c2a200a733e2f36c5a150ba4701936f8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.3"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
|
||||
@@ -966,6 +1034,14 @@
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.0.7"
|
||||
},
|
||||
"python-slugify": {
|
||||
"hashes": [
|
||||
"sha256:70ca6ea68fe63ecc8fa4fcf00ae651fc8a5d02d93dcd12ae6d4fc7ca46c4d395",
|
||||
"sha256:ce0d46ddb668b3be82f4ed5e503dbc33dd815d83e2eb6824211310d3fb172a27"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==8.0.1"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588",
|
||||
@@ -1118,6 +1194,13 @@
|
||||
],
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"text-unidecode": {
|
||||
"hashes": [
|
||||
"sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8",
|
||||
"sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"
|
||||
],
|
||||
"version": "==1.3"
|
||||
},
|
||||
"texttable": {
|
||||
"hashes": [
|
||||
"sha256:290348fb67f7746931bcdfd55ac7584ecd4e5b0846ab164333f0794b121760f2",
|
||||
@@ -1125,6 +1208,14 @@
|
||||
],
|
||||
"version": "==1.6.7"
|
||||
},
|
||||
"tomli": {
|
||||
"hashes": [
|
||||
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
|
||||
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
|
||||
],
|
||||
"markers": "python_version < '3.11'",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36",
|
||||
@@ -1215,19 +1306,19 @@
|
||||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:cfcb20d5784428f31d89889e68b26efeda90f231c3119eef4af8b25ad405c55f",
|
||||
"sha256:d5ac6599951fdd519ed26c6fe15c41a7aa4021cb9adce33167344f8ce5cdb07b"
|
||||
"sha256:b2d178c8a56fe3e4c9b123dccdff20e9555d12a597b72627fa659aa6295e238a",
|
||||
"sha256:db6443fd2c65d9f35f671b03bacb0592b62d06884395ed65d75922ccddc34c2e"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.28.12"
|
||||
"version": "==1.28.13"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:7e5db466c762a071bb58c9a39d070f1333ce4f4ba6fdf9820ba21e87bd4c7e29",
|
||||
"sha256:86380672151866b5e425636e3ebad74f2b83e7163e36ef5d38d11a04b9cba33b"
|
||||
"sha256:78b96afbd88b8bd4c0967611a4cedddd9ea33d8601309dc351f81cbb5479d976",
|
||||
"sha256:9a5080ea2a444f0447a7a1a79f64252ae2a1417b6c13a54656ee991cb610dd4e"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.31.12"
|
||||
"version": "==1.31.13"
|
||||
},
|
||||
"cachecontrol": {
|
||||
"extras": [
|
||||
@@ -1395,7 +1486,7 @@
|
||||
"sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac",
|
||||
"sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==3.2.0"
|
||||
},
|
||||
"cryptography": {
|
||||
@@ -1782,7 +1873,7 @@
|
||||
"sha256:4659bc2a667783e7a15d190f6fccf8b2486685b6dba4c19c3876314769c57526",
|
||||
"sha256:b4fa3a7a0be38243123cf9d1f3518da10c51bdb165a2b2985566247f9155a7d3"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"markers": "python_full_version >= '3.6.0'",
|
||||
"version": "==32.0.1"
|
||||
},
|
||||
"pluggy": {
|
||||
@@ -1845,7 +1936,7 @@
|
||||
"sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32",
|
||||
"sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==7.4.0"
|
||||
},
|
||||
"pytest-env": {
|
||||
@@ -1955,7 +2046,7 @@
|
||||
"sha256:8f87bc7ee54675732fa66a05ebfe489e27264caeeff3728c945d25971b6485ec",
|
||||
"sha256:d653d6bccede5844304c605d5aac802c7cf9621efd700b46c7ec2b51ea914898"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==13.4.2"
|
||||
},
|
||||
"s3transfer": {
|
||||
|
||||
21
README.md
21
README.md
@@ -15,7 +15,9 @@ The [Notify API](https://github.com/GSA/notifications-api) provides the UI's bac
|
||||
|
||||
### Common steps
|
||||
|
||||
1. Install pre-requisites for setup:
|
||||
1. Install pre-requisites for setup (on a Mac):
|
||||
- Install XCode or at least the XCode Command Line Tools
|
||||
- [Homebrew](https://brew.sh/) (follow instructions on page)
|
||||
- [jq](https://stedolan.github.io/jq/): `brew install jq`
|
||||
- [terraform](https://www.terraform.io/): `brew install terraform` or `brew install tfenv` and use `tfenv` to install `terraform ~> 1.4.0`
|
||||
- [cf-cli@8](https://docs.cloudfoundry.org/cf-cli/install-go-cli.html): `brew install cloudfoundry/tap/cf-cli@8`
|
||||
@@ -44,6 +46,23 @@ The [Notify API](https://github.com/GSA/notifications-api) provides the UI's bac
|
||||
|
||||
`make bootstrap`
|
||||
|
||||
If you run into certificate errors at the `playwright install` step, try doing this:
|
||||
|
||||
1. Run `brew --prefix` to see Homebrew's root directory
|
||||
|
||||
1. Create or modify the local `.env` file in the project and add this line:
|
||||
|
||||
`NODE_EXTRA_CA_CERTS=/CHANGE-TO-HOMEBREW-INSTALL-PATH/etc/ca-certificates/cert.pem`
|
||||
|
||||
Make sure to change `CHANGE-TO-HOMEBREW-INSTALL-PATH` to the path given by `brew --prefix` in the step above.
|
||||
For example, if `brew --prefix` gave `/opt/homebrew` as output, then the line would look like this:
|
||||
|
||||
`NODE_EXTRA_CA_CERTS=/opt/homebrew/etc/ca-certificates/cert.pem`
|
||||
|
||||
1. Save the changes to the `.env` file
|
||||
|
||||
1. Run `make bootstrap` again
|
||||
|
||||
1. Run the Flask server
|
||||
|
||||
`make run-flask`
|
||||
|
||||
120
docs/end_to_end_tests.md
Normal file
120
docs/end_to_end_tests.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Working with End-to-End Tests
|
||||
|
||||
End-to-End (E2E) tests are an important part of a assessing the overall
|
||||
integrity and stability of a system. They are a part of the overall
|
||||
test suite and serve the function of simulating a user working through
|
||||
the application. By having comprehensive E2E tests in place, we can
|
||||
instill higher confidence that future changes and refactorings won't
|
||||
negatively impact any user experience or break existing functionality.
|
||||
|
||||
The US Notify project leverages [`pytest`](https://pytest.org/) for its
|
||||
existing test suite (at least on the Python side of things) and is now
|
||||
leveraging [Playwright for Python](https://playwright.dev/python/)
|
||||
along with its `pytest` plugin for the E2E tests.
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
To work with the E2E tests in US Notify, you need to make sure you have
|
||||
all of the necessary components installed. The quick and easy way to do
|
||||
this is to use the Makefile as you did for the initial project setup. In
|
||||
fact, if you've already done this, you are already set to go! If not,
|
||||
then run the bootstrap command in your shell:
|
||||
|
||||
```sh
|
||||
make bootstrap
|
||||
```
|
||||
|
||||
This takes care of installing all of your dependencies, including those
|
||||
now needed for Playwright.
|
||||
|
||||
If you run into certificate errors at the `playwright install` step, try
|
||||
doing this:
|
||||
|
||||
1. Run `brew --prefix` to see Homebrew's root directory
|
||||
|
||||
1. Create or modify the local `.env` file in the project and add this line:
|
||||
|
||||
`NODE_EXTRA_CA_CERTS=/CHANGE-TO-HOMEBREW-INSTALL-PATH/etc/ca-certificates/cert.pem`
|
||||
|
||||
Make sure to change `CHANGE-TO-HOMEBREW-INSTALL-PATH` to the path
|
||||
given by `brew --prefix` in the step above. For example, if `brew --prefix`
|
||||
gave `/opt/homebrew` as output, then the line would look like this:
|
||||
|
||||
`NODE_EXTRA_CA_CERTS=/opt/homebrew/etc/ca-certificates/cert.pem`
|
||||
|
||||
1. Save the changes to the `.env` file
|
||||
|
||||
1. Run `make bootstrap` again
|
||||
|
||||
|
||||
### Manual Installation
|
||||
|
||||
If you need to install things separately, you'll still need to make sure
|
||||
your environment is set up and configured as outlined in the README.
|
||||
|
||||
At your shell in the project root folder, run the following commands:
|
||||
|
||||
```sh
|
||||
pipenv install pytest-playwright
|
||||
pipenv run playwright install --with-deps
|
||||
```
|
||||
|
||||
This will install Playwright and its `pytest` plugin, then the
|
||||
additional dependencies that Playwright requires.
|
||||
|
||||
See more details on the [Playwright for Python Installation page](https://playwright.dev/python/docs/intro).
|
||||
|
||||
|
||||
## Local Configuration
|
||||
|
||||
In order to run the E2E tests successfully on your local machine, you'll also
|
||||
need to make sure you have a `.env` file in the root project folder, and that it
|
||||
has at least these environment variables set in it:
|
||||
|
||||
```
|
||||
NOTIFY_STAGING_URI
|
||||
NOTIFY_STAGING_HTTP_AUTH_USER
|
||||
NOTIFY_STAGING_HTTP_AUTH_PASSWORD
|
||||
```
|
||||
|
||||
This file is **not** checked into source control and is configured to be
|
||||
ignored in the project's `.gitignore` file; please be careful that it is
|
||||
not committed to the repo and pushed!
|
||||
|
||||
|
||||
## Running E2E Tests Locally
|
||||
|
||||
To run the E2E tests on your local machine, type this command in your
|
||||
shell at the project root directory:
|
||||
|
||||
```sh
|
||||
make e2e-test
|
||||
```
|
||||
|
||||
You should see `pytest` start producing output and the existing E2E
|
||||
tests run in multiple headless browsers.
|
||||
|
||||
|
||||
## How to Create and Maintain E2E Tests
|
||||
|
||||
All of the E2E tests are found in the `tests/end_to_end` folder and are
|
||||
written as `pytest` scripts using [Playwright's Python Framework](https://playwright.dev/python/docs/writing-tests).
|
||||
|
||||
|
||||
## Maintaining E2E Tests with GitHub
|
||||
|
||||
The E2E tests are configured to run as a separate GitHub action as a
|
||||
part of our other checks found in `.github/workflows/checks.yml`.
|
||||
|
||||
The E2E tests are not run as a part of the regular unit test suite; if
|
||||
you look at the `Makefile` you'll see that the tests are two separate
|
||||
commands, with the E2E tests configured separately.
|
||||
|
||||
This is done for a couple of reasons:
|
||||
|
||||
- Keeps unit tests isolated from the E2E tests
|
||||
- Allows us to configure E2E tests separately
|
||||
|
||||
The environment variables are managed as a part of the GitHub
|
||||
repository settings.
|
||||
@@ -3384,3 +3384,15 @@ def webauthn_credential_2():
|
||||
'registration_response': 'stuff',
|
||||
'created_at': '2021-05-14T16:57:14.154185Z',
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def end_to_end_auth_context(browser):
|
||||
# Create a context with HTTP Authentication credentials for Playwright E2E
|
||||
# tests.
|
||||
context = browser.new_context(http_credentials={
|
||||
'username': os.environ.get('NOTIFY_STAGING_HTTP_AUTH_USER'),
|
||||
'password': os.environ.get('NOTIFY_STAGING_HTTP_AUTH_PASSWORD'),
|
||||
})
|
||||
|
||||
yield context
|
||||
|
||||
109
tests/end_to_end/test_landing_and_sign_in_pages.py
Normal file
109
tests/end_to_end/test_landing_and_sign_in_pages.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
from playwright.sync_api import expect
|
||||
|
||||
|
||||
def test_landing_page(end_to_end_auth_context):
|
||||
# Open a new page and go to the staging site.
|
||||
page = end_to_end_auth_context.new_page()
|
||||
page.goto(os.environ.get('NOTIFY_STAGING_URI'))
|
||||
|
||||
# Check the page title exists and matches what we expect.
|
||||
expect(page).to_have_title(re.compile('U.S. Notify'))
|
||||
|
||||
# Retrieve some prominent elements on the page for testing.
|
||||
main_header = page.get_by_role(
|
||||
'heading',
|
||||
name='Send text messages to your participants'
|
||||
)
|
||||
sign_in_button = page.get_by_role('link', name='Sign in')
|
||||
benefits_studio_email = page.get_by_role(
|
||||
'link',
|
||||
name='tts-benefits-studio@gsa.gov'
|
||||
)
|
||||
|
||||
# Check to make sure the elements are visible.
|
||||
expect(main_header).to_be_visible()
|
||||
expect(sign_in_button).to_be_visible()
|
||||
expect(benefits_studio_email).to_be_visible()
|
||||
|
||||
# Check to make sure the sign-in button and email links are correct.
|
||||
expect(sign_in_button).to_have_attribute('href', '/sign-in')
|
||||
expect(benefits_studio_email).to_have_attribute(
|
||||
'href',
|
||||
'mailto:tts-benefits-studio@gsa.gov'
|
||||
)
|
||||
|
||||
# Retrieve all other main content headers and check that they're
|
||||
# visible.
|
||||
content_headers = [
|
||||
'Control your content',
|
||||
'See how your messages perform',
|
||||
'No technical integration needed',
|
||||
'About the product',
|
||||
]
|
||||
|
||||
for content_header in content_headers:
|
||||
expect(
|
||||
page.get_by_role('heading', name=re.compile(content_header))
|
||||
).to_be_visible()
|
||||
|
||||
|
||||
def test_sign_in_page(end_to_end_auth_context):
|
||||
# Open a new page and go to the staging site.
|
||||
page = end_to_end_auth_context.new_page()
|
||||
page.goto(os.environ.get('NOTIFY_STAGING_URI'))
|
||||
|
||||
sign_in_button = page.get_by_role('link', name='Sign in')
|
||||
|
||||
# Test trying to sign in.
|
||||
sign_in_button.click()
|
||||
|
||||
# Check the page title exists and matches what we expect.
|
||||
# NOTE: The dash is a special character! It had to be copied from
|
||||
# the template itself.
|
||||
# TODO: Improve this check, or change it so no special character is
|
||||
# needed. Better yet, fix the template(s) character too.
|
||||
expect(page).to_have_title(re.compile('Sign in – U.S. Notify'))
|
||||
|
||||
# Check for the sign in heading.
|
||||
sign_in_heading = page.get_by_role('heading', name='Sign in')
|
||||
expect(sign_in_heading).to_be_visible()
|
||||
|
||||
# Check for the sign in form elements.
|
||||
# NOTE: Playwright cannot find input elements by role and recommends using
|
||||
# get_by_label() instead; however, hidden form elements do not have
|
||||
# labels associated with them, hence the XPath!
|
||||
# See https://playwright.dev/python/docs/api/class-page#page-get-by-label
|
||||
# and https://playwright.dev/python/docs/locators#locate-by-css-or-xpath
|
||||
# for more information.
|
||||
email_address_input = page.get_by_label('Email address')
|
||||
password_input = page.get_by_label('Password')
|
||||
csrf_token = page.locator('xpath=//input[@name="csrf_token"]')
|
||||
continue_button = page.get_by_role('button', name=re.compile('Continue'))
|
||||
forgot_password_link = page.get_by_role(
|
||||
'link',
|
||||
name='Forgot your password?'
|
||||
)
|
||||
|
||||
# Make sure form elements are visible and not visible as expected.
|
||||
expect(email_address_input).to_be_visible()
|
||||
expect(password_input).to_be_visible()
|
||||
expect(continue_button).to_be_visible()
|
||||
expect(forgot_password_link).to_be_visible()
|
||||
|
||||
expect(csrf_token).to_be_hidden()
|
||||
|
||||
# Make sure form elements are configured correctly with the right
|
||||
# attributes.
|
||||
expect(email_address_input).to_have_attribute('type', 'email')
|
||||
expect(password_input).to_have_attribute('type', 'password')
|
||||
expect(csrf_token).to_have_attribute('type', 'hidden')
|
||||
expect(continue_button).to_have_attribute('type', 'submit')
|
||||
expect(forgot_password_link).to_have_attribute(
|
||||
'href',
|
||||
'/forgot-password'
|
||||
)
|
||||
|
||||
# TODO: Figure out how to actually sign in...
|
||||
Reference in New Issue
Block a user