import re import allure import pytest from playwright.sync_api import Page, expect @pytest.mark.login_page class TestLoginPage: """Anonymized E2E examples from an enterprise Playwright project.""" @pytest.mark.e2e @pytest.mark.parametrize( "username,password,expected_error", [ pytest.param( "valid_user", "invalid_password", "Unable to logon with specified login and password", id="invalid-password", ), pytest.param( "unknown_user", "valid_password", "Unable to logon with specified login and password", id="unknown-user", ), pytest.param( "", "valid_password", "Form validation failed", id="empty-username", ), pytest.param( "valid_user", "", "Form validation failed", id="empty-password", ), pytest.param( r"!@#$%^&*()_+QWERTYUIOP{}ASDFGHJKL:\"|~ZXCVBNM<>?±§ ", r"!@#$%^&*()_+QWERTYUIOP{}ASDFGHJKL:\"|~ZXCVBNM<>?±§ ", "Unable to logon with specified login and password", id="special-characters", ), pytest.param( "qwertyuiopasdfghjklzxcvbnm" * 2, "qwertyuiopasdfghjklzxcvbnm" * 2, "Form validation failed", id="overlong-input", ), pytest.param( "non_latin_user", "non_latin_password", "Form validation failed", id="non-latin-input", ), ], ) def test_login_negative( self, login_page: Page, login_page_object, username: str, password: str, expected_error: str, ): with allure.step("Fill login and password"): login_page_object.login_field.fill(username) login_page_object.password_field.fill(password) with allure.step("Click Logon button"): login_page_object.logon_btn.click() with allure.step("Check error message"): expect(login_page.get_by_text(expected_error)).to_contain_text(expected_error) @pytest.mark.e2e def test_login_positive(self, login_page: Page, login_page_object, test_user): with allure.step("Fill valid credentials"): login_page_object.login_field.fill(test_user.login) login_page_object.password_field.fill(test_user.password) with allure.step("Click Logon button"): login_page_object.logon_btn.click() with allure.step("Check successful login"): expect(login_page).not_to_have_url(login_page.url) @pytest.mark.e2e def test_password_reset_positive( self, login_page: Page, login_page_object, password_reset_user, mail_checker, ): with allure.step("Open password reset form"): login_page_object.forgot_password_link.click() with allure.step("Close password reset form"): login_page_object.close_btn.click() expect(login_page_object.reset_pass_txt).to_be_hidden() with allure.step("Reopen password reset form"): login_page_object.forgot_password_link.click() with allure.step("Fill login and email"): login_page_object.login_field.fill(password_reset_user.login) login_page_object.email_field.fill(password_reset_user.email) with allure.step("Submit password reset request"): login_page_object.next_btn.click() with allure.step("Check reset email"): mail = mail_checker.wait_for_email(positive=True, timeout=60) print("Received email:", mail["subject"]) with allure.step("Check confirmation message"): expect(login_page).to_contain_text( "Password reset confirmation message" ) @pytest.mark.e2e @pytest.mark.parametrize( "login,email,expected_result", [ pytest.param("test_user", " ", "Form validation failed", id="empty-email"), pytest.param("test_user", "@", "Form validation failed", id="invalid-email-1"), pytest.param("test_user", "test@", "Form validation failed", id="invalid-email-2"), pytest.param( "test_user", "test@test.", "Form validation failed", id="invalid-email-3", ), pytest.param( "test_user", ".test@test.com", "Form validation failed", id="invalid-email-4", ), pytest.param( "test_user", "te..st@test.com", "Form validation failed", id="invalid-email-5", ), pytest.param( "test_user", "non_latin@test.com", "Form validation failed", id="non-latin-email", ), pytest.param( "test_user", "test@test.com", "Reset password request was accepted", id="unknown-email-for-valid-user", ), pytest.param( "unknown_user", "test@test.com", "Reset password request was accepted", id="unknown-user", ), pytest.param( "", "test@test.com", "Form validation failed", id="empty-login", ), pytest.param( "test_user", "test@test", "Reset password request was accepted", id="email-without-tld", ), pytest.param( "test_user", "!@test", "Reset password request was accepted", id="non-standard-email-format", ), ], ) def test_password_reset_negative( self, login_page: Page, login_page_object, mail_checker, login: str, email: str, expected_result: str, ): with allure.step("Open password reset form"): login_page_object.forgot_password_link.click() with allure.step("Fill login and email"): login_page_object.login_field.fill(login) login_page_object.email_field.fill(email) if expected_result == "Form validation failed": with allure.step("Verify submit button is disabled"): expect(login_page_object.next_btn).to_be_disabled() else: with allure.step("Submit password reset request"): login_page_object.next_btn.click() with allure.step("Check application response"): expect(login_page).to_contain_text(expected_result) with allure.step("Check that no reset email is sent"): mail_checker.wait_for_email(positive=False, timeout=20) @pytest.mark.e2e def test_password_reset_security_questions_positive( self, login_page: Page, login_page_object, security_questions_user, mail_checker, ): with allure.step("Open password reset form"): login_page_object.forgot_password_link.click() with allure.step("Fill login and email"): login_page_object.login_field.fill(security_questions_user.login) login_page_object.email_field.fill(security_questions_user.email) with allure.step("Submit password reset request"): login_page_object.next_btn.click() answers = [] expected_questions = { "question_type_a": "answer_a", "question_type_b": "answer_b", "question_type_c": "answer_c", "question_type_d": "answer_d", } with allure.step("Answer security questions"): for index in range(1, 5): question_text = login_page.get_by_text( re.compile(fr"Question {index}") ).inner_text() current_answer = None question_lower = question_text.lower() for question_type, answer in expected_questions.items(): if question_type in question_lower: current_answer = answer break assert current_answer is not None, ( f"Unknown security question: {question_text}" ) answers.append(current_answer) assert len(answers) == len(set(answers)), ( f"Duplicate security question detected: {question_text}" ) login_page_object.answer_field.fill(current_answer) login_page_object.next_btn.nth(1).click() with allure.step("Check password reset email"): mail = mail_checker.wait_for_email(positive=True, timeout=60) print("Received email:", mail["subject"]) with allure.step("Check successful password reset"): expect(login_page).to_contain_text("Password reset completed") @pytest.mark.e2e def test_password_reset_security_questions_negative( self, login_page: Page, login_page_object, security_questions_user, ): with allure.step("Open password reset form"): login_page_object.forgot_password_link.click() with allure.step("Fill login and email"): login_page_object.login_field.fill(security_questions_user.login) login_page_object.email_field.fill(security_questions_user.email) with allure.step("Submit password reset request"): login_page_object.next_btn.click() with allure.step("Submit invalid answers"): for _ in range(3): login_page_object.answer_field.fill("invalid_answer") login_page_object.next_btn.nth(1).click() expect(login_page).to_contain_text( "Incorrect answer. Try again" ) login_page_object.ok_btn.click() with allure.step("Check cooldown timer"): expect(login_page_object.sixty_btn).to_be_disabled() expect(login_page_object.sixty_btn).to_contain_text(re.compile(r"\d+")) with allure.step("Wait for cooldown to finish"): expect(login_page_object.next_btn.nth(1)).to_be_enabled(timeout=61_000) expect(login_page_object.next_btn.nth(1)).not_to_contain_text( re.compile(r"\d+") )