Remove old frontend tests
This commit is contained in:
@ -7,7 +7,7 @@ all = [ {ref="fmt"}, {ref="lint"}, {ref="check"}, {ref="test"} ]
|
|||||||
"ci:fmt" = "ruff format --check ${PWD}" # fail if not formatted
|
"ci:fmt" = "ruff format --check ${PWD}" # fail if not formatted
|
||||||
"ci:lint" = "ruff check ${PWD}"
|
"ci:lint" = "ruff check ${PWD}"
|
||||||
[tool.poe.tasks.coverage]
|
[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}"
|
cwd = "${POE_PWD}"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -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()
|
|
||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -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
|
|
||||||
@ -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)
|
|
||||||
@ -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)))
|
|
||||||
)
|
|
||||||
@ -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))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@ -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)
|
|
||||||
@ -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")
|
|
||||||
@ -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')]"
|
|
||||||
)
|
|
||||||
Reference in New Issue
Block a user