def click_on_listings(self, listings, selector=DEFAULT_ROW_SELECTOR): d = self.driver # check checkboxes listings_selected = 0 while True: listing_rows = self.listing_rows() listings_to_select = [ r for r in listing_rows if r.find_element_by_css_selector(selector).text in listings ] for listing_row in listings_to_select: span = listing_row.find_element_by_css_selector(selector) d.execute_script("arguments[0].scrollIntoView(true);", span) click(span) sleep(1) listings_selected += 1 if listings_selected >= len(listings): break pages = self.page_nums(self.BULK_PAGE_NUMS, self.BULK_PAGE_INDEXES) if pages[1] <= pages[2]: next_page_button = self.next_page_button() click(next_page_button) sleep(2) else: raise Exception( "Error: click_on_listings: could not find listing to click on" )
def test_sync_updates_tags(self): """ Tests that data is written to the database when [Sync Updates] is clicked """ expected_data = [['1', '{Tag01,AAA,BBB,CCC}'], ['2', '{Tag01,AAA,BBB,CCC}'], ['3', '{Tag01,AAA,BBB,CCC}']] select_listings_to_edit(self.driver) d = self.driver bp = BulkPage(d) send_keys(bp.operation_input(), 'AAA,BBB ,CCC') click(bp.operation_apply()) # Check apply button assert bp.operation_apply().is_enabled( ) is False, 'Apply button is enabled' click(bp.sync_updates_button()) # Check updated data in DB wait_for_assert(expected_data, lambda: run_sql('HIVE', 'select_tags_modified', True), 'Unexpected tags data in DB')
def sync_changes(self, timeout_sec=5): click(self.sync_updates_button()) wait_for_web_assert(False, lambda: self.sync_updates_button().is_enabled(), 'Sync button is not disabled after sync', delay_sec=1, retries=timeout_sec)
def test_create_tag_special_chars(self): """ Tests that a tag can be created in bulk edit with czech chars, but not special chars """ expected_tags = [ ['Tag01', 'žvýkačky'], ['Tag01', 'žvýkačky'], ['Tag01', 'žvýkačky'], ] select_listings_to_edit(self.driver) d = self.driver bp = BulkPage(d) send_keys(bp.operation_input(), 'žvýkačky') click(bp.operation_apply()) apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ') tag_names = bp.tag_names() assert tag_names == expected_tags send_keys(bp.operation_input(), 'me@site') err = bp.error_baloon() assert err == "Tag can only include spaces, letters, hyphens, and numbers"
def test_create_category(self): """ Tests that a category can be created in bulk edit """ expected_listings_01 = [ 'First something 1234 (1)\nClothing\nMen\'s Clothing\nSocks\nChoose Category', 'Second something 1235 (2)\nClothing\nMen\'s Clothing\nSocks\nChoose Category', 'Third something LG-512a (3)\nClothing\nMen\'s Clothing\nPants' ] expected_listings_02 = [ 'First something 1234 (1)\nAccessories\nCostume Accessories\nCostume Tails & Ears\nCostume Ears', 'Second something 1235 (2)\nAccessories\nCostume Accessories\nCostume Tails & Ears\nCostume Ears', 'Third something LG-512a (3)\nAccessories\nCostume Accessories\nCostume Tails & Ears\nCostume Ears' ] self.select_listings_to_edit() d = self.driver bp = BulkPage(d) actual_listings = bp.listing_rows_texts_sorted() assert actual_listings == expected_listings_01 bp.select_category(['Accessories', 'Costume Accessories', 'Costume Tails & Ears', 'Costume Ears']) # Apply changes click(bp.operation_apply()) actual_listings = bp.listing_rows_texts_sorted() assert actual_listings == expected_listings_02 apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ')
def test_bulk_category_variations_validation(self): """ Test verifies that error message is shown when attempting to change Category to incompatible with existing Variation property / scale on the listing, and that Category is not changed for such listing """ expected_categories = [ ['Jewelry', 'Brooches'], ['Jewelry', 'Brooches'], ['Clothing', 'Women\'s Clothing', 'Dresses'] ] category = ['Jewelry', 'Brooches'] bp = BulkPage(self.driver) # change to incompatible category (3rd listing) bp.select_category(category) row = bp.listing_row('Product #3 with two variations with quantity on both and pricing on both') # check that error is shown assert bp.error_baloon_texts(row) ==\ ['The selected category is not compatible with the variations of this listing'],\ 'Incorrect validation error message for listing #3' # Apply and check that category was set for 1st and 2nd listings, for 3rd it hasn't changed click(bp.operation_apply()) for i, row in enumerate(bp.listing_rows()): category_names = bp.category_names(row) assert category_names == expected_categories[i]
def test_edit_single_category(self): """ Tests that a single category can be edited """ expected_listings_01 = [ 'First something 1234 (1)\nClothing\nMen\'s Clothing\nSocks\nChoose Category', 'Second something 1235 (2)\nClothing\nMen\'s Clothing\nSocks\nChoose Category', 'Third something LG-512a (3)\nClothing\nMen\'s Clothing\nPants' ] expected_data = [['1', '1761']] self.select_listings_to_edit() d = self.driver bp = BulkPage(d) actual_listings = bp.listing_rows_texts_sorted() assert actual_listings == expected_listings_01 # update category of the 1st listing row = bp.listing_row('First something 1234 (1)') bp.select_category(['Accessories', 'Costume Accessories', 'Costume Tails & Ears', 'Costume Ears'], row, True) click(bp.sync_updates_button()) wait_for_assert(expected_data, lambda: run_sql('HIVE', 'select_taxonomy_id_modified', True), 'Unexpected taxonomy ID in DB')
def test_delete_tag(self): """ Tests that tags can be deleted in bulk """ expected_tags = [ [], [], [], ] select_listings_to_edit(self.driver, 'Delete') d = self.driver bp = BulkPage(d) tag_field = bp.operation_input() click(tag_field) send_keys(tag_field, 'Tag') send_keys(tag_field, '01') click(bp.operation_apply()) apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ') tag_names = bp.tag_names() assert tag_names == expected_tags
def test_title_add_before_length(self): """ Tests add before where length limit is exceeded """ long_text = 'Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong' expected_listings_1 = [ long_text + 'First something 1234 (1)\n2 characters remaining', long_text + 'Second something 1235 (2)\n1 character remaining', long_text + 'Third something LG-512a (3)\n1 character over limit' ] expected_listings_2 = [ long_text + 'First something 1234 (1)\n2 characters remaining', long_text + 'Second something 1235 (2)\n1 character remaining', 'Third something LG-512a (3)\n113 characters remaining' ] select_listings_to_edit(self.driver) d = self.driver bp = BulkPage(d) input_field = bp.operation_input() # Test long text send_keys(input_field, long_text) listings = bp.listing_rows_texts_sorted() assert listings == expected_listings_1 # Apply (client only) click(bp.operation_apply()) sleep(1) listings = bp.listing_rows_texts_sorted() assert listings == expected_listings_2 apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ')
def test_selection_clear_filters(self): """ Tests that the selection is reset when you change filters """ d = self.driver pg = MainPage(d) pg.select_filter_tab('Active') sleep(1) # select all cb_all = pg.listing_select_all_checkbox() click(cb_all) sleep(2) assert pg.edit_listings_button().text == 'Edit 102 Listings' # Click a filter checkbox cb = pg.filter_checkbox('CATEGORIES', 'Clothing') click(cb) sleep(2) # check that no checkboxes are checked assert pg.edit_listings_button().text == 'Edit' listing_rows = pg.listing_rows() for listing_row in listing_rows: row_class = listing_row.get_attribute('class') assert 'selected' not in row_class.split(' ') # ! selected
def select_listings_to_edit(request): """ select listings for bulk, - self.listings_to_select is on of: None -> use default ["listing1", "listin2"...] -> use this "ALL" -> select all - self.listing_status -> e.g. 'Draft' - choose `self.bulk_tab` """ self = request.node.parent.obj mp = MainPage(self.driver) bp = BulkPage(self.driver) try: listing_status = self.listing_status except AttributeError: listing_status = None try: listings_to_select = self.listings_to_select except AttributeError: listings_to_select = None try: bulk_tab = self.bulk_tab except AttributeError: bulk_tab = None mp.select_listings_to_edit(listings_to_select, status=listing_status) if bulk_tab: click(bp.edit_part(bulk_tab))
def close_intercom(self): """ try to find intercom close button (if exists), click it """ d = self.driver window_selectors = ['div.intercom-chat-composer', 'intercom-block'] button_selectors = [ 'div.intercom-chat-dismiss-button', 'div.intercom-launcher-hovercard-close' ] # move to the IC window, so that the close button is displayed for selector in window_selectors: try: win = d.find_element_by_css_selector(selector) action = ActionChains(d) action.move_to_element(win) action.perform() except: pass for selector in button_selectors: try: b = d.find_element_by_css_selector(selector) click(b) except: pass
def select_listings_to_edit(driver, operation='Add Before'): mp = MainPage(driver) bp = BulkPage(driver) mp.select_listings_to_edit() click(bp.edit_part('Description')) bp.select_operation(operation)
def test_inline_section_remove(self): """ Tests removing section from a single listing """ expected_section_names = ['Summer Sale', 'Choose Section'] expected_api_calls = [{ 'PUT': '/v2/listings/100002?shop_section_id=0', 'body': { 'listing_id': 100002, 'state': 'active' } }] bp = BulkPage(self.driver) bp.select_single_section('Second something 1235', 'None') # Check listings assert bp.section_names() == expected_section_names # Check that sync button is enabled after clicking on Apply wait_for_web_assert(True, bp.sync_updates_button().is_enabled, 'Sync button is not enabled') # Sync changes click(bp.sync_updates_button()) # Check that sync button is disabled after clicking on Sync wait_for_web_assert(False, bp.sync_updates_button().is_enabled, 'Sync button is not disabled') # Check API calls to Etsy emulator - section should be set to None on one listing check_etsy_emulator_requests(expected_api_calls)
def select_listings_to_edit(driver, operation='Add'): mp = MainPage(driver) bp = BulkPage(driver) mp.select_listings_to_edit() click(bp.edit_part('Tags')) bp.select_operation(operation)
def test_inventory_sku_change_to(self): """ Tests Change to operation for SKU editor :return: """ expected_listings = [ 'Product #1 without variations\n550', 'Product #2 with one variation with pricing\nCHANGE', 'Product #3 with two variations with quantity on both and pricing on both\nCHANGE' ] # Change SKUs on 2nd and 3rd listing operation = 'Change To' bis = BulkPageInventorySku(self.driver, self.ts) bis.select_operation(operation) # unselect 1st bis.click_on_listings(['Product #1 without variations']) # enter new SKU send_keys(bis.sku_input(), 'CHANGE') # Apply and check results click(bis.operation_apply()) wait_for_web_assert(False, bis.operation_apply().is_enabled, 'Apply button is not disabled') assert bis.listing_rows_texts_sorted() == expected_listings
def test_sync_updates_title(self): """ Tests that data is written to the database when [Sync Updates] is clicked It also tests that data are correctly processed in more than one batch (see HIVE-1216). """ # Configure Hive to process changes in batches of two listings # Env variable must be set before Hive is started os.environ['SYNC_UPDATES_BATCH_SIZE'] = '2' expected_data = [['1', 'hello First something 1234 (1)'], ['2', 'hello Second something 1235 (2)'], ['3', 'hello Third something LG-512a (3)']] select_listings_to_edit(self.driver) bp = BulkPage(self.driver) input_field = bp.operation_input() send_keys(input_field, 'hello ') # click on Apply and check Apply button click(bp.operation_apply()) wait_for_web_assert(False, bp.operation_apply().is_enabled, 'Apply button is enabled') # Sync changes click(bp.sync_updates_button()) # Check data in DB wait_for_assert(expected_data, lambda: run_sql('HIVE', 'select_title_modified', True), 'Unexpected title data in DB')
def test_title_replace(self): """ Tests title replace - basic test """ expected_listings_1 = [ 'Prvni something 1234 (1)\n116 characters remaining', 'Second something 1235 (2)\n115 characters remaining', 'Third something LG-512a (3)\n113 characters remaining' ] select_listings_to_edit(self.driver, 'Find & Replace') d = self.driver bp = BulkPage(d) input_find_field = bp.operation_input_find() input_replace_field = bp.operation_input_replace() # Normal Replace send_keys(input_find_field, 'First') send_keys(input_replace_field, 'Prvni') listings = bp.listing_rows_texts_sorted() assert listings == expected_listings_1 # Apply (client only) click(bp.operation_apply()) sleep(1) listings = bp.listing_rows_texts_sorted() assert listings == expected_listings_1 apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ')
def test_title_delete(self): """ Tests tile delete basic """ expected_listings_1 = [ 'First something 1234 (1)\n122 characters remaining', 'Second something 1235 (2)\n115 characters remaining', 'Third something LG-512a (3)\n113 characters remaining' ] expected_listings_2 = [ 'Second something 1235 (2)\n115 characters remaining', 'Third something LG-512a (3)\n113 characters remaining', 'something 1234 (1)\n122 characters remaining' ] select_listings_to_edit(self.driver, 'Delete') d = self.driver bp = BulkPage(d) input_field = bp.operation_input() # Normal Delete send_keys(input_field, 'First ') listings = bp.listing_rows_texts_sorted() assert listings == expected_listings_1 # Apply (client only) click(bp.operation_apply()) sleep(1) listings = bp.listing_rows_texts_sorted() assert listings == expected_listings_2 apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ')
def test_add_shop_basic(self): expected_data = [ [ '100001', 'VarTEST Tangle Free Headphones w/mic Earbuds, Custom Wrapped Match Your Phone Case iPhone 6 Plus 5 4 iPad iPod Android Smartphone Phone', 'draft' ], [ '100002', 'Vartest TEST Sea Tangle Free Earbuds iPhone Android Tablets iPod by MyBuds', 'draft' ], [ '100003', 'Vartest TEST SALE! Wild Berry Wrapped Earbuds or EarPods for iPhone/Android', 'draft' ], [ '100006', 'MC Test Hand Built Ring Catchers The Perfect Party Favor for Your Next Event megha', 'inactive' ] ] self.set_etsy_testcase('listings_09') self.stop_all() run_sql('HIVE', 'listings_no_shop', retry=2) self.restart_all() lpg = LoginPage(self.driver) lpg.login(page=self.login_url_http) lpg.go_to_etsy() lpg.wait_during_sync_from_etsy() d = self.driver pg = MainPage(d) # check the menu contais the shop channel_button = pg.channel_button() click(channel_button) wait_for_web_assert('ETSYGetvelaTest2', lambda: channel_button.text) menu_items = d.find_elements_by_css_selector('div.shops-menu li') assert len(menu_items) == 1 assert (menu_items[0].is_displayed()) shop_names = [t.text for t in menu_items] assert shop_names == ['GetvelaTest2'] # number of listings ['Active', 'Draft', 'Inactive'], Note: expired listings are not imported listing_counts_by_status = [t.text for t in pg.filter_tabs_counts()] assert listing_counts_by_status == ['0', '3', '1'] # Check imported listings - basic data data = run_sql('HIVE', 'select_product_short_info', True) assert data == expected_data, 'Unexpected product data in DB'
def select_listings_to_edit(self, operation=None): mp = MainPage(self.driver) bp = BulkPage(self.driver) mp.select_listings_to_edit() click(bp.edit_part('Quantity')) if operation is not None: bp.select_operation(operation)
def select_listings_to_edit(driver, occasion=None): mp = MainPage(driver) bp = BulkPage(driver) mp.select_listings_to_edit(checked_listings='ALL') click(bp.edit_part('Occasion')) if occasion is not None: bp.select_occasion(occasion)
def select_listings_to_edit(driver, holiday=None): mp = MainPage(driver) bp = BulkPage(driver) mp.select_listings_to_edit(checked_listings='ALL') click(bp.edit_part('Holiday')) if holiday is not None: bp.select_holiday(holiday)
def set_single_title(self, row_title, new_title): row = self.listing_row(row_title, self.TITLE_ROW_SELECTOR) title_element = row.find_element(*self.TITLE_ELEMENT_REL_LOCATOR) click(title_element) input_element = self.wait_for_child_element( row, self.TITLE_INPUT_REL_LOCATOR) input_element.clear() send_keys(input_element, new_title + Keys.ENTER) self.wait_for_child_element(row, self.TITLE_ELEMENT_REL_LOCATOR)
def change_shop(self, shop_name): click(self.choose_shop_button()) self.wait_for_child_element(self.driver, self.SHOPS_MENU_LOCATOR) try: shop_menu_item = self.driver.find_element_by_xpath( self.SHOP_MENU_ITEM_XPATH.format(shop_name=shop_name)) except NoSuchElementException: raise ValueError('Shop "%s" not found in the menu' % shop_name) click(shop_menu_item)
def setup_method(self, method): super().setup_method(method) lpg = LoginPage(self.driver) lpg.login(page=self.login_url_http) mp = MainPage(self.driver) bp = BulkPage(self.driver) mp.select_listings_to_edit() click(bp.edit_part('Photos'))
def test_inventory_update_single_price(self): """ Tests that single price can be updated """ expected_listings_02 = { 'Product #1 without variations': '$10.50', 'Product #2 with one variation with pricing': [('Beige', '$1.00'), ('Black', '$2.00'), ('Blue', '$3.00'), ('Silver', '$4.00'), ('White', '$5.00'), ('Yellow', '$6.00'), ('Custom color 1', '$7.00'), ('Custom color 2', '$8.00')], 'Product #3 with two variations with quantity on both and pricing on both': [ ('XXS US Women\'s', 'Material 1', '$99.00'), ('XXS US Women\'s', 'Material 2', '$99.00'), ('XXS US Women\'s', 'Material 3', '$99.00'), ('One size (plus) US Women\'s', 'Material 1', '$99.00'), ('One size (plus) US Women\'s', 'Material 2', '$99.00'), ('One size (plus) US Women\'s', 'Material 3', '$99.00'), ('Custom size 1 US Women\'s', 'Material 1', '$99.00'), ('Custom size 1 US Women\'s', 'Material 2', '$99.00'), ('Custom size 1 US Women\'s', 'Material 3', '$99.00'), ] } bip = BulkPageInventoryPrice(self.driver, self.ts) actual_listings = bip.listing_details() self.check_listing_options(actual_listings, expected_listings_01) # unselect 1st bip.click_on_listings(['Product #1 without variations']) # unselect 2nd bip.click_on_listings(['Product #2 with one variation with pricing']) # perform individual (inline) change of listing #1 row = bip.listing_row('Product #1 without variations') assert bip.product_price_text(row) == '$500.00' bip.set_individual_price(row, '10.50') # perform bulk change of selected listings (only 3rd) bip.select_operation('Change To') input_field = bip.operation_input_dolars() send_keys(input_field, '99') # apply changes click(bip.operation_apply()) wait_for_web_assert(False, bip.operation_apply().is_enabled, 'Apply button is enabled') # check listings actual_listings = bip.listing_details() self.check_listing_options(actual_listings, expected_listings_02)
def test_create_tag_multi_over(self): """ Tests that multiple tags can be created in bulk edit, but no more than 13 """ expected_tags_01 = [ ['Tag01'], ['Tag01'], ['Tag01', 'AAA', 'BBB', 'CCC'], ] expected_tags_02 = [ [ 'Tag01', '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11' ], [ 'Tag01', '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11' ], [ 'Tag01', 'AAA', 'BBB', 'CCC', '00', '01', '02', '03', '04', '05', '06', '07', '08' ], ] select_listings_to_edit(self.driver) d = self.driver bp = BulkPage(d) # deselect 2, 3 bp.click_on_listings( ['Second something 1235 (2)', 'Third something LG-512a (3)']) # append AAA BBB CCC tags to the 1st listing send_keys(bp.operation_input(), 'AAA,BBB ,CCC') click(bp.operation_apply()) apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ') tag_names = bp.tag_names() assert tag_names == expected_tags_01 # select 2, 3 again bp.click_on_listings( ['Second something 1235 (2)', 'Third something LG-512a (3)']) send_keys( bp.operation_input(), '00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15') click(bp.operation_apply()) apply_class = bp.operation_apply().get_attribute('class') assert 'inactive' in apply_class.split(' ') tag_names = bp.tag_names() assert tag_names == expected_tags_02
def test_inventory_increase_price_dollars(self): """ Tests that a price can be increased in bulk edit """ expected_listings_02 = { 'Product #1 without variations': '$510.00', 'Product #2 with one variation with pricing': [ ('Beige', '$11.00'), ('Black', '$12.00'), ('Blue', '$13.00'), ('Silver', '$14.00'), ('White', '$15.00'), ('Yellow', '$16.00'), ('Custom color 1', '$17.00'), ('Custom color 2', '$18.00'), ], 'Product #3 with two variations with quantity on both and pricing on both': [ ('XXS US Women\'s', 'Material 1', '$10.00'), ('XXS US Women\'s', 'Material 2', '$20.00'), ('XXS US Women\'s', 'Material 3', '$30.00'), ('One size (plus) US Women\'s', 'Material 1', '$40.00'), ('One size (plus) US Women\'s', 'Material 2', '$50.00'), ('One size (plus) US Women\'s', 'Material 3', '$60.00'), ('Custom size 1 US Women\'s', 'Material 1', '$70.00'), ('Custom size 1 US Women\'s', 'Material 2', '$80.00'), ('Custom size 1 US Women\'s', 'Material 3', '$90.00'), ] } operation = 'Increase By' bip = BulkPageInventoryPrice(self.driver, self.ts) actual_listings = bip.listing_details() self.check_listing_options(actual_listings, expected_listings_01) # unselect 3rd bip.click_on_listings([ 'Product #3 with two variations with quantity on both and pricing on both' ]) bip.select_operation(operation) input_field = bip.operation_input_dolars() send_keys(input_field, '10') actual_listings = bip.listing_details() self.check_listing_options(actual_listings, expected_listings_02) # Apply changes click(bip.operation_apply()) actual_listings = bip.listing_details() self.check_listing_options(actual_listings, expected_listings_02) assert bip.operation_apply().is_enabled( ) is False, 'Apply button is enabled'
def click_login_link(self): for i in range(2, -1, -1): try: e = self.driver.find_element(*self.LOGIN_LINK) click(e) sleep(1) break except Exception as e: print('Warning cannot click on login link:', e) if i == 0: raise