This is an automated email from the ASF dual-hosted git repository.

jongyoul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 931a84ea3f [ZEPPELIN-6409][ZEPPELIN-6400] Fix Selenium integration 
test flakiness after
931a84ea3f is described below

commit 931a84ea3fa3a13d4d6ed491d2f7036071451f6f
Author: Jongyoul Lee <[email protected]>
AuthorDate: Sat Apr 11 20:35:21 2026 +0900

    [ZEPPELIN-6409][ZEPPELIN-6400] Fix Selenium integration test flakiness after
    
    ## Summary
    
    - **`authenticationUser()`**: Replace `sleep(1000)` with explicit wait for 
the navbar user dropdown to appear (proves login succeeded and AngularJS digest 
is done), then force-dismiss any lingering Bootstrap modal backdrop via jQuery
    - **`logoutUser()`**: Use `clickableWait()` instead of raw `findElement()` 
for robust element interaction; wrap modal close button in try-catch
    - **`testAngularRunParagraph()`**: Fix race condition where 
`waitForParagraph("FINISHED")` matched the *previous* run's state. Use 
`stalenessOf` to detect paragraph output refresh, then `visibilityWait` for the 
new element, and JavaScript click to bypass ng-click overlay issues
    
    ## Context
    
    After ZEPPELIN-6400 moved `ZeppelinConfiguration` from 
`zeppelin-interpreter` to `zeppelin-zengine`, `RemoteInterpreterServer.init()` 
changed from loading config via `ZeppelinConfiguration.load()` + overlay to 
pure `Properties`-based initialization. This subtle timing change in 
interpreter startup exposed pre-existing Selenium test flakiness in the 
`test-selenium-with-spark-module-for-spark-3-5` CI job.
    
    The CI failures were:
    - `InterpreterModeActionsIT.testPerUserIsolatedAction` — 
`ElementClickInterceptedException` because login modal was still visible when 
clicking the navigation dropdown
    - `ZeppelinIT.testAngularRunParagraph` — `TimeoutException` due to race 
condition: after re-running an Angular paragraph, the old output element was 
matched before the new one rendered
    
    ## Test plan
    
    - [x] CI: `frontend.yml` — `test-selenium-with-spark-module-for-spark-3-5` 
job passes
    - [x] CI: `frontend.yml` — All other E2E jobs remain green (Playwright auth 
failure is unrelated Firefox keyboard shortcut flakiness)
    
    Closes #5209 from jongyoul/ZEPPELIN-6409-fix-selenium-tests.
    
    Signed-off-by: Jongyoul Lee <[email protected]>
---
 .../org/apache/zeppelin/AbstractZeppelinIT.java    | 35 ++++++++++++++++------
 .../apache/zeppelin/integration/ZeppelinIT.java    | 25 ++++++++++++++--
 2 files changed, 48 insertions(+), 12 deletions(-)

diff --git 
a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
 
b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
index 6d2746eeab..1c5e8be00c 100644
--- 
a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
+++ 
b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java
@@ -61,21 +61,38 @@ abstract public class AbstractZeppelinIT {
         By.xpath("//*[@id='loginModalContent']//button[contains(.,'Login')]"),
         MAX_BROWSER_TIMEOUT_SEC).click();
 
-    ZeppelinITUtils.sleep(1000, false);
+    // Wait for the logged-in navbar user dropdown to appear (indicates login 
completed
+    // and Angular digest cycle has updated the DOM), then dismiss any 
leftover modal overlay
+    visibilityWait(
+        By.xpath("//div[contains(@class, 
'navbar-collapse')]//li//button[contains(@class, 'nav-btn dropdown-toggle 
ng-scope')]"),
+        MAX_BROWSER_TIMEOUT_SEC);
+    try {
+      ((JavascriptExecutor) manager.getWebDriver()).executeScript(
+          "$('.modal-backdrop').remove(); $('#loginModal').modal('hide');");
+    } catch (Exception e) {
+      // ignore if jQuery/Bootstrap not ready
+    }
+    ZeppelinITUtils.sleep(500, false);
   }
 
   protected void logoutUser(String userName) throws URISyntaxException {
     ZeppelinITUtils.sleep(500, false);
-    manager.getWebDriver().findElement(
-        By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" 
+ userName + "')]")).click();
+    clickableWait(
+        By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" 
+ userName + "')]"),
+        MAX_BROWSER_TIMEOUT_SEC).click();
     ZeppelinITUtils.sleep(500, false);
-    manager.getWebDriver().findElement(
-        By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" 
+ userName + "')]//a[@ng-click='navbar.logout()']")).click();
+    clickableWait(
+        By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" 
+ userName + "')]//a[@ng-click='navbar.logout()']"),
+        MAX_BROWSER_TIMEOUT_SEC).click();
     ZeppelinITUtils.sleep(2000, false);
-    if (manager.getWebDriver().findElement(
-        By.xpath("//*[@id='loginModal']//div[contains(@class, 
'modal-header')]/button")).isDisplayed()) {
-      manager.getWebDriver().findElement(
-          By.xpath("//*[@id='loginModal']//div[contains(@class, 
'modal-header')]/button")).click();
+    try {
+      WebElement closeButton = manager.getWebDriver().findElement(
+          By.xpath("//*[@id='loginModal']//div[contains(@class, 
'modal-header')]/button"));
+      if (closeButton.isDisplayed()) {
+        closeButton.click();
+      }
+    } catch (NoSuchElementException e) {
+      // login modal close button not found, which is fine
     }
     manager.getWebDriver().get(new 
URI(manager.getWebDriver().getCurrentUrl()).resolve("/classic/#/").toString());
     ZeppelinITUtils.sleep(500, false);
diff --git 
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java
 
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java
index 003f7cc537..745cfd284b 100644
--- 
a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java
+++ 
b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java
@@ -33,11 +33,15 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
+import java.time.Duration;
 import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.Keys;
 import org.openqa.selenium.StaleElementReferenceException;
 import org.openqa.selenium.TimeoutException;
 import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -326,16 +330,31 @@ class ZeppelinIT extends AbstractZeppelinIT {
               "%angular <div id=\\'angularRunParagraph\\' 
ng-click=\\'z.runParagraph(\""
                       + secondParagraphId.trim()
                       + "\")\\'>Run second paragraph</div>");
+
+      // Capture old output element before re-run to detect when it gets 
replaced
+      WebElement oldAngularDiv = manager.getWebDriver().findElement(By.xpath(
+              getParagraphXPath(1) + "//div[@id=\"angularRunParagraph\"]"));
+
       runParagraph(1);
+
+      // Wait for the old output element to become stale (proves the paragraph 
output
+      // was actually refreshed, avoiding race where waitForParagraph sees the 
old FINISHED state)
+      new WebDriverWait(manager.getWebDriver(), 
Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))
+              .until(ExpectedConditions.stalenessOf(oldAngularDiv));
+
       waitForParagraph(1, "FINISHED");
 
+      // Wait for new Angular output to render
+      WebElement newAngularDiv = visibilityWait(By.xpath(
+              getParagraphXPath(1) + "//div[@id=\"angularRunParagraph\"]"), 
MAX_BROWSER_TIMEOUT_SEC);
+
       // Set new text value for 2nd paragraph
       setTextOfParagraph(2, "%sh echo NEW_VALUE");
 
-      // Click on 1 paragraph to trigger z.runParagraph() function
-
+      // Click on Angular-rendered div to trigger z.runParagraph() function.
+      // Use JavaScript click to bypass overlay/clickability issues with 
ng-click elements.
+      ((JavascriptExecutor) 
manager.getWebDriver()).executeScript("arguments[0].click();", newAngularDiv);
       ZeppelinITUtils.sleep(1000, false);
-      clickAndWait(By.xpath(getParagraphXPath(1) + 
"//div[@id=\"angularRunParagraph\"]"));
 
       waitForParagraph(2, "FINISHED");
 

Reply via email to