✅ Решения заданий — Урок 07
⚡ Решения
Все 4 задания решены с WebDriverWait + EC. Ключевые EC: presence_of_element_located — Load Delay; text_to_be_present_in_element — AJAX и Calculator; url_contains — OrangeHRM.
Решение 1. Ожидание появления кнопки с задержкой
# test_load_delay.py
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
@pytest.fixture
def driver():
# Устанавливаем ChromeDriver через WebDriverManager
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("http://www.uitestingplayground.com/loaddelay") # Открываем страницу
yield driver
driver.quit() # Закрываем браузер после теста
def test_wait_for_button(driver):
wait = WebDriverWait(driver, 15) # Ожидание до 15 секунд
# Ждём, пока кнопка появится на странице
button = wait.until(
EC.presence_of_element_located(
(By.XPATH, "//button[text()='Button Appearing After Delay']")
)
)
# Проверяем, что кнопка действительно появилась
assert button.is_displayed(), "Кнопка не появилась!"
Почему presence_of_element_located? Кнопка физически добавляется в DOM с задержкой. Нам достаточно убедиться, что она появилась — видимость здесь не критична. После нахождения через presence проверяем видимость через is_displayed().
Решение 2. Авторизация в OrangeHRM
Вариант А — проверка заголовка
# test_orangehrm.py
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
@pytest.fixture
def driver():
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login")
yield driver
driver.quit()
def test_login_to_orangehrm(driver):
wait = WebDriverWait(driver, 10) # Явное ожидание до 10 секунд
# Вводим имя пользователя
username_field = driver.find_element(By.NAME, "username")
username_field.send_keys("Admin")
# Вводим пароль
password_field = driver.find_element(By.NAME, "password")
password_field.send_keys("admin123")
# Нажимаем кнопку Login
login_button = driver.find_element(By.XPATH, "//button[@type='submit']")
login_button.click()
# Ожидаем появления заголовка "Dashboard"
dashboard_header = wait.until(
EC.text_to_be_present_in_element((By.TAG_NAME, "h6"), "Dashboard")
)
# Проверяем, что заголовок содержит "Dashboard"
assert dashboard_header, "Текст заголовка не содержит 'Dashboard'"
Вариант Б — проверка URL
# Добавьте в test_orangehrm.py
def test_login_and_check_url(driver):
wait = WebDriverWait(driver, 10)
driver.find_element(By.NAME, "username").send_keys("Admin")
driver.find_element(By.NAME, "password").send_keys("admin123")
driver.find_element(By.XPATH, "//button[@type='submit']").click()
# Ожидаем, пока URL изменится и будет содержать "dashboard"
wait.until(EC.url_contains("dashboard"))
# Проверяем, что в URL содержится "dashboard"
assert "dashboard" in driver.current_url, \
f"Ожидаемый URL не содержит 'dashboard': {driver.current_url}"
Какой вариант лучше? Вариант Б (URL) чуть надёжнее — URL меняется на уровне браузера и не зависит от скорости рендеринга конкретного элемента. Вариант А нагляднее демонстрирует паттерн ожидания текста.
Решение 3. Slow Calculator
# test_calc.py
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
@pytest.fixture
def driver():
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("https://bonigarcia.dev/selenium-webdriver-java/slow-calculator.html")
yield driver
driver.quit()
def test_slow_calculator(driver):
wait = WebDriverWait(driver, 50) # Ожидание до 50 секунд (задержка 45 сек)
# Вводим задержку 45 секунд в поле #delay
delay_input = driver.find_element(By.CSS_SELECTOR, "#delay")
delay_input.clear()
delay_input.send_keys("45")
# Нажимаем кнопки: 7, +, 8, =
driver.find_element(By.XPATH, "//span[text()='7']").click()
driver.find_element(By.XPATH, "//span[text()='+']").click()
driver.find_element(By.XPATH, "//span[text()='8']").click()
driver.find_element(By.XPATH, "//span[text()='=']").click()
# Ждём появления результата "15" через 45 секунд
result_element = wait.until(
EC.text_to_be_present_in_element((By.CSS_SELECTOR, ".screen"), "15")
)
# Проверяем, что результат действительно 15
assert result_element, "Ожидаемый результат '15' не отобразился!"
Ключевые решения: (1) clear() перед вводом задержки — поле может содержать значение по умолчанию. (2) Таймаут 50 сек, а не 45 — нужен небольшой запас сверх задержки. (3) text_to_be_present_in_element на элемент .screen — ждём именно результата "15".
Решение 4. Валидация формы
# test_form_validation.py
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.service import Service
@pytest.fixture
def driver():
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.get("https://bonigarcia.dev/selenium-webdriver-java/data-types.html")
yield driver
driver.quit()
def test_form_validation(driver):
wait = WebDriverWait(driver, 10)
# Заполняем форму
driver.find_element(By.NAME, "first-name").send_keys("Hans")
driver.find_element(By.NAME, "last-name").send_keys("Schmidt")
driver.find_element(By.NAME, "address").send_keys("Berliner Straße, 55-3")
driver.find_element(By.NAME, "email").send_keys("test@itch.de")
driver.find_element(By.NAME, "phone").send_keys("+4917623456789")
# Поле Zip code оставляем пустым
driver.find_element(By.NAME, "zip-code").clear()
driver.find_element(By.NAME, "city").send_keys("Berlin")
driver.find_element(By.NAME, "country").send_keys("Deutschland")
driver.find_element(By.NAME, "job-position").send_keys("QA")
driver.find_element(By.NAME, "company").send_keys("ITCH")
# Нажимаем кнопку Submit
driver.find_element(By.XPATH, "//button[@type='submit']").click()
# Ожидаем, пока поле Zip code станет невалидным (класс is-invalid)
wait.until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, "input[name='zip-code'].is-invalid")
)
)
zip_field = driver.find_element(By.NAME, "zip-code")
assert "is-invalid" in zip_field.get_attribute("class"), \
"Поле Zip code не подсвечено красным!"
# Ожидаем и проверяем, что остальные поля валидны (класс is-valid)
valid_fields = ["first-name", "last-name", "address", "email",
"phone", "city", "country", "job-position", "company"]
for field_name in valid_fields:
wait.until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, f"input[name='{field_name}'].is-valid")
)
)
field = driver.find_element(By.NAME, field_name)
assert "is-valid" in field.get_attribute("class"), \
f"Поле {field_name} не подсвечено зелёным!"
Паттерн проверки классов: CSS-селектор input[name='zip-code'].is-invalid ждёт появления элемента, у которого одновременно name="zip-code" И класс is-invalid. Это надёжнее, чем найти поле и проверить класс без ожидания.