fix: Selenium tests via scroll_and_click (#8150)
* fix: selenium tests scroll_and_click * fix: reduce default timeout to 5 seconds * fix: also use scroll_and_click on test_upcoming_materials_modal * fix: remove conditional check on restoring scroll CSS * fix: restore conditional check on restoring scroll CSS * chore: code comments and adding jstest.py to coverage ignore
This commit is contained in:
parent
d530e9aaba
commit
de494790b6
|
@ -249,7 +249,9 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
|
||||||
self.assertTrue(s1_element.is_displayed()) # should still be displayed
|
self.assertTrue(s1_element.is_displayed()) # should still be displayed
|
||||||
self.assertIn('hidden-parent', s1_element.get_attribute('class'),
|
self.assertIn('hidden-parent', s1_element.get_attribute('class'),
|
||||||
'Session should be hidden when parent disabled')
|
'Session should be hidden when parent disabled')
|
||||||
s1_element.click() # try to select
|
|
||||||
|
self.scroll_and_click((By.CSS_SELECTOR, '#session{}'.format(s1.pk)))
|
||||||
|
|
||||||
self.assertNotIn('selected', s1_element.get_attribute('class'),
|
self.assertNotIn('selected', s1_element.get_attribute('class'),
|
||||||
'Session should not be selectable when parent disabled')
|
'Session should not be selectable when parent disabled')
|
||||||
|
|
||||||
|
@ -299,9 +301,9 @@ class EditMeetingScheduleTests(IetfSeleniumTestCase):
|
||||||
'Session s1 should have moved to second meeting day')
|
'Session s1 should have moved to second meeting day')
|
||||||
|
|
||||||
# swap timeslot column - put session in a differently-timed timeslot
|
# swap timeslot column - put session in a differently-timed timeslot
|
||||||
self.driver.find_element(By.CSS_SELECTOR,
|
self.scroll_and_click((By.CSS_SELECTOR,
|
||||||
'.day .swap-timeslot-col[data-timeslot-pk="{}"]'.format(slot1b.pk)
|
'.day .swap-timeslot-col[data-timeslot-pk="{}"]'.format(slot1b.pk)
|
||||||
).click() # open modal on the second timeslot for room1
|
)) # open modal on the second timeslot for room1
|
||||||
self.assertTrue(self.driver.find_element(By.CSS_SELECTOR, "#swap-timeslot-col-modal").is_displayed())
|
self.assertTrue(self.driver.find_element(By.CSS_SELECTOR, "#swap-timeslot-col-modal").is_displayed())
|
||||||
self.driver.find_element(By.CSS_SELECTOR,
|
self.driver.find_element(By.CSS_SELECTOR,
|
||||||
'#swap-timeslot-col-modal input[name="target_timeslot"][value="{}"]'.format(slot4.pk)
|
'#swap-timeslot-col-modal input[name="target_timeslot"][value="{}"]'.format(slot4.pk)
|
||||||
|
@ -1373,13 +1375,8 @@ class InterimTests(IetfSeleniumTestCase):
|
||||||
self.assertFalse(modal_div.is_displayed())
|
self.assertFalse(modal_div.is_displayed())
|
||||||
|
|
||||||
# Click the 'materials' button
|
# Click the 'materials' button
|
||||||
open_modal_button = self.wait.until(
|
open_modal_button_locator = (By.CSS_SELECTOR, '[data-bs-target="#modal-%s"]' % slug)
|
||||||
expected_conditions.element_to_be_clickable(
|
self.scroll_and_click(open_modal_button_locator)
|
||||||
(By.CSS_SELECTOR, '[data-bs-target="#modal-%s"]' % slug)
|
|
||||||
),
|
|
||||||
'Modal open button not found or not clickable',
|
|
||||||
)
|
|
||||||
open_modal_button.click()
|
|
||||||
self.wait.until(
|
self.wait.until(
|
||||||
expected_conditions.visibility_of(modal_div),
|
expected_conditions.visibility_of(modal_div),
|
||||||
'Modal did not become visible after clicking open button',
|
'Modal did not become visible after clicking open button',
|
||||||
|
|
|
@ -598,6 +598,7 @@ TEST_CODE_COVERAGE_EXCLUDE_FILES = [
|
||||||
"ietf/review/import_from_review_tool.py",
|
"ietf/review/import_from_review_tool.py",
|
||||||
"ietf/utils/patch.py",
|
"ietf/utils/patch.py",
|
||||||
"ietf/utils/test_data.py",
|
"ietf/utils/test_data.py",
|
||||||
|
"ietf/utils/jstest.py",
|
||||||
]
|
]
|
||||||
|
|
||||||
# These are code line regex patterns
|
# These are code line regex patterns
|
||||||
|
|
|
@ -12,6 +12,8 @@ try:
|
||||||
from selenium import webdriver
|
from selenium import webdriver
|
||||||
from selenium.webdriver.firefox.service import Service
|
from selenium.webdriver.firefox.service import Service
|
||||||
from selenium.webdriver.firefox.options import Options
|
from selenium.webdriver.firefox.options import Options
|
||||||
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
|
from selenium.webdriver.support import expected_conditions
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
skip_selenium = True
|
skip_selenium = True
|
||||||
|
@ -87,6 +89,48 @@ class IetfSeleniumTestCase(IetfLiveServerTestCase):
|
||||||
# actions = ActionChains(self.driver)
|
# actions = ActionChains(self.driver)
|
||||||
# actions.move_to_element(element).perform()
|
# actions.move_to_element(element).perform()
|
||||||
|
|
||||||
|
def scroll_and_click(self, element_locator, timeout_seconds=5):
|
||||||
|
"""
|
||||||
|
Selenium has restrictions around clicking elements outside the viewport, so
|
||||||
|
this wrapper encapsulates the boilerplate of forcing scrolling and clicking.
|
||||||
|
|
||||||
|
:param element_locator: A two item tuple of a Selenium locator eg `(By.CSS_SELECTOR, '#something')`
|
||||||
|
"""
|
||||||
|
|
||||||
|
# so that we can restore the state of the webpage after clicking
|
||||||
|
original_html_scroll_behaviour_to_restore = self.driver.execute_script('return document.documentElement.style.scrollBehavior')
|
||||||
|
original_html_overflow_to_restore = self.driver.execute_script('return document.documentElement.style.overflow')
|
||||||
|
|
||||||
|
original_body_scroll_behaviour_to_restore = self.driver.execute_script('return document.body.style.scrollBehavior')
|
||||||
|
original_body_overflow_to_restore = self.driver.execute_script('return document.body.style.overflow')
|
||||||
|
|
||||||
|
self.driver.execute_script('document.documentElement.style.scrollBehavior = "auto"')
|
||||||
|
self.driver.execute_script('document.documentElement.style.overflow = "auto"')
|
||||||
|
|
||||||
|
self.driver.execute_script('document.body.style.scrollBehavior = "auto"')
|
||||||
|
self.driver.execute_script('document.body.style.overflow = "auto"')
|
||||||
|
|
||||||
|
element = self.driver.find_element(element_locator[0], element_locator[1])
|
||||||
|
self.scroll_to_element(element)
|
||||||
|
|
||||||
|
# Note that Selenium itself seems to have multiple definitions of 'clickable'.
|
||||||
|
# You might expect that the following wait for the 'element_to_be_clickable'
|
||||||
|
# would confirm that the following .click() would succeed but it doesn't.
|
||||||
|
# That's why the preceeding code attempts to force scrolling to bring the
|
||||||
|
# element into the viewport to allow clicking.
|
||||||
|
WebDriverWait(self.driver, timeout_seconds).until(expected_conditions.element_to_be_clickable(element_locator))
|
||||||
|
|
||||||
|
element.click()
|
||||||
|
|
||||||
|
if original_html_scroll_behaviour_to_restore:
|
||||||
|
self.driver.execute_script(f'document.documentElement.style.scrollBehavior = "{original_html_scroll_behaviour_to_restore}"')
|
||||||
|
if original_html_overflow_to_restore:
|
||||||
|
self.driver.execute_script(f'document.documentElement.style.overflow = "{original_html_overflow_to_restore}"')
|
||||||
|
|
||||||
|
if original_body_scroll_behaviour_to_restore:
|
||||||
|
self.driver.execute_script(f'document.body.style.scrollBehavior = "{original_body_scroll_behaviour_to_restore}"')
|
||||||
|
if original_body_overflow_to_restore:
|
||||||
|
self.driver.execute_script(f'document.body.style.overflow = "{original_body_overflow_to_restore}"')
|
||||||
|
|
||||||
class presence_of_element_child_by_css_selector:
|
class presence_of_element_child_by_css_selector:
|
||||||
"""Wait for presence of a child of a WebElement matching a CSS selector
|
"""Wait for presence of a child of a WebElement matching a CSS selector
|
||||||
|
|
Loading…
Reference in a new issue