Compare commits

...

24 Commits

Author SHA1 Message Date
Cliff Hill
eac8f8cddb End to end woes continue.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-05-12 12:43:12 -04:00
Cliff Hill
c22e216d79 Working on getting the service to be used.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-04-30 12:45:55 -04:00
Cliff Hill
db3c4d170e Getting closer...
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-04-14 12:29:36 -04:00
Cliff Hill
921985904c More conftest goodness.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-04-08 12:56:47 -04:00
Cliff Hill
53e1f792b3 Ok, looks like I can access the api finally.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-03-21 11:03:22 -04:00
Cliff Hill
33ce7c8094 Attempting to make a new notify admin client for e2e that works.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-03-10 15:36:51 -04:00
Cliff Hill
122a91e482 Stuff was done, will get back to this momentarily.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-03-10 14:25:36 -04:00
Cliff Hill
34706ee839 Cleaning things up for an additional user.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-02-13 11:02:02 -05:00
Cliff Hill
2f1acec0f5 Working on making a test user.
Signed-off-by: Cliff Hill <clifford.hill@gsa.gov>
2025-01-31 11:56:26 -05:00
Andrew Shumway
7fe7c0f095 Format 2025-01-28 09:06:08 -07:00
Beverly Nguyen
0dfad834bf Merge pull request #2288 from GSA/update-join-notify-template 2025-01-22 08:45:23 -08:00
Beverly Nguyen
86dfdb66df Merge pull request #2287 from GSA/revert-2206-2125-send-message-a11y-audit-unique-ids 2025-01-22 08:44:47 -08:00
Carlo Costino
17c6cd6e03 Update no-cost service details
This changeset updates the no-cost service details to show the correct amount of messages for the first year (100,000 instead of 250,000).

Signed-off-by: Carlo Costino <carlo.costino@gsa.gov>
2025-01-22 10:32:28 -05:00
Beverly Nguyen
084a5e37fc Revert "Send Message A11Y Audit - Unique IDs and also refactor error message on templates page" 2025-01-21 22:20:44 -08:00
Beverly Nguyen
56af19637e Merge pull request #2283 from GSA/sheevdave-patch-1
Update pull_request_template.md
2025-01-21 16:43:47 -08:00
Beverly Nguyen
6615d4fccb Merge pull request #2206 from GSA/2125-send-message-a11y-audit-unique-ids
Send Message A11Y Audit - Unique IDs and also refactor error message on templates page
2025-01-21 15:30:13 -08:00
Sheev Davé
ac79edf613 Update pull_request_template.md
Added a11y checks to PR template
2025-01-21 12:03:35 -08:00
Beverly Nguyen
1e261fd353 fixed testing 2024-12-18 15:30:48 -08:00
Beverly Nguyen
1df019e78c adding required html field 2024-12-18 12:40:45 -08:00
Beverly Nguyen
ca5e5ce04c Merge branch 'main' into 2125-send-message-a11y-audit-unique-ids 2024-12-17 11:48:05 -08:00
Beverly Nguyen
56381f5b27 adding id 2024-12-17 10:06:10 -08:00
Beverly Nguyen
12636d6a69 adding error annoucement 2024-12-12 23:31:22 -08:00
Beverly Nguyen
b731cd62bb adding error annoucement 2024-12-12 23:08:25 -08:00
Beverly Nguyen
17f758bace added id and also refactor error message on templates page 2024-12-12 18:42:03 -08:00
6 changed files with 412 additions and 3 deletions

View File

@@ -20,3 +20,8 @@ Please enter a detailed description here.
* Consideration 1
* Consideration 2
* Consideration ...
## A11y Checks (if applicable)
* Conduct automated tests through [AxeDevTools](https://www.deque.com/axe/devtools/) and [WAVE](https://wave.webaim.org/)
* Review the [Manual Checklist](https://docs.google.com/document/d/192bBXStebdXWtYhZQ73qaWMJhGcuSB1W6c9YBXhWZvc/edit?usp=sharing)

View File

@@ -183,6 +183,16 @@ class E2ETest(Staging):
"notify-admin-logo-upload-bucket-staging"
)
API_HOST_NAME = "http://localhost:6011" # nosec B105 - only used in development
# credential overrides
DANGEROUS_SALT = "development-notify-salt"
SECRET_KEY = "dev-notify-secret-key" # nosec B105 - only used in development
# ADMIN_CLIENT_USER_NAME is called ADMIN_CLIENT_ID in api repo, they should match
ADMIN_CLIENT_USER_NAME = "notify-admin"
ADMIN_CLIENT_SECRET = (
"dev-notify-secret-key" # nosec B105 - only used in development
)
class Demo(Staging):
HEADER_COLOUR = "#6F72AF" # $mauve

View File

@@ -85,8 +85,9 @@ class NotifyAdminAPIClient(BaseAPIClient):
abort(403)
def post(self, *args, **kwargs):
self.check_inactive_service()
self.check_inactive_user(args)
if os.getenv('NOTIFY_ENVIRONMENT') != "e2etest":
self.check_inactive_service()
self.check_inactive_user(args)
return super().post(*args, **kwargs)
def put(self, *args, **kwargs):

View File

@@ -34,7 +34,7 @@
{% set product_highlights = [
{
"svg_src": "#chat",
"card_heading": "Up to 250,000 messages to use over your first year*",
"card_heading": "Up to 100,000 messages to use over your first year*",
},
{
"svg_src": "#phone",

View File

@@ -1,11 +1,53 @@
import datetime
import os
from contextlib import contextmanager
from unittest.mock import patch
import pytest
from axe_core_python.sync_playwright import Axe
from flask import Flask, current_app, url_for
from flask import session as flask_session
from flask_login import login_user
from flask.testing import FlaskClient
from app import create_app
from app.models.service import Service
from app.models.user import User
from app.notify_client.service_api_client import service_api_client
from app.notify_client.user_api_client import user_api_client
from notifications_python_client.errors import HTTPError
from .. import TestClient
E2E_TEST_URI = os.getenv("NOTIFY_E2E_TEST_URI")
class TestClient(FlaskClient):
def login(self, user, mocker=None, service=None):
# Skipping authentication here and just log them in
model_user = User(user)
with self.session_transaction() as session:
session["current_session_id"] = model_user.current_session_id
session["user_id"] = model_user.id
if mocker:
mocker.patch("app.user_api_client.get_user", return_value=user)
if mocker and service:
with self.session_transaction() as session:
session["service_id"] = service["id"]
mocker.patch(
"app.service_api_client.get_service", return_value={"data": service}
)
with patch("app.events_api_client.create_event"):
login_user(model_user, force=True) # forces the user to be logged in.
with self.session_transaction() as test_session:
for key, value in flask_session.items():
test_session[key] = value
def logout(self, user):
self.get(url_for("main.sign_out"))
@pytest.fixture
def end_to_end_context(browser):
context = browser.new_context()
@@ -36,3 +78,107 @@ def check_axe_report(page):
"minor",
"moderate",
], f"Accessibility violation: {violation}"
@pytest.fixture
def notify_admin_e2e():
os.environ["NOTIFY_ENVIRONMENT"] = "e2etest"
application = Flask("app")
create_app(application)
application.test_client_class = TestClient
with application.app_context():
yield application
@pytest.fixture
def default_user(notify_admin_e2e):
user_data = user_api_client.get_user_by_email(os.getenv("NOTIFY_E2E_TEST_EMAIL"))
return user_data
@pytest.fixture
def client(notify_admin_e2e, default_user):
"""
Do not use this fixture directly use `client_request` instead
"""
with notify_admin_e2e.test_request_context(), notify_admin_e2e.test_client() as client:
client.allow_subdomain_redirects = True
try:
client.login(default_user)
yield client
finally:
client.logout(default_user)
# Need e2e service defined here?
@pytest.fixture()
def default_service(browser, client, default_user):
current_date_time = datetime.datetime.now()
now = current_date_time.strftime("%m/%d/%Y %H:%M:%S")
browser_type = browser.browser_type.name
service_name = f"E2E Federal Test Service {now} - {browser_type}"
service_id = service_api_client.create_service(
service_name=service_name,
organization_type="federal",
message_limit=current_app.config["DEFAULT_SERVICE_LIMIT"],
restricted=True,
user_id=default_user["id"],
email_from=default_user["email_address"],
)
print("*" * 80)
print(service_id)
service_data = service_api_client.get_service(service_id)
service = Service(service_data)
from pprint import pprint
pprint(dir(service))
try:
yield service
finally:
service_api_client.archive_service(service.id, None)
@contextmanager
def _set_up_user(
default_service,
name,
email_addr,
phone,
password,
auth_type,
permissions,
folder_permissions,
):
user = user_api_client.get_user_by_email_or_none(email_addr)
if user is None:
user = user_api_client.register_user(
name, email_addr, phone, password, auth_type
)
user_api_client.add_user_to_service(
default_service.id, user.id, permissions, folder_permissions
)
user_api_client.activate_user(user.id)
yield user
user_api_client.deactivate_user(user.id)
service_api_client.remove_user_from_service(user.id, default_service.id)
@pytest.fixture
def admin_user(default_service):
with _set_up_user(
default_service,
"E2E Admin Test",
"admin@nowhere.huh",
"1234567890",
"password",
"sms",
) as user:
yield user

View File

@@ -0,0 +1,247 @@
import datetime
import os
import re
import uuid
from playwright.sync_api import expect
from tests.conftest import create_user
from tests.end_to_end.conftest import check_axe_report
E2E_TEST_URI = os.getenv("NOTIFY_E2E_TEST_URI")
def create_new_template(page):
current_service_link = page.get_by_text("Current service")
expect(current_service_link).to_be_visible()
current_service_link.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
send_messages_button = page.get_by_role("link", name="Send messages")
expect(send_messages_button).to_be_visible()
send_messages_button.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
create_template_button = page.get_by_role("button", name="New template")
expect(create_template_button).to_be_visible()
create_template_button.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
start_with_a_blank_template_radio = page.get_by_text("Start with a blank template")
expect(start_with_a_blank_template_radio).to_be_visible()
start_with_a_blank_template_radio.click()
continue_button = page.get_by_role("button", name="Continue")
# continue_button = page.get_by_text("Continue")
expect(continue_button).to_be_visible()
continue_button.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
template_name_input = page.get_by_text("Template name")
expect(template_name_input).to_be_visible()
template_name = str(uuid.uuid4())
template_name_input.fill(template_name)
message_input = page.get_by_role("textbox", name="Message")
expect(message_input).to_be_visible()
message = "Test message for e2e test"
message_input.fill(message)
save_button = page.get_by_text("Save")
expect(save_button).to_be_visible()
save_button.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
assert template_name in page.content()
assert message in page.content()
def update_template(page):
# Check update template button is visible
update_template_button = page.get_by_text("Edit this template")
expect(update_template_button).to_be_visible()
update_template_button.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
assert "Edit text message template" in page.content()
# Update template name and message
template_name_input = page.get_by_text("Template name")
expect(template_name_input).to_be_visible()
template_name = str(uuid.uuid4())
template_name_input.fill(template_name)
message_input = page.get_by_role("textbox", name="Message")
expect(message_input).to_be_visible()
message = "Test message is updated for e2e test"
message_input.fill(message)
# Save new template info
save_button = page.get_by_text("Save")
expect(save_button).to_be_visible()
save_button.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
# Check new template name, message and last edited text are on page.
assert template_name in page.content()
assert message in page.content()
# assert "Last edited just now" in page.content()
def delete_template(page):
# Check delete template link is visible
delete_template_link = page.get_by_text("Delete this template")
expect(delete_template_link).to_be_visible()
delete_template_link.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
# Check confirmation text is visible
assert "Are you sure you want to delete" in page.content()
# Check that the delete button is visible
delete_button = page.get_by_text("Yes, delete")
expect(delete_button).to_be_visible()
delete_button.click()
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
assert "Select or create a template" in page.content()
def test_campaign_manager_core_user_story(default_service, end_to_end_context):
create_user()
page = end_to_end_context.new_page()
# page.goto(f"{E2E_TEST_URI}/sign-in")
# Wait for the next page to fully load.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
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=page.context.browser.browser_type.name,
# )
# page.goto(f"{E2E_TEST_URI}/accounts")
# Check to make sure that we've arrived at the next page.
# page.wait_for_load_state("domcontentloaded")
# check_axe_report(page)
# Check to make sure that we've arrived at the next page.
# Check the page title exists and matches what we expect.
# expect(page).to_have_title(re.compile("Choose service"))
# Check for the sign in heading.
# sign_in_heading = page.get_by_role("heading", name="Choose service")
# expect(sign_in_heading).to_be_visible()
# Retrieve some prominent elements on the page for testing.
# add_service_button = page.get_by_role(
# "button", name=re.compile("Add a new service")
# )
# expect(add_service_button).to_be_visible()
# existing_service_link = page.get_by_role("link", name=new_service_name)
# Check to see if the service was already created - if so, we should fail.
# TODO: Figure out how to make this truly isolated, and/or work in a
# delete service workflow.
# expect(existing_service_link).to_have_count(0)
# Click on add a new service.
a # dd_service_button.click()
# Check to make sure that we've arrived at the next page.
# page.wait_for_load_state("domcontentloaded")
# check_axe_report(page)
# Check for the sign in heading.
# about_heading = page.get_by_role("heading", name="About your service")
# expect(about_heading).to_be_visible()
# Retrieve some prominent elements on the page for testing.
# service_name_input = page.locator('xpath=//input[@name="name"]')
# add_service_button = page.get_by_role("button", name=re.compile("Add service"))
# expect(service_name_input).to_be_visible()
# expect(add_service_button).to_be_visible()
# Fill in the form.
# service_name_input.fill(new_service_name)
# Click on add service.
# add_service_button.click()
# Check to make sure that we've arrived at the next page.
# page.wait_for_load_state("domcontentloaded")
# check_axe_report(page)
# TODO this fails on staging due to duplicate results on 'get_by_text'
# Check for the service name title and heading.
# service_heading = page.get_by_text(new_service_name, exact=True)
# expect(service_heading).to_be_visible()
print("*" * 80)
print(default_service.name)
print("*" * 80)
expect(page).to_have_title(re.compile(default_service.name))
create_new_template(page)
update_template(page)
delete_template(page)
_teardown(page)
def _teardown(page):
page.click("text='Settings'")
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
page.click("text='Delete this service'")
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
page.click("text='Yes, delete'")
# Check to make sure that we've arrived at the next page.
page.wait_for_load_state("domcontentloaded")
check_axe_report(page)
# Check to make sure that we've arrived at the next page.
# Check the page title exists and matches what we expect.
expect(page).to_have_title(re.compile("Choose service"))