Skip to content

[ZEPPELIN-1836] Make testAngularRunParagraph wait for rendered Angular output#5250

Draft
jongyoul wants to merge 3 commits into
apache:masterfrom
jongyoul:ZEPPELIN-selenium-angular-paragraph
Draft

[ZEPPELIN-1836] Make testAngularRunParagraph wait for rendered Angular output#5250
jongyoul wants to merge 3 commits into
apache:masterfrom
jongyoul:ZEPPELIN-selenium-angular-paragraph

Conversation

@jongyoul
Copy link
Copy Markdown
Member

What is this PR for?

testAngularRunParagraph has been failing on every frontend.yml test-selenium-with-spark-module-for-spark-3-5 run on master since the last green build at 6353224 on 2026-04-23. The failure is always at ZeppelinIT.java:348:

org.openqa.selenium.TimeoutException: Expected condition failed: waiting for visibility of element located by By.xpath: (//div[@ng-controller="ParagraphCtrl"])[1]//div[@id="angularRunParagraph"] (tried for 30 second(s) with 500 milliseconds interval)

Tracing the server log confirms the angular paragraph re-run completes successfully on the server side (paragraph FINISHED, result broadcast) and the stalenessOf(oldAngularDiv) check before visibilityWait does succeed — so the old angularRunParagraph div is detached as expected. The new div, however, is not detected as visible within 30s.

The race lives on the frontend side of the re-render: AngularJS' renderAngular() does elem.html(generated) and then $compile(elem.contents())(paragraphScope). Between those two calls the result div can be momentarily detached or empty, which is exactly the window visibilityWait polls into. Once it gets a stale reference, the wait does not refetch.

This builds on the stalenessOf + JavaScript-click fix from ZEPPELIN-6409 (#5209). That fix proved the old output was being torn down; this PR makes the wait for the new output equally tolerant of mid-$compile DOM churn.

What type of PR is it?

Bug Fix

Todos

  • Replace single visibilityWait with a content-aware polling wait that re-finds the element and ignores StaleElementReferenceException
  • Mirror the content-based pattern already used after the first run (waitForText(\"Run second paragraph\", ...))

What is the Jira issue?

How should this be tested?

  • CI frontend.ymltest-selenium-with-spark-module-for-spark-3-5 should run ZeppelinIT.testAngularRunParagraph to completion without timing out at line 348.
  • Local repro (slow, requires -Pweb-classic and Spark 3.5):
    ./mvnw verify -DfailIfNoTests=false -pl zeppelin-integration \
      -Pweb-classic -Pintegration -Pspark-scala-2.12 -Pspark-3.5 -Pweb-dist -Pusing-source-tree \
      -Dit.test=ZeppelinIT#testAngularRunParagraph
    

Screenshots (if appropriate)

N/A

Questions:

  • Does the license files need to update? No
  • Is there breaking changes for older versions? No
  • Does this needs documentation? No

jongyoul and others added 3 commits May 18, 2026 22:40
…r output

After the rerun, visibilityWait alone races against AngularJS $compile —
the result div can briefly detach or render empty before settling, so the
wait times out at 30s on master frontend.yml runs.

Replace the single visibilityWait with a polling lambda that re-finds the
element each iteration, tolerates StaleElementReferenceException, and only
returns once the div is displayed *and* shows the expected text. This
mirrors the content-based pattern already used after the first run.

Builds on the stalenessOf + JS click fix from ZEPPELIN-6409.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lar paragraph

The 4ms FINISHED on the rerun + missing replacement div pointed at the
paragraph executing with stale (or empty) text: ACE's setValue does not
fire the 'input' event that paragraph.controller.js binds aceChanged
to, so paragraph.text never commits. If the angular paragraph's editor
was closed after the first run, $scope.editor is falsy and
getEditorValue() falls back to paragraph.text — sending the old body
to the interpreter, which echoes back an empty/stale ANGULAR result.
That explains the stalenessOf success followed by no new div.

Force the commit by writing the new text directly onto the paragraph
scope, syncing the ACE buffer when present, and running $apply.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…on race

The previous scope-commit attempt still saw the rerun finish in ~3ms with no
new div in 30s. That matches a stale/empty paragraph.text reaching the
backend, not just a render race:

* setTextOfParagraph(1, ...) clicks `icon-size-fullscreen`. After the first
  %angular run the paragraph has editorHide=true, so this toggle re-mounts
  the ACE editor; ace.edit(id).setValue() races with that re-mount.
* ACE setValue() does not fire the editor's 'input' event, so the binding
  $scope.editor.on('input', aceChanged) never runs and paragraph.text is
  never committed.
* runParagraphFromButton calls getEditorValue(), which returns
  paragraph.text when $scope.editor is falsy (between teardown and the new
  binding from the toggle). The backend then receives the previous body — or
  an empty one — and the AngularInterpreter echoes back identical/empty
  ANGULAR data. elem.html(empty) detaches the old div (stalenessOf passes)
  while leaving no replacement, which is exactly the observed timeline.

Drive the rerun through the controller's own runParagraph(text, ...) so
the new text is delivered no matter what the editor is doing. Tighten the
new-render wait to also require the ng-click attribute, so a stale-text
echo cannot satisfy the condition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jongyoul jongyoul force-pushed the ZEPPELIN-selenium-angular-paragraph branch from 60c3d75 to 92b58d2 Compare May 18, 2026 13:51
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