diff --git a/pyproject.toml b/pyproject.toml index dd15dcb..f8fc1d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ all = [ {ref="fmt"}, {ref="lint"}, {ref="check"}, {ref="test"} ] "ci:fmt" = "ruff format --check ${PWD}" # fail if not formatted "ci:lint" = "ruff check ${PWD}" [tool.poe.tasks.coverage] -cmd = "pytest --ignore ${POE_PWD}/tests/integration/frontend --cov-config=${PWD}/.coveragerc --cov --cov-report=html --cov-report=term-missing --alluredir allure-results" +cmd = "pytest --cov-config=${PWD}/.coveragerc --cov --cov-report=html --cov-report=term-missing --alluredir allure-results" cwd = "${POE_PWD}" diff --git a/tests/frontend/__init__.py b/tests/frontend/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/tests/frontend/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/frontend/conftest.py b/tests/frontend/conftest.py deleted file mode 100644 index 27dcfb5..0000000 --- a/tests/frontend/conftest.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Test fixtures for the frontend.""" - -import asyncio -import secrets -import tempfile -import threading -import time -from pathlib import Path - -import pytest -import requests -import uvicorn - - -from sshecret_admin.core.app import create_admin_app -from sshecret_admin.core.settings import AdminServerSettings -from sshecret_backend.app import create_backend_app -from sshecret_backend.settings import BackendSettings -from sshecret_backend.testing import create_test_token - -from tests.helpers import create_test_admin_user, in_tempdir -from tests.types import PortFactory, TestPorts - - -@pytest.fixture(name="ui_test_ports", scope="session") -def generate_test_ports(unused_tcp_port_factory: PortFactory) -> TestPorts: - """Generate the test ports.""" - test_ports = TestPorts( - backend=unused_tcp_port_factory(), - admin=unused_tcp_port_factory(), - sshd=unused_tcp_port_factory(), - ) - print(f"{test_ports=!r}") - return test_ports - - -@pytest.fixture(scope="function", name="ui_backend_server") -def run_backend_server(ui_test_ports: TestPorts): - """Run the backend server in a thread.""" - port = ui_test_ports.backend - - with tempfile.TemporaryDirectory() as tmp_dir: - backend_work_path = Path(tmp_dir) - db_file = backend_work_path / "backend.db" - backend_settings = BackendSettings(database=str(db_file.absolute())) - backend_app = create_backend_app(backend_settings) - token = create_test_token(backend_settings) - - config = uvicorn.Config( - app=backend_app, port=port, host="127.0.0.1", log_level="warning" - ) - server = uvicorn.Server(config) - - def run(): - asyncio.run(server.serve()) - - thread = threading.Thread(target=run) - thread.start() - - backend_url = f"http://127.0.0.1:{port}" - for _ in range(30): - try: - r = requests.get(backend_url) - if r.status_code < 500: - break - except Exception: - pass - time.sleep(1) - else: - raise RuntimeError("Backend server did not start in time") - - yield backend_url, token - - server.should_exit = True - thread.join() - - -@pytest.fixture(scope="function", name="ui_admin_server") -def run_admin_server(ui_test_ports: TestPorts, ui_backend_server: tuple[str, str]): - """Run the admin server in a thread.""" - backend_url, backend_token = ui_backend_server - port = ui_test_ports.admin - secret_key = secrets.token_urlsafe(32) - - with in_tempdir() as admin_work_path: - admin_db = admin_work_path / "ssh_admin.db" - admin_settings = AdminServerSettings.model_validate( - { - "sshecret_backend_url": backend_url, - "backend_token": backend_token, - "secret_key": secret_key, - "listen_address": "127.0.0.1", - "port": port, - "database": str(admin_db.absolute()), - "password_manager_directory": str(admin_work_path.absolute()), - } - ) - - admin_app = create_admin_app(admin_settings) - config = uvicorn.Config( - app=admin_app, port=port, host="127.0.0.1", log_level="warning" - ) - server = uvicorn.Server(config) - - def run(): - asyncio.run(server.serve()) - - thread = threading.Thread(target=run) - thread.start() - - admin_url = f"http://127.0.0.1:{port}" - admin_password = secrets.token_urlsafe(10) - create_test_admin_user(admin_settings, "test", admin_password) - - for _ in range(30): - try: - r = requests.get(admin_url) - if r.status_code < 500: - break - except Exception: - pass - time.sleep(1) - else: - raise RuntimeError("Admin server did not start in time") - - yield admin_url, ("test", admin_password) - - server.should_exit = True - thread.join() diff --git a/tests/frontend/helpers/__init__.py b/tests/frontend/helpers/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/tests/frontend/helpers/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/frontend/helpers/auth.py b/tests/frontend/helpers/auth.py deleted file mode 100644 index 4e40ae0..0000000 --- a/tests/frontend/helpers/auth.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Auth helpers.""" - -from selenium.webdriver.common.by import By -from selenium.webdriver.remote.webdriver import WebDriver -from tests.integration.types import AdminServer -from .wait_helpers import wait_until_url_contains - -def login(ui_admin_server: AdminServer, driver: WebDriver) -> WebDriver: - """Log in.""" - admin_url, credentials = ui_admin_server - username, password = credentials - - driver.get(admin_url + "/login") - username_input = driver.find_element(By.NAME, "username") - password_input = driver.find_element(By.NAME, "password") - submit_button = driver.find_element(By.XPATH, "//button[@type='submit']") - assert username_input is not None - assert password_input is not None - assert submit_button.text.lower() == "sign in" - - username_input.clear() - username_input.send_keys(username) - password_input.send_keys(password) - - - submit_button.click() - - wait_until_url_contains(driver, "/dashboard") - - return driver diff --git a/tests/frontend/helpers/db.py b/tests/frontend/helpers/db.py deleted file mode 100644 index 1c15107..0000000 --- a/tests/frontend/helpers/db.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Database helpers. - -Allows pre-loading database for tests. -""" - -from collections.abc import Iterator -from contextlib import contextmanager -import httpx -from sshecret.crypto import generate_private_key, generate_public_key_string - - -class DatabasePreloader: - """Database preloader class.""" - - def __init__(self, admin_url: str, username: str, password: str) -> None: - """Instantiate class to populate database.""" - self.admin_url: str = admin_url - self.username: str = username - self.password: str = password - - @contextmanager - def login(self) -> Iterator[httpx.Client]: - """Login and yield client.""" - login_client = httpx.Client(base_url=self.admin_url) - resp = login_client.post( - "api/v1/token", - data={"username": self.username, "password": self.password} - ) - assert resp.status_code == 200 - data = resp.json() - token = data["access_token"] - headers = {"Authorization": f"Bearer {token}"} - with httpx.Client(base_url=self.admin_url, headers=headers) as client: - yield client - - def create_client(self, *names: str) -> None: - """Create one or more clients.""" - with self.login() as http_client: - for name in names: - private_key = generate_private_key() - public_key = generate_public_key_string(private_key.public_key()) - data = { - "name": name, - "description": "Test client", - "public_key": public_key, - "sources": ["0.0.0.0/0", "::/0"], - } - resp = http_client.post("api/v1/clients/", json=data) - resp.raise_for_status() - - def create_secret(self, *secrets: tuple[str, list[str]]) -> None: - """Create secret. - - Argument format is (secret_name, [client1, client2, ...]) - - Clients must exist. - """ - with self.login() as http_client: - for name, clients in secrets: - data = { - "name": name, - "clients": clients, - "value": {"auto_generate": True, "length": 32} - } - - http_client.post("api/v1/secrets/", json=data) diff --git a/tests/frontend/helpers/wait_helpers.py b/tests/frontend/helpers/wait_helpers.py deleted file mode 100644 index 61e8e17..0000000 --- a/tests/frontend/helpers/wait_helpers.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -Collection of waiting statements. -""" - -from selenium.webdriver.remote.webdriver import WebDriver -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC -from selenium.webdriver.common.by import By - - -def wait_for_url_change(driver: WebDriver, old_url: str, timeout: int = 10) -> None: - WebDriverWait(driver, timeout).until(lambda d: d.current_url != old_url) - - -def wait_until_url_contains(driver: WebDriver, text: str, timeout: int = 10) -> None: - WebDriverWait(driver, timeout).until(lambda d: text in d.current_url) - - -def wait_for_element(driver: WebDriver, by: str, value: str, timeout: int = 10): - return WebDriverWait(driver, timeout).until( - EC.presence_of_element_located((by, value)) - ) - - -def wait_for_element_with_text( - driver: WebDriver, tag: str, text: str, timeout: int = 10 -): - return WebDriverWait(driver, timeout).until( - EC.text_to_be_present_in_element((By.TAG_NAME, tag), text) - ) - - -def wait_for_clickable(driver: WebDriver, by: str, value: str, timeout: int = 10): - return WebDriverWait(driver, timeout).until(EC.element_to_be_clickable((by, value))) - - -def wait_for_element_to_be_visisble(driver: WebDriver, id: str, timeout: int = 10): - return WebDriverWait(driver, timeout).until( - EC.visibility_of_element_located((By.ID, id)) - ) - - -def wait_for_element_to_be_disabled( - driver: WebDriver, by: str, value: str, timeout: int = 10 -): - """Wait for an element to be disabled.""" - return WebDriverWait(driver, timeout).until( - EC.none_of(EC.element_to_be_clickable((by, value))) - ) - - -def wait_for_alert(driver: WebDriver, timeout: int = 10): - """Wait for an alert.""" - return WebDriverWait(driver, timeout).until(lambda d: d.switch_to.alert) - - -def wait_for_element_to_disappear( - driver: WebDriver, by: str, value: str, timeout: int = 10 -): - """Wait for an element to disappear.""" - return WebDriverWait(driver, timeout).until( - EC.none_of(EC.presence_of_element_located((by, value))) - ) diff --git a/tests/frontend/test_clients.py b/tests/frontend/test_clients.py deleted file mode 100644 index 9cea055..0000000 --- a/tests/frontend/test_clients.py +++ /dev/null @@ -1,217 +0,0 @@ -"""Tests for the client page.""" - -from selenium.webdriver.common.by import By -from selenium.webdriver.remote.webdriver import WebDriver -import pytest -from selenium.webdriver.support.ui import WebDriverWait -from selenium.webdriver.support import expected_conditions as EC -from sshecret.crypto import generate_private_key, generate_public_key_string - -from tests.integration.types import AdminServer - -from .helpers.auth import login -from .helpers import wait_helpers - -@pytest.fixture -def client_page(ui_admin_server: AdminServer, driver: WebDriver) -> WebDriver: - """Log in and show the client page.""" - admin_url = ui_admin_server[0] - driver = login(ui_admin_server, driver) - driver.get(admin_url + "/clients") - return driver - - -class TestClientPage: - """Test client page.""" - - def test_client_page_loaded(self, client_page: WebDriver) -> None: - """Test that the client page loads.""" - # Ensure that the create client button is present - client_page.refresh() - create_client_button = client_page.find_element(By.ID, "createClientButton") - assert create_client_button is not None - # Ensure that the table is loaded - client_table = client_page.find_element(By.ID, "clientListTable") - assert client_table is not None - - def test_create_client_button(self, client_page: WebDriver) -> None: - """Test that the Create Client button works.""" - client_page.refresh() - create_client_button = client_page.find_element(By.ID, "createClientButton") - assert create_client_button is not None - - create_client_button.click() - - wait_helpers.wait_for_element_to_be_visisble(client_page, "drawer-create-client-default") - - add_client_button = client_page.find_element(By.XPATH, "//button[@type='submit']") - assert add_client_button.text.lower() == "add client" - - def test_create_client(self, client_page: WebDriver) -> None: - """Test create clients.""" - client_page.refresh() - private_key = generate_private_key() - public_key = generate_public_key_string(private_key.public_key()) - - create_client_button = client_page.find_element(By.ID, "createClientButton") - assert create_client_button is not None - - create_client_button.click() - - wait_helpers.wait_for_element_to_be_visisble(client_page, "drawer-create-client-default") - - drawer = client_page.find_element(By.ID, "drawer-create-client-default") - assert drawer is not None - name_input = drawer.find_element(By.NAME, "name") - assert name_input is not None - description_input = drawer.find_element(By.NAME, "description") - assert description_input is not None - sources_input = drawer.find_element(By.NAME, "sources") - assert sources_input is not None - public_key_input = drawer.find_element(By.NAME, "public_key") - assert public_key_input is not None - - - name_input.send_keys("testuser") - description_input.send_keys("Test") - sources_input.clear() - sources_input.send_keys("0.0.0.0/0, ::/0") - public_key_input.send_keys(public_key) - validation_field = drawer.find_element(By.ID, "clientPublicKeyValidation") - assert validation_field is not None - error_message = validation_field.find_elements(By.TAG_NAME, "p") - assert len(error_message) == 0 - - # Submit the request - - add_client_button = drawer.find_element(By.XPATH, "//button[@type='submit']") - assert add_client_button.text.lower() == "add client" - - add_client_button.click() - - client_appeared = wait_helpers.wait_for_element_with_text(client_page, "td", "testuser") - assert client_appeared is not False - - def test_delete_client(self, client_page: WebDriver) -> None: - """Test deletion of a test client.""" - self.test_create_client(client_page) - client_page.refresh() - client_field = client_page.find_element(By.XPATH, "//tr/td[contains(text(), 'testuser')]") - assert client_field is not None - row = client_field.find_element(By.XPATH, "./..") - assert row is not None - assert row.tag_name == "tr" - row_id = row.get_attribute("id") - assert row_id is not None - print(row_id) - client_id = row_id[7:] - - wait_helpers.wait_for_element_to_be_visisble(client_page, row_id) - - delete_button = client_page.find_element(By.ID, f"deleteClientButton-{client_id}") - assert delete_button is not None - - delete_button.click() - - drawer_name = f"drawer-delete-{row_id}" - wait_helpers.wait_for_element_to_be_visisble(client_page, drawer_name) - drawer = client_page.find_element(By.ID, drawer_name) - - assert drawer is not None - - confirm_button = drawer.find_element(By.XPATH, "//button[contains(text(), 'Yes, delete the client')]") - assert confirm_button is not None - confirm_button.click() - - WebDriverWait(client_page, 10).until( - EC.none_of( - EC.presence_of_element_located((By.ID, row_id)) - ) - ) - - def test_update_client(self, client_page: WebDriver) -> None: - """Test updating a client.""" - self.test_create_client(client_page) - - client_page.refresh() - client_field = client_page.find_element(By.XPATH, "//tr/td[contains(text(), 'testuser')]") - assert client_field is not None - row = client_field.find_element(By.XPATH, "./..") - assert row is not None - assert row.tag_name == "tr" - row_id = row.get_attribute("id") - assert row_id is not None - print(row_id) - client_id = row_id[7:] - - wait_helpers.wait_for_element_to_be_visisble(client_page, row_id) - update_button = client_page.find_element(By.ID, f"updateClientButton-{client_id}") - assert update_button is not None - - update_button.click() - - drawer_name = f"drawer-update-{row_id}" - - wait_helpers.wait_for_element_to_be_visisble(client_page, drawer_name) - - drawer = client_page.find_element(By.ID, drawer_name) - description_input = drawer.find_element(By.NAME, "description") - - description_input.clear() - - description_input.send_keys("New Description") - - confirm_button = drawer.find_element(By.XPATH, "//button[contains(text(), 'Update')]") - assert confirm_button is not None - confirm_button.click() - - WebDriverWait(client_page, 10).until( - EC.text_to_be_present_in_element((By.XPATH, f"//tr[@id='{row_id}']/td[3]"), "New Description") - ) - - - def test_delete_from_update_client(self, client_page: WebDriver) -> None: - """Test updating a client.""" - self.test_create_client(client_page) - - client_page.refresh() - client_field = client_page.find_element(By.XPATH, "//tr/td[contains(text(), 'testuser')]") - assert client_field is not None - row = client_field.find_element(By.XPATH, "./..") - assert row is not None - assert row.tag_name == "tr" - row_id = row.get_attribute("id") - assert row_id is not None - print(row_id) - client_id = row_id[7:] - - wait_helpers.wait_for_element_to_be_visisble(client_page, row_id) - update_button = client_page.find_element(By.ID, f"updateClientButton-{client_id}") - assert update_button is not None - - update_button.click() - - drawer_name = f"drawer-update-{row_id}" - - wait_helpers.wait_for_element_to_be_visisble(client_page, drawer_name) - - drawer = client_page.find_element(By.ID, drawer_name) - description_input = drawer.find_element(By.NAME, "description") - - description_input.clear() - - description_input.send_keys("New Description") - - delete_button = drawer.find_element(By.ID, f"delete-button-{client_id}") - assert delete_button is not None - delete_button.click() - - alert = WebDriverWait(client_page, 10).until(lambda d: d.switch_to.alert) - assert alert.text == "Are you sure?" - alert.accept() - - WebDriverWait(client_page, 10).until( - EC.none_of( - EC.presence_of_element_located((By.ID, row_id)) - ) - ) diff --git a/tests/frontend/test_dashboard.py b/tests/frontend/test_dashboard.py deleted file mode 100644 index 0417f4e..0000000 --- a/tests/frontend/test_dashboard.py +++ /dev/null @@ -1,79 +0,0 @@ -"""Test of the dashboard landing page.""" - -import time -import allure -import pytest -from selenium.webdriver import ActionChains -from selenium.webdriver.common.by import By -from selenium.webdriver.remote.webdriver import WebDriver -from selenium.webdriver.support.select import Select - -from tests.integration.types import AdminServer - -from .helpers.auth import login -from .helpers.db import DatabasePreloader -from .helpers.wait_helpers import ( - wait_for_element_to_be_visisble, -) - - -class TestDashboardPage: - """Test dashboard page.""" - - @pytest.fixture(autouse=True) - def login(self, ui_admin_server: AdminServer, driver: WebDriver) -> None: - """Login.""" - login(ui_admin_server, driver) - - @pytest.fixture(autouse=True) - def create_testdata(self, ui_admin_server: AdminServer) -> None: - """Preload some test data.""" - test_clients = ["client1", "client2", "client3"] - admin_url, (username, password) = ui_admin_server - db = DatabasePreloader(admin_url, username, password) - db.create_client(*test_clients) - secrets = [ - ("secret1", ["client1", "client2"]), - ("secret2", ["client1"]), - ("secret3", ["client3"]), - ("secret4", ["client2"]), - ] - db.create_secret(*secrets) - - @allure.title("Test Dashboard view") - def test_dashboard_elements(self, driver: WebDriver) -> None: - """Test elements on the dashboard.""" - wait_for_element_to_be_visisble(driver, "dashboard-stats-panel") - stats_clients = driver.find_element(By.ID, "stats-client-count") - assert stats_clients.text == "3" - stats_secrets = driver.find_element(By.ID, "stats-secret-count") - assert stats_secrets.text == "4" - stats_audit = driver.find_element(By.ID, "stats-audit-count") - assert stats_audit.text.isdecimal() - assert int(stats_audit.text) > 0 - - # Check that there is at least one row in each audit table - login_table = driver.find_element(By.ID, "last-login-events") - login_table_rows = login_table.find_elements(By.XPATH, ".//tr") - assert len(login_table_rows) > 1 - - audit_table = driver.find_element(By.ID, "last-audit-events") - audit_table_rows = audit_table.find_elements(By.XPATH, ".//tr") - assert len(audit_table_rows) > 1 - - # Find a questionmark hover - login_info_btn = login_table_rows[-1].find_element(By.XPATH, "./td[1]//button") - login_info_target = login_info_btn.get_attribute("data-popover-target") - assert login_info_target is not None - - ActionChains(driver).move_to_element(login_info_btn).perform() - - wait_for_element_to_be_visisble(driver, login_info_target) - - audit_info_btn = audit_table_rows[-1].find_element(By.XPATH, "./td[1]//button") - - audit_info_target = audit_info_btn.get_attribute("data-popover-target") - assert audit_info_target is not None - - ActionChains(driver).move_to_element(audit_info_btn).perform() - wait_for_element_to_be_visisble(driver, audit_info_target) diff --git a/tests/frontend/test_login.py b/tests/frontend/test_login.py deleted file mode 100644 index 595fdc0..0000000 --- a/tests/frontend/test_login.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Tests for the login.""" - -from selenium.webdriver.remote.webdriver import WebDriver -from tests.integration.types import AdminServer - -from .helpers.auth import login -from .helpers import wait_helpers - -def test_login(ui_admin_server: AdminServer, driver: WebDriver) -> None: - """Test login.""" - driver = login(ui_admin_server, driver) - print(driver.current_url) - assert driver.current_url.endswith("/dashboard") - - -def test_logout(ui_admin_server: AdminServer, driver: WebDriver) -> None: - """Test logout function.""" - admin_url = ui_admin_server[0] - driver = login(ui_admin_server, driver) - assert driver.current_url.endswith("/dashboard") - driver.get(admin_url + "/logout") - wait_helpers.wait_until_url_contains(driver, "/login") - assert driver.current_url.endswith("/login") diff --git a/tests/frontend/test_secrets.py b/tests/frontend/test_secrets.py deleted file mode 100644 index 98f820f..0000000 --- a/tests/frontend/test_secrets.py +++ /dev/null @@ -1,189 +0,0 @@ -"""Tests for the secrets page.""" - -import allure -import pytest -from selenium.webdriver.common.by import By -from selenium.webdriver.remote.webdriver import WebDriver -from selenium.webdriver.support.select import Select -from tests.integration.types import AdminServer - -from .helpers.auth import login -from .helpers.db import DatabasePreloader -from .helpers.wait_helpers import ( - wait_for_alert, - wait_for_element, - wait_for_element_to_be_disabled, - wait_for_element_to_be_visisble, - wait_for_element_to_disappear, - wait_for_element_with_text, -) - - -class TestSecretsPage: - """Test secrets page.""" - - @pytest.fixture(autouse=True) - def login(self, ui_admin_server: AdminServer, driver: WebDriver) -> None: - """Log in and navigate to secrets page..""" - admin_url = ui_admin_server[0] - driver = login(ui_admin_server, driver) - driver.get(admin_url + "/secrets") - - @pytest.fixture(autouse=True) - def create_testdata(self, ui_admin_server: AdminServer) -> None: - """Preload some test data.""" - test_clients = ["client1", "client2", "client3"] - admin_url, (username, password) = ui_admin_server - db = DatabasePreloader(admin_url, username, password) - db.create_client(*test_clients) - - @allure.title("Test secret creation") - @allure.description("Verify that secrets can be created") - def test_create_secret(self, driver: WebDriver) -> None: - """Test creation of secrets.""" - driver.refresh() - create_secret_button = driver.find_element(By.ID, "createSecretButton") - assert create_secret_button is not None - create_secret_button.click() - wait_for_element_to_be_visisble(driver, "drawer-create-secret-default") - - drawer = driver.find_element(By.ID, "drawer-create-secret-default") - assert drawer is not None - name_input = drawer.find_element(By.NAME, "name") - value_input = drawer.find_element(By.NAME, "value") - client_select = drawer.find_element(By.NAME, "clients") - client_select_node = Select(client_select) - - name_input.send_keys("testsecret") - value_input.send_keys("secret") - client_select_node.select_by_visible_text("client1") - - add_secret_button = drawer.find_element(By.XPATH, "//button[@type='submit']") - add_secret_button.click() - - client_appeared = wait_for_element_with_text(driver, "td", "testsecret") - - assert client_appeared is not False - - secret_name_field = driver.find_element( - By.XPATH, "//tr/td[contains(text(), 'testsecret')]" - ) - secret_row = secret_name_field.find_element(By.XPATH, "./..") - client_field = secret_row.find_element(By.CLASS_NAME, "secret-client-list") - secret_client = client_field.find_element( - By.XPATH, "//span[contains(text(), 'client1')]" - ) - assert secret_client is not None - - @allure.title("Test auto-generating secrets") - @allure.description("Test creation of a secret with automatic value") - def test_auto_secret_creation(self, driver: WebDriver) -> None: - """Test creation of secret with automatic value.""" - driver.refresh() - create_secret_button = driver.find_element(By.ID, "createSecretButton") - assert create_secret_button is not None - create_secret_button.click() - wait_for_element_to_be_visisble(driver, "drawer-create-secret-default") - - drawer = driver.find_element(By.ID, "drawer-create-secret-default") - assert drawer is not None - name_input = drawer.find_element(By.NAME, "name") - value_input = drawer.find_element(By.NAME, "value") - - # The auto generate checkbox is obscured by a dynamic div. - # We find the label and its nested div - - auto_generate_label = drawer.find_element(By.ID, "autoGenerateCheckboxLabel") - # find the first div - checkbox_div = auto_generate_label.find_element(By.TAG_NAME, "div") - checkbox_div.click() - wait_for_element_to_be_disabled(driver, By.NAME, "value") - client_select = drawer.find_element(By.NAME, "clients") - client_select_node = Select(client_select) - - name_input.send_keys("autosecret") - client_select_node.deselect_all() - client_select_node.select_by_visible_text("client1") - client_select_node.select_by_visible_text("client2") - - add_secret_button = drawer.find_element(By.XPATH, "//button[@type='submit']") - add_secret_button.click() - - client_appeared = wait_for_element_with_text(driver, "td", "autosecret") - - secret_name_field = driver.find_element( - By.XPATH, "//tr/td[contains(text(), 'autosecret')]" - ) - secret_row = secret_name_field.find_element(By.XPATH, "./..") - client_field = secret_row.find_element(By.CLASS_NAME, "secret-client-list") - secret_client1 = client_field.find_element( - By.XPATH, "//span[contains(text(), 'client1')]" - ) - assert secret_client1 is not None - - secret_client2 = client_field.find_element( - By.XPATH, "//span[contains(text(), 'client2')]" - ) - assert secret_client2 is not None - - @allure.title("Test manage client access") - def test_manage_client_access(self, driver: WebDriver) -> None: - """Test the manage client access button.""" - # Use the previous step to create a secret assigned to two clients. - self.test_auto_secret_creation(driver) - driver.refresh() - # Find the manage client access button - # btn_id = "client-secret-modal-autosecret" - manage_btn = driver.find_element(By.ID, "manage-client-access-btn-autosecret") - assert manage_btn is not None - manage_btn.click() - wait_for_element_to_be_visisble(driver, "client-secret-modal-autosecret") - modal = driver.find_element(By.ID, "client-secret-modal-autosecret") - assert modal is not None - client_pills = modal.find_elements(By.CLASS_NAME, "pill-client-secret") - assert len(client_pills) == 2 - - # Remove client1 - remove_pill_btn_id = "btn-remove-client-client1-secret-autosecret" - remove_btn = modal.find_element(By.ID, remove_pill_btn_id) - assert remove_btn is not None - remove_btn.click() - alert = wait_for_alert(driver) - alert.accept() - - # Wait for the client pill to disappear. - wait_for_element_to_disappear( - driver, - By.XPATH, - "//td[@id='secret-client-list-autosecret']/span[contains(text(), 'client1')]", - ) - - # Add a different client. - client_select_field = modal.find_element(By.NAME, "client") - assert client_select_field is not None - assert client_select_field.tag_name == "select" - - client_select = Select(client_select_field) - client_select.select_by_visible_text("client3") - - give_access = modal.find_element(By.XPATH, "//button[@type='submit']") - assert "give access" in give_access.text.lower() - give_access.click() - wait_for_element(driver, By.ID, "client-secret-autosecret-pill-client3") - - @allure.title("Test secret deletion") - def test_delete_secret(self, driver: WebDriver) -> None: - """Test deleting a secret.""" - self.test_auto_secret_creation(driver) - driver.refresh() - delete_btn_id = "delete-secret-btn-autosecret" - delete_btn = driver.find_element(By.ID, delete_btn_id) - - delete_btn.click() - - alert = wait_for_alert(driver) - alert.accept() - - wait_for_element_to_disappear( - driver, By.XPATH, "//td[contains(text(), 'autosecret')]" - )