From 8de8d29335bc533b1309b9d1def252c0e0f276e5 Mon Sep 17 00:00:00 2001 From: Gerodotry <60816964+Gerodotry@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:55:43 +0200 Subject: [PATCH 1/3] issues --- pages/cart_page.py | 22 +++++++++--- pages/home_page.py | 38 +++++++++++++++----- pages/login_page.py | 63 +++++++++++++++++++++------------ pages/product_page.py | 18 +++++++--- pages/search_page.py | 15 ++++---- tests/test_buy_flow.py | 41 ++++++--------------- tests/test_buy_product.py | 34 ------------------ tests/test_login.py | 26 ++++++-------- tests/test_open_product_page.py | 41 +++++++++++---------- 9 files changed, 150 insertions(+), 148 deletions(-) delete mode 100644 tests/test_buy_product.py diff --git a/pages/cart_page.py b/pages/cart_page.py index 07e3caa..bc0622b 100644 --- a/pages/cart_page.py +++ b/pages/cart_page.py @@ -1,10 +1,24 @@ from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + class CartPage: - CHECKOUT_BUTTON = "/html/body/div/div/div/div[2]/div[2]/div/div[2]/div/div/div/div[3]/div/div[2]/button" - def __init__(self, driver): + def __init__(self, driver, timeout=20): self.driver = driver + self.wait = WebDriverWait(driver, timeout) + + @property + def cart_title(self): + return self.wait.until( + EC.visibility_of_element_located( + (By.XPATH, "//h2[normalize-space()='Ваш кошик товарів']") + ) + ) - def checkout_button_exists(self): - return len(self.driver.find_elements(By.XPATH, self.CHECKOUT_BUTTON)) > 0 + def cart_title_exists(self): + try: + return self.cart_title.is_displayed() + except: + return False diff --git a/pages/home_page.py b/pages/home_page.py index daaaea5..1cc785a 100644 --- a/pages/home_page.py +++ b/pages/home_page.py @@ -5,21 +5,43 @@ class HomePage: URL = "https://epicentrk.ua/" - FIRST_PRODUCT = "/html/body/div/div/div/main/div/div/div[3]/div[2]/div[5]/div/div/ul/li[1]/div/div/a" - SEARCH_BUTTON = "//button[@aria-label='Пошук']//*[name()='svg']" - def __init__(self, driver, timeout=10): + def __init__(self, driver, timeout=15): self.driver = driver self.wait = WebDriverWait(driver, timeout) def open(self): self.driver.get(self.URL) + # Очікуємо появу першого товару саме через ТВОЙ локатор ✅ + self.wait.until( + EC.presence_of_element_located( + (By.XPATH, "(//div[@itemtype='https://schema.org/Product']//p[@itemprop='name']/a)[1]") + ) + ) + + @property + def first_product(self): + return self.wait.until( + EC.element_to_be_clickable( + (By.XPATH, "(//div[@itemtype='https://schema.org/Product']//p[@itemprop='name']/a)[1]") + ) + ) + + @property + def search_button(self): + return self.wait.until( + EC.element_to_be_clickable( + (By.XPATH, "//button[@aria-label='Пошук']//*[name()='svg']") + ) + ) def search_button_exists(self): - return len(self.driver.find_elements(By.XPATH, self.SEARCH_BUTTON)) > 0 + try: + return self.search_button.is_displayed() + except: + return False def click_first_product(self): - product = self.wait.until( - EC.element_to_be_clickable((By.XPATH, self.FIRST_PRODUCT)) - ) - ActionChains(self.driver).move_to_element(product).pause(0.1).click().perform() + product = self.first_product + ActionChains(self.driver).scroll_to_element(product).perform() + product.click() diff --git a/pages/login_page.py b/pages/login_page.py index d20621e..617d52e 100644 --- a/pages/login_page.py +++ b/pages/login_page.py @@ -1,47 +1,64 @@ from selenium.webdriver.common.by import By -from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException -import time - class LoginPage: - LOGIN_BUTTON = "//button[@data-testid='login']" - INPUT_PHONE = "//input[@name='login']" - INPUT_PASSWORD = "//input[@type='password']" - SUBMIT_BUTTON = "//button[@data-auth-type='login']" - ERROR_MESSAGE = "//*[contains(text(),'Невірний') or contains(text(),'помилка')]" def __init__(self, driver, timeout=12): self.driver = driver self.wait = WebDriverWait(driver, timeout) + @property + def login_button(self): + return self.wait.until(EC.element_to_be_clickable(( + By.CSS_SELECTOR, "button[data-testid='login']" + ))) + + @property + def phone_input(self): + return self.wait.until(EC.element_to_be_clickable(( + By.CSS_SELECTOR, "input[name='login']" + ))) + + @property + def password_input(self): + return self.wait.until(EC.element_to_be_clickable(( + By.CSS_SELECTOR, "input[type='password']" + ))) + + @property + def submit_button(self): + return self.wait.until(EC.element_to_be_clickable(( + By.CSS_SELECTOR, "button[data-auth-type='login']" + ))) + + @property + def error_message(self): + return self.wait.until(EC.visibility_of_element_located(( + By.XPATH, "//*[contains(text(),'Невірний') or contains(text(),'помилка')]" + ))) + def open_login_form(self): - el = self.wait.until(EC.element_to_be_clickable((By.XPATH, self.LOGIN_BUTTON))) - ActionChains(self.driver).move_to_element(el).click().perform() - print("✅ Відкрили форму входу") - time.sleep(2) + self.login_button.click() def enter_phone(self, phone): - field = self.wait.until(EC.element_to_be_clickable((By.XPATH, self.INPUT_PHONE))) - field.click() - field.clear() - field.send_keys(phone) + self.phone_input.clear() + self.phone_input.send_keys(phone) def enter_password(self, password): - field = self.wait.until(EC.element_to_be_clickable((By.XPATH, self.INPUT_PASSWORD))) - field.click() - field.clear() - field.send_keys(password) + self.password_input.clear() + self.password_input.send_keys(password) def submit_login(self): - btn = self.wait.until(EC.element_to_be_clickable((By.XPATH, self.SUBMIT_BUTTON))) - ActionChains(self.driver).move_to_element(btn).click().perform() + self.submit_button.click() def error_displayed(self): try: - self.wait.until(EC.visibility_of_element_located((By.XPATH, self.ERROR_MESSAGE))) + self.error_message return True except TimeoutException: return False + + def login_error_visible(self): + return self.error_displayed() diff --git a/pages/product_page.py b/pages/product_page.py index 29042b7..ac61211 100644 --- a/pages/product_page.py +++ b/pages/product_page.py @@ -1,18 +1,26 @@ from selenium.webdriver.common.by import By -from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC +from selenium.common.exceptions import TimeoutException class ProductPage: - BUY_BTN = "//button[@data-product-buy-button]" def __init__(self, driver, timeout=10): self.driver = driver self.wait = WebDriverWait(driver, timeout) + @property + def buy_button(self): + return self.wait.until(EC.element_to_be_clickable(( + By.CSS_SELECTOR, "button[data-product-buy-button]" + ))) + def click_buy(self): - btn = self.wait.until(EC.element_to_be_clickable((By.XPATH, self.BUY_BTN))) - ActionChains(self.driver).move_to_element(btn).click().perform() + self.buy_button.click() def buy_button_exists(self): - return len(self.driver.find_elements(By.XPATH, self.BUY_BTN)) > 0 \ No newline at end of file + try: + self.buy_button # Якщо не знайде -> TimeoutException + return True + except TimeoutException: + return False diff --git a/pages/search_page.py b/pages/search_page.py index 5ae7b27..96060f1 100644 --- a/pages/search_page.py +++ b/pages/search_page.py @@ -1,23 +1,22 @@ - from selenium.webdriver.common.by import By -from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class HomePage: URL = "https://epicentrk.ua/" - FIRST_PRODUCT = "(//main//li//a[contains(@href,'/p/')])[1]" - def __init__(self, driver, timeout=10): self.driver = driver self.wait = WebDriverWait(driver, timeout) + @property + def first_product(self): + return self.wait.until(EC.element_to_be_clickable(( + By.XPATH, "(//main//li//a[contains(@href,'/p/')])[1]" + ))) + def open(self): self.driver.get(self.URL) def click_first_product(self): - product = self.wait.until( - EC.element_to_be_clickable((By.XPATH, self.FIRST_PRODUCT)) - ) - ActionChains(self.driver).move_to_element(product).click().perform() + self.first_product.click() diff --git a/tests/test_buy_flow.py b/tests/test_buy_flow.py index 9d2c343..7e3e04f 100644 --- a/tests/test_buy_flow.py +++ b/tests/test_buy_flow.py @@ -1,35 +1,14 @@ -import time -from selenium import webdriver -from selenium.webdriver.chrome.service import Service -from webdriver_manager.chrome import ChromeDriverManager - -from pages.home_page import HomePage -from pages.product_page import ProductPage -from pages.cart_page import CartPage - -driver = None -home = None -product = None -cart = None -def setup_module(): - global driver, home, product, cart - driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) - driver.maximize_window() - home = HomePage(driver) - product = ProductPage(driver) - cart = CartPage(driver) -def teardown_module(): - driver.quit() -def test_step1_open_product(): +def test_step1_open_product(home, driver): home.open() - time.sleep(2) home.click_first_product() - time.sleep(3) assert "/ua/shop/" in driver.current_url and driver.current_url.endswith(".html"), \ - " Не потрапили на сторінку товару!" -def test_step2_buy_btn_exists(): - assert product.buy_button_exists(), " Кнопка 'Купити' не знайдена!" -def test_step3_buy_and_checkout_btn(): + "❌ Не потрапили на сторінку товару!" + + +def test_step2_buy_btn_exists(product): + assert product.buy_button_exists(), "❌ Кнопка 'Купити' не знайдена!" + + +def test_step3_buy_and_checkout_btn(product, cart): product.click_buy() - time.sleep(5) - assert cart.checkout_button_exists(), " Кнопка 'Оформити покупку' не знайдена!" + assert cart.cart_title_exists(), "❌ Кошик не відкрився!" diff --git a/tests/test_buy_product.py b/tests/test_buy_product.py deleted file mode 100644 index a806801..0000000 --- a/tests/test_buy_product.py +++ /dev/null @@ -1,34 +0,0 @@ -import time -from selenium import webdriver -from selenium.webdriver.chrome.service import Service -from webdriver_manager.chrome import ChromeDriverManager - -from pages.home_page import HomePage -from pages.product_page import ProductPage -from pages.cart_page import CartPage - - -def test_buy_first_product(): - driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) - driver.maximize_window() - - home = HomePage(driver) - product = ProductPage(driver) - cart = CartPage(driver) - home.open() - time.sleep(2) - - assert home.search_button_exists(), " Кнопка пошуку не знайдена!" - print(" Кнопка пошуку знайдена") - home.click_first_product() - time.sleep(3) - - assert product.buy_button_exists(), " Кнопка 'Купити' не знайдена!" - print("Кнопка 'Купити' знайдена") - - product.click_buy() - time.sleep(3) - assert cart.checkout_button_exists(), " Кнопка Оформити покупку не знайдена!" - print(" Кнопка 'Оформити покупку' знайдена ") - - driver.quit() diff --git a/tests/test_login.py b/tests/test_login.py index a4c0b4c..3edcc7b 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -1,4 +1,3 @@ -import time from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager @@ -10,31 +9,26 @@ from pages.login_page import LoginPage -def test_login_invalid_credentials(): +def test_login_valid_credentials(): driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) driver.maximize_window() - wait = WebDriverWait(driver, 10) + wait = WebDriverWait(driver, 15) home = HomePage(driver) login = LoginPage(driver) + home.open() - time.sleep(2) login.open_login_form() - time.sleep(2) login.enter_phone("+38 (097) 904-46-37") login.enter_password(".WMWAzPp%w,/_6b") - time.sleep(1) login.submit_login() - time.sleep(3) - driver.refresh() - time.sleep(3) - user_name_xpath = "/html/body/div/div/div/div[1]/header/div/div[1]/div[6]/div/button/span[2]" - try: - user_name = wait.until( - EC.visibility_of_element_located((By.XPATH, user_name_xpath)) + + user_name_span = wait.until( + EC.visibility_of_element_located( + (By.XPATH, "//button[@data-testid='login']//span[contains(normalize-space(),'Павло')]") ) - print(" Ім’я:", user_name.text) - except: - raise AssertionError("❌ Не знайдено ім’я користувача після входу!") + ) + + assert "Павло" in user_name_span.text, " Ім’я користувача не з’явилося після входу!" driver.quit() diff --git a/tests/test_open_product_page.py b/tests/test_open_product_page.py index 1d69ef9..8f651b6 100644 --- a/tests/test_open_product_page.py +++ b/tests/test_open_product_page.py @@ -4,32 +4,35 @@ 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.common.action_chains import ActionChains -import time + def test_search_kley(): driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) driver.maximize_window() - driver.get("https://epicentrk.ua/") - time.sleep(3) - search_input = driver.find_element(By.CSS_SELECTOR, "input[type='search']") + wait = WebDriverWait(driver, 20) + + driver.get("https://epicentrk.ua/ua/") + + search_input = wait.until( + EC.element_to_be_clickable((By.CSS_SELECTOR, "input[type='search']")) + ) search_input.send_keys("клей") - time.sleep(1) - search_button = driver.find_element(By.CSS_SELECTOR, "button[aria-label='Пошук']") - driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", search_button) - time.sleep(0.5) - button_svg = driver.find_element(By.XPATH, "//button[@aria-label='Пошук']//*[name()='svg']") - ActionChains(driver).move_to_element(button_svg).pause(0.1).click().perform() - print("✅ Клік по кнопці пошуку виконано!") - WebDriverWait(driver, 10).until( - EC.url_contains("/ua/shop/kley/") + + search_button_svg = wait.until( + EC.element_to_be_clickable( + (By.XPATH, "//button[@aria-label='Пошук']//*[name()='svg']") + ) ) - current_url = driver.current_url - print("🔎 Поточний URL:", current_url) + search_button_svg.click() + print(" Клік по кнопці пошуку виконано!") + - assert "/ua/shop/kley/" in current_url, \ - f"❌ Помилка переходу: {current_url}" + wait.until( + EC.presence_of_element_located( + (By.XPATH, "//div[@itemtype='https://schema.org/Product']") + ) + ) + print(" Результати пошуку завантажені!") - time.sleep(3) driver.quit() From c7e7a1220cd8c474432c16e198d096ab5aab1782 Mon Sep 17 00:00:00 2001 From: Gerodotry <60816964+Gerodotry@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:01:23 +0100 Subject: [PATCH 2/3] =?UTF-8?q?Liubun=20=D0=B2=D0=B8=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=BD=D1=8F=20=D0=BF=D0=BE=D0=BC=D0=B8?= =?UTF-8?q?=D0=BB=D0=BE=D0=BA=20#2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 21 +++++++++++ pages/search_page.py | 2 +- pytest.ini | 4 +++ tests/conftest.py | 64 +++++++++++++++++++++++++++++++++ tests/test_buy_flow.py | 33 ++++++++++++----- tests/test_login.py | 37 ++++++++----------- tests/test_open_product_page.py | 38 ++++++++------------ 7 files changed, 143 insertions(+), 56 deletions(-) create mode 100644 .gitignore create mode 100644 pytest.ini create mode 100644 tests/conftest.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b34605 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd + +# Virtual environment +.venv/ +env/ +venv/ + +# Environment variables +.env + +# IDE +.idea/ +.vscode/ + +# Selenium logs / reports +reports/ +screenshots/ diff --git a/pages/search_page.py b/pages/search_page.py index 96060f1..4687ea6 100644 --- a/pages/search_page.py +++ b/pages/search_page.py @@ -2,7 +2,7 @@ from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC -class HomePage: +class SearchPage: URL = "https://epicentrk.ua/" def __init__(self, driver, timeout=10): diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..60608cc --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +markers = + e2e: end-to-end UI tests (slow, require live site) + diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..f77a777 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,64 @@ +import pytest +import os +from selenium import webdriver +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.chrome.options import Options +from webdriver_manager.chrome import ChromeDriverManager +from dotenv import load_dotenv + +from pages.home_page import HomePage +from pages.login_page import LoginPage +from pages.product_page import ProductPage +from pages.cart_page import CartPage +from pages.search_page import SearchPage + + +@pytest.fixture(scope="session") +def driver(): + """Ініціалізація WebDriver на всю сесію""" + options = Options() + options.add_argument("--start-maximized") + # options.add_argument("--headless") # для CI + + driver = webdriver.Chrome( + service=Service(ChromeDriverManager().install()), + options=options + ) + yield driver + driver.quit() + + +@pytest.fixture(scope="session") +def credentials(): + load_dotenv() + phone = os.getenv("TEST_PHONE") + password = os.getenv("TEST_PASSWORD") + + assert phone, "Не знайдено TEST_PHONE у .env" + assert password, "Не знайдено TEST_PASSWORD у .env" + return {"phone": phone, "password": password} + + +@pytest.fixture(scope="function") +def home_page(driver): + return HomePage(driver) + + +@pytest.fixture(scope="function") +def login_page(driver): + return LoginPage(driver) + + +@pytest.fixture(scope="function") +def product_page(driver): + return ProductPage(driver) + + +@pytest.fixture(scope="function") +def cart_page(driver): + return CartPage(driver) + + +@pytest.fixture(scope="function") +def search_page(driver): + return SearchPage(driver) diff --git a/tests/test_buy_flow.py b/tests/test_buy_flow.py index 7e3e04f..beb35c6 100644 --- a/tests/test_buy_flow.py +++ b/tests/test_buy_flow.py @@ -1,14 +1,31 @@ -def test_step1_open_product(home, driver): - home.open() - home.click_first_product() +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC +import pytest + +@pytest.mark.e2e +def test_step1_open_product(home_page, driver): + wait = WebDriverWait(driver, 20) + home_page.open() + home_page.click_first_product() + wait.until(EC.url_matches(r"/ua/shop/.+\.html$")) assert "/ua/shop/" in driver.current_url and driver.current_url.endswith(".html"), \ - "❌ Не потрапили на сторінку товару!" + "Не потрапили на сторінку товару!" + print("Сторінка товару успішно відкрита.") +@pytest.mark.e2e +def test_step2_buy_btn_exists(product, driver): + wait = WebDriverWait(driver, 15) + wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-product-buy-button]"))) -def test_step2_buy_btn_exists(product): - assert product.buy_button_exists(), "❌ Кнопка 'Купити' не знайдена!" + assert product.buy_button_exists(), "Кнопка 'Купити' не знайдена!" +@pytest.mark.e2e +def test_step3_buy_and_checkout_btn(product, cart, driver): + wait = WebDriverWait(driver, 15) -def test_step3_buy_and_checkout_btn(product, cart): product.click_buy() - assert cart.cart_title_exists(), "❌ Кошик не відкрився!" + + wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "[data-cart-product-item]"))) + + assert cart.cart_title_exists(), "Кошик не відкрився!" diff --git a/tests/test_login.py b/tests/test_login.py index 3edcc7b..477d9b7 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -1,34 +1,25 @@ -from selenium import webdriver -from selenium.webdriver.chrome.service import Service -from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC +import pytest -from pages.home_page import HomePage -from pages.login_page import LoginPage +@pytest.mark.e2e +def test_login_valid_credentials(driver, home_page, login_page, credentials): + wait = WebDriverWait(driver, 10) + home_page.open() + login_page.open_login_form() + login_page.enter_phone(credentials["phone"]) + login_page.enter_password(credentials["password"]) + login_page.submit_login() -def test_login_valid_credentials(): - driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) - driver.maximize_window() - wait = WebDriverWait(driver, 15) - - home = HomePage(driver) - login = LoginPage(driver) - - home.open() - login.open_login_form() - login.enter_phone("+38 (097) 904-46-37") - login.enter_password(".WMWAzPp%w,/_6b") - login.submit_login() - - user_name_span = wait.until( + profile_button = wait.until( EC.visibility_of_element_located( - (By.XPATH, "//button[@data-testid='login']//span[contains(normalize-space(),'Павло')]") + (By.CSS_SELECTOR, "button[data-testid='login']") ) ) - assert "Павло" in user_name_span.text, " Ім’я користувача не з’явилося після входу!" + user_name_span = profile_button.find_element(By.CSS_SELECTOR, "span._cjioPkQR") - driver.quit() + assert user_name_span.text.strip() != "", "Ім’я користувача не відображено після входу!" + print(f" Успішний вхід") diff --git a/tests/test_open_product_page.py b/tests/test_open_product_page.py index 8f651b6..c5743bf 100644 --- a/tests/test_open_product_page.py +++ b/tests/test_open_product_page.py @@ -1,38 +1,28 @@ -from selenium import webdriver from selenium.webdriver.common.by import By -from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC -from webdriver_manager.chrome import ChromeDriverManager - - -def test_search_kley(): - driver = webdriver.Chrome(service=Service(ChromeDriverManager().install())) - driver.maximize_window() - - wait = WebDriverWait(driver, 20) - +import pytest +@pytest.mark.e2e +def test_search_kley(driver): + wait = WebDriverWait(driver, 15) driver.get("https://epicentrk.ua/ua/") search_input = wait.until( - EC.element_to_be_clickable((By.CSS_SELECTOR, "input[type='search']")) + EC.element_to_be_clickable((By.CSS_SELECTOR, "input[data-ui-input][type='search']")) ) + search_input.clear() search_input.send_keys("клей") - search_button_svg = wait.until( - EC.element_to_be_clickable( - (By.XPATH, "//button[@aria-label='Пошук']//*[name()='svg']") - ) + search_button = wait.until( + EC.element_to_be_clickable((By.CSS_SELECTOR, "button[aria-label='Пошук']")) ) - search_button_svg.click() - print(" Клік по кнопці пошуку виконано!") - + search_button.click() - wait.until( - EC.presence_of_element_located( - (By.XPATH, "//div[@itemtype='https://schema.org/Product']") + products = wait.until( + EC.presence_of_all_elements_located( + (By.CSS_SELECTOR, "a[data-category-link='true'][title*='Клей']") ) ) - print(" Результати пошуку завантажені!") - driver.quit() + assert any("клей" in p.text.lower() for p in products), "Не знайдено товарів із 'клей'" + print(f"✅ Знайдено {len(products)} товарів зі словом 'клей'") From 1819e26b7ab964e680edcc8385c1b09b0da092b5 Mon Sep 17 00:00:00 2001 From: Gerodotry <60816964+Gerodotry@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:05:10 +0100 Subject: [PATCH 3/3] Add GitHub Actions workflow for Python tests This workflow runs unit tests and Selenium end-to-end tests on push and pull request events for the dev and main branches. --- .github/workflows/tests.yml | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..8c516de --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,51 @@ +name: Run Python Tests + +on: + push: + branches: [ dev, main ] + pull_request: + branches: [ dev, main ] + +jobs: + unit_tests: + name: Tests + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Run unit tests + run: pytest -m "not e2e" --maxfail=1 --disable-warnings -q + + e2e_tests: + name: Selenium Tests + runs-on: ubuntu-latest + needs: unit_tests + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + sudo apt-get update + sudo apt-get install -y chromium-browser chromium-chromedriver + + - name: Run E2E tests + run: pytest -m e2e --maxfail=1 --disable-warnings -q