-
Notifications
You must be signed in to change notification settings - Fork 0
lab6_liubun_selenium #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: test
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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.
| 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) |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| assert "/ua/shop/kley/" in current_url, \ | ||
| f"❌ Помилка переходу: {current_url}" | ||
|
|
||
| time.sleep(3) |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| 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")) | |
| ) |
| 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) |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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).
| 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]"))) |
| EC.visibility_of_element_located((By.XPATH, user_name_xpath)) | ||
| ) | ||
| print(" Ім’я:", user_name.text) | ||
| except: |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| product = ProductPage(driver) | ||
| cart = CartPage(driver) | ||
| home.open() | ||
| time.sleep(2) |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| 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(): |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| 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): |
| time.sleep(2) | ||
| home.click_first_product() | ||
| time.sleep(3) |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| assert product.buy_button_exists(), " Кнопка 'Купити' не знайдена!" | ||
| def test_step3_buy_and_checkout_btn(): | ||
| product.click_buy() | ||
| time.sleep(5) |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
|
|
||
| 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" |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| 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]' |
| 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" |
Copilot
AI
Oct 28, 2025
There was a problem hiding this comment.
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.
| 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 |
lipskydan
left a comment
There was a problem hiding this 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.
| 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(),'помилка')]" |
There was a problem hiding this comment.
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.
| 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']" |
There was a problem hiding this comment.
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]" |
There was a problem hiding this comment.
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.
| URL = "https://epicentrk.ua/" | ||
|
|
||
| FIRST_PRODUCT = "(//main//li//a[contains(@href,'/p/')])[1]" |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
pull request автоматизовані UI-тести для вебсайту Епіцентр