Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/actions/setup-virtual-display/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: 'Setup virtual display'
description: 'Start an Xvfb virtual display and export DISPLAY for headed browser tests'

runs:
using: 'composite'
steps:
- name: Setup virtual display
shell: bash
run: |
sudo Xvfb :99 -ac -screen 0 1280x1024x24 >/dev/null 2>&1 &
disown
echo "DISPLAY=:99" >> $GITHUB_ENV
30 changes: 5 additions & 25 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,7 @@ jobs:
run: npm ci

- name: Setup virtual display
run: |
sudo apt-get update
sudo apt-get install -y xvfb
sudo Xvfb :99 -ac -screen 0 1280x1024x24 &
echo "DISPLAY=:99" >> $GITHUB_ENV
uses: ./.github/actions/setup-virtual-display

- name: Run lint
env:
Expand Down Expand Up @@ -672,11 +668,7 @@ jobs:
chrome-version: stable

- name: Setup virtual display
run: |
sudo apt-get update
sudo apt-get install -y xvfb
sudo Xvfb :99 -ac -screen 0 1280x1024x24 &
echo "DISPLAY=:99" >> $GITHUB_ENV
uses: ./.github/actions/setup-virtual-display

- name: Build/Setup test components
run: npm run setup-tests.py
Expand Down Expand Up @@ -777,11 +769,7 @@ jobs:
chrome-version: stable

- name: Setup virtual display
run: |
sudo apt-get update
sudo apt-get install -y xvfb
sudo Xvfb :99 -ac -screen 0 1280x1024x24 &
echo "DISPLAY=:99" >> $GITHUB_ENV
uses: ./.github/actions/setup-virtual-display

- name: Install HTML components dependencies
working-directory: components/dash-html-components
Expand Down Expand Up @@ -974,11 +962,7 @@ jobs:
chrome-version: stable

- name: Setup virtual display
run: |
sudo apt-get update
sudo apt-get install -y xvfb
sudo Xvfb :99 -ac -screen 0 1280x1024x24 &
echo "DISPLAY=:99" >> $GITHUB_ENV
uses: ./.github/actions/setup-virtual-display

- name: Remove DCC Python package and run tests
run: |
Expand Down Expand Up @@ -1058,11 +1042,7 @@ jobs:
chrome-version: stable

- name: Setup virtual display
run: |
sudo apt-get update
sudo apt-get install -y xvfb
sudo Xvfb :99 -ac -screen 0 1280x1024x24 &
echo "DISPLAY=:99" >> $GITHUB_ENV
uses: ./.github/actions/setup-virtual-display

- name: Install Table test dependencies
working-directory: components/dash-table
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
- [#3646](https://github.com/plotly/dash/pull/3646) Remove React 16 support (`16.14.0` is no longer an accepted value for `REACT_VERSION` / `_set_react_version`).

### Fixed
- Unpin `selenium` in the testing requirements (was capped at `<=4.2.0`, from 2022) and require `>=4.11.0`. The old cap predated Selenium Manager, so the pinned selenium could not drive the current stable Chrome (151+) that CI installs, producing widespread `StaleElementReferenceException`/`TimeoutException` flakiness across the browser-based integration tests. Modern selenium auto-provisions a matching chromedriver, restoring stable CI runs.
- [#3941](https://github.com/plotly/dash/pull/3941) Fix the FastAPI and Quart backends opening a WebSocket connection on every page load, even for apps with no WebSocket callbacks. The renderer keyed the connection on the mere presence of WebSocket infrastructure (always advertised by these backends) rather than on whether it was needed. The socket now opens eagerly only when `websocket_callbacks=True`; with just per-callback `websocket=True` it opens lazily on the first such callback dispatch, and an app with no WebSocket callbacks never opens one. Fixes [#3939](https://github.com/plotly/dash/issues/3939).
- [#3916](https://github.com/plotly/dash/pull/3916) Fixed a regression where dragging multiple files into `dcc.Upload` would upload only the first file when `multiple=True`
- [#3922](https://github.com/plotly/dash/pull/3922) Fix `dcc.Input(type="number")` stepper behavior when only `min` is set.
Expand Down
46 changes: 23 additions & 23 deletions components/dash-core-components/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions components/dash-core-components/tests/dash_core_components_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,18 @@ def click_and_hold_at_coord_fractions(self, elem_or_selector, fx, fy):
elem = self._get_element(elem_or_selector)

ActionChains(self.driver).move_to_element_with_offset(
elem, elem.size["width"] * fx, elem.size["height"] * fy
elem,
int(elem.size["width"] * (fx - 0.5)),
int(elem.size["height"] * (fy - 0.5)),
).click_and_hold().perform()

def move_to_coord_fractions(self, elem_or_selector, fx, fy):
elem = self._get_element(elem_or_selector)

ActionChains(self.driver).click_and_hold().move_to_element_with_offset(
elem, elem.size["width"] * fx, elem.size["height"] * fy
elem,
int(elem.size["width"] * (fx - 0.5)),
int(elem.size["height"] * (fy - 0.5)),
).perform()

def release(self):
Expand All @@ -120,7 +124,11 @@ def click_and_drag_at_coord_fractions(self, elem_or_selector, fx1, fy1, fx2, fy2
elem = self._get_element(elem_or_selector)

ActionChains(self.driver).move_to_element_with_offset(
elem, elem.size["width"] * fx1, elem.size["height"] * fy1
elem,
int(elem.size["width"] * (fx1 - 0.5)),
int(elem.size["height"] * (fy1 - 0.5)),
).click_and_hold().move_to_element_with_offset(
elem, elem.size["width"] * fx2, elem.size["height"] * fy2
elem,
int(elem.size["width"] * (fx2 - 0.5)),
int(elem.size["height"] * (fy2 - 0.5)),
).release().perform()
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,16 @@ def handleClick(clickData):

dash_dcc.find_elements("g .xy")[0].click()

data = dash_dcc.wait_for_element("#test-text-area").get_attribute("value")
# The clickData callback also fires once on load with clickData=None (value
# "null"); wait for the click's real payload before parsing, otherwise we
# race that initial value and json.loads returns None.
wait.until(
lambda: (dash_dcc.find_element("#test-text-area").get_attribute("value") or "")
not in ("", "null"),
timeout=3,
)

data = dash_dcc.find_element("#test-text-area").get_attribute("value")
assert data != "", "graph clickData must contain data"

data = json.loads(data)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# -*- coding: utf-8 -*-

from selenium.webdriver.common.by import By

import dash.testing.wait as wait
from dash import Dash, Input, Output, dcc, html


Expand Down Expand Up @@ -71,11 +74,21 @@ def update_md(nclicks):

# a highlighted node will have <span> children which are what color the text
code = dash_dcc.wait_for_element("code[data-highlighted='yes']")
assert len(code.find_elements_by_tag_name("span")) == 2
assert len(code.find_elements(By.TAG_NAME, "span")) == 2

dash_dcc.find_element("#md-trigger").click()

code = dash_dcc.wait_for_element("code[data-highlighted='yes']")
assert len(code.find_elements_by_tag_name("span")) == 3
# The click swaps the markdown via a callback and the block is re-highlighted
# asynchronously; poll for the new span count instead of reading it right
# after the click, which races the re-render and sees the old content.
wait.until(
lambda: len(
dash_dcc.find_element("code[data-highlighted='yes']").find_elements(
By.TAG_NAME, "span"
)
)
== 3,
timeout=4,
)

assert dash_dcc.get_logs() == []
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,14 @@ def make_output(*args):

dash_dcc.find_element("#dropdownsingle").click()
dash_dcc.find_element(".dash-dropdown-content .dash-dropdown-search").send_keys(
"one" + Keys.ENTER
"one"
)
# Wait for the option list to filter before pressing Enter; otherwise Enter
# can fire before "one" narrows the list and nothing gets selected, leaving
# this field null after reload.
dash_dcc.wait_for_element(".dash-dropdown-content .dash-dropdown-option")
dash_dcc.find_element(".dash-dropdown-content .dash-dropdown-search").send_keys(
Keys.ENTER
)

dash_dcc.find_element("#dropdownmulti").click()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,10 @@ def update_tooltip_content(hoverData):
elem = dash_dcc.find_element("#graph .nsewdrag")

with lock:
# hover on the center of the graph
# hover on the center of the graph (offset is measured from the
# element center in selenium >= 4.3, so 0, 0 is the center)
ActionChains(dash_dcc.driver).move_to_element_with_offset(
elem, elem.size["width"] / 2, elem.size["height"] / 2
elem, 0, 0
).click().perform()
dash_dcc.wait_for_text_to_equal("#graph-tooltip", loading_text)

Expand All @@ -83,7 +84,7 @@ def update_tooltip_content(hoverData):
elem = dash_dcc.find_element("#graph .nsewdrag")

ActionChains(dash_dcc.driver).move_to_element_with_offset(
elem, 5, elem.size["height"] - 5
elem, int(5 - elem.size["width"] / 2), int(elem.size["height"] / 2 - 5)
).perform()

until(lambda: not dash_dcc.find_element("#graph-tooltip").is_displayed(), 3)
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import time
from selenium.webdriver.common.by import By
from dash import Dash, dcc, html


Expand Down Expand Up @@ -41,16 +42,16 @@ def test_upca001_upload_children_gallery(dash_dcc):
time.sleep(0.5)
dash_dcc.percy_snapshot("upca001 children gallery")

first_child = dash_dcc.find_element("#upload").find_element_by_css_selector(
":first-child"
first_child = dash_dcc.find_element("#upload").find_element(
By.CSS_SELECTOR, ":first-child"
)
# Check that there is no default style since className is specified
style = first_child.get_attribute("style")
assert "opacity: 0.5" not in style

first_child = dash_dcc.find_element(
"#upload-no-className"
).find_element_by_css_selector(":first-child")
first_child = dash_dcc.find_element("#upload-no-className").find_element(
By.CSS_SELECTOR, ":first-child"
)

# Check that there is default style since no className is specified
style = first_child.get_attribute("style")
Expand Down
Loading
Loading