Skip to content

Serve the alternate UI framework locally instead of from a CDN - #288

Draft
evnchn wants to merge 1 commit into
mainfrom
fix/element-plus-cdn-flake
Draft

Serve the alternate UI framework locally instead of from a CDN#288
evnchn wants to merge 1 commit into
mainfrom
fix/element-plus-cdn-flake

Conversation

@evnchn

@evnchn evnchn commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Drafted by Claude Code on evnchn's behalf.

Fork staging PR — for review before anything goes upstream. Carries a judgement call worth a maintainer's opinion — see "Decision for review" below.

Motivation

tests/test_alternate_ui_frameworks.py::test_element_plus fetched https://unpkg.com/element-plus at test time. It was the only test in the suite with an external network dependency, and it fails in the merge queue when that fetch is slow.

Observed (run 30927252265, py3.11) — the page load itself stalls, so it dies before any assertion:

    screen.open('/')
E   selenium ... {'error': 'timeout', 'message': 'timeout: Timed out receiving message from renderer: 3xx'}

Reproducing it locally with CDP network blocking surfaced two distinct failure modes, not one:

CDN behaviour symptom
slow / hanging page-load TimeoutException (what CI hit)
blocked / refused page loads, el-button never upgrades → NoSuchElementException

and in both cases the console logs Uncaught ReferenceError: ElementPlus is not defined, which screen_plugin.py turns into a job failure independently of the test result.

Implementation

Serve the alternate framework from the local test server instead of a CDN:

@app.get('/alternate-ui.js')
def alternate_ui():
    return PlainTextResponse(UI_FRAMEWORK_BUNDLE, media_type='text/javascript')

Deliberately kept as a <script defer> external script, not an inline one, so the test still exercises the ordering that matters — that vue_config_script's app.use(...) runs after a deferred external bundle has loaded. An inline stub would have quietly dropped that coverage. The rest of the path (add_body_htmlvue_config_script → custom element renders) is unchanged.

Follows the existing precedent in tests/test_aggrid.py::test_set_module_source, which already serves a JS bundle from a test route.

Verification

It passes, and — more importantly — it can still fail. A stub test that is vacuously green would be worse than the flake it replaces, so I sabotaged the line under test:

normal                                   : 2 passed in 1.79s
vue_config_script line replaced with pass: 1 failed   ← the test genuinely guards the integration

Offline by construction — the only URL referenced is the relative /alternate-ui.js; no external host is contacted. Runtime drops to ~1.8 s with no network variance.

Gates: pre-commit all Passed · mypy clean over 245 source files · pylint 10.00/10.

The approach I tried first, and why I abandoned it

My first attempt kept the real CDN and skipped the test when it was unavailable:

with contextlib.suppress(TimeoutException):
    screen.open('/')
if not screen.selenium.execute_script('return window.ElementPlus !== undefined'):
    screen.allowed_js_errors.append('ElementPlus is not defined')
    pytest.skip('unpkg.com did not serve element-plus')

It worked — verified 1 skipped with the CDN blocked and 2 passed with it up, including whitelisting the console error that would otherwise fail teardown regardless of the skip.

Rejected anyway. window.ElementPlus === undefined does not only mean "CDN down" — it is also what you get if unpkg changes the bundle shape, or if a NiceGUI regression breaks add_body_html / vue_config_script ordering. The skip would convert a real regression into permanently green CI that tests nothing. Trading a loud flake for a silent hole is a bad trade. (Raised as a MUST-FIX by a second-lineage review; I agree with it.)

Decision for review

This removes CI's dependence on unpkg.com, at the cost of no longer proving that a real third-party framework works — it proves NiceGUI's plumbing works with an external deferred bundle, using a synthetic one.

If that coverage is wanted, the alternatives are:

  1. Vendor a pinned element-plus asset into the repo and serve it from the same route — keeps real coverage, offline, but commits a large third-party bundle.
  2. Keep test_element_plus as an opt-in test excluded from the default CI run (e.g. behind a marker), so the offline test guards every run and the real-CDN one is available on demand.

Happy to switch to either; option 2 is a small addition on top of this PR.

Progress

  • The PR title is a short phrase starting with a verb like "Add ...", "Fix ...", "Update ...", "Remove ...", etc.
  • The implementation is complete.
  • This PR does not address a security issue.
  • Pytests have been added/updated — this PR is a test change.
  • Documentation is not necessary.
  • No breaking changes to the public API — test-only change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant