Skip to content

Commit 2345350

Browse files
authored
Merge pull request #4185 from askerry/fix_race
Add wait_for_tag to avoid race condition in display isolation test
2 parents b61cd92 + f995db4 commit 2345350

File tree

2 files changed

+61
-7
lines changed

2 files changed

+61
-7
lines changed

notebook/tests/selenium/test_display_isolation.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
An object whose metadata contains an "isolated" tag must be isolated
44
from the rest of the document.
55
"""
6+
from .utils import wait_for_tag
67

78

89
def test_display_isolation(notebook):
@@ -26,7 +27,7 @@ def isolated_html(notebook):
2627
"""
2728
red = 'rgb(255, 0, 0)'
2829
blue = 'rgb(0, 0, 255)'
29-
test_str = "<div id='test'>Should be red from non-isolation</div>"
30+
test_str = "<div id='test'>Should turn red from non-isolation</div>"
3031
notebook.add_and_execute_cell(content="display(HTML(%r))" % test_str)
3132
non_isolated = (
3233
"<style>div{color:%s;}</style>" % red +
@@ -41,6 +42,8 @@ def isolated_html(notebook):
4142
isolated)
4243
notebook.add_and_execute_cell(content=display_i)
4344

45+
iframe = wait_for_tag(notebook.browser, "iframe", single=True)
46+
4447
# The non-isolated div will be in the body
4548
non_isolated_div = notebook.body.find_element_by_id("non-isolated")
4649
assert non_isolated_div.value_of_css_property("color") == red
@@ -50,11 +53,13 @@ def isolated_html(notebook):
5053
assert test_div.value_of_css_property("color") == red
5154

5255
# The isolated div will be in an iframe, only that element will be blue
53-
iframe = notebook.body.find_element_by_tag_name("iframe")
5456
notebook.browser.switch_to.frame(iframe)
5557
isolated_div = notebook.browser.find_element_by_id("isolated")
5658
assert isolated_div.value_of_css_property("color") == blue
5759
notebook.browser.switch_to.default_content()
60+
# Clean up the html test cells
61+
for i in range(1, len(notebook.cells)):
62+
notebook.delete_cell(1)
5863

5964

6065
def isolated_svg(notebook):
@@ -73,16 +78,19 @@ def isolated_svg(notebook):
7378
content="display_svg(SVG(s1), metadata=dict(isolated=True))")
7479
notebook.add_and_execute_cell(
7580
content="display_svg(SVG(s2), metadata=dict(isolated=True))")
76-
iframes = notebook.body.find_elements_by_tag_name("iframe")
81+
iframes = wait_for_tag(notebook.browser, "iframe", wait_for_n=2)
7782

7883
# The first rectangle will be red
79-
notebook.browser.switch_to.frame(iframes[1])
84+
notebook.browser.switch_to.frame(iframes[0])
8085
isolated_svg_1 = notebook.browser.find_element_by_id('r1')
8186
assert isolated_svg_1.value_of_css_property("fill") == yellow
8287
notebook.browser.switch_to.default_content()
8388

8489
# The second rectangle will be black
85-
notebook.browser.switch_to.frame(iframes[2])
90+
notebook.browser.switch_to.frame(iframes[1])
8691
isolated_svg_2 = notebook.browser.find_element_by_id('r2')
8792
assert isolated_svg_2.value_of_css_property("fill") == black
8893

94+
# Clean up the svg test cells
95+
for i in range(1, len(notebook.cells)):
96+
notebook.delete_cell(1)

notebook/tests/selenium/utils.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import time
33
from selenium.webdriver import ActionChains
44
from selenium.webdriver.common.by import By
5+
from selenium.common.exceptions import WebDriverException
56
from selenium.webdriver.common.keys import Keys
67
from selenium.webdriver.support.ui import WebDriverWait
78
from selenium.webdriver.support import expected_conditions as EC
@@ -12,13 +13,33 @@
1213
pjoin = os.path.join
1314

1415

15-
def wait_for_selector(driver, selector, timeout=10, visible=False, single=False):
16+
def wait_for_selector(driver, selector, timeout=10, visible=False, single=False, wait_for_n=1):
17+
if wait_for_n > 1:
18+
return _wait_for_multiple(
19+
driver, By.CSS_SELECTOR, selector, timeout, wait_for_n, visible)
1620
return _wait_for(driver, By.CSS_SELECTOR, selector, timeout, visible, single)
1721

18-
def wait_for_tag(driver, tag, timeout=10, visible=False, single=False):
22+
23+
def wait_for_tag(driver, tag, timeout=10, visible=False, single=False, wait_for_n=1):
24+
if wait_for_n > 1:
25+
return _wait_for_multiple(
26+
driver, By.TAG_NAME, tag, timeout, wait_for_n, visible)
1927
return _wait_for(driver, By.TAG_NAME, tag, timeout, visible, single)
2028

29+
2130
def _wait_for(driver, locator_type, locator, timeout=10, visible=False, single=False):
31+
"""Waits `timeout` seconds for the specified condition to be met. Condition is
32+
met if any matching element is found. Returns located element(s) when found.
33+
34+
Args:
35+
driver: Selenium web driver instance
36+
locator_type: type of locator (e.g. By.CSS_SELECTOR or By.TAG_NAME)
37+
locator: name of tag, class, etc. to wait for
38+
timeout: how long to wait for presence/visibility of element
39+
visible: if True, require that element is not only present, but visible
40+
single: if True, return a single element, otherwise return a list of matching
41+
elements
42+
"""
2243
wait = WebDriverWait(driver, timeout)
2344
if single:
2445
if visible:
@@ -33,6 +54,31 @@ def _wait_for(driver, locator_type, locator, timeout=10, visible=False, single=F
3354
return wait.until(conditional((locator_type, locator)))
3455

3556

57+
def _wait_for_multiple(driver, locator_type, locator, timeout, wait_for_n, visible=False):
58+
"""Waits until `wait_for_n` matching elements to be present (or visible).
59+
Returns located elements when found.
60+
61+
Args:
62+
driver: Selenium web driver instance
63+
locator_type: type of locator (e.g. By.CSS_SELECTOR or By.TAG_NAME)
64+
locator: name of tag, class, etc. to wait for
65+
timeout: how long to wait for presence/visibility of element
66+
wait_for_n: wait until this number of matching elements are present/visible
67+
visible: if True, require that elements are not only present, but visible
68+
"""
69+
wait = WebDriverWait(driver, timeout)
70+
71+
def multiple_found(driver):
72+
elements = driver.find_elements(locator_type, locator)
73+
if visible:
74+
elements = [e for e in elements if e.is_displayed()]
75+
if len(elements) < wait_for_n:
76+
return False
77+
return elements
78+
79+
return wait.until(multiple_found)
80+
81+
3682
class CellTypeError(ValueError):
3783

3884
def __init__(self, message=""):

0 commit comments

Comments
 (0)