Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Stabilize flaky UI test #7620

Merged
merged 29 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
229dbeb
test: Stabilize flaky UI test
hoxbro Jan 16, 2025
256f430
Add expect to test_player_visible_loop_options
hoxbro Jan 16, 2025
a0779d1
Try to recreate the feed_el
hoxbro Jan 16, 2025
52e1cba
Fix to eager int conversion of empty string
hoxbro Jan 16, 2025
ff67b6c
Add more to scroll_to_latest
hoxbro Jan 16, 2025
832083e
Try to improve test_tabulator_patching_and_styling
hoxbro Jan 16, 2025
6f6c567
Merge branch 'main' into test_ui
hoxbro Jan 16, 2025
b8cbcf7
Updates to test-feed
hoxbro Jan 16, 2025
89941d8
Update to test_tabulator
hoxbro Jan 16, 2025
a778d3b
Try to remove global reruns
hoxbro Jan 16, 2025
7cb5b22
player test
hoxbro Jan 17, 2025
f4055c8
test tabulator
hoxbro Jan 17, 2025
6aa8adf
Mark convert and jupyter test as flaky
hoxbro Jan 17, 2025
3e815e1
chat test
hoxbro Jan 17, 2025
a834ebb
Mark feed as flaky
hoxbro Jan 17, 2025
5e1a0c6
Update test_feed
hoxbro Jan 17, 2025
2ec4eb1
Update test_icon flaky
hoxbro Jan 17, 2025
070195a
Set timeout to 30 min
hoxbro Jan 17, 2025
02e24f9
Fix flaky tests
hoxbro Jan 17, 2025
17f862f
Mark all reload test as flaky
hoxbro Jan 17, 2025
f44475c
Set longer timeout for custom tests
philippjfr Jan 17, 2025
ff95fa6
Fix type
philippjfr Jan 17, 2025
727a226
Close handles
philippjfr Jan 17, 2025
a5e1e5a
Only render first row to avoid complicating selector
philippjfr Jan 17, 2025
541cb12
revert back to previous state
hoxbro Jan 17, 2025
1dc2d90
Wait for images to load
hoxbro Jan 17, 2025
048b7c7
Increase timeout for windows
hoxbro Jan 17, 2025
6d8c794
Some tweaks to Feed test
philippjfr Jan 17, 2025
fe126dc
Update panel/tests/ui/io/test_convert.py
philippjfr Jan 17, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ jobs:
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
timeout-minutes: 90
timeout-minutes: 30
steps:
- uses: holoviz-dev/holoviz_tasks/pixi_install@v0
with:
Expand Down
1 change: 1 addition & 0 deletions panel/tests/chat/test_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,7 @@ def callback(contents, user, instance):

feed = ChatFeed(callback=callback)
feed.send("Message", respond=True)
await async_wait_until(lambda: len(feed.objects) == 2)
await async_wait_until(lambda: feed.objects[-1].object == "helloooo")
assert chat_feed._placeholder not in chat_feed._chat_log

Expand Down
1 change: 1 addition & 0 deletions panel/tests/command/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ def test_compile_component(py_file):
assert 'function render() {\n console.log("foo");\n}' in bundle.read_text()
finally:
bundle.unlink()
p.kill()
1 change: 1 addition & 0 deletions panel/tests/ui/chat/test_chat_interface_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def edit_callback(content, index, instance):

# find the input field and type new message
chat_input = page.locator(".bk-input").first
page.wait_for_timeout(200)
chat_input.fill("Edited")

# click enter
Expand Down
2 changes: 1 addition & 1 deletion panel/tests/ui/io/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
allow_module_level=True
)

pytestmark = pytest.mark.ui
pytestmark = [pytest.mark.ui, pytest.mark.flaky(max_runs=3)]


if os.name == "wt":
philippjfr marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
3 changes: 1 addition & 2 deletions panel/tests/ui/io/test_jupyter_server_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@

from panel.tests.util import wait_until

pytestmark = pytest.mark.jupyter

pytestmark = [pytest.mark.jupyter, pytest.mark.flaky(max_runs=3)]


def test_jupyter_server(page, jupyter_preview):
Expand Down
5 changes: 2 additions & 3 deletions panel/tests/ui/io/test_reload.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
try:
from playwright.sync_api import expect

pytestmark = pytest.mark.ui
pytestmark = [pytest.mark.ui, pytest.mark.flaky(reruns=3, reason="Writing files can sometimes be unpredictable")]
except ImportError:
pytestmark = pytest.mark.skip("playwright not available")
pytestmark = [pytest.mark.skip("playwright not available")]

from panel.io.state import state
from panel.tests.util import serve_component, wait_until
Expand Down Expand Up @@ -80,7 +80,6 @@

expect(page.locator('.alert')).to_have_count(1)

@pytest.mark.flaky(reruns=3, reason="Writing files can sometimes be unpredictable")
def test_reload_app_on_local_module_change(page, autoreload, py_files):
py_file, module = py_files
import_name = pathlib.Path(module.name).stem
Expand All @@ -104,4 +103,4 @@
pathlib.Path(module.name).touch()
time.sleep(0.1)

wait_until(lambda: expect(page.locator('.markdown')).to_have_text('bar'), page)

Check failure on line 106 in panel/tests/ui/io/test_reload.py

View workflow job for this annotation

GitHub Actions / ui:test-ui:macos-latest

test_reload_app_on_local_module_change TimeoutError: wait_until timed out in 5000 milliseconds: Locator expected to have text 'bar' Actual value: foo Call log: LocatorAssertions.to_have_text with timeout 5000ms - waiting for locator(".markdown") - locator resolved to <div class="bk-panel-models-markup-HTML markdown"></div> - unexpected value "foo " - locator resolved to <div class="bk-panel-models-markup-HTML markdown"></div> - unexpected value "foo " - locator resolved to <div class="bk-panel-models-markup-HTML markdown"></div> - unexpected value "foo " - locator resolved to <div class="bk-panel-models-markup-HTML markdown"></div> - unexpected value "foo " - locator resolved to <div class="bk-panel-models-markup-HTML markdown"></div> - unexpected value "foo " - locator resolved to <div class="bk-panel-models-markup-HTML markdown"></div> - unexpected value "foo " - locator resolved to <div class="bk-panel-models-markup-HTML markdown"></div> - unexpected value "foo "
1 change: 1 addition & 0 deletions panel/tests/ui/layout/test_column.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ def test_column_scroll_position_param_updated(page):
expect(column).to_have_js_property('scrollTop', 175)


@pytest.mark.flaky(reruns=3)
def test_column_scroll_to(page):
col = Column(
*list(range(100)),
Expand Down
16 changes: 9 additions & 7 deletions panel/tests/ui/layout/test_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from panel.layout.spacer import Spacer
from panel.tests.util import serve_component, wait_until

pytestmark = pytest.mark.ui
pytestmark = [pytest.mark.ui, pytest.mark.flaky(max_runs=3)]

ITEMS = 100 # 1000 items make the CI flaky

Expand Down Expand Up @@ -49,7 +49,7 @@ def test_feed_view_latest(page):
# Assert scroll is not at 0 (view_latest)
wait_until(lambda: feed_el.evaluate('(el) => el.scrollTop') > 0, page)

wait_until(lambda: int(page.locator('pre').last.inner_text()) > 0.9 * ITEMS, page)
wait_until(lambda: int(page.locator('pre').last.inner_text() or 0) > 0.9 * ITEMS, page)


def test_feed_view_scroll_to_latest(page):
Expand Down Expand Up @@ -127,11 +127,13 @@ def test_feed_scroll_to_latest_within_limit(page):
# assert auto scroll works; i.e. distance from bottom is 0
feed.append(Spacer(styles=dict(background='yellow'), width=200, height=200))

feed.scroll_to_latest(scroll_limit=100)
feed.scroll_to_latest(scroll_limit=1000)

def case():
philippjfr marked this conversation as resolved.
Show resolved Hide resolved
cmd = '(el) => el.scrollHeight - el.scrollTop - el.clientHeight'
assert feed_el.evaluate(cmd) == 0

wait_until(lambda: feed_el.evaluate(
'(el) => el.scrollHeight - el.scrollTop - el.clientHeight'
) == 0, page)
wait_until(case, page)


def test_feed_view_scroll_button(page):
Expand All @@ -150,7 +152,7 @@ def test_feed_view_scroll_button(page):

# Assert scroll is not at 0 (view_latest)
wait_until(lambda: feed_el.evaluate('(el) => el.scrollTop') > 0, page)
wait_until(lambda: int(page.locator('pre').last.inner_text()) > 50, page)
wait_until(lambda: int(page.locator('pre').last.inner_text() or 0) > 50, page)

def test_feed_dynamic_objects(page):
feed = Feed(height=250, load_buffer=10)
Expand Down
2 changes: 1 addition & 1 deletion panel/tests/ui/pane/test_markup.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def test_html_model_no_stylesheet(page):
serve_component(page, html)

header_element = page.locator('h1:has-text("Header")')
assert header_element.is_visible()
expect(header_element).to_be_visible()
assert header_element.text_content() == "Header"

def test_anchor_scroll(page):
Expand Down
7 changes: 7 additions & 0 deletions panel/tests/ui/test_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
pytestmark = pytest.mark.ui


@pytest.fixture(scope="module", autouse=True)
def set_expect_timeout():
expect.set_options(timeout=10_000)
yield
expect.set_options(timeout=5_000)
philippjfr marked this conversation as resolved.
Show resolved Hide resolved


class JSUpdate(JSComponent):

text = param.String()
Expand Down
7 changes: 5 additions & 2 deletions panel/tests/ui/widgets/test_icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,12 @@ def cb(event):

# update size
icon.size = "8em"
assert page.locator(".icon-tabler-ad-filled").bounding_box()["width"] >= 96
wait_until(lambda: page.locator(".icon-tabler-ad-filled").bounding_box() is not None, page)
wait_until(lambda: page.locator(".icon-tabler-ad-filled").bounding_box()["width"] > 96, page)

icon.size = "1em"
wait_until(lambda: page.locator(".icon-tabler-ad-filled").bounding_box()["width"] <= 24, page)
wait_until(lambda: page.locator(".icon-tabler-ad-filled").bounding_box() is not None, page)
wait_until(lambda: page.locator(".icon-tabler-ad-filled").bounding_box()["width"] < 24, page)


def test_toggle_icon_svg(page):
Expand Down
10 changes: 8 additions & 2 deletions panel/tests/ui/widgets/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ def create_file(value):
download = download_info.value
tmp = tempfile.NamedTemporaryFile(suffix='.txt')
download.save_as(tmp.name)
assert tmp.file.read().decode('utf-8') == 'abc'
try:
assert tmp.file.read().decode('utf-8') == 'abc'
finally:
tmp.close()

page.click('.bk-tab:not(.bk-active)')
page.click('.bk-tab:not(.bk-active)')
Expand All @@ -71,4 +74,7 @@ def create_file(value):
download = download_info.value
tmp = tempfile.NamedTemporaryFile(suffix='.txt')
download.save_as(tmp.name)
assert tmp.file.read().decode('utf-8') == 'abcdef'
try:
assert tmp.file.read().decode('utf-8') == 'abcdef'
finally:
tmp.close()
17 changes: 9 additions & 8 deletions panel/tests/ui/widgets/test_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test_name(page):
player = Player(name='test')
serve_component(page, player)

assert page.is_visible('label')
expect(page.locator('label')).to_have_count(3)
assert page.query_selector('.pn-player-value') is None

name = page.locator('.pn-player-title:has-text("test")')
Expand All @@ -75,16 +75,17 @@ def test_name_and_show_value(page):
player = Player(name='test', show_value=True)
serve_component(page, player)

assert page.is_visible('label')
expect(page.locator('label')).to_have_count(3)
assert page.query_selector('.pn-player-value') is not None

name = page.locator('.pn-player-title:has-text("test")')
expect(name).to_have_count(1)

def test_player_visible_buttons(page):
player = Player(visible_buttons=["play", "pause"])
serve_component(page, player)

assert page.is_visible(".play")
expect(page.locator(".play")).to_be_visible()
assert page.is_visible(".pause")
assert not page.is_visible(".reverse")
assert not page.is_visible(".first")
Expand All @@ -104,14 +105,14 @@ def test_player_visible_loop_options(page):
player = Player(visible_loop_options=["loop", "once"])
serve_component(page, player)

assert page.is_visible(".loop")
assert page.is_visible(".once")
assert not page.is_visible(".reflect")
expect(page.locator(".loop")).to_be_visible()
expect(page.locator(".once")).to_be_visible()
expect(page.locator(".reflect")).to_be_hidden()

player.visible_loop_options = ["reflect"]
expect(page.locator(".reflect")).to_be_visible()
assert not page.is_visible(".loop")
assert not page.is_visible(".once")
expect(page.locator(".loop")).to_be_hidden()
expect(page.locator(".once")).to_be_hidden()


def test_player_scale_buttons(page):
Expand Down
11 changes: 8 additions & 3 deletions panel/tests/ui/widgets/test_tabulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@
cell_edit = page.locator('input[type="date"]')
new_date = "1980-01-01"
cell_edit.fill(new_date)
page.wait_for_timeout(100)
# Need to Enter to validate the change
page.locator('input[type="date"]').press('Enter')
expect(page.locator(f'text="{new_date}"')).to_have_count(1)
Expand All @@ -597,6 +598,7 @@
cell_edit = page.locator('input[type="date"]')
new_date2 = "1990-01-01"
cell_edit.fill(new_date2)
page.wait_for_timeout(100)
# Escape invalidates the change
page.locator('input[type="date"]').press('Escape')
expect(page.locator(f'text="{new_date2}"')).to_have_count(0)
Expand Down Expand Up @@ -1081,11 +1083,11 @@
widths = 100
width = int(((df_mixed.shape[1] + 1) * widths) / 2)
df_mixed['tomodify'] = 'target'
widget = Tabulator(df_mixed, width=width, widths=widths)
widget = Tabulator(df_mixed.iloc[:1], width=width, widths=widths)

serve_component(page, widget)

cell = page.locator('text="target"').first
cell = page.locator('text="target"')
# Scroll to the right
cell.scroll_into_view_if_needed()
page.wait_for_timeout(200)
Expand Down Expand Up @@ -2432,6 +2434,8 @@

serve_component(page, widget)

expect(page.locator('.tabulator-cell')).not_to_have_count(0)

# Changing the highest value in the int column should
# update the style so that this cell gets a yellow background
widget.patch({'int': [(0, 100)]}, as_index=False)
Expand Down Expand Up @@ -2869,6 +2873,7 @@
assert len(widget.current_view) == 2


@pytest.mark.flaky(max_runs=3)
@pytest.mark.parametrize('pagination', ['remote', 'local'])
def test_tabulator_edit_event_and_header_filters_same_column_pagination(page, pagination):
df = pd.DataFrame({
Expand Down Expand Up @@ -2897,7 +2902,7 @@
cell = page.locator('text="B"').first
cell.click()
editable_cell = page.locator('input[type="text"]')
editable_cell.fill("Q")

Check failure on line 2905 in panel/tests/ui/widgets/test_tabulator.py

View workflow job for this annotation

GitHub Actions / ui:test-ui:macos-latest

test_tabulator_edit_event_and_header_filters_same_column_pagination[local] playwright._impl._errors.TimeoutError: Locator.fill: Timeout 20000ms exceeded. Call log: waiting for locator("input[type=\"text\"]")
editable_cell.press('Enter')

wait_until(lambda: len(values) == 1, page)
Expand All @@ -2907,7 +2912,6 @@
assert len(widget.current_view) == 4

page.locator('text="Last"').click()
page.wait_for_timeout(200)

# Check the table has the right number of rows
expect(page.locator('.tabulator-row')).to_have_count(2)
Expand Down Expand Up @@ -3494,6 +3498,7 @@
widget = Tabulator(df, sorters=[{"field": "x", "dir": "desc"}])

serve_component(page, widget)
expect(page.locator('.tabulator-cell')).to_have_count(0)

df2 = pd.DataFrame({'x': [0, 96, 116]})
widget.value = df2
Expand Down
2 changes: 1 addition & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ packaging = "*"
_install-ui = 'playwright install chromium'

[feature.test-ui.tasks.test-ui]
cmd = 'pytest panel/tests/ui --ui --browser chromium -n logical --dist loadgroup --reruns 3 --reruns-delay 10'
cmd = 'pytest panel/tests/ui --ui --browser chromium -n logical --dist loadgroup'
depends-on = ["_install-ui"]

# =============================================
Expand Down
Loading