Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file added pages/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions pages/cart_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from selenium.webdriver.common.by import By

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"
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolute XPath is extremely brittle and will break with any DOM structure change. Use a more robust selector based on element attributes, CSS classes, or data attributes.

Suggested change
CHECKOUT_BUTTON = "/html/body/div/div/div/div[2]/div[2]/div/div[2]/div/div/div/div[3]/div/div[2]/button"
CHECKOUT_BUTTON = '//*[@id="checkout"]' # Use a unique id attribute for the checkout button

Copilot uses AI. Check for mistakes.

def __init__(self, driver):
self.driver = driver

def checkout_button_exists(self):
return len(self.driver.find_elements(By.XPATH, self.CHECKOUT_BUTTON)) > 0
25 changes: 25 additions & 0 deletions pages/home_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
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 = "/html/body/div/div/div/main/div/div/div[3]/div[2]/div[5]/div/div/ul/li[1]/div/div/a"
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolute XPath is brittle and will break with minor DOM changes. Use a more robust selector like '(//main//li//a[contains(@href,"/p/")])[1]' which focuses on semantic meaning rather than exact DOM position.

Suggested change
FIRST_PRODUCT = "/html/body/div/div/div/main/div/div/div[3]/div[2]/div[5]/div/div/ul/li[1]/div/div/a"
FIRST_PRODUCT = '(//main//li//a[contains(@href,"/p/")])[1]'

Copilot uses AI. Check for mistakes.
SEARCH_BUTTON = "//button[@aria-label='Пошук']//*[name()='svg']"
Comment on lines +7 to +9
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not store CSS/XPath selectors separately.
Create IWebElement as class properties instead.


def __init__(self, driver, timeout=10):
self.driver = driver
self.wait = WebDriverWait(driver, timeout)

def open(self):
self.driver.get(self.URL)

def search_button_exists(self):
return len(self.driver.find_elements(By.XPATH, self.SEARCH_BUTTON)) > 0

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()
47 changes: 47 additions & 0 deletions pages/login_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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(),'помилка')]"
Comment on lines +10 to +14
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not store CSS/XPath selectors separately.
Create IWebElement as class properties instead.


def __init__(self, driver, timeout=12):
self.driver = driver
self.wait = WebDriverWait(driver, timeout)

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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not use Thread.Sleep.
Implement logical waits that wait for specific web elements instead.


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)

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)

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()

def error_displayed(self):
try:
self.wait.until(EC.visibility_of_element_located((By.XPATH, self.ERROR_MESSAGE)))
return True
except TimeoutException:
return False
18 changes: 18 additions & 0 deletions pages/product_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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 ProductPage:
BUY_BTN = "//button[@data-product-buy-button]"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not store CSS/XPath selectors separately.
Create IWebElement as class properties instead.


def __init__(self, driver, timeout=10):
self.driver = driver
self.wait = WebDriverWait(driver, timeout)

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()

def buy_button_exists(self):
return len(self.driver.find_elements(By.XPATH, self.BUY_BTN)) > 0
23 changes: 23 additions & 0 deletions pages/search_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

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]"
Comment on lines +8 to +10
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not store CSS/XPath selectors separately.
Create IWebElement as class properties instead.


def __init__(self, driver, timeout=10):
self.driver = driver
self.wait = WebDriverWait(driver, timeout)

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()
Empty file added tests/__init__.py
Empty file.
35 changes: 35 additions & 0 deletions tests/test_buy_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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():
home.open()
time.sleep(2)
home.click_first_product()
time.sleep(3)
Comment on lines +25 to +27
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded time.sleep() calls make tests slow and unreliable. Replace with explicit waits for specific conditions.

Copilot uses AI. Check for mistakes.
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():
Comment on lines +10 to +32
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module-level global variables for test fixtures is an anti-pattern. Consider using pytest fixtures with appropriate scope instead of setup_module/teardown_module for better test isolation and maintainability.

Suggested change
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():
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():
import pytest
@pytest.fixture(scope="module")
def driver():
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.maximize_window()
yield driver
driver.quit()
@pytest.fixture(scope="module")
def home(driver):
return HomePage(driver)
@pytest.fixture(scope="module")
def product(driver):
return ProductPage(driver)
@pytest.fixture(scope="module")
def cart(driver):
return CartPage(driver)
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(product):
assert product.buy_button_exists(), " Кнопка 'Купити' не знайдена!"
def test_step3_buy_and_checkout_btn(product, cart):

Copilot uses AI. Check for mistakes.
product.click_buy()
time.sleep(5)
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded time.sleep() calls make tests slow and unreliable. Replace with explicit waits for specific conditions.

Copilot uses AI. Check for mistakes.
assert cart.checkout_button_exists(), " Кнопка 'Оформити покупку' не знайдена!"
34 changes: 34 additions & 0 deletions tests/test_buy_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
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)
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded time.sleep() calls make tests slow and unreliable. Replace with explicit waits for specific conditions such as element visibility or clickability.

Copilot uses AI. Check for mistakes.

assert home.search_button_exists(), " Кнопка пошуку не знайдена!"
print(" Кнопка пошуку знайдена")
home.click_first_product()
time.sleep(3)
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded time.sleep() calls make tests slow and unreliable. Replace with explicit waits for specific conditions such as element visibility or clickability.

Copilot uses AI. Check for mistakes.

assert product.buy_button_exists(), " Кнопка 'Купити' не знайдена!"
print("Кнопка 'Купити' знайдена")

product.click_buy()
time.sleep(3)
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded time.sleep() calls make tests slow and unreliable. Replace with explicit waits for specific conditions such as element visibility or clickability.

Copilot uses AI. Check for mistakes.
assert cart.checkout_button_exists(), " Кнопка Оформити покупку не знайдена!"
print(" Кнопка 'Оформити покупку' знайдена ")

driver.quit()
40 changes: 40 additions & 0 deletions tests/test_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import time
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

from pages.home_page import HomePage
from pages.login_page import LoginPage


def test_login_invalid_credentials():
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.maximize_window()
wait = WebDriverWait(driver, 10)

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)
Comment on lines +21 to +30
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple hardcoded time.sleep() calls make tests slow and unreliable. Replace with explicit waits using WebDriverWait for specific conditions (e.g., element visibility, page load completion).

Suggested change
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)
# Wait for the login button to be visible on the home page
wait.until(EC.visibility_of_element_located((By.XPATH, "//button[contains(@class, 'login')]")))
login.open_login_form()
# Wait for the phone input field to be visible in the login form
wait.until(EC.visibility_of_element_located((By.XPATH, "//input[@name='phone']")))
login.enter_phone("+38 (097) 904-46-37")
login.enter_password(".WMWAzPp%w,/_6b")
# Wait for the password field to be visible before submitting
wait.until(EC.visibility_of_element_located((By.XPATH, "//input[@name='password']")))
login.submit_login()
# Wait for either an error message or the user name to appear after login attempt
wait.until(
EC.any_of(
EC.visibility_of_element_located((By.XPATH, "/html/body/div/div/div/div[1]/header/div/div[1]/div[6]/div/button/span[2]")),
EC.visibility_of_element_located((By.XPATH, "//div[contains(@class, 'error-message')]"))
)
)
driver.refresh()
# Wait for the user name element to be visible after refresh
wait.until(EC.visibility_of_element_located((By.XPATH, "/html/body/div/div/div/div[1]/header/div/div[1]/div[6]/div/button/span[2]")))

Copilot uses AI. Check for mistakes.
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))
)
print(" Ім’я:", user_name.text)
except:
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bare except clause catches all exceptions including system exits. Specify the exception type, such as 'except TimeoutException:' to handle only the expected failure case.

Copilot uses AI. Check for mistakes.
raise AssertionError("❌ Не знайдено ім’я користувача після входу!")

driver.quit()
35 changes: 35 additions & 0 deletions tests/test_open_product_page.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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
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']")
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)
Comment on lines +15 to +21
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple hardcoded time.sleep() calls make tests slow and unreliable. Since WebDriverWait is already imported and used on line 25, replace these sleep calls with explicit waits for specific conditions.

Copilot uses AI. Check for mistakes.
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/")
)
current_url = driver.current_url
print("🔎 Поточний URL:", current_url)

assert "/ua/shop/kley/" in current_url, \
f"❌ Помилка переходу: {current_url}"

time.sleep(3)
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple hardcoded time.sleep() calls make tests slow and unreliable. Since WebDriverWait is already imported and used on line 25, replace these sleep calls with explicit waits for specific conditions.

Suggested change
time.sleep(3)
# Wait for the search results container to be visible before quitting
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, "div.catalog-products"))
)

Copilot uses AI. Check for mistakes.
driver.quit()