From e54b98a80e2ef09b8168d88f3cfc983f2f2e601e Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 28 Sep 2020 18:17:07 +0200 Subject: [PATCH] e2e: cleanup tests, remove XPATH selectors --- e2e/test_flows_enroll.py | 14 ++++------- e2e/test_flows_login.py | 3 +-- e2e/test_flows_otp.py | 20 +++++++--------- e2e/test_flows_stage_setup.py | 2 +- e2e/test_provider_oauth2_github.py | 15 ++++-------- e2e/test_provider_oauth2_grafana.py | 24 ++++++++----------- e2e/test_provider_oauth2_oidc.py | 7 ++---- e2e/test_provider_saml.py | 13 ++++------ e2e/test_source_oauth.py | 11 ++++----- e2e/test_source_saml.py | 24 +++++-------------- passbook/core/templates/base/page.html | 4 ++-- .../templates/providers/oauth2/consent.html | 8 +++---- passbook/providers/oauth2/views/userinfo.py | 8 +++---- .../templates/providers/saml/consent.html | 2 +- .../stages/identification/login.html | 2 +- passbook/stages/otp_time/stage.py | 4 +--- 16 files changed, 60 insertions(+), 101 deletions(-) diff --git a/e2e/test_flows_enroll.py b/e2e/test_flows_enroll.py index aee1884c1..110635861 100644 --- a/e2e/test_flows_enroll.py +++ b/e2e/test_flows_enroll.py @@ -104,8 +104,7 @@ class TestFlowsEnroll(SeleniumTestCase): self.wait_for_url(self.url("passbook_core:user-settings")) self.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - "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" @@ -205,16 +204,11 @@ class TestFlowsEnroll(SeleniumTestCase): self.driver.switch_to.window(self.driver.window_handles[0]) # We're now logged in - self.wait.until( - ec.presence_of_element_located( - (By.XPATH, "//a[contains(@href, '/-/user/')]") - ) - ) - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click() + self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) + self.driver.find_element(By.ID, "user-settings").click() self.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - "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" diff --git a/e2e/test_flows_login.py b/e2e/test_flows_login.py index 6c7325b14..188bc1a02 100644 --- a/e2e/test_flows_login.py +++ b/e2e/test_flows_login.py @@ -21,6 +21,5 @@ class TestFlowsLogin(SeleniumTestCase): 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.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - USER().username, + self.driver.find_element(By.ID, "user-settings").text, USER().username, ) diff --git a/e2e/test_flows_otp.py b/e2e/test_flows_otp.py index 0a9c955b7..fd9cfc8cc 100644 --- a/e2e/test_flows_otp.py +++ b/e2e/test_flows_otp.py @@ -10,6 +10,7 @@ from django_otp.plugins.otp_static.models import StaticDevice, StaticToken from django_otp.plugins.otp_totp.models import TOTPDevice from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as ec from e2e.utils import USER, SeleniumTestCase from passbook.flows.models import Flow, FlowStageBinding @@ -45,9 +46,9 @@ class TestFlowsOTP(SeleniumTestCase): 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(Keys.ENTER) + self.wait_for_url(self.url("passbook_core:overview")) self.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - USER().username, + self.driver.find_element(By.ID, "user-settings").text, USER().username, ) def test_otp_totp_setup(self): @@ -61,12 +62,11 @@ class TestFlowsOTP(SeleniumTestCase): 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.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - USER().username, + self.driver.find_element(By.ID, "user-settings").text, USER().username, ) self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click() - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").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, "Time-based OTP").click() @@ -78,9 +78,8 @@ class TestFlowsOTP(SeleniumTestCase): By.CSS_SELECTOR, ".pf-c-card__body a.pf-c-button" ).click() - otp_uri = self.driver.find_element( - By.CSS_SELECTOR, "#flow-body > div > form > div:nth-child(3) > div" - ).get_attribute("aria-label") + self.wait.until(ec.presence_of_element_located((By.ID, "qr"))) + otp_uri = self.driver.find_element(By.ID, "qr").get_attribute("data-otpuri") # Parse the OTP URI, extract the secret and get the next token otp_args = urlparse(otp_uri) @@ -109,12 +108,11 @@ class TestFlowsOTP(SeleniumTestCase): 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.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - USER().username, + self.driver.find_element(By.ID, "user-settings").text, USER().username, ) self.driver.find_element(By.CSS_SELECTOR, ".pf-c-page__header").click() - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").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() diff --git a/e2e/test_flows_stage_setup.py b/e2e/test_flows_stage_setup.py index 58ccb4065..355ab1600 100644 --- a/e2e/test_flows_stage_setup.py +++ b/e2e/test_flows_stage_setup.py @@ -38,7 +38,7 @@ class TestFlowsStageSetup(SeleniumTestCase): 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.CSS_SELECTOR, ".pf-c-page__header").click() - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").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, "Change password").click() self.driver.find_element(By.ID, "id_password").send_keys(new_password) diff --git a/e2e/test_provider_oauth2_github.py b/e2e/test_provider_oauth2_github.py index f2cfb6ef1..b38dfd978 100644 --- a/e2e/test_provider_oauth2_github.py +++ b/e2e/test_provider_oauth2_github.py @@ -89,7 +89,7 @@ class TestProviderOAuth2Github(SeleniumTestCase): self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.wait_for_url("http://localhost:3000/?orgId=1") - self.driver.find_element(By.XPATH, "//a[contains(@href, '/profile')]").click() + self.driver.get("http://localhost:3000/profile") self.assertEqual( self.driver.find_element(By.CLASS_NAME, "page-header__title").text, USER().username, @@ -142,17 +142,12 @@ class TestProviderOAuth2Github(SeleniumTestCase): sleep(1) - self.assertIn( - app.name, - self.driver.find_element( - By.XPATH, "/html/body/div[2]/div/main/div/form/div[2]/p[1]" - ).text, + self.assertEqual( + app.name, self.driver.find_element(By.ID, "application-name").text, ) self.assertEqual( "GitHub Compatibility: Access you Email addresses", - self.driver.find_element( - By.XPATH, "/html/body/div[2]/div/main/div/form/div[2]/ul/li[1]" - ).text, + self.driver.find_element(By.ID, "scope-user:email").text, ) self.driver.find_element( By.CSS_SELECTOR, @@ -163,7 +158,7 @@ class TestProviderOAuth2Github(SeleniumTestCase): ).click() self.wait_for_url("http://localhost:3000/?orgId=1") - self.driver.find_element(By.XPATH, "//a[contains(@href, '/profile')]").click() + self.driver.get("http://localhost:3000/profile") self.assertEqual( self.driver.find_element(By.CLASS_NAME, "page-header__title").text, USER().username, diff --git a/e2e/test_provider_oauth2_grafana.py b/e2e/test_provider_oauth2_grafana.py index a65474b88..ad0aaf41b 100644 --- a/e2e/test_provider_oauth2_grafana.py +++ b/e2e/test_provider_oauth2_grafana.py @@ -154,7 +154,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): 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(Keys.ENTER) - self.driver.find_element(By.XPATH, "//a[contains(@href, '/profile')]").click() + self.wait_for_url("http://localhost:3000/?orgId=1") + self.driver.get("http://localhost:3000/profile") self.assertEqual( self.driver.find_element(By.CLASS_NAME, "page-header__title").text, USER().name, @@ -212,7 +213,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): 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(Keys.ENTER) - self.driver.find_element(By.XPATH, "//a[contains(@href, '/profile')]").click() + self.wait_for_url("http://localhost:3000/?orgId=1") + self.driver.get("http://localhost:3000/profile") self.assertEqual( self.driver.find_element(By.CLASS_NAME, "page-header__title").text, USER().name, @@ -235,7 +237,7 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): ).get_attribute("value"), USER().email, ) - self.driver.find_element(By.CSS_SELECTOR, "[href='/logout']").click() + self.driver.get("http://localhost:3000/logout") self.wait_for_url( self.url( "passbook_providers_oauth2:end-session", @@ -279,11 +281,8 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): 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.assertIn( - app.name, - self.driver.find_element( - By.XPATH, "/html/body/div[2]/div/main/div/form/div[2]/p[1]" - ).text, + self.assertEqual( + app.name, self.driver.find_element(By.ID, "application-name").text, ) self.wait.until( ec.presence_of_element_located((By.CSS_SELECTOR, "[type=submit]")) @@ -291,12 +290,9 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): sleep(1) self.driver.find_element(By.CSS_SELECTOR, "[type=submit]").click() - self.wait.until( - ec.presence_of_element_located( - (By.XPATH, "//a[contains(@href, '/profile')]") - ) - ) - self.driver.find_element(By.XPATH, "//a[contains(@href, '/profile')]").click() + self.wait_for_url("http://localhost:3000/?orgId=1") + self.driver.get("http://localhost:3000/profile") + self.assertEqual( self.driver.find_element(By.CLASS_NAME, "page-header__title").text, USER().name, diff --git a/e2e/test_provider_oauth2_oidc.py b/e2e/test_provider_oauth2_oidc.py index 99732bc83..c59419695 100644 --- a/e2e/test_provider_oauth2_oidc.py +++ b/e2e/test_provider_oauth2_oidc.py @@ -200,11 +200,8 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): 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.assertIn( - app.name, - self.driver.find_element( - By.XPATH, "/html/body/div[2]/div/main/div/form/div[2]/p[1]" - ).text, + self.assertEqual( + app.name, self.driver.find_element(By.ID, "application-name").text, ) self.wait.until( ec.presence_of_element_located((By.CSS_SELECTOR, "[type=submit]")) diff --git a/e2e/test_provider_saml.py b/e2e/test_provider_saml.py index 9a68b075f..984b3ad12 100644 --- a/e2e/test_provider_saml.py +++ b/e2e/test_provider_saml.py @@ -93,7 +93,7 @@ class TestProviderSAML(SeleniumTestCase): self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.wait_for_url("http://localhost:9009/") self.assertEqual( - self.driver.find_element(By.XPATH, "/html/body/pre").text, + self.driver.find_element(By.CSS_SELECTOR, "pre").text, f"Hello, {USER().name}!", ) @@ -124,17 +124,14 @@ class TestProviderSAML(SeleniumTestCase): 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(Keys.ENTER) - self.assertIn( - app.name, - self.driver.find_element( - By.XPATH, "/html/body/div[2]/div/main/div/form/div[2]/p[1]" - ).text, + self.assertEqual( + app.name, self.driver.find_element(By.ID, "application-name").text, ) sleep(1) self.driver.find_element(By.CSS_SELECTOR, "[type=submit]").click() self.wait_for_url("http://localhost:9009/") self.assertEqual( - self.driver.find_element(By.XPATH, "/html/body/pre").text, + self.driver.find_element(By.CSS_SELECTOR, "pre").text, f"Hello, {USER().name}!", ) @@ -172,7 +169,7 @@ class TestProviderSAML(SeleniumTestCase): self.driver.find_element(By.ID, "id_password").send_keys(Keys.ENTER) self.wait_for_url("http://localhost:9009/") self.assertEqual( - self.driver.find_element(By.XPATH, "/html/body/pre").text, + self.driver.find_element(By.CSS_SELECTOR, "pre").text, f"Hello, {USER().name}!", ) diff --git a/e2e/test_source_oauth.py b/e2e/test_source_oauth.py index bbb2367e5..5ad145380 100644 --- a/e2e/test_source_oauth.py +++ b/e2e/test_source_oauth.py @@ -145,8 +145,7 @@ class TestSourceOAuth2(SeleniumTestCase): self.wait_for_url(self.url("passbook_core:user-settings")) self.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - "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" @@ -199,7 +198,7 @@ class TestSourceOAuth2(SeleniumTestCase): """test OAuth Source With With OIDC (enroll and authenticate again)""" self.test_oauth_enroll() # We're logged in at the end of this, log out and re-login - self.driver.find_element(By.CSS_SELECTOR, "[aria-label=logout]").click() + self.driver.find_element(By.ID, "logout").click() self.wait.until( ec.presence_of_element_located( @@ -229,8 +228,7 @@ class TestSourceOAuth2(SeleniumTestCase): self.wait_for_url(self.url("passbook_core:user-settings")) self.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - "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" @@ -324,8 +322,7 @@ class TestSourceOAuth1(SeleniumTestCase): self.wait_for_url(self.url("passbook_core:user-settings")) self.assertEqual( - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").text, - "example-user", + self.driver.find_element(By.ID, "user-settings").text, "example-user", ) self.assertEqual( self.driver.find_element(By.ID, "id_username").get_attribute("value"), diff --git a/e2e/test_source_saml.py b/e2e/test_source_saml.py index 8f5f29101..b154c4b27 100644 --- a/e2e/test_source_saml.py +++ b/e2e/test_source_saml.py @@ -130,12 +130,8 @@ class TestSourceSAML(SeleniumTestCase): self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) # Wait until we're logged in - self.wait.until( - ec.presence_of_element_located( - (By.XPATH, "//a[contains(@href, '/-/user/')]") - ) - ) - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click() + self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) + self.driver.find_element(By.ID, "user-settings").click() # Wait until we've loaded the user info page self.wait.until(ec.presence_of_element_located((By.ID, "id_username"))) @@ -183,12 +179,8 @@ class TestSourceSAML(SeleniumTestCase): self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) # Wait until we're logged in - self.wait.until( - ec.presence_of_element_located( - (By.XPATH, "//a[contains(@href, '/-/user/')]") - ) - ) - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click() + self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) + self.driver.find_element(By.ID, "user-settings").click() # Wait until we've loaded the user info page self.wait.until(ec.presence_of_element_located((By.ID, "id_username"))) @@ -234,12 +226,8 @@ class TestSourceSAML(SeleniumTestCase): self.driver.find_element(By.ID, "password").send_keys(Keys.ENTER) # Wait until we're logged in - self.wait.until( - ec.presence_of_element_located( - (By.XPATH, "//a[contains(@href, '/-/user/')]") - ) - ) - self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").click() + self.wait.until(ec.presence_of_element_located((By.ID, "user-settings"))) + self.driver.find_element(By.ID, "user-settings").click() # Wait until we've loaded the user info page self.wait.until(ec.presence_of_element_located((By.ID, "id_username"))) diff --git a/passbook/core/templates/base/page.html b/passbook/core/templates/base/page.html index d66ae5955..6abf0788e 100644 --- a/passbook/core/templates/base/page.html +++ b/passbook/core/templates/base/page.html @@ -44,12 +44,12 @@
diff --git a/passbook/providers/oauth2/templates/providers/oauth2/consent.html b/passbook/providers/oauth2/templates/providers/oauth2/consent.html index 0fb2170c7..6dea2e852 100644 --- a/passbook/providers/oauth2/templates/providers/oauth2/consent.html +++ b/passbook/providers/oauth2/templates/providers/oauth2/consent.html @@ -6,13 +6,13 @@

{% blocktrans with name=context.application.name %} - You're about to sign into {{ name }}. + You're about to sign into {{ name }}. {% endblocktrans %}

{% trans "Application requires following permissions" %}

-
    - {% for scope in context.scope_descriptions %} -
  • {{ scope }}
  • +
      + {% for scope_name, description in context.scope_descriptions.items %} +
    • {{ description }}
    • {% endfor %}
    {{ hidden_inputs }} diff --git a/passbook/providers/oauth2/views/userinfo.py b/passbook/providers/oauth2/views/userinfo.py index d281751fa..eb1d324fa 100644 --- a/passbook/providers/oauth2/views/userinfo.py +++ b/passbook/providers/oauth2/views/userinfo.py @@ -22,14 +22,14 @@ class UserInfoView(View): """Create a dictionary with all the requested claims about the End-User. See: http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse""" - def get_scope_descriptions(self, scopes: List[str]) -> List[str]: + def get_scope_descriptions(self, scopes: List[str]) -> Dict[str, str]: """Get a list of all Scopes's descriptions""" - scope_descriptions = [] + scope_descriptions = {} for scope in ScopeMapping.objects.filter(scope_name__in=scopes).order_by( "scope_name" ): if scope.description != "": - scope_descriptions.append(scope.description) + scope_descriptions[scope.scope_name] = scope.description # GitHub Compatibility Scopes are handeled differently, since they required custom paths # Hence they don't exist as Scope objects github_scope_map = { @@ -44,7 +44,7 @@ class UserInfoView(View): } for scope in scopes: if scope in github_scope_map: - scope_descriptions.append(github_scope_map[scope]) + scope_descriptions[scope] = github_scope_map[scope] return scope_descriptions def get_claims(self, token: RefreshToken) -> Dict[str, Any]: diff --git a/passbook/providers/saml/templates/providers/saml/consent.html b/passbook/providers/saml/templates/providers/saml/consent.html index f998f7119..0618a3c94 100644 --- a/passbook/providers/saml/templates/providers/saml/consent.html +++ b/passbook/providers/saml/templates/providers/saml/consent.html @@ -6,7 +6,7 @@

    {% blocktrans with name=context.application.name %} - You're about to sign into {{ name }}. + You're about to sign into {{ name }}. {% endblocktrans %}

    {{ hidden_inputs }} diff --git a/passbook/stages/identification/templates/stages/identification/login.html b/passbook/stages/identification/templates/stages/identification/login.html index 86c7fe8a5..8a6a68c5d 100644 --- a/passbook/stages/identification/templates/stages/identification/login.html +++ b/passbook/stages/identification/templates/stages/identification/login.html @@ -14,7 +14,7 @@ {% if application_pre %}

    {% blocktrans with app_name=application_pre.name %} - Login to continue to {{ app_name }}. + Login to continue to {{ app_name }}. {% endblocktrans %}

    {% endif %} diff --git a/passbook/stages/otp_time/stage.py b/passbook/stages/otp_time/stage.py index 182ea22c6..251027646 100644 --- a/passbook/stages/otp_time/stage.py +++ b/passbook/stages/otp_time/stage.py @@ -36,9 +36,7 @@ class OTPTimeStageView(FormView, StageView): qr_code = QRCode(image_factory=SvgFillImage) qr_code.add_data(device.config_url) svg_image = tostring(qr_code.make_image().get_image()) - sr_wrapper = ( - f'
    {force_str(svg_image)}
    ' - ) + sr_wrapper = f'
    {force_str(svg_image)}
    ' return sr_wrapper def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: