tests: update e2e tests for SPA

This commit is contained in:
Jens Langhammer 2020-11-23 14:24:42 +01:00
parent 401359a73f
commit 34f54a96cf
8 changed files with 69 additions and 97 deletions

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
custom: ["https://www.paypal.me/beryju"] github: [BeryJu]

View File

@ -8,6 +8,7 @@ from docker.types import Healthcheck
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support import expected_conditions as ec
from passbook.core.models import User
from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding
from passbook.stages.email.models import EmailStage, EmailTemplates from passbook.stages.email.models import EmailStage, EmailTemplates
from passbook.stages.identification.models import IdentificationStage from passbook.stages.identification.models import IdentificationStage
@ -100,25 +101,13 @@ class TestFlowsEnroll(SeleniumTestCase):
self.driver.find_element(By.ID, "id_email").send_keys("foo@bar.baz") self.driver.find_element(By.ID, "id_email").send_keys("foo@bar.baz")
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click() self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
self.wait.until(ec.presence_of_element_located((By.LINK_TEXT, "foo"))) self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "pb-sidebar")))
self.driver.find_element(By.LINK_TEXT, "foo").click() self.driver.get(self.shell_url("passbook_core:user-settings"))
self.wait_for_url(self.url("passbook_core:user-settings")) user = User.objects.get(username="foo")
self.assertEqual( self.assertEqual(user.username, "foo")
self.driver.find_element(By.ID, "user-settings").text, self.assertEqual(user.name, "some name")
"foo", self.assertEqual(user.email, "foo@bar.baz")
)
self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
)
self.assertEqual(
self.driver.find_element(By.ID, "id_name").get_attribute("value"),
"some name",
)
self.assertEqual(
self.driver.find_element(By.ID, "id_email").get_attribute("value"),
"foo@bar.baz",
)
@retry() @retry()
@override_settings(EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend") @override_settings(EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend")
@ -207,21 +196,7 @@ class TestFlowsEnroll(SeleniumTestCase):
self.driver.switch_to.window(self.driver.window_handles[0]) self.driver.switch_to.window(self.driver.window_handles[0])
# We're now logged in # We're now logged in
self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "pb-sidebar")))
self.driver.find_element(By.ID, "user-settings").click() self.driver.get(self.shell_url("passbook_core:user-settings"))
self.assertEqual( self.assert_user(User.objects.get(username="foo"))
self.driver.find_element(By.ID, "user-settings").text,
"foo",
)
self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
)
self.assertEqual(
self.driver.find_element(By.ID, "id_name").get_attribute("value"),
"some name",
)
self.assertEqual(
self.driver.find_element(By.ID, "id_email").get_attribute("value"),
"foo@bar.baz",
)

View File

@ -21,7 +21,5 @@ class TestFlowsLogin(SeleniumTestCase):
self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER)
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.find_element(By.ID, "user-settings").text, self.assert_user(USER())
USER().username,
)

View File

@ -13,6 +13,8 @@ from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec from selenium.webdriver.support import expected_conditions as ec
from passbook.flows.models import Flow, FlowStageBinding from passbook.flows.models import Flow, FlowStageBinding
from passbook.stages.otp_static.models import OTPStaticStage
from passbook.stages.otp_time.models import OTPTimeStage
from passbook.stages.otp_validate.models import OTPValidateStage from passbook.stages.otp_validate.models import OTPValidateStage
from tests.e2e.utils import USER, SeleniumTestCase, retry from tests.e2e.utils import USER, SeleniumTestCase, retry
@ -47,11 +49,8 @@ class TestFlowsOTP(SeleniumTestCase):
totp = TOTP(device.bin_key, device.step, device.t0, device.digits, device.drift) totp = TOTP(device.bin_key, device.step, device.t0, device.digits, device.drift)
self.driver.find_element(By.ID, "id_code").send_keys(totp.token()) self.driver.find_element(By.ID, "id_code").send_keys(totp.token())
self.driver.find_element(By.ID, "id_code").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_code").send_keys(Keys.ENTER)
self.wait_for_url(self.url("passbook_core:overview")) self.wait_for_url(self.shell_url("passbook_core:overview"))
self.assertEqual( self.assert_user(USER())
self.driver.find_element(By.ID, "user-settings").text,
USER().username,
)
@retry() @retry()
def test_otp_totp_setup(self): def test_otp_totp_setup(self):
@ -64,23 +63,19 @@ class TestFlowsOTP(SeleniumTestCase):
self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER)
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.find_element(By.ID, "user-settings").text, self.assert_user(USER())
USER().username,
self.driver.get(
self.url(
"passbook_flows:configure",
stage_uuid=OTPTimeStage.objects.first().stage_uuid,
)
) )
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click()
self.driver.get(self.url("passbook_core:user-settings"))
self.driver.find_element(By.LINK_TEXT, "Time-based OTP").click()
# Remember the current URL as we should end up back here # Remember the current URL as we should end up back here
destination_url = self.driver.current_url destination_url = self.driver.current_url
self.driver.find_element(
By.CSS_SELECTOR, ".pf-c-card__body a.pf-c-button"
).click()
self.wait.until(ec.presence_of_element_located((By.ID, "qr"))) self.wait.until(ec.presence_of_element_located((By.ID, "qr")))
otp_uri = self.driver.find_element(By.ID, "qr").get_attribute("data-otpuri") otp_uri = self.driver.find_element(By.ID, "qr").get_attribute("data-otpuri")
@ -111,23 +106,19 @@ class TestFlowsOTP(SeleniumTestCase):
self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER)
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.assertEqual( self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.find_element(By.ID, "user-settings").text, self.assert_user(USER())
USER().username,
self.driver.get(
self.url(
"passbook_flows:configure",
stage_uuid=OTPStaticStage.objects.first().stage_uuid,
)
) )
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click()
self.driver.find_element(By.ID, "user-settings").click()
self.wait_for_url(self.url("passbook_core:user-settings"))
self.driver.find_element(By.LINK_TEXT, "Static OTP").click()
# Remember the current URL as we should end up back here # Remember the current URL as we should end up back here
destination_url = self.driver.current_url destination_url = self.driver.current_url
self.driver.find_element(
By.CSS_SELECTOR, ".pf-c-card__body a.pf-c-button"
).click()
token = self.driver.find_element( token = self.driver.find_element(
By.CSS_SELECTOR, ".pb-otp-tokens li:nth-child(1)" By.CSS_SELECTOR, ".pb-otp-tokens li:nth-child(1)"
).text ).text

View File

@ -38,16 +38,20 @@ class TestFlowsStageSetup(SeleniumTestCase):
self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER)
self.driver.find_element(By.ID, "id_password").send_keys(USER().username) self.driver.find_element(By.ID, "id_password").send_keys(USER().username)
self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER)
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click() self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.find_element(By.ID, "user-settings").click()
self.wait_for_url(self.url("passbook_core:user-settings")) self.driver.get(
self.driver.find_element(By.LINK_TEXT, "Change password").click() self.url(
"passbook_flows:configure",
stage_uuid=PasswordStage.objects.first().stage_uuid,
)
)
self.driver.find_element(By.ID, "id_password").send_keys(new_password) self.driver.find_element(By.ID, "id_password").send_keys(new_password)
self.driver.find_element(By.ID, "id_password_repeat").click() self.driver.find_element(By.ID, "id_password_repeat").click()
self.driver.find_element(By.ID, "id_password_repeat").send_keys(new_password) self.driver.find_element(By.ID, "id_password_repeat").send_keys(new_password)
self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click() self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click()
self.wait_for_url(self.url("passbook_core:user-settings")) self.wait_for_url(self.shell_url("passbook_core:overview"))
# Because USER() is cached, we need to get the user manually here # Because USER() is cached, we need to get the user manually here
user = User.objects.get(username=USER().username) user = User.objects.get(username=USER().username)
self.assertTrue(user.check_password(new_password)) self.assertTrue(user.check_password(new_password))

View File

@ -140,14 +140,10 @@ class TestSourceOAuth2(SeleniumTestCase):
self.driver.find_element(By.NAME, "username").send_keys("foo") self.driver.find_element(By.NAME, "username").send_keys("foo")
self.driver.find_element(By.NAME, "username").send_keys(Keys.ENTER) self.driver.find_element(By.NAME, "username").send_keys(Keys.ENTER)
# Wait until we've loaded the user info page # Wait until we've logged in
self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text,
"foo",
)
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo" self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
) )
@ -202,7 +198,7 @@ class TestSourceOAuth2(SeleniumTestCase):
"""test OAuth Source With With OIDC (enroll and authenticate again)""" """test OAuth Source With With OIDC (enroll and authenticate again)"""
self.test_oauth_enroll() self.test_oauth_enroll()
# We're logged in at the end of this, log out and re-login # We're logged in at the end of this, log out and re-login
self.driver.find_element(By.ID, "logout").click() self.driver.get(self.url("passbook_flows:default-invalidation"))
self.wait.until( self.wait.until(
ec.presence_of_element_located( ec.presence_of_element_located(
@ -226,13 +222,10 @@ class TestSourceOAuth2(SeleniumTestCase):
) )
self.driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click() self.driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) # Wait until we've logged in
self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text,
"foo",
)
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo" self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
) )
@ -322,13 +315,10 @@ class TestSourceOAuth1(SeleniumTestCase):
# Wait until we've loaded the user info page # Wait until we've loaded the user info page
sleep(2) sleep(2)
self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) # Wait until we've logged in
self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
self.assertEqual(
self.driver.find_element(By.ID, "user-settings").text,
"example-user",
)
self.assertEqual( self.assertEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), self.driver.find_element(By.ID, "id_username").get_attribute("value"),
"example-user", "example-user",

View File

@ -133,11 +133,10 @@ class TestSourceSAML(SeleniumTestCase):
self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
# Wait until we're logged in # Wait until we're logged in
self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
# Wait until we've loaded the user info page # Wait until we've loaded the user info page
self.wait.until(ec.presence_of_element_located((By.ID, "id_username")))
self.assertNotEqual( self.assertNotEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "" self.driver.find_element(By.ID, "id_username").get_attribute("value"), ""
) )
@ -185,11 +184,10 @@ class TestSourceSAML(SeleniumTestCase):
self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
# Wait until we're logged in # Wait until we're logged in
self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
# Wait until we've loaded the user info page # Wait until we've loaded the user info page
self.wait.until(ec.presence_of_element_located((By.ID, "id_username")))
self.assertNotEqual( self.assertNotEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "" self.driver.find_element(By.ID, "id_username").get_attribute("value"), ""
) )
@ -235,11 +233,10 @@ class TestSourceSAML(SeleniumTestCase):
self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER)
# Wait until we're logged in # Wait until we're logged in
self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) self.wait_for_url(self.shell_url("passbook_core:overview"))
self.driver.get(self.url("passbook_core:user-settings")) self.driver.get(self.url("passbook_core:user-settings"))
# Wait until we've loaded the user info page # Wait until we've loaded the user info page
self.wait.until(ec.presence_of_element_located((By.ID, "id_username")))
self.assertNotEqual( self.assertNotEqual(
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "" self.driver.find_element(By.ID, "id_username").get_attribute("value"), ""
) )

View File

@ -1,4 +1,5 @@
"""passbook e2e testing utilities""" """passbook e2e testing utilities"""
import json
from functools import wraps from functools import wraps
from glob import glob from glob import glob
from importlib.util import module_from_spec, spec_from_file_location from importlib.util import module_from_spec, spec_from_file_location
@ -17,11 +18,13 @@ from docker import DockerClient, from_env
from docker.models.containers import Container from docker.models.containers import Container
from selenium import webdriver from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.common.exceptions import NoSuchElementException, TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.remote.webdriver import WebDriver from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support.ui import WebDriverWait
from structlog import get_logger from structlog import get_logger
from passbook.core.api.users import UserSerializer
from passbook.core.models import User from passbook.core.models import User
@ -100,6 +103,20 @@ class SeleniumTestCase(StaticLiveServerTestCase):
"""reverse `view` with `**kwargs` into full URL using live_server_url""" """reverse `view` with `**kwargs` into full URL using live_server_url"""
return self.live_server_url + reverse(view, kwargs=kwargs) return self.live_server_url + reverse(view, kwargs=kwargs)
def shell_url(self, view, **kwargs) -> str:
"""same as self.url() but show URL in shell"""
return f"{self.live_server_url}/#{reverse(view, kwargs=kwargs)}"
def assert_user(self, expected_user: User):
"""Check users/me API and assert it matches expected_user"""
self.driver.get(self.url("passbook_api:user-me") + "?format=json")
user_json = self.driver.find_element(By.CSS_SELECTOR, "pre").text
user = UserSerializer(data=json.loads(user_json))
user.is_valid()
self.assertEqual(user["username"].value, expected_user.username)
self.assertEqual(user["name"].value, expected_user.name)
self.assertEqual(user["email"].value, expected_user.email)
def apply_default_data(self): def apply_default_data(self):
"""apply objects created by migrations after tables have been truncated""" """apply objects created by migrations after tables have been truncated"""
# Find all migration files # Find all migration files