Skip to content
Open
4 changes: 3 additions & 1 deletion nicegui/elements/echart/echart.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ export default {
return;
}
convertDynamicProperties(this.options, true);
this.chart.setOption(this.options, { notMerge: this.chart.options?.series.length != this.options.series.length });
this.chart.setOption(this.options, {
notMerge: this.chart.options?.series?.length != this.options.series?.length,
});
},
run_chart_method(name, ...args) {
if (name.startsWith(":")) {
Expand Down
1 change: 1 addition & 0 deletions nicegui/testing/screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def __init__(self, selenium: webdriver.Chrome, caplog: pytest.LogCaptureFixture,
self.connected = threading.Event()
app.on_connect(self.connected.set)
self.url = f'http://localhost:{self.PORT}'
self.allow_js_errors: bool = False

def start_server(self) -> None:
"""Start the webserver in a separate thread."""
Expand Down
7 changes: 7 additions & 0 deletions nicegui/testing/screen_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,10 @@ def screen(nicegui_reset_globals, # noqa: F811, pylint: disable=unused-argument
shutil.rmtree(DOWNLOAD_DIR)
if logs:
pytest.fail('There were unexpected ERROR logs.', pytrace=False)

if screen_.is_open:
browser_logs = screen_.selenium.get_log('browser')
js_errors = [e for e in browser_logs if str(e.get('level', '')).upper() in (
'SEVERE', 'ERROR')]
if js_errors and not screen_.allow_js_errors:
pytest.fail(f'JavaScript console errors:\n{js_errors}', pytrace=False)
Copy link

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message format {js_errors} will display the raw list representation which is hard to read. Consider formatting the errors more clearly, such as joining individual error messages or extracting relevant fields like message and source.

Suggested change
pytest.fail(f'JavaScript console errors:\n{js_errors}', pytrace=False)
formatted_errors = "\n".join(
f"- {e.get('message', str(e))}" for e in js_errors
)
pytest.fail(f'JavaScript console errors:\n{formatted_errors}', pytrace=False)

Copilot uses AI. Check for mistakes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not do that. Want full context.

1 change: 1 addition & 0 deletions tests/test_chat_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def page():
with pytest.raises(ValueError):
ui.chat_message('80€', text_html=True)

screen.allow_js_errors = True # Reason: accessing /x will trigger JS errors
screen.open('/')
screen.should_contain('10€')
screen.should_contain('20€')
Expand Down
2 changes: 1 addition & 1 deletion tests/test_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ class MyButton(ui.button):
def test_invalid_tags(screen: Screen):
@ui.page('/')
def page():
good_tags = ['div', 'div-1', 'DIV', 'däv', 'div_x', '🙂']
good_tags = ['div', 'div-1', 'DIV', 'däv', 'div_x'] # '🙂' is not valid, as it turns out
bad_tags = ['<div>', 'hi hi', 'hi/ho', 'foo$bar']
for tag in good_tags:
ui.element(tag)
Expand Down
11 changes: 10 additions & 1 deletion tests/test_endpoint_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,23 @@ def get_openapi_paths() -> set[str]:


def test_endpoint_documentation_default(screen: Screen):
@ui.page('/')
def page():
ui.markdown('Hey!')

screen.open('/')
assert get_openapi_paths() == set()


def test_endpoint_documentation_page_only(screen: Screen):
screen.ui_run_kwargs['endpoint_documentation'] = 'page'

@ui.page('/')
def page():
ui.markdown('Hey!')

screen.open('/')
assert get_openapi_paths() == set()
assert get_openapi_paths() == {'/'}
Copy link

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion change from set() to {'/'} suggests the test expectation has changed. However, the test name test_endpoint_documentation_page_only implies it should only document pages, but now it expects the root path to be documented. Verify this is the intended behavior.

Copilot uses AI. Check for mistakes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intended behaviour. Since added @ui.page('/') to all tests, thetest_endpoint_documentation_page_only would have {'/'} in get_openapi_paths()



def test_endpoint_documentation_internal_only(screen: Screen):
Expand Down
1 change: 1 addition & 0 deletions tests/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def page():
ui.html('<img src=x onerror=Quasar.Notify.create({message:"C"})>', sanitize=lambda x: x.replace('C', 'C!'))
ui.html('<img src=x onerror=Quasar.Notify.create({message:"D"})>', sanitize=Sanitizer().sanitize)

screen.allow_js_errors = True # Reason: accessing /x will trigger JS errors
screen.open('/')
screen.should_contain('A')
screen.should_contain('B')
Expand Down
2 changes: 2 additions & 0 deletions tests/test_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ def test_exception(screen: Screen):
def page():
raise RuntimeError('some exception')

screen.allow_js_errors = True # Reason: accessing / will trigger JS errors
screen.open('/')
screen.should_contain('500')
screen.should_contain('Server error')
Expand Down Expand Up @@ -310,5 +311,6 @@ async def page():
await asyncio.sleep(1)
ui.label('all done')

screen.allow_js_errors = True # Reason: / will error out due to intentional delay
screen.open('/')
screen.assert_py_logger('WARNING', re.compile('Response for / not ready after 0.5 seconds'))
1 change: 1 addition & 0 deletions tests/test_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ def page():
ui.label(app.storage.user.get('message', 'no message'))

core.app.user_middleware.clear() # remove the session middlewares added by prepare_simulation by default
screen.allow_js_errors = True # Reason: accessing / will trigger JS errors (it is missing)
screen.open('/')
screen.assert_py_logger('ERROR', 'app.storage.user needs a storage_secret passed in ui.run()')

Expand Down