From 01c18cc33798b0a6593c11d39d231097462e2287 Mon Sep 17 00:00:00 2001 From: havja Date: Mon, 21 Dec 2020 11:15:27 +0100 Subject: [PATCH] Add waiter for page load after selected Taurus actions (#1443) --- bzt/modules/apiritif/generator.py | 6 ++++++ bzt/resources/selenium_extras.py | 9 +++++++++ ...feat-add-waiter-after-apiritif-actions.change | 1 + tests/resources/selenium/external_logging.py | 3 ++- .../selenium/generated_from_requests.py | 13 ++++++++++++- .../generated_from_requests_appium_browser.py | 2 +- .../generated_from_requests_flow_markers.py | 2 +- .../selenium/generated_from_requests_foreach.py | 16 +++++++++++++++- .../generated_from_requests_if_then_else.py | 10 +++++++++- .../generated_from_requests_loop_variables.py | 3 ++- .../selenium/generated_from_requests_remote.py | 2 +- .../selenium/generated_from_requests_shadow.py | 16 +++++++++++++++- .../selenium/generated_from_requests_v2.py | 8 +++++++- 13 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 site/dat/docs/changes/feat-add-waiter-after-apiritif-actions.change diff --git a/bzt/modules/apiritif/generator.py b/bzt/modules/apiritif/generator.py index 300498b3a4..30601b0ceb 100644 --- a/bzt/modules/apiritif/generator.py +++ b/bzt/modules/apiritif/generator.py @@ -97,6 +97,8 @@ class ApiritifScriptGenerator(object): 'resize', 'maximize', 'alert', 'waitFor' ]) + ACTIONS_WITH_WAITER = ['go', 'click', 'doubleclick', 'contextclick', 'drag', 'select', 'type', 'script'] + EXECUTION_BLOCKS = "|".join(['if', 'loop', 'foreach']) # Python AST docs: https://greentreesnakes.readthedocs.io/en/latest/ @@ -723,6 +725,9 @@ def _gen_action(self, action_config): if not action_elements and not self.ignore_unknown_actions: raise TaurusInternalException("Could not build code for action: %s" % action_config) + if atype.lower() in self.ACTIONS_WITH_WAITER: + action_elements.append(ast_call(func=ast_attr("waiter"), args=[])) + return [ast.Expr(element) for element in action_elements] def _gen_foreach_mngr(self, action_config): @@ -1108,6 +1113,7 @@ def _gen_imports(self): imports.append(ast.parse(self.IMPORTS % source).body) self.selenium_extras.add("get_locator") + self.selenium_extras.add("waiter") extra_names = [ast.alias(name=name, asname=None) for name in self.selenium_extras] imports.append( ast.ImportFrom( diff --git a/bzt/resources/selenium_extras.py b/bzt/resources/selenium_extras.py index 6280d39c03..6a074c4374 100644 --- a/bzt/resources/selenium_extras.py +++ b/bzt/resources/selenium_extras.py @@ -445,3 +445,12 @@ def close_window(window_name=None): switch_window(window_name) _get_driver().close() + +def waiter(): + """ + Allows waiting for page to finish loading before performing other actions on non completely loaded page + """ + WebDriverWait(_get_driver(), _get_timeout())\ + .until(lambda driver: driver.execute_script('return document.readyState') == 'complete', + message="Timeout occurred while waiting for page to finish loading.") + diff --git a/site/dat/docs/changes/feat-add-waiter-after-apiritif-actions.change b/site/dat/docs/changes/feat-add-waiter-after-apiritif-actions.change new file mode 100644 index 0000000000..3e7edcb0af --- /dev/null +++ b/site/dat/docs/changes/feat-add-waiter-after-apiritif-actions.change @@ -0,0 +1 @@ +Added waiter for page load after selected Apiritif actions diff --git a/tests/resources/selenium/external_logging.py b/tests/resources/selenium/external_logging.py index fcb881f543..1fa8f63f59 100644 --- a/tests/resources/selenium/external_logging.py +++ b/tests/resources/selenium/external_logging.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import dialogs_replace, add_logging_handlers, get_locator +from bzt.resources.selenium_extras import dialogs_replace, add_logging_handlers, waiter, get_locator class TestSample(unittest.TestCase): @@ -44,6 +44,7 @@ def _1_Test(self): self.driver.get('http://blazedemo.com/') dialogs_replace() + waiter() apiritif.external_log('end: go(http://blazedemo.com/)') apiritif.external_log('start: log(leaving blazedemo)') apiritif.external_log('leaving blazedemo') diff --git a/tests/resources/selenium/generated_from_requests.py b/tests/resources/selenium/generated_from_requests.py index 9dd238a732..410ecb0a5f 100644 --- a/tests/resources/selenium/generated_from_requests.py +++ b/tests/resources/selenium/generated_from_requests.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import dialogs_answer_on_next_confirm, dialogs_get_next_alert, dialogs_answer_on_next_prompt, dialogs_get_next_confirm, dialogs_answer_on_next_alert, get_locator, wait_for, switch_window, close_window, dialogs_replace, switch_frame, dialogs_get_next_prompt, open_window +from bzt.resources.selenium_extras import dialogs_get_next_prompt, close_window, open_window, switch_window, dialogs_replace, get_locator, waiter, dialogs_answer_on_next_confirm, dialogs_get_next_alert, dialogs_answer_on_next_prompt, switch_frame, dialogs_answer_on_next_alert, dialogs_get_next_confirm, wait_for reader_1 = apiritif.CSVReaderPerThread('first.csv', loop=True) reader_2 = apiritif.CSVReaderPerThread('second.csv', loop=False) @@ -61,11 +61,13 @@ def _1_(self): ActionChains(self.driver).double_click(self.driver.find_element( var_loc_chain[0], var_loc_chain[1])).perform() + waiter() var_loc_chain = get_locator([{'xpath': '/html/body/div[3]/form/select[1]'}]) ActionChains(self.driver).context_click(self.driver.find_element( var_loc_chain[0], var_loc_chain[1])).perform() + waiter() var_loc_chain = get_locator([{'xpath': '/html/body/div[3]/form/select[1]'}]) ActionChains(self.driver).click_and_hold(self.driver.find_element( @@ -81,6 +83,7 @@ def _1_(self): Select(self.driver.find_element( var_loc_select[0], var_loc_select[1])).select_by_visible_text('London') + waiter() var_loc_keys = get_locator([{'css': 'body input.btn.btn-primary'}]) self.driver.find_element( @@ -110,6 +113,7 @@ def _1_(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).send_keys('B') + waiter() var_loc_keys = get_locator([{'name': 'toPort'}]) self.driver.find_element( @@ -123,16 +127,19 @@ def _1_(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).send_keys(Keys.ENTER) + waiter() var_loc_keys = get_locator([{'xpath': '//div[3]/form/select[1]//option[3]'}]) self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() var_loc_keys = get_locator([{'xpath': '//div[3]/form/select[2]//option[6]'}]) self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() switch_window('0') open_window('some.url') switch_window('win_ser_local') @@ -148,6 +155,7 @@ def _1_(self): var_loc_keys[0], var_loc_keys[1]).submit() self.driver.execute_script("alert('This is Sparta');") + waiter() for i in range(10): if ((i % 2) == 0): @@ -161,6 +169,7 @@ def _1_(self): source[1]), self.driver.find_element( target[0], target[1])).perform() + waiter() switch_frame(self.driver.find_element(By.NAME, 'my_frame')) switch_frame(self.driver.find_element(By.NAME, 'top_frame')) switch_frame(self.driver.find_element(By.XPATH, "//*[@id='result']")) @@ -188,6 +197,7 @@ def _1_(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() self.vars['Title'] = self.driver.title @@ -210,6 +220,7 @@ def _1_(self): self.driver.get('http:\\blazemeter.com') dialogs_replace() + waiter() dialog = dialogs_get_next_alert() self.assertIsNotNone(dialog, 'No dialog of type alert appeared') diff --git a/tests/resources/selenium/generated_from_requests_appium_browser.py b/tests/resources/selenium/generated_from_requests_appium_browser.py index d7549d63af..1a39db5f49 100644 --- a/tests/resources/selenium/generated_from_requests_appium_browser.py +++ b/tests/resources/selenium/generated_from_requests_appium_browser.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import wait_for, dialogs_replace, get_locator +from bzt.resources.selenium_extras import dialogs_replace, get_locator, wait_for, waiter class TestLocScAppium(unittest.TestCase): diff --git a/tests/resources/selenium/generated_from_requests_flow_markers.py b/tests/resources/selenium/generated_from_requests_flow_markers.py index a043ed510c..f1d92a9a20 100644 --- a/tests/resources/selenium/generated_from_requests_flow_markers.py +++ b/tests/resources/selenium/generated_from_requests_flow_markers.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import wait_for, dialogs_replace, get_locator, add_flow_markers +from bzt.resources.selenium_extras import get_locator, wait_for, dialogs_replace, waiter, add_flow_markers class TestLocSc(unittest.TestCase): diff --git a/tests/resources/selenium/generated_from_requests_foreach.py b/tests/resources/selenium/generated_from_requests_foreach.py index 2896dfcdd1..8905503033 100644 --- a/tests/resources/selenium/generated_from_requests_foreach.py +++ b/tests/resources/selenium/generated_from_requests_foreach.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import get_locator, get_elements +from bzt.resources.selenium_extras import get_locator, waiter, get_elements class TestLocSc(unittest.TestCase): @@ -63,15 +63,21 @@ def _1_Foreach_test(self): else: raise NoSuchElementException(("The element '%s' (tag name: '%s', text: '%s') is not a contenteditable element" % ('el', el.tag_name, el.text))) el.click() + waiter() var_loc_keys = get_locator([{'css': 'input-cls'}, {'xpath': '//input'}], el) el.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() ActionChains(self.driver).double_click(el).perform() + waiter() ActionChains(self.driver).double_click(el).perform() + waiter() ActionChains(self.driver).context_click(el).perform() + waiter() ActionChains(self.driver).context_click(el).perform() + waiter() ActionChains(self.driver).click_and_hold(el).perform() ActionChains(self.driver).click_and_hold(el).perform() ActionChains(self.driver).release(el).perform() @@ -85,23 +91,29 @@ def _1_Foreach_test(self): ActionChains(self.driver).drag_and_drop(el, self.driver.find_element( target[0], target[1])).perform() + waiter() source = get_locator([{'id': 'id34'}]) ActionChains(self.driver).drag_and_drop(self.driver.find_element( source[0], source[1]), el).perform() + waiter() target = get_locator([{'id': 'id12'}]) ActionChains(self.driver).drag_and_drop(el, self.driver.find_element( target[0], target[1])).perform() + waiter() source = get_locator([{'id': 'id34'}]) ActionChains(self.driver).drag_and_drop(self.driver.find_element( source[0], source[1]), el).perform() + waiter() Select(el).select_by_visible_text('value') + waiter() Select(el).select_by_visible_text('value') + waiter() self.vars['my_var'] = el.get_attribute('innerText') @@ -112,8 +124,10 @@ def _1_Foreach_test(self): self.vars['my_var'] = el.get_attribute('value') el.clear() el.send_keys('text') + waiter() el.clear() el.send_keys('text') + waiter() el.submit() el.submit() el.send_keys(Keys.ENTER) diff --git a/tests/resources/selenium/generated_from_requests_if_then_else.py b/tests/resources/selenium/generated_from_requests_if_then_else.py index 9bb87348a1..cc3532377f 100644 --- a/tests/resources/selenium/generated_from_requests_if_then_else.py +++ b/tests/resources/selenium/generated_from_requests_if_then_else.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import get_locator, dialogs_replace +from bzt.resources.selenium_extras import dialogs_replace, waiter, get_locator class TestLocSc(unittest.TestCase): @@ -44,6 +44,7 @@ def _1_Conditions_test(self): self.driver.get('http://blazedemo.com') dialogs_replace() + waiter() test = self.driver.execute_script('return document.getElementsByName("fromPort")[0].length > 0;') if test: @@ -52,6 +53,7 @@ def _1_Conditions_test(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() sleep(1.0) test = self.driver.execute_script('return document.getElementsByClassName("table")[0].rows.length > 5;') @@ -61,6 +63,7 @@ def _1_Conditions_test(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() test = self.driver.execute_script('return document.getElementById("{}").value === \'\';'.format(self.vars['input_name_id'])) if test: @@ -72,6 +75,7 @@ def _1_Conditions_test(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).send_keys('John Doe') + waiter() else: var_loc_keys = get_locator([{'id': self.vars['input_name_id']}]) @@ -81,11 +85,13 @@ def _1_Conditions_test(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).send_keys('Jack Green') + waiter() var_loc_keys = get_locator([{'xpath': '/html/body/div[2]/form/div[11]/div/input'}]) self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() sleep(5.0) else: @@ -99,6 +105,7 @@ def _1_Conditions_test(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).send_keys('my text') + waiter() test = self.driver.execute_script('return window.screen.width > 1000;') if test: @@ -111,6 +118,7 @@ def _1_Conditions_test(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() def test_locsc(self): self._1_Conditions_test() diff --git a/tests/resources/selenium/generated_from_requests_loop_variables.py b/tests/resources/selenium/generated_from_requests_loop_variables.py index f051e0c04e..a41dbd93ba 100644 --- a/tests/resources/selenium/generated_from_requests_loop_variables.py +++ b/tests/resources/selenium/generated_from_requests_loop_variables.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import get_loop_range, get_locator +from bzt.resources.selenium_extras import get_locator, get_loop_range, waiter class TestLocSc(unittest.TestCase): @@ -47,6 +47,7 @@ def _1_None(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() def test_locsc(self): self._1_None() diff --git a/tests/resources/selenium/generated_from_requests_remote.py b/tests/resources/selenium/generated_from_requests_remote.py index 98c7396abb..742f2b70f4 100644 --- a/tests/resources/selenium/generated_from_requests_remote.py +++ b/tests/resources/selenium/generated_from_requests_remote.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import add_flow_markers, dialogs_replace, get_locator, wait_for +from bzt.resources.selenium_extras import add_flow_markers, waiter, wait_for, dialogs_replace, get_locator class TestLocScRemote(unittest.TestCase): diff --git a/tests/resources/selenium/generated_from_requests_shadow.py b/tests/resources/selenium/generated_from_requests_shadow.py index 45ded41767..7b5fcc65ac 100644 --- a/tests/resources/selenium/generated_from_requests_shadow.py +++ b/tests/resources/selenium/generated_from_requests_shadow.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import find_element_by_shadow, get_locator +from bzt.resources.selenium_extras import waiter, find_element_by_shadow, get_locator class TestLocSc(unittest.TestCase): @@ -61,16 +61,22 @@ def _1_Shadow_locators_test(self): raise NoSuchElementException(("The element (shadow: '%s') is not a contenteditable element" % ('c-basic, lightning-accordion-section, .slds-button',))) find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').click() + waiter() find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').click() + waiter() ActionChains(self.driver).double_click(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).perform() + waiter() ActionChains(self.driver).double_click(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).perform() + waiter() ActionChains(self.driver).context_click(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).perform() + waiter() ActionChains(self.driver).context_click(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).perform() + waiter() ActionChains(self.driver).click_and_hold(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).perform() @@ -93,28 +99,34 @@ def _1_Shadow_locators_test(self): ActionChains(self.driver).drag_and_drop(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button'), self.driver.find_element( target[0], target[1])).perform() + waiter() source = get_locator([{'id': 'id34'}]) ActionChains(self.driver).drag_and_drop(self.driver.find_element( source[0], source[1]), find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).perform() + waiter() target = get_locator([{'id': 'id12'}]) ActionChains(self.driver).drag_and_drop(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button'), self.driver.find_element( target[0], target[1])).perform() + waiter() source = get_locator([{'id': 'id34'}]) ActionChains(self.driver).drag_and_drop(self.driver.find_element( source[0], source[1]), find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).perform() + waiter() Select(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).select_by_visible_text('value') + waiter() Select(find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button')).select_by_visible_text('value') + waiter() self.vars['my_var'] = find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').get_attribute('innerText') @@ -130,9 +142,11 @@ def _1_Shadow_locators_test(self): find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').clear() find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').send_keys('text') + waiter() find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').clear() find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').send_keys('text') + waiter() find_element_by_shadow('c-basic, lightning-accordion-section, .slds-button').submit() diff --git a/tests/resources/selenium/generated_from_requests_v2.py b/tests/resources/selenium/generated_from_requests_v2.py index 6b93874132..c76f228bef 100644 --- a/tests/resources/selenium/generated_from_requests_v2.py +++ b/tests/resources/selenium/generated_from_requests_v2.py @@ -19,7 +19,7 @@ from selenium.webdriver.support import expected_conditions as econd from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.keys import Keys -from bzt.resources.selenium_extras import switch_window, open_window, dialogs_get_next_prompt, dialogs_answer_on_next_confirm, dialogs_answer_on_next_alert, wait_for, dialogs_replace, dialogs_get_next_alert, dialogs_get_next_confirm, get_locator, close_window, dialogs_answer_on_next_prompt, switch_frame +from bzt.resources.selenium_extras import switch_frame, waiter, dialogs_replace, dialogs_get_next_alert, close_window, wait_for, dialogs_get_next_confirm, dialogs_answer_on_next_alert, dialogs_get_next_prompt, get_locator, open_window, switch_window, dialogs_answer_on_next_confirm, dialogs_answer_on_next_prompt class TestLocSc(unittest.TestCase): @@ -42,6 +42,7 @@ def _1_Test_V2(self): self.driver.get('http://blazedemo.com') dialogs_replace() + waiter() self.driver.set_window_size('750', '750') switch_window(0) @@ -68,6 +69,7 @@ def _1_Test_V2(self): source[1]), self.driver.find_element( target[0], target[1])).perform() + waiter() var_loc_as = get_locator([{'css': 'myclass'}, {'xpath': '/html/body/div[3]/h2'}]) self.assertEqual(self.driver.find_element( @@ -97,6 +99,7 @@ def _1_Test_V2(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).click() + waiter() var_loc_keys = get_locator([{'xpath': '/doc/abc'}, {'css': 'body > div.container > table > tbody > tr:nth-child(1) > td:nth-child(2) > input'}]) self.driver.find_element( @@ -110,12 +113,15 @@ def _1_Test_V2(self): self.driver.find_element( var_loc_keys[0], var_loc_keys[1]).send_keys('myusername') + waiter() var_loc_select = get_locator([{'css': 'myclass'}, {'xpath': '//*[@id="cardType"]'}]) Select(self.driver.find_element( var_loc_select[0], var_loc_select[1])).select_by_visible_text('American Express') + waiter() self.driver.execute_script('window.scrollTo(0, document.body.scrollHeight);') + waiter() for i in range(10): if ((i % 2) == 0):