diff --git a/tests/test_webinterface.py b/tests/test_webinterface.py index e88af22..1e613f1 100644 --- a/tests/test_webinterface.py +++ b/tests/test_webinterface.py @@ -1,7 +1,10 @@ import pytest from bs4 import BeautifulSoup +from flask_security.utils import find_user from imaginaerraum_door_admin.door_handle import DoorHandle import re +import secrets + def test_login(browser, live_server): response = browser.get(f'http://localhost:{live_server.port}') @@ -10,15 +13,15 @@ def test_login(browser, live_server): response = browser.get(f'http://localhost:{live_server.port}/login') - email_form = browser.find_element_by_id('email').send_keys('gandalf@shire.me') - password_form = browser.find_element_by_id('password').send_keys('shadowfax') - submit_button = browser.find_element_by_id('submit').click() + email_form = browser.find_element('id', 'email').send_keys('gandalf@shire.me') + password_form = browser.find_element('id', 'password').send_keys('shadowfax') + submit_button = browser.find_element('id', 'submit').click() assert 'Tür öffnen' in browser.page_source def extract_csrf_token(response): - soup = BeautifulSoup(response.data) + soup = BeautifulSoup(response.data, 'html.parser') csrf_token = soup.find('input', attrs={'id': 'csrf_token'})['value'] return csrf_token @@ -39,7 +42,7 @@ def headless_login(client, user='gandalf@shire.me', password='shadowfax'): def test_login_headless(client): response = headless_login(client) - soup = BeautifulSoup(response.data) + soup = BeautifulSoup(response.data, 'html.parser') # make sure login succeeded -> Tür öffnen button will appear assert any(['Tür öffnen' in link.contents[0] for link in soup.findAll('a', attrs={'class': ['btn'], 'role': 'button'})]) @@ -52,6 +55,7 @@ def client_authenticated(client): yield client + @pytest.mark.parametrize("url,function", [('/open', 'open_door'), ('/close', 'close_door')]) def test_access_door_button(client_authenticated, mocker, url, function): mocker.patch('imaginaerraum_door_admin.door_handle.DoorHandle.' + function) @@ -87,14 +91,14 @@ def test_manage_admins(client_authenticated): assert "gandalf@shire.me" in response.data.decode() -def test_create_admin(client_authenticated): +def create_user(client_authenticated, username, email): # visit admin management page response = client_authenticated.get('/manage_admins') csrf_token = extract_csrf_token(response) # post data for creating a new admin - payload = {'name': 'bilbo', - 'email': 'bilbo@shire.me', + payload = {'name': username, + 'email': email, 'csrf_token': csrf_token} response = client_authenticated.post('/manage_admins', data=payload, follow_redirects=True) @@ -107,18 +111,167 @@ def test_create_admin(client_authenticated): assert match is not None extracted_password = match['password'] + return extracted_password + + +@pytest.fixture +def temp_user(client_authenticated): + """Fixture for creating a temporary user for testing""" + username = secrets.token_hex(4) + email = username + '@example.com' + + # create user for test + password = create_user(client_authenticated, username, email) + + return {'username': username, + 'email': email, + 'password': password} + + +@pytest.fixture +def temp_admin(client_authenticated): + """Fixture for creating a temporary admin user for testing""" + username = secrets.token_hex(4) + email = username + '@example.com' + + # create user for test + password = create_user(client_authenticated, username, email) + + response = client_authenticated.get( + f"/promote_admin/{username}", + follow_redirects=True) + user = find_user(username) + assert user.has_role('admin') + + return {'username': username, + 'email': email, + 'password': password} + + +def test_create_admin(client_authenticated): + password = create_user(client_authenticated, 'bilbo', 'bilbo@shire.me') + # log out current user response = client_authenticated.get('/logout') # try to log in new user using the extracted password response = headless_login(client_authenticated, user='bilbo', - password=extracted_password) + password=password) # - see if it works - soup = BeautifulSoup(response.data) + soup = BeautifulSoup(response.data, 'html.parser') # make sure login succeeded # -> username should be displayed assert 'Benutzer bilbo' in soup.decode() # -> Tür öffnen button will appear - assert any(['Tür öffnen' in link.contents[0] for link in soup.findAll('a', attrs={'class': ['btn'], 'role': 'button'})]) + assert any(['Tür öffnen' in link.contents[0] for link in + soup.findAll('a', attrs={'class': ['btn'], 'role': 'button'})]) + + +def test_activate_deactivate_user(temp_user, client_authenticated): + response = client_authenticated.get('/admin_toggle_active/nosuchuser', + follow_redirects=True) + assert 'Ungültiger Nutzer' in response.data.decode() + + # deactivate the user + response = client_authenticated.get(f"/admin_toggle_active/{temp_user['username']}", + follow_redirects=True) + # make sure the user is now inactive + user = find_user(temp_user['username']) + assert user is not None + assert not user.active + + # activate the user again + client_authenticated.get(f"/admin_toggle_active/{temp_user['username']}", + follow_redirects=True) + + # now the user should be active again + user = find_user(temp_user['username']) + assert user is not None + assert user.active + + +def test_delete_admin(temp_user, client_authenticated): + # first we test deleting a non-existing user + response = client_authenticated.post('/delete_admins/nosuchuser', + follow_redirects=True) + assert 'Ungültiger Nutzer' in response.data.decode() + + # next, we create a temporary user and try to delete that one + response = client_authenticated.post(f"/delete_admins/{temp_user['username']}", + follow_redirects=True) + + # we need to deactivate the user first + assert 'Bitte den Benutzer zuerst deaktivieren.' in response.data.decode() + # make sure the user still exists + user = find_user(temp_user['username']) + assert user is not None + + # deactivate the user and try deleting it again + response = client_authenticated.get(f"/admin_toggle_active/{temp_user['username']}", + follow_redirects=True) + + # try deleting it without filling in the confirmation form + response = client_authenticated.post(f"/delete_admins/{temp_user['username']}", + follow_redirects=True) + assert 'Der eingegebene Nutzername stimmt nicht überein' in response.data.decode() + # make sure the user still exists + user = find_user(temp_user['username']) + assert user is not None + + # now we send the confirmation data with the request + response = client_authenticated.get(f"/delete_admins/{temp_user['username']}", + follow_redirects=True) + csrf_token = extract_csrf_token(response) + payload = {'name': temp_user['username'], 'csrf_token': csrf_token} + response = client_authenticated.post( + f"/delete_admins/{temp_user['username']}", + data=payload, + follow_redirects=True) + assert f"Benutzer {temp_user['username']} wurde gelöscht." in response.data.decode() + + # make sure the user now is gone + user = find_user(temp_user['username']) + assert user is None + + +def test_promote_user(temp_user, client_authenticated): + # first we test with a non-existing user + response = client_authenticated.get('/promote_admin/nosuchuser', + follow_redirects=True) + assert 'Ungültiger Nutzer' in response.data.decode() + + user = find_user(temp_user['username']) + assert user is not None + assert not user.has_role('admin') + # grant admin permissions to test user + response = client_authenticated.get(f"/promote_admin/{temp_user['username']}", + follow_redirects=True) + assert user.has_role('admin') + + # try granting admin permissions again + response = client_authenticated.get(f"/promote_admin/{temp_user['username']}", + follow_redirects=True) + assert f"Benutzer {temp_user['username']} hat bereits Admin-Rechte!" + assert user.has_role('admin') + + +def test_demote_user(temp_admin, client_authenticated): + # first we test with a non-existing user + response = client_authenticated.get('/demote_admin/nosuchuser', + follow_redirects=True) + assert 'Ungültiger Nutzer' in response.data.decode() + + user = find_user(temp_admin['username']) + assert user.has_role('admin') + # try removing admin permissions + response = client_authenticated.get(f"/demote_admin/{temp_admin['username']}", + follow_redirects=True) + assert not user.has_role('admin') + + # try removing admin permissions + response = client_authenticated.get(f"/demote_admin/{temp_admin['username']}", + follow_redirects=True) + assert f"Benutzer {temp_admin['username']} ist bereits kein Admin!" + assert not user.has_role('admin')