diff --git a/e2e/test_enroll_2_step.py b/e2e/test_enroll.py similarity index 69% rename from e2e/test_enroll_2_step.py rename to e2e/test_enroll.py index d06db4b33..800fac47f 100644 --- a/e2e/test_enroll_2_step.py +++ b/e2e/test_enroll.py @@ -1,13 +1,56 @@ -"""Test 2-step enroll flow""" +"""Test Enroll flow""" +from time import sleep + +from django.test import override_settings from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as ec +from docker import DockerClient, from_env +from docker.models.containers import Container +from docker.types import Healthcheck from e2e.utils import USER, SeleniumTestCase +from passbook.flows.models import Flow, FlowDesignation, FlowStageBinding +from passbook.policies.expression.models import ExpressionPolicy +from passbook.policies.models import PolicyBinding +from passbook.stages.email.models import EmailStage, EmailTemplates +from passbook.stages.identification.models import IdentificationStage +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(SeleniumTestCase): - """Test 2-step enroll flow""" +class TestEnroll(SeleniumTestCase): + """Test Enroll flow""" + + def setUp(self): + super().setUp() + self.container = self.setup_client() + + def setup_client(self) -> Container: + """Setup test IdP container""" + client: DockerClient = from_env() + container = client.containers.run( + image="mailhog/mailhog", + detach=True, + network_mode="host", + auto_remove=True, + healthcheck=Healthcheck( + test=["CMD", "wget", "-s", "http://localhost:8025"], + interval=5 * 100 * 1000000, + start_period=1 * 100 * 1000000, + ), + ) + while True: + container.reload() + status = container.attrs.get("State", {}).get("Health", {}).get("Status") + if status == "healthy": + return container + sleep(1) + + def tearDown(self): + self.container.kill() + super().tearDown() # pylint: disable=too-many-statements def setup_test_enroll_2_step(self): @@ -317,3 +360,117 @@ class TestEnroll2Step(SeleniumTestCase): self.driver.find_element(By.ID, "id_email").get_attribute("value"), "foo@bar.baz", ) + + @override_settings(EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend") + def test_enroll_email(self): + """Test enroll with Email verification""" + # 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() + email_stage = EmailStage.objects.create( + name="enroll-email", + host="localhost", + port=1025, + template=EmailTemplates.ACCOUNT_CONFIRM, + ) + 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="return 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, + ) + + # Attach enrollment flow to identification stage + ident_stage: IdentificationStage = IdentificationStage.objects.first() + ident_stage.enrollment_flow = flow + ident_stage.save() + + 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=email_stage, order=3) + FlowStageBinding.objects.create(flow=flow, stage=user_login, order=4) + + self.driver.get(self.live_server_url) + 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(USER().username) + self.driver.find_element(By.ID, "id_password_repeat").send_keys(USER().username) + 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() + sleep(3) + + # Open Mailhog + self.driver.get("http://localhost:8025") + + # Click on first message + self.driver.find_element(By.CLASS_NAME, "msglist-message").click() + sleep(3) + self.driver.switch_to.frame(self.driver.find_element(By.CLASS_NAME, "tab-pane")) + self.driver.find_element(By.ID, "confirm").click() + self.driver.close() + self.driver.switch_to.window(self.driver.window_handles[0]) + + # We're now logged in + sleep(3) + 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.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/passbook/stages/email/templates/stages/email/for_email/account_confirmation.html b/passbook/stages/email/templates/stages/email/for_email/account_confirmation.html index 598601226..b384a8cd1 100644 --- a/passbook/stages/email/templates/stages/email/for_email/account_confirmation.html +++ b/passbook/stages/email/templates/stages/email/for_email/account_confirmation.html @@ -18,7 +18,7 @@ - +
{% trans 'Confirm Account' %} {% trans 'Confirm Account' %}
diff --git a/passbook/stages/email/templates/stages/email/for_email/password_reset.html b/passbook/stages/email/templates/stages/email/for_email/password_reset.html index 4003b1e9c..c023c3087 100644 --- a/passbook/stages/email/templates/stages/email/for_email/password_reset.html +++ b/passbook/stages/email/templates/stages/email/for_email/password_reset.html @@ -23,7 +23,7 @@ - +
{% trans 'Reset Password' %} {% trans 'Reset Password' %}