From 10d3c3688aafe1baa0745c4ad9dfa3294a809581 Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Tue, 9 Jul 2019 20:46:52 +0300 Subject: [PATCH 01/11] Create Positions selenium element --- shopelectro/selenium/elements/positions.py | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 shopelectro/selenium/elements/positions.py diff --git a/shopelectro/selenium/elements/positions.py b/shopelectro/selenium/elements/positions.py new file mode 100644 index 00000000..7d799aa8 --- /dev/null +++ b/shopelectro/selenium/elements/positions.py @@ -0,0 +1,43 @@ +from contextlib import contextmanager + +from selenium.common.exceptions import TimeoutException +from selenium.webdriver.support import expected_conditions as EC + +from shopelectro.selenium import SiteDriver, elements + + +class Positions: + + def __init__(self, driver: SiteDriver, position_type: elements.Product, locator): + self.driver = driver + self.position_type = position_type + self.locator = locator + + @contextmanager + def wait_changes(self): + def are_changed(_): + try: + return positions_before != self.all() + except TimeoutException: + # An exception can be raised from a position's equality method. + # In most cases this means that some positions are stale, + # so we return False in order to re-execute this wait function. + return False + + positions_before = self.all() + yield + self.driver.wait.until(are_changed) + + def first(self) -> elements.Product: + return self.position_type(self.driver, 0) + + def all(self) -> [elements.Product]: + try: + # use short_wait to avoid long pauses in case of the empty cart + positions_count = len(self.driver.short_wait.until(EC.presence_of_all_elements_located( + self.locator + ))) + except TimeoutException: + positions_count = 0 + + return [self.position_type(self.driver, i) for i in range(positions_count)] From bba10c1917de3459df2a00b51a55266134eb99f3 Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Tue, 9 Jul 2019 20:49:44 +0300 Subject: [PATCH 02/11] Reuse Positions for Cart class --- shopelectro/selenium/elements/__init__.py | 5 ++-- shopelectro/selenium/elements/cart.py | 35 +++++----------------- shopelectro/selenium/elements/positions.py | 6 ++-- 3 files changed, 13 insertions(+), 33 deletions(-) diff --git a/shopelectro/selenium/elements/__init__.py b/shopelectro/selenium/elements/__init__.py index bb9e4aaf..6fdb59c0 100644 --- a/shopelectro/selenium/elements/__init__.py +++ b/shopelectro/selenium/elements/__init__.py @@ -1,5 +1,6 @@ -from .button import Button from .exceptions import Unavailable +from .button import Button from .input import Input -from .product import CatalogCard, ProductCard, CartPosition +from .product import * from .cart import Cart +from .positions import Positions diff --git a/shopelectro/selenium/elements/cart.py b/shopelectro/selenium/elements/cart.py index 15aea396..acbb9f26 100644 --- a/shopelectro/selenium/elements/cart.py +++ b/shopelectro/selenium/elements/cart.py @@ -15,6 +15,11 @@ class Cart: def __init__(self, driver: SiteDriver): self.driver = driver + self.positions = elements.Positions( + driver, + elements.CartPosition, + (By.CLASS_NAME, 'basket-item'), + ) def _hover(self): cart = self.driver.wait.until(EC.visibility_of_element_located( @@ -25,36 +30,10 @@ def _hover(self): (By.CLASS_NAME, 'js-cart-wrapper') )) - # @todo #920:15m Document the Cart.wait_changes. - # Cover corner cases with TimeoutException. - - @contextmanager - def wait_changes(self): - def wait_changes(browser): - try: - return positions_before != self.positions() - except TimeoutException: - return False - - positions_before = self.positions() - yield - self.driver.wait.until(wait_changes) - - def positions(self) -> [elements.CartPosition]: - try: - # use short_wait to avoid long pauses in case of the empty cart - positions_count = len(self.driver.short_wait.until(EC.presence_of_all_elements_located( - (By.CLASS_NAME, 'basket-item') - ))) - except TimeoutException: - positions_count = 0 - - return [elements.CartPosition(self.driver, i) for i in range(positions_count)] - def remove(self, position: elements.CartPosition): - with self.wait_changes(): + with self.positions.wait_changes(): self._hover() - position.remove_from_cart() + position.remove() def clear(self): self._hover() diff --git a/shopelectro/selenium/elements/positions.py b/shopelectro/selenium/elements/positions.py index 7d799aa8..f77bbb6f 100644 --- a/shopelectro/selenium/elements/positions.py +++ b/shopelectro/selenium/elements/positions.py @@ -19,9 +19,9 @@ def are_changed(_): try: return positions_before != self.all() except TimeoutException: - # An exception can be raised from a position's equality method. - # In most cases this means that some positions are stale, - # so we return False in order to re-execute this wait function. + # An exception can be raised from a position's equality method. + # In most cases this means that some positions are stale, + # so we return False in order to continue wait changes. return False positions_before = self.all() From 16dea9d77ca3f8974086ff444ce8f56bb7ea0c6f Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Tue, 9 Jul 2019 20:50:05 +0300 Subject: [PATCH 03/11] Create OrderPositions class --- shopelectro/selenium/elements/product.py | 57 ++++++++++++++++++++---- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/shopelectro/selenium/elements/product.py b/shopelectro/selenium/elements/product.py index d2fe9317..2fd5fc45 100644 --- a/shopelectro/selenium/elements/product.py +++ b/shopelectro/selenium/elements/product.py @@ -21,12 +21,18 @@ def price(self): def quantity(self): raise Unavailable('determine the product quantity.') - def add_to_cart(self): + def add(self): raise Unavailable('add the product to the card.') - def remove_from_cart(self): + def remove(self): raise Unavailable('remove the product from the card.') + def __hash__(self): + raise NotImplementedError('Provide __hash__ implementation for the class.') + + def __eq__(self, other: 'Product'): + return hash(self) == hash(other) + class CatalogCard(Product): @@ -79,7 +85,7 @@ def vendor_code(self): (By.XPATH, self._build_xpath('div[2]/div[1]')) )).text.split(' ')[1] - def add_to_cart(self): + def add(self): Button(self.driver, (By.XPATH, self._build_xpath('div[2]/div[5]/button'))).click() @@ -88,7 +94,7 @@ class ProductCard(Product): def __init__(self, driver: SiteDriver): self.driver = driver - def add_to_cart(self): + def add(self): Button(self.driver, (By.CLASS_NAME, 'js-to-cart-on-product-page')).click() @@ -107,9 +113,6 @@ def __hash__(self): + el.get_attribute('data-product-count') ) - def __eq__(self, other: 'CartPosition'): - return hash(self) == hash(other) - def _data_element(self): # use short_wait, because a position could be stale return self.driver.short_wait.until(EC.presence_of_element_located( @@ -125,5 +128,43 @@ def price(self): def quantity(self): return self._data_element().get_attribute('data-product-count') - def remove_from_cart(self): + def remove(self): Button(self.driver, (By.XPATH, f'{self.xpath}i')).click() + + +class OrderPosition(Product): + """Represent a product position on order page.""" + + def __init__(self, driver: SiteDriver, index: int): + self.driver = driver + # xpath indexes starts from 1 + self.xpath = f'//div[@id="js-order-list"]/div[2]/div[{index + 1}]/' + + def __hash__(self): + return hash( + self.vendor_code() + + '/' + + self.quantity() + ) + + def vendor_code(self): + return self.driver.short_wait.until(EC.visibility_of_element_located( + (By.XPATH, f'{self.xpath}div[1]') + )).text + + def quantity(self): + return self.driver.short_wait.until(EC.visibility_of_element_located( + (By.XPATH, f'{self.xpath}div[4]/div[2]/input') + )).value + + def set(self, quantity: int): + raise NotImplementedError + + def increase(self): + raise NotImplementedError + + def decrease(self): + raise NotImplementedError + + def remove(self): + Button(self.driver, (By.XPATH, f'{self.xpath}div[6]/div')).click() From c86d84a0ae3b06b5c830a6a1b177612b99f48fbb Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Tue, 9 Jul 2019 20:50:49 +0300 Subject: [PATCH 04/11] Adopt classes to Positions --- shopelectro/selenium/pages/category.py | 4 ++-- shopelectro/selenium/pages/product.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shopelectro/selenium/pages/category.py b/shopelectro/selenium/pages/category.py index ceb41e3c..5bcd6260 100644 --- a/shopelectro/selenium/pages/category.py +++ b/shopelectro/selenium/pages/category.py @@ -51,6 +51,6 @@ def add_to_cart(self, products: typing.List[elements.CatalogCard] = None): default = [elements.CatalogCard.with_index(self.driver, i) for i in range(6)] products = products or default - with self.cart().wait_changes(): + with self.cart().positions.wait_changes(): for product in products: - product.add_to_cart() + product.add() diff --git a/shopelectro/selenium/pages/product.py b/shopelectro/selenium/pages/product.py index 097ab372..b15e49bd 100644 --- a/shopelectro/selenium/pages/product.py +++ b/shopelectro/selenium/pages/product.py @@ -18,5 +18,5 @@ def path(self): return reverse('product', args=(self.vendor_code,)) def add_to_cart(self): - with self.cart().wait_changes(): - elements.ProductCard(self.driver).add_to_cart() + with self.cart().positions.wait_changes(): + elements.ProductCard(self.driver).add() From a32c6df2580f1ffe1624981db2ad3164d7863e1b Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Tue, 9 Jul 2019 20:51:06 +0300 Subject: [PATCH 05/11] Implement OrderPage class --- shopelectro/selenium/pages/order.py | 37 +++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/shopelectro/selenium/pages/order.py b/shopelectro/selenium/pages/order.py index 551378b6..6c2e7ea1 100644 --- a/shopelectro/selenium/pages/order.py +++ b/shopelectro/selenium/pages/order.py @@ -1,25 +1,48 @@ -from shopelectro.models import PaymentOptions -from shopelectro.selenium.elements import Input, Button -from shopelectro.selenium.pages import Page +from contextlib import contextmanager +from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from pages.models import CustomPage +from shopelectro.models import PaymentOptions +from shopelectro.selenium import elements, SiteDriver +from shopelectro.selenium.pages import Page # @todo #682:120m Implement and reuse shopelectro.selenium.OrderPage for selenium tests. class OrderPage(Page): - def __init__(self, driver): + def __init__(self, driver: SiteDriver): super().__init__(driver) - self.submit_button = Button(self.driver, (By.ID, 'submit-order')) + self.submit_button = elements.Button(self.driver, (By.ID, 'submit-order')) + self.positions = elements.Positions( + driver, + elements.OrderPosition, + (By.XPATH, '//div[@id="js-order-list"]/div[2]/div'), + ) @property def path(self): return CustomPage.objects.get(slug='order').url + def set(self, position: elements.OrderPosition, quantity: int): + with self.positions.wait_changes(): + position.set(quantity) + + def increase(self, position: elements.OrderPosition): + with self.positions.wait_changes(): + position.increase() + + def decrease(self, position: elements.OrderPosition): + with self.positions.wait_changes(): + position.decrease() + + def remove(self, position: elements.OrderPosition): + with self.positions.wait_changes(): + position.remove() + def fill_contacts( self, name='Name', city='Санкт-Петербург', phone='2222222222', email='test@test.test', ): @@ -31,7 +54,7 @@ def fill_contacts( } for id_, value in contacts.items(): - Input(self.driver, (By.ID, id_)).send_keys(value) + elements.Input(self.driver, (By.ID, id_)).send_keys(value) def make_order(self): self.submit_button.click() @@ -44,7 +67,7 @@ def select_payment_type(self, payment_option: PaymentOptions): f'It should be one of: {PaymentOptions}' ) - item = Button( + item = elements.Button( self.driver, (By.CSS, f'input[name="payment_type"][value="{payment_option.name}"]'), ) From cbea8c2bb1e3a171c80b6d0726fcb2659f6ba2c5 Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Tue, 9 Jul 2019 20:51:47 +0300 Subject: [PATCH 06/11] Create YandexEcommerce.remove_from_order_page test. Reduce code duplication --- shopelectro/tests/tests_js_analytics.py | 154 +++++++++++------------- 1 file changed, 70 insertions(+), 84 deletions(-) diff --git a/shopelectro/tests/tests_js_analytics.py b/shopelectro/tests/tests_js_analytics.py index 0ba30e27..079bd39a 100644 --- a/shopelectro/tests/tests_js_analytics.py +++ b/shopelectro/tests/tests_js_analytics.py @@ -100,6 +100,53 @@ def get_goals(self) -> selenium.Goals: goals.fetch() return goals + def assert_add(self, product: Product, goal_position: int): + reached_goals = self.get_goals() + self.assertTrue(reached_goals) + reached = reached_goals[goal_position] # Ignore CPDBear + + self.assertIn('add', reached) + self.assertEqual(reached['currencyCode'], 'RUB') + + reached_detail = reached['add'] + self.assertEqual( + len(reached_detail['products']), + 1, + ) + + self.assertEqual( + reached_detail['products'][0], + { + 'id': product.id, + 'name': product.name, + 'brand': product.get_brand_name(), + 'quantity': 1, + 'category': product.category.name, + } + ) + + def assert_remove(self, product: Product, goal_position: int): + reached_goals = self.get_goals() + self.assertTrue(reached_goals) + + reached = reached_goals[goal_position] + self.assertIn('remove', reached) + self.assertEqual(reached['currencyCode'], 'RUB') + + reached_remove = reached['remove'] + self.assertEqual( + len(reached_remove['products']), + 1, + ) + + self.assertEqual( + reached_remove['products'][0], + { + 'id': product.id, + 'quantity': 1, + } + ) + def test_purchase(self): self.buy() order = self.last_order() @@ -163,26 +210,7 @@ def test_clear_cart(self): # Ignore CPDBear page.add_to_cart() page.cart().clear() # Ignore CPDBear - reached_goals = self.get_goals() - self.assertTrue(reached_goals) - - reached = reached_goals[2] - self.assertIn('remove', reached) - self.assertEqual(reached['currencyCode'], 'RUB') - - reached_remove = reached['remove'] - self.assertEqual( - len(reached_remove['products']), - 1, - ) - - self.assertEqual( - reached_remove['products'][0], - { - 'id': product.id, - 'quantity': 1, - } - ) + self.assert_remove(product, 2) def test_remove_from_cart(self): product = Product.objects.first() @@ -190,28 +218,9 @@ def test_remove_from_cart(self): page.load() page.add_to_cart() cart = page.cart() - cart.remove(cart.positions()[0]) + cart.remove(cart.positions.first()) - reached_goals = self.get_goals() - self.assertTrue(reached_goals) - - reached = reached_goals[2] - self.assertIn('remove', reached) - self.assertEqual(reached['currencyCode'], 'RUB') - - reached_remove = reached['remove'] - self.assertEqual( - len(reached_remove['products']), - 1, - ) - - self.assertEqual( - reached_remove['products'][0], - { - 'id': product.id, - 'quantity': 1, - } - ) + self.assert_remove(product, 2) def test_add_from_product_page(self): product = Product.objects.first() @@ -219,29 +228,7 @@ def test_add_from_product_page(self): page.load() page.add_to_cart() - reached_goals = self.get_goals() - self.assertTrue(reached_goals) - - reached = reached_goals[1] # Ignore CPDBear - self.assertIn('add', reached) - self.assertEqual(reached['currencyCode'], 'RUB') - - reached_detail = reached['add'] - self.assertEqual( - len(reached_detail['products']), - 1, - ) - - self.assertEqual( - reached_detail['products'][0], - { - 'id': product.id, - 'name': product.name, - 'brand': product.get_brand_name(), - 'quantity': 1, - 'category': product.category.name, - } - ) + self.assert_add(product, 1) def test_add_from_category_page(self): product = Product.objects.first() @@ -250,29 +237,28 @@ def test_add_from_category_page(self): card = page.find_card(product.id) page.add_to_cart([card]) - reached_goals = self.get_goals() - self.assertTrue(reached_goals) + self.assert_add(product, 0) - reached = reached_goals[0] - self.assertIn('add', reached) - self.assertEqual(reached['currencyCode'], 'RUB') + def test_remove_from_order_page(self): + product = Product.objects.first() + product_page = selenium.Product(self.browser, product.vendor_code) + product_page.load() + product_page.add_to_cart() - reached_detail = reached['add'] - self.assertEqual( - len(reached_detail['products']), - 1, - ) + order_page = selenium.OrderPage(self.browser) + order_page.load() + order_page.remove(order_page.positions.first()) - self.assertEqual( - reached_detail['products'][0], - { - 'id': product.id, - 'name': product.name, - 'brand': product.get_brand_name(), - 'quantity': 1, - 'category': product.category.name, - } - ) + self.assert_remove(product, 0) + + def test_increase_from_order_page(self): + pass + + def test_decrease_from_order_page(self): + pass + + def test_set_from_order_page(self): + pass @tag('slow') From c2d3f90cd6ea5a7896fa4d85b527a011de9588dc Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Tue, 9 Jul 2019 20:54:35 +0300 Subject: [PATCH 07/11] Apply linter rules --- shopelectro/selenium/elements/cart.py | 3 --- shopelectro/selenium/elements/positions.py | 14 +++++++------- shopelectro/selenium/pages/order.py | 3 --- shopelectro/tests/tests_js_analytics.py | 15 +++++++-------- 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/shopelectro/selenium/elements/cart.py b/shopelectro/selenium/elements/cart.py index acbb9f26..290fa86f 100644 --- a/shopelectro/selenium/elements/cart.py +++ b/shopelectro/selenium/elements/cart.py @@ -1,6 +1,3 @@ -from contextlib import contextmanager - -from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support import expected_conditions as EC diff --git a/shopelectro/selenium/elements/positions.py b/shopelectro/selenium/elements/positions.py index f77bbb6f..daafd867 100644 --- a/shopelectro/selenium/elements/positions.py +++ b/shopelectro/selenium/elements/positions.py @@ -11,7 +11,7 @@ class Positions: def __init__(self, driver: SiteDriver, position_type: elements.Product, locator): self.driver = driver self.position_type = position_type - self.locator = locator + self.condition = EC.presence_of_all_elements_located(self.locator) @contextmanager def wait_changes(self): @@ -19,9 +19,9 @@ def are_changed(_): try: return positions_before != self.all() except TimeoutException: - # An exception can be raised from a position's equality method. - # In most cases this means that some positions are stale, - # so we return False in order to continue wait changes. + # An exception can be raised from a position's equality method. + # In most cases this means that some positions are stale, + # so we continue waiting changes. return False positions_before = self.all() @@ -34,9 +34,9 @@ def first(self) -> elements.Product: def all(self) -> [elements.Product]: try: # use short_wait to avoid long pauses in case of the empty cart - positions_count = len(self.driver.short_wait.until(EC.presence_of_all_elements_located( - self.locator - ))) + positions_count = len(self.driver.short_wait.until( + self.condition + )) except TimeoutException: positions_count = 0 diff --git a/shopelectro/selenium/pages/order.py b/shopelectro/selenium/pages/order.py index 6c2e7ea1..85e3b800 100644 --- a/shopelectro/selenium/pages/order.py +++ b/shopelectro/selenium/pages/order.py @@ -1,6 +1,3 @@ -from contextlib import contextmanager - -from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC diff --git a/shopelectro/tests/tests_js_analytics.py b/shopelectro/tests/tests_js_analytics.py index 079bd39a..8fdc1dad 100644 --- a/shopelectro/tests/tests_js_analytics.py +++ b/shopelectro/tests/tests_js_analytics.py @@ -87,8 +87,7 @@ class YandexEcommerce(Ecommerce): fixtures = ['dump.json'] - # @todo #820:120m Test Yandex ecommerce add and remove goals from the order page. - # Get rid of code duplications. + # @todo #939:120m Test Yandex ecommerce increase/decrease/set goals from the order page. def tearDown(self): # delete the session to clear the cart @@ -100,15 +99,15 @@ def get_goals(self) -> selenium.Goals: goals.fetch() return goals - def assert_add(self, product: Product, goal_position: int): + def assert_add(self, product: Product, goal_position: int): # Ignore CPDBear reached_goals = self.get_goals() self.assertTrue(reached_goals) - reached = reached_goals[goal_position] # Ignore CPDBear + reached = reached_goals[goal_position] self.assertIn('add', reached) self.assertEqual(reached['currencyCode'], 'RUB') - reached_detail = reached['add'] + reached_detail = reached['add'] # Ignore CPDBear self.assertEqual( len(reached_detail['products']), 1, @@ -186,7 +185,7 @@ def test_product_detail(self): self.assertIn('detail', reached) self.assertEqual(reached['currencyCode'], 'RUB') - reached_detail = reached['detail'] # Ignore CPDBear + reached_detail = reached['detail'] self.assertEqual( len(reached_detail['products']), 1, @@ -203,12 +202,12 @@ def test_product_detail(self): } ) - def test_clear_cart(self): # Ignore CPDBear + def test_clear_cart(self): product = Product.objects.first() page = selenium.Product(self.browser, product.vendor_code) page.load() page.add_to_cart() - page.cart().clear() # Ignore CPDBear + page.cart().clear() self.assert_remove(product, 2) From 325d5a10f5daa0e7d8e8565138635dbe7aa157eb Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Wed, 10 Jul 2019 16:28:30 +0300 Subject: [PATCH 08/11] Fix typo --- shopelectro/selenium/elements/positions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shopelectro/selenium/elements/positions.py b/shopelectro/selenium/elements/positions.py index daafd867..ad1812c4 100644 --- a/shopelectro/selenium/elements/positions.py +++ b/shopelectro/selenium/elements/positions.py @@ -11,7 +11,7 @@ class Positions: def __init__(self, driver: SiteDriver, position_type: elements.Product, locator): self.driver = driver self.position_type = position_type - self.condition = EC.presence_of_all_elements_located(self.locator) + self.condition = EC.presence_of_all_elements_located(locator) @contextmanager def wait_changes(self): From fe5f0df34d8a063030143004935fb950c729dfa3 Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Fri, 12 Jul 2019 21:05:07 +0300 Subject: [PATCH 09/11] Review fixes --- .gitignore | 4 ++-- shopelectro/selenium/analytics_goals.py | 3 +++ shopelectro/selenium/elements/positions.py | 8 +++++--- shopelectro/selenium/elements/product.py | 6 +++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index e69209f9..6d43a8f8 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,6 @@ database/ .DS_store *.orig venv/ -.sublime-project -.sublime-workspace +*.sublime-project +*.sublime-workspace diff --git a/shopelectro/selenium/analytics_goals.py b/shopelectro/selenium/analytics_goals.py index 7f82dd82..968b073b 100644 --- a/shopelectro/selenium/analytics_goals.py +++ b/shopelectro/selenium/analytics_goals.py @@ -23,6 +23,9 @@ def __iter__(self): def __getitem__(self, index: int): raise NotImplementedError + def __bool__(self): + return bool(list(self)) + class YandexEcommerceGoals(Goals): # Ignore PyDocStyleBear """ diff --git a/shopelectro/selenium/elements/positions.py b/shopelectro/selenium/elements/positions.py index ad1812c4..fd7526df 100644 --- a/shopelectro/selenium/elements/positions.py +++ b/shopelectro/selenium/elements/positions.py @@ -19,9 +19,11 @@ def are_changed(_): try: return positions_before != self.all() except TimeoutException: - # An exception can be raised from a position's equality method. - # In most cases this means that some positions are stale, - # so we continue waiting changes. + """ + An exception can be raised from a position's equality method. + In most cases this means that some positions are stale, + so we continue waiting changes. + """ return False positions_before = self.all() diff --git a/shopelectro/selenium/elements/product.py b/shopelectro/selenium/elements/product.py index 2fd5fc45..9af98f18 100644 --- a/shopelectro/selenium/elements/product.py +++ b/shopelectro/selenium/elements/product.py @@ -154,16 +154,16 @@ def vendor_code(self): def quantity(self): return self.driver.short_wait.until(EC.visibility_of_element_located( - (By.XPATH, f'{self.xpath}div[4]/div[2]/input') + (By.XPATH, f'{self.xpath}//input') )).value def set(self, quantity: int): raise NotImplementedError - def increase(self): + def increase(self, times=1): raise NotImplementedError - def decrease(self): + def decrease(self, times=1): raise NotImplementedError def remove(self): From b146b21dbc7fbbd3153ed17ce0b53286e071e91d Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Fri, 12 Jul 2019 21:08:29 +0300 Subject: [PATCH 10/11] Edit todo to fix assertion for cart clear goal --- shopelectro/tests/tests_js_analytics.py | 1 + 1 file changed, 1 insertion(+) diff --git a/shopelectro/tests/tests_js_analytics.py b/shopelectro/tests/tests_js_analytics.py index 8fdc1dad..cba876fa 100644 --- a/shopelectro/tests/tests_js_analytics.py +++ b/shopelectro/tests/tests_js_analytics.py @@ -88,6 +88,7 @@ class YandexEcommerce(Ecommerce): fixtures = ['dump.json'] # @todo #939:120m Test Yandex ecommerce increase/decrease/set goals from the order page. + # Create assertion for cart clear goal. def tearDown(self): # delete the session to clear the cart From 016109a9e1e2721a5ea3ee1e42c207297ac02ae3 Mon Sep 17 00:00:00 2001 From: Artemiy Rodionov Date: Fri, 12 Jul 2019 21:30:57 +0300 Subject: [PATCH 11/11] Apply linter rules --- shopelectro/tests/tests_js_analytics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shopelectro/tests/tests_js_analytics.py b/shopelectro/tests/tests_js_analytics.py index cba876fa..d9925fce 100644 --- a/shopelectro/tests/tests_js_analytics.py +++ b/shopelectro/tests/tests_js_analytics.py @@ -203,7 +203,7 @@ def test_product_detail(self): } ) - def test_clear_cart(self): + def test_clear_cart(self): # Ignore CPDBear product = Product.objects.first() page = selenium.Product(self.browser, product.vendor_code) page.load()