Skip to content

Conversation

@Gerodotry
Copy link
Owner

@Gerodotry Gerodotry commented Oct 28, 2025

pull request автоматизовані UI-тести для вебсайту Епіцентр

@Gerodotry Gerodotry requested a review from lipskydan October 28, 2025 09:25
@Gerodotry Gerodotry changed the title new lab6_liubun_selenium Oct 28, 2025
@lipskydan lipskydan requested a review from Copilot October 28, 2025 09:28
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces automated UI tests for the Epicentr (epicentrk.ua) e-commerce website using Selenium WebDriver. The tests cover core user workflows including product search, login, and purchase flows.

Key changes:

  • Implements Page Object Model (POM) pattern with separate page classes for Home, Product, Cart, and Login pages
  • Adds four test scenarios: product search, user login, product purchase, and multi-step purchase flow
  • Uses explicit waits and ActionChains for robust element interactions

Reviewed Changes

Copilot reviewed 9 out of 12 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
tests/test_open_product_page.py Tests product search functionality for "клей" keyword
tests/test_login.py Tests login flow with credentials and verifies user name display
tests/test_buy_product.py Tests complete product purchase flow from homepage to cart
tests/test_buy_flow.py Tests purchase flow as separate steps with shared browser session
pages/search_page.py Page object for search functionality (contains misnamed HomePage class)
pages/product_page.py Page object for product page interactions
pages/login_page.py Page object for login form interactions
pages/home_page.py Page object for homepage interactions
pages/cart_page.py Page object for shopping cart interactions
Files not reviewed (1)
  • .idea/misc.xml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +21
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)
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.
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.
Comment on lines +21 to +30
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)
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.
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.
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.
Comment on lines +10 to +32
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():
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.
Comment on lines +25 to +27
time.sleep(2)
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.

Copilot uses AI. Check for mistakes.
assert product.buy_button_exists(), " Кнопка 'Купити' не знайдена!"
def test_step3_buy_and_checkout_btn():
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.

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

@lipskydan lipskydan left a comment

Choose a reason for hiding this comment

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

General note — please add the text of each manual step as a comment before its implementation in the test cases.

Comment on lines +10 to +14
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(),'помилка')]"
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.

Comment on lines +7 to +9
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']"
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.

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.

Comment on lines +8 to +10
URL = "https://epicentrk.ua/"

FIRST_PRODUCT = "(//main//li//a[contains(@href,'/p/')])[1]"
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.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants