diff --git a/e2e/__init__.py b/e2e/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml new file mode 100644 index 000000000..2519ac3fa --- /dev/null +++ b/e2e/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.7' + +services: + hub: + image: dosel/zalenium + command: start + ports: + - 4444:4444 + environment: + PULL_SELENIUM_IMAGE: 'true' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /tmp/videos:/home/seluser/videos + privileged: true diff --git a/e2e/test_enroll_2_step.py b/e2e/test_enroll_2_step.py new file mode 100644 index 000000000..1a05d058b --- /dev/null +++ b/e2e/test_enroll_2_step.py @@ -0,0 +1,109 @@ +"""Test 2-step enroll flow""" +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities + +from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding +from passbook.policies.expression.models import ExpressionPolicy +from passbook.policies.models import PolicyBinding +from passbook.stages.prompt.models import FieldTypes, Prompt, PromptStage +from passbook.stages.user_login.models import UserLoginStage +from passbook.stages.user_write.models import UserWriteStage + + +class TestEnroll2Step(StaticLiveServerTestCase): + """Test 2-step enroll flow""" + + host = "0.0.0.0" + port = 8001 + + def setUp(self): + self.driver = webdriver.Remote( + command_executor="http://localhost:4444/wd/hub", + desired_capabilities=DesiredCapabilities.CHROME, + ) + self.driver.implicitly_wait(2) + + def tearDown(self): + super().tearDown() + self.driver.quit() + + def test_enroll_2_step(self): + """Test 2-step enroll flow""" + # First stage fields + username_prompt = Prompt.objects.create( + field_key="username", label="Username", order=0, type=FieldTypes.TEXT + ) + password = Prompt.objects.create( + field_key="password", label="Password", order=1, type=FieldTypes.PASSWORD + ) + password_repeat = Prompt.objects.create( + field_key="password_repeat", + label="Password (repeat)", + order=2, + type=FieldTypes.PASSWORD, + ) + + # Second stage fields + name_field = Prompt.objects.create( + field_key="name", label="Name", order=0, type=FieldTypes.TEXT + ) + email = Prompt.objects.create( + field_key="email", label="E-Mail", order=1, type=FieldTypes.EMAIL + ) + + # Stages + first_stage = PromptStage.objects.create(name="prompt-stage-first") + first_stage.fields.set([username_prompt, password, password_repeat]) + first_stage.save() + second_stage = PromptStage.objects.create(name="prompt-stage-second") + second_stage.fields.set([name_field, email]) + second_stage.save() + user_write = UserWriteStage.objects.create(name="enroll-user-write") + user_login = UserLoginStage.objects.create(name="enroll-user-login") + + # Password checking policy + password_policy = ExpressionPolicy.objects.create( + name="policy-enrollment-password-equals", + expression="{{ request.context.password == request.context.password_repeat }}", + ) + PolicyBinding.objects.create( + target=first_stage, policy=password_policy, order=0 + ) + + flow = Flow.objects.create( + name="default-enrollment-flow", + slug="default-enrollment-flow", + designation=FlowDesignation.ENROLLMENT, + ) + + FlowStageBinding.objects.create(flow=flow, stage=first_stage, order=0) + FlowStageBinding.objects.create(flow=flow, stage=second_stage, order=1) + FlowStageBinding.objects.create(flow=flow, stage=user_write, order=2) + FlowStageBinding.objects.create(flow=flow, stage=user_login, order=3) + self.driver.get(f"http://host.docker.internal:{self.port}") + self.driver.find_element(By.CSS_SELECTOR, "[role=enroll]").click() + self.driver.find_element(By.ID, "id_username").send_keys("foo") + self.driver.find_element(By.ID, "id_password").send_keys("pbadmin") + self.driver.find_element(By.ID, "id_password_repeat").send_keys("pbadmin") + self.driver.find_element(By.CSS_SELECTOR, ".pf-c-button").click() + self.driver.find_element(By.ID, "id_name").send_keys("some name") + 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.LINK_TEXT, "foo").click() + self.assertEqual( + self.driver.find_element(By.XPATH, "//a[contains(@href, '/-/user/')]").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", + ) diff --git a/e2e/test_login_default.py b/e2e/test_login_default.py new file mode 100644 index 000000000..e21e3ed27 --- /dev/null +++ b/e2e/test_login_default.py @@ -0,0 +1,54 @@ +"""test default login flow""" +import string +from random import SystemRandom + +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from django.core.management import call_command +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities +from selenium.webdriver.common.keys import Keys + +from passbook.core.models import User + + +class TestLogin(StaticLiveServerTestCase): + """test default login flow""" + + host = "0.0.0.0" + port = 8000 + + def setUp(self): + self.driver = webdriver.Remote( + command_executor="http://localhost:4444/wd/hub", + desired_capabilities=DesiredCapabilities.CHROME, + ) + self.driver.implicitly_wait(2) + self.password = "".join( + SystemRandom().choice(string.ascii_uppercase + string.digits) + for _ in range(8) + ) + User.objects.create_superuser( + username="pbadmin", email="admin@example.tld", password=self.password + ) + call_command("migrate", "--fake", "passbook_flows", "0001_initial") + call_command("migrate", "passbook_flows", "0002_default_flows") + + def tearDown(self): + super().tearDown() + self.driver.quit() + + def test_login(self): + """test default login flow""" + self.driver.get( + f"http://host.docker.internal:{self.port}/flows/default-authentication-flow/?next=%2F" + ) + self.driver.find_element(By.ID, "id_uid_field").click() + self.driver.find_element(By.ID, "id_uid_field").send_keys("admin@example.tld") + self.driver.find_element(By.ID, "id_uid_field").send_keys(Keys.ENTER) + self.driver.find_element(By.ID, "id_password").send_keys(self.password) + 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, + "pbadmin", + ) diff --git a/passbook/stages/identification/templates/stages/identification/login.html b/passbook/stages/identification/templates/stages/identification/login.html index d95ebd675..95079ae13 100644 --- a/passbook/stages/identification/templates/stages/identification/login.html +++ b/passbook/stages/identification/templates/stages/identification/login.html @@ -43,12 +43,12 @@ {% if enroll_url %} {% endif %} {% if recovery_url %} {% endif %}