Skip to content

Commit 847b46f

Browse files
committed
fix tests or run fresh browser
1 parent 4add6c6 commit 847b46f

23 files changed

Lines changed: 1312 additions & 1054 deletions

.test_durations

Lines changed: 331 additions & 331 deletions
Large diffs are not rendered by default.

components/dash-core-components/.test_durations

Lines changed: 319 additions & 305 deletions
Large diffs are not rendered by default.

components/dash-core-components/tests/conftest.py

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,25 @@ def wait_timeout(self):
5151

5252
def start_server(self, app, **kwargs):
5353
"""start the local server with app"""
54+
# Ensure browser is on blank page before starting new server
55+
self._ensure_blank_page()
5456
self.server(app, **kwargs)
5557
self.server_url = self.server.url
5658

59+
def _ensure_blank_page(self):
60+
"""Ensure browser is on a blank page with no stale content."""
61+
try:
62+
current_url = self.driver.current_url
63+
if current_url != "about:blank":
64+
self.driver.get("about:blank")
65+
# Wait for blank page to fully load
66+
from selenium.webdriver.support.wait import WebDriverWait
67+
from selenium.webdriver.support import expected_conditions as EC
68+
69+
WebDriverWait(self.driver, 2).until(EC.url_to_be("about:blank"))
70+
except Exception:
71+
pass
72+
5773
@property
5874
def server_url(self):
5975
return self._url
@@ -64,12 +80,37 @@ def server_url(self, value):
6480
self.wait_for_page()
6581

6682
def wait_for_page(self, url=None, timeout=10):
67-
from selenium.common.exceptions import TimeoutException
83+
from selenium.common.exceptions import (
84+
TimeoutException,
85+
StaleElementReferenceException,
86+
)
87+
from selenium.webdriver.support.wait import WebDriverWait
88+
from selenium.webdriver.common.by import By
6889
from dash.testing.errors import DashAppLoadingError
6990

70-
self.driver.get(self._url if url is None else url)
91+
target_url = self._url if url is None else url
92+
93+
# Navigate to the target URL
94+
self.driver.get(target_url)
95+
7196
try:
72-
self.wait_for_element_by_css_selector("#react-entry-point", timeout=timeout)
97+
# Wait for URL to match (handles redirects)
98+
WebDriverWait(self.driver, timeout).until(
99+
lambda d: target_url in d.current_url
100+
)
101+
102+
# Wait for react entry point with staleness check
103+
def fresh_react_entry(driver):
104+
try:
105+
elem = driver.find_element(By.CSS_SELECTOR, "#react-entry-point")
106+
# Verify element is interactive (not stale)
107+
_ = elem.is_displayed()
108+
return elem
109+
except StaleElementReferenceException:
110+
return False
111+
112+
WebDriverWait(self.driver, timeout).until(fresh_react_entry)
113+
73114
except TimeoutException as exc:
74115
raise DashAppLoadingError("Dash app failed to load") from exc
75116

@@ -167,13 +208,33 @@ def get_logs(self):
167208
return None
168209

169210
def _reset_browser_state(self):
211+
"""Clear browser state between tests."""
212+
try:
213+
# Stop any running JavaScript
214+
self.driver.execute_script("window.stop();")
215+
except Exception:
216+
pass
217+
170218
try:
171219
self.driver.delete_all_cookies()
172220
except Exception:
173221
pass
222+
174223
try:
224+
# Navigate to blank page
175225
self.driver.get("about:blank")
226+
227+
# Wait for navigation to complete
228+
from selenium.webdriver.support.wait import WebDriverWait
229+
from selenium.webdriver.support import expected_conditions as EC
230+
231+
WebDriverWait(self.driver, 2).until(EC.url_to_be("about:blank"))
232+
233+
# Clear storage
176234
self.clear_storage()
235+
236+
# Reset timestamp for log filtering
237+
self._last_ts = 0
177238
except Exception:
178239
pass
179240

@@ -213,6 +274,24 @@ def dash_dcc(request, dash_thread_server, _dcc_browser_session):
213274
yield dc
214275

215276

277+
@pytest.fixture
278+
def dash_dcc_fresh_browser(request, dash_thread_server, tmpdir):
279+
"""DCC test fixture with a fresh browser instance (for tests that need isolation)."""
280+
with DashCoreComponentsComposite(
281+
dash_thread_server,
282+
browser=request.config.getoption("webdriver"),
283+
remote=request.config.getoption("remote"),
284+
remote_url=request.config.getoption("remote_url"),
285+
headless=request.config.getoption("headless"),
286+
options=request.config.hook.pytest_setup_options(),
287+
download_path=tmpdir.mkdir("download").strpath,
288+
percy_assets_root=request.config.getoption("percy_assets"),
289+
percy_finalize=request.config.getoption("nopercyfinalize"),
290+
pause=request.config.getoption("pause"),
291+
) as dc:
292+
yield dc
293+
294+
216295
@pytest.fixture
217296
def dash_dcc_headed(request, dash_thread_server, tmpdir):
218297
with DashCoreComponentsComposite(

components/dash-core-components/tests/integration/calendar/test_a11y_date_picker_single.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ def test_a11y003_keyboard_navigation_arrows(dash_dcc):
147147
assert dash_dcc.get_logs() == []
148148

149149

150-
def test_a11y004_keyboard_navigation_home_end(dash_dcc):
150+
def test_a11y004_keyboard_navigation_home_end(dash_dcc_fresh_browser):
151+
dash_dcc = dash_dcc_fresh_browser
151152
app = create_date_picker_app(
152153
{
153154
"date": "2021-01-15", # Friday, Jan 15, 2021
@@ -367,7 +368,8 @@ def test_a11y008_all_keyboard_keys_respect_disabled_days(dash_dcc):
367368
assert dash_dcc.get_logs() == []
368369

369370

370-
def test_a11y009_keyboard_space_selects_date(dash_dcc):
371+
def test_a11y009_keyboard_space_selects_date(dash_dcc_fresh_browser):
372+
dash_dcc = dash_dcc_fresh_browser
371373
app = create_date_picker_app(
372374
{
373375
"date": "2021-01-15",

components/dash-core-components/tests/integration/calendar/test_portal.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,13 @@ def test_dppt000_datepicker_single_default(dash_dcc):
7777
assert dash_dcc.get_logs() == []
7878

7979

80-
def test_dppt001_datepicker_single_with_portal(dash_dcc):
80+
def test_dppt001_datepicker_single_with_portal(dash_dcc_fresh_browser):
8181
"""Test DatePickerSingle with with_portal=True.
8282
8383
Verifies that the calendar opens in a portal (document.body) and all
84-
elements are clickable.
84+
elements are clickable. Uses fresh browser to avoid state bleeding.
8585
"""
86+
dash_dcc = dash_dcc_fresh_browser
8687
app = Dash(__name__)
8788

8889
app.layout = html.Div(
@@ -113,12 +114,13 @@ def test_dppt001_datepicker_single_with_portal(dash_dcc):
113114
assert dash_dcc.get_logs() == []
114115

115116

116-
def test_dppt006_fullscreen_portal_close_button_keyboard(dash_dcc):
117+
def test_dppt006_fullscreen_portal_close_button_keyboard(dash_dcc_fresh_browser):
117118
"""Test fullscreen portal dismiss behavior and keyboard accessibility.
118119
119120
Verifies clicking background doesn't close the portal and close button
120-
is keyboard-accessible.
121+
is keyboard-accessible. Uses fresh browser to avoid state bleeding.
121122
"""
123+
dash_dcc = dash_dcc_fresh_browser
122124
app = Dash(__name__)
123125
app.layout = html.Div(
124126
[
@@ -359,12 +361,14 @@ def test_dppt004_datepicker_range_with_fullscreen_portal(dash_dcc):
359361
click_everything_in_datepicker("#dpr-fullscreen", dash_dcc)
360362

361363

362-
def test_dppt005_portal_has_correct_classes(dash_dcc):
364+
def test_dppt005_portal_has_correct_classes(dash_dcc_fresh_browser):
363365
"""Test that portal datepickers have the correct CSS classes.
364366
365367
Verifies that default datepickers don't have portal classes, while
366368
with_portal=True datepickers have the portal class but not fullscreen class.
369+
Uses fresh browser to avoid state bleeding.
367370
"""
371+
dash_dcc = dash_dcc_fresh_browser
368372
app = Dash(__name__)
369373

370374
app.layout = html.Div(

components/dash-core-components/tests/integration/confirmdialog/test_confirm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
],
2727
],
2828
)
29-
def test_cnfd001_dialog(dash_dcc, confirm_callback, confirms, components):
29+
def test_cnfd001_dialog(dash_dcc_fresh_browser, confirm_callback, confirms, components):
30+
dash_dcc = dash_dcc_fresh_browser
3031
app = Dash(__name__)
3132
app.layout = html.Div(components + [html.Div(id="confirmed")])
3233

components/dash-core-components/tests/integration/interval/test_interval.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
import time
44

55

6-
def test_intv001_interval(dash_dcc):
6+
def test_intv001_interval(dash_dcc_fresh_browser):
7+
dash_dcc = dash_dcc_fresh_browser
78
app = Dash(__name__)
89
app.layout = html.Div(
910
[

components/dash-core-components/tests/integration/link/test_absolute_path.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44

55
@pytest.mark.DCC782
6-
def test_lipa001_path(dash_dcc):
6+
def test_lipa001_path(dash_dcc_fresh_browser):
7+
dash_dcc = dash_dcc_fresh_browser
78
app = Dash(__name__)
89
app.layout = html.Div(
910
[

components/dash-core-components/tests/integration/misc/test_persistence.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from dash import Dash, Input, Output, dcc, html
77

88

9-
def test_msps001_basic_persistence(dash_dcc):
9+
def test_msps001_basic_persistence(dash_dcc_fresh_browser):
10+
dash_dcc = dash_dcc_fresh_browser
1011
app = Dash(__name__)
1112

1213
app.layout = html.Div(

components/dash-core-components/tests/integration/misc/test_platter.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from selenium.common.exceptions import WebDriverException
66

77

8-
def test_mspl001_dcc_components_platter(platter_app, dash_dcc):
8+
def test_mspl001_dcc_components_platter(platter_app, dash_dcc_fresh_browser):
9+
dash_dcc = dash_dcc_fresh_browser
910
dash_dcc.driver.set_window_size(800, 600)
1011
dash_dcc.start_server(platter_app)
1112

0 commit comments

Comments
 (0)