Skip to content
Merged
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
38 changes: 38 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version: 2.1

orbs:
browser-tools: circleci/browser-tools@1.4.0

jobs:
test:
docker:
- image: cimg/python:3.9.9-node
auth:
username: dashautomation
password: $DASH_PAT_DOCKERHUB
steps:
- checkout
- browser-tools/install-chrome
- browser-tools/install-chromedriver
- run:
name: Install Python deps
command: |
python -m venv venv && . venv/bin/activate
pip install --upgrade pip wheel
pip install -r tests/requirements.txt
- run:
name: Build package
command: |
. venv/bin/activate
npm ci
npm run build
- run:
name: Run tests
command: |
. venv/bin/activate
pytest --headless

workflows:
run-tests:
jobs:
- test
2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
[pytest]
junit_family = xunit1

testpaths = tests/
addopts = -rsxX -vv
log_format = %(asctime)s | %(levelname)s | %(name)s:%(lineno)d | %(message)s
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
50 changes: 50 additions & 0 deletions tests/test_column_drag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from dash import Dash, html
from dash_ag_grid import AgGrid
import plotly.express as px

from . import utils


df = px.data.election()
default_display_cols = ["district_id", "district", "winner"]


def test_cd001_drag_columns(dash_duo):
app = Dash()
app.layout = html.Div([
AgGrid(
id="grid",
rowData=df.to_dict("records"),
columnDefs=[
{"headerName": col.capitalize(), "field": col}
for col in default_display_cols
],
)
])

dash_duo.start_server(app)

grid = utils.Grid(dash_duo, "grid")

grid.wait_for_all_header_texts(["District_id", "District", "Winner"])
grid.wait_for_pinned_cols(0)
grid.wait_for_viewport_cols(3)

grid.drag_col(2, 0) # last column first but not pinned

grid.wait_for_all_header_texts(["Winner", "District_id", "District"])
grid.wait_for_pinned_cols(0)
grid.wait_for_viewport_cols(3)

grid.pin_col(1) # middle column pinned

grid.wait_for_all_header_texts(["District_id", "Winner", "District"])
grid.wait_for_pinned_cols(1)
grid.wait_for_viewport_cols(2)

# pin first non-pinned column by dragging it to its own left edge
grid.pin_col(1, 1)

grid.wait_for_all_header_texts(["District_id", "Winner", "District"])
grid.wait_for_pinned_cols(2)
grid.wait_for_viewport_cols(1)
35 changes: 35 additions & 0 deletions tests/test_filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from dash import Dash, html
from dash_ag_grid import AgGrid
import plotly.express as px

from . import utils


df = px.data.election()
default_display_cols = ["district_id", "district", "winner"]


def test_fi001_floating_filter(dash_duo):
app = Dash()
app.layout = html.Div([
AgGrid(
id="grid",
rowData=df.to_dict("records"),
columnDefs=[
{"headerName": col.capitalize(), "field": col}
for col in default_display_cols
],
defaultColDef={"filter": True, "floatingFilter": True}
)
])

dash_duo.start_server(app)

grid = utils.Grid(dash_duo, "grid")

grid.wait_for_cell_text(0, 1, "101-Bois-de-Liesse")

grid.set_filter(0, "12")

grid.wait_for_cell_text(0, 1, "112-DeLorimier")
grid.wait_for_rendered_rows(5)
98 changes: 98 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from selenium.webdriver.common.action_chains import ActionChains

from dash.testing.wait import until
from dash.testing.errors import TestingTimeoutError

# we use zero-based columns, but aria colindex is one-based
# so we need to add 1 in a lot of places

class Grid:
def __init__(self, dash_duo, grid_id):
self.dash_duo = dash_duo
self.id = grid_id

def get_header_cell(self, col):
return self.dash_duo.find_element(
f'#{self.id} [aria-rowindex="1"] .ag-header-cell[aria-colindex="{col + 1}"]'
)

def wait_for_header_text(self, col, expected):
self.dash_duo.wait_for_text_to_equal(
f'#{self.id} [aria-rowindex="1"] .ag-header-cell[aria-colindex="{col + 1}"] .ag-header-cell-text',
expected
)

def wait_for_all_header_texts(self, expected):
for col, val in enumerate(expected):
self.wait_for_header_text(col, val)
cols = len(self.dash_duo.find_elements(f'#{self.id} [aria-rowindex="1"] .ag-header-cell'))
assert cols == len(expected)

def _wait_for_count(self, selector, expected, description):
try:
until(lambda: len(self.dash_duo.find_elements(selector)) == expected, timeout=3)
except TestingTimeoutError:
els = self.dash_duo.find_elements(selector)
raise ValueError(f"found {len(els)} {description}, expected {expected}")


def wait_for_pinned_cols(self, expected):
# TODO: is there a pinned right?
self._wait_for_count(
f'#{self.id} .ag-pinned-left-header [aria-rowindex="1"] .ag-header-cell',
expected,
"pinned_cols"
)

def wait_for_viewport_cols(self, expected):
self._wait_for_count(
f'#{self.id} .ag-header-viewport [aria-rowindex="1"] .ag-header-cell',
expected,
"viewport_cols"
)

def drag_col(self, from_index, to_index):
from_col = self.get_header_cell(from_index)
to_col = self.get_header_cell(to_index)
(
ActionChains(self.dash_duo.driver)
.move_to_element(from_col)
.click_and_hold()
.move_to_location(
to_col.location["x"] + to_col.size["width"] * 0.8,
to_col.location["y"] + to_col.size["height"] * 0.5
)
.pause(0.5)
.release()
).perform()

def pin_col(self, col, pinned_cols=0):
from_col = self.get_header_cell(col)
pin_col = self.get_header_cell(pinned_cols)
(
ActionChains(self.dash_duo.driver)
.move_to_element(from_col)
.click_and_hold()
.move_to_location(
pin_col.location["x"] + pin_col.size["width"] * 0.1,
pin_col.location["y"] + pin_col.size["height"] * 0.5
)
.pause(1)
.release()
).perform()

def wait_for_rendered_rows(self, expected):
self._wait_for_count(f"#{self.id} .ag-row", expected, "rendered rows")

def wait_for_cell_text(self, row, col, expected):
self.dash_duo.wait_for_text_to_equal(
f'#{self.id} .ag-row[row-index="{row}"] .ag-cell[aria-colindex="{col + 1}"]',
expected
)

def set_filter(self, col, val):
filter_input = self.dash_duo.find_element(
f'#{self.id} .ag-floating-filter[aria-colindex="{col + 1}"] input'
)
self.dash_duo.clear_input(filter_input)
filter_input.send_keys(val)