mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-05-03 15:41:06 -04:00
Add E2E documentation and clean E2E tests
This changeset adds additional documentation for how to write new E2E tests and cleans up the two existing tests slightly to make better use of the fixtures that are defined. Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
This commit is contained in:
@@ -106,6 +106,105 @@ 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).
|
||||
|
||||
Inside the `tests/end_to_end` folder you'll see a `conftest.py` file,
|
||||
which is similar to the one found in the root `tests` folder but is
|
||||
specific to the E2E tests.
|
||||
|
||||
There a few fixtures defined in here, but the three most important at
|
||||
this time are these:
|
||||
|
||||
- `end_to_end_context`: A Playwright context object needed to interact
|
||||
with a browser instance.
|
||||
- `authenticated_page`: A Playwright page object that has gone through
|
||||
the sign in process the E2E user is authenticated.
|
||||
- `unauthenticated_page`: A Playwright page object that has only loaded
|
||||
the home page; no authentication done.
|
||||
|
||||
In short, if you're starting a test from scratch and testing pages that
|
||||
do not require authentication, you'll start with the
|
||||
`unauthenticated_page` fixture and work from there.
|
||||
|
||||
Any test that requires you to be authenticated, you'll start with the
|
||||
`authenticated_page` object as that'll have taken care of getting
|
||||
everything set for you and logged into the site with the E2E test user.
|
||||
|
||||
The `end_to_end_context` fixture is there more for the two page than for
|
||||
direct use, but there may be instances where it's easier to get data
|
||||
or manipulate tests in ways that are better done with the context object
|
||||
instead of working back from the page object.
|
||||
|
||||
|
||||
### Creating a new test file
|
||||
|
||||
If you want to create a new test file to help organize tests (a great
|
||||
idea!), it will be handy to import the Playwright `expect` and set the
|
||||
base URL/URI for yourself, like this:
|
||||
|
||||
```python
|
||||
from playwright.sync_api import expect
|
||||
|
||||
E2E_TEST_URI = os.getenv("NOTIFY_E2E_TEST_URI")
|
||||
```
|
||||
|
||||
By importing Playwright's `expect` object for tests and setting
|
||||
something like `E2E_TEST_URI` for yourself, it will make writing tests
|
||||
much easier.
|
||||
|
||||
|
||||
### Using the fixtures
|
||||
|
||||
To use the `authenticated_page` or `unauthenticated_page` fixtures, you
|
||||
start by defining a test function and then passing in the fixture you
|
||||
need as a positional argument. This works the same as the other
|
||||
functions defined to create a test for pytest.
|
||||
|
||||
For example, the test for the landing page starts with this:
|
||||
|
||||
```python
|
||||
def test_landing_page(unauthenticated_page):
|
||||
page = unauthenticated_page
|
||||
...
|
||||
```
|
||||
|
||||
Note the passing in of the `unauthenticated_page` fixture - there is no
|
||||
need to import this or anything, just pass it into the function. pytest
|
||||
takes care of everything else for you.
|
||||
|
||||
The second line that defines a `page` variable is a convenience, since
|
||||
you'll be referencing the page object a lot. This is recommended to
|
||||
help keep tests readable while keeping fixture names descriptive.
|
||||
|
||||
If you need to test an authenticate page, such as the accounts page,
|
||||
use the `authenticated_page` fixture instead, like so:
|
||||
|
||||
```python
|
||||
def test_add_new_service_workflow(authenticated_page):
|
||||
page = authenticated_page
|
||||
...
|
||||
```
|
||||
|
||||
Again, it's helpful to assign the fixture to a `page` variable for easy
|
||||
reference throughout the test.
|
||||
|
||||
Lastly, if you need want access to the Playwright context object that is
|
||||
used behind the page fixtures, you can reference it directly as well:
|
||||
|
||||
```python
|
||||
def test_add_new_service_workflow(authenticated_page, end_to_end_context):
|
||||
page = authenticated_page
|
||||
|
||||
# Prepare for adding a new service later in the test.
|
||||
current_date_time = datetime.datetime.now()
|
||||
new_service_name = "E2E Federal Test Service {now} - {browser_type}".format(
|
||||
now=current_date_time.strftime("%m/%d/%Y %H:%M:%S"),
|
||||
browser_type=end_to_end_context.browser.browser_type.name,
|
||||
)
|
||||
...
|
||||
```
|
||||
|
||||
In this example, I've used the context to get to the browser object
|
||||
itself to get the name of the browser for test data.
|
||||
|
||||
|
||||
## Maintaining E2E Tests with GitHub
|
||||
|
||||
|
||||
@@ -89,17 +89,30 @@ def end_to_end_authenticated_context(browser):
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def authenticated_page(end_to_end_context):
|
||||
# Open a new page and go to the staging site.
|
||||
def unauthenticated_page(end_to_end_context):
|
||||
page = end_to_end_context.new_page()
|
||||
|
||||
page.goto(f"{E2E_TEST_URI}/")
|
||||
|
||||
sign_in_button = page.get_by_role("link", name="Sign in")
|
||||
# Wait for the next page to fully load.
|
||||
page.wait_for_load_state("domcontentloaded")
|
||||
|
||||
return page
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def authenticated_page(end_to_end_context):
|
||||
# Open a new page and go to the site.
|
||||
page = end_to_end_context.new_page()
|
||||
page.goto(f"{E2E_TEST_URI}/")
|
||||
|
||||
# Wait for the next page to fully load.
|
||||
page.wait_for_load_state("domcontentloaded")
|
||||
|
||||
# Sign in to the site - E2E test accounts are set to flow through.
|
||||
sign_in_button = page.get_by_role("link", name="Sign in")
|
||||
sign_in_button.click()
|
||||
|
||||
# Wait for the next page to fully load.
|
||||
page.wait_for_load_state("domcontentloaded")
|
||||
|
||||
return page
|
||||
|
||||
@@ -9,10 +9,6 @@ E2E_TEST_URI = os.getenv("NOTIFY_E2E_TEST_URI")
|
||||
|
||||
def test_add_new_service_workflow(authenticated_page, end_to_end_context):
|
||||
page = authenticated_page
|
||||
page.goto(f"{E2E_TEST_URI}/")
|
||||
|
||||
# Wait for the next page to fully load.
|
||||
page.wait_for_load_state("domcontentloaded")
|
||||
|
||||
# Prepare for adding a new service later in the test.
|
||||
current_date_time = datetime.datetime.now()
|
||||
|
||||
@@ -6,13 +6,8 @@ from playwright.sync_api import expect
|
||||
E2E_TEST_URI = os.getenv("NOTIFY_E2E_TEST_URI")
|
||||
|
||||
|
||||
def test_landing_page(end_to_end_context):
|
||||
# Open a new page and go to the staging site.
|
||||
page = end_to_end_context.browser.new_page()
|
||||
page.goto(f"{E2E_TEST_URI}/")
|
||||
|
||||
# Check to make sure that we've arrived at the next page.
|
||||
page.wait_for_load_state("domcontentloaded")
|
||||
def test_landing_page(unauthenticated_page):
|
||||
page = unauthenticated_page
|
||||
|
||||
# Check the page title exists and matches what we expect.
|
||||
expect(page).to_have_title(re.compile("Notify.gov"))
|
||||
|
||||
Reference in New Issue
Block a user