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

chanholee pushed a commit to branch branch-0.12
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/branch-0.12 by this push:
     new 5196cbfbdc [ZEPPELIN-6358] simplify utils, promote POM usage, and 
consolidate base logic from #5101
5196cbfbdc is described below

commit 5196cbfbdcb0ce4a2e04a939592788bad0b8111d
Author: YONGJAE LEE(이용재) <[email protected]>
AuthorDate: Sun Feb 22 20:40:14 2026 +0900

    [ZEPPELIN-6358] simplify utils, promote POM usage, and consolidate base 
logic from #5101
    
    ### What is this PR for?
    
    ### PR Description
    
    This PR improves the readability and maintainability of the E2E notebook 
tests.
    
    - Removed over-abstracted util and wrapper methods
    - Moved test logic from util files into the test cases
    - Simplified page objects to focus on direct UI interactions
    - Consolidated shared logic into a base page class
    
    As a result, the tests are clearer, flatter, and easier to maintain.
    
    ### What type of PR is it?
    Refactoring
    
    ### Todos
    
    ### What is the Jira issue?
    ZEPPELIN-6358
    
    ### How should this be tested?
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Closes #5131 from dididy/e2e/notebook-edited.
    
    Signed-off-by: ChanHo Lee <[email protected]>
    (cherry picked from commit 1662cbdaf057d375d34cf911cb5a96a03744cd71)
---
 zeppelin-web-angular/e2e/models/base-page.ts       |  69 +++++-
 .../models/{theme.page.ts => dark-mode-page.ts}    |  14 +-
 zeppelin-web-angular/e2e/models/home-page.ts       | 144 +++---------
 zeppelin-web-angular/e2e/models/home-page.util.ts  | 233 -------------------
 zeppelin-web-angular/e2e/models/login-page.ts      |  20 +-
 .../e2e/models/notebook-repo-item.util.ts          |  37 +++
 .../e2e/models/notebook-repos-page.ts              |  29 ++-
 .../e2e/models/notebook-repos-page.util.ts         | 137 -----------
 zeppelin-web-angular/e2e/models/notebook.util.ts   |  24 +-
 .../e2e/models/published-paragraph-page.ts         |  32 +--
 .../e2e/models/published-paragraph-page.util.ts    | 222 +-----------------
 zeppelin-web-angular/e2e/models/workspace-page.ts  |   9 -
 .../e2e/models/workspace-page.util.ts              |  38 +---
 zeppelin-web-angular/e2e/tests/app.spec.ts         |  14 +-
 .../anonymous-login-redirect.spec.ts               | 102 +++++----
 .../e2e/tests/home/home-page-elements.spec.ts      |  63 +++---
 .../home/home-page-enhanced-functionality.spec.ts  |  60 +++--
 .../tests/home/home-page-external-links.spec.ts    |  48 ++--
 .../e2e/tests/home/home-page-layout.spec.ts        |  14 +-
 .../tests/home/home-page-note-operations.spec.ts   |  43 ++--
 .../tests/home/home-page-notebook-actions.spec.ts  |  67 ++++--
 .../notebook/published/published-paragraph.spec.ts | 251 ++++++++++++++++-----
 .../e2e/tests/theme/dark-mode.spec.ts              |  86 +++----
 .../notebook-repo-item-display.spec.ts             |   2 +-
 .../notebook-repos/notebook-repo-item-edit.spec.ts |  15 +-
 .../notebook-repo-item-form-validation.spec.ts     |  42 +---
 .../notebook-repo-item-settings.spec.ts            |  26 +--
 .../notebook-repo-item-workflow.spec.ts            |  33 +--
 .../notebook-repos-page-structure.spec.ts          |  13 +-
 .../e2e/tests/workspace/workspace-main.spec.ts     |  37 ++-
 zeppelin-web-angular/e2e/utils.ts                  |   2 +-
 31 files changed, 707 insertions(+), 1219 deletions(-)

diff --git a/zeppelin-web-angular/e2e/models/base-page.ts 
b/zeppelin-web-angular/e2e/models/base-page.ts
index c3d9004fde..539f096cbb 100644
--- a/zeppelin-web-angular/e2e/models/base-page.ts
+++ b/zeppelin-web-angular/e2e/models/base-page.ts
@@ -10,7 +10,7 @@
  * limitations under the License.
  */
 
-import { Locator, Page } from '@playwright/test';
+import { expect, Locator, Page } from '@playwright/test';
 
 export const E2E_TEST_FOLDER = 'E2E_TEST_FOLDER';
 export const BASE_URL = 'http://localhost:4200';
@@ -23,12 +23,32 @@ export class BasePage {
   readonly zeppelinPageHeader: Locator;
   readonly zeppelinHeader: Locator;
 
+  readonly modalTitle: Locator;
+  readonly modalBody: Locator;
+  readonly modalContent: Locator;
+
+  readonly okButton: Locator;
+  readonly cancelButton: Locator;
+  readonly runButton: Locator;
+
+  readonly welcomeTitle: Locator;
+
   constructor(page: Page) {
     this.page = page;
     this.zeppelinNodeList = page.locator('zeppelin-node-list');
     this.zeppelinWorkspace = page.locator('zeppelin-workspace');
     this.zeppelinPageHeader = page.locator('zeppelin-page-header');
     this.zeppelinHeader = page.locator('zeppelin-header');
+
+    this.modalTitle = page.locator('.ant-modal-confirm-title, 
.ant-modal-title');
+    this.modalBody = page.locator('.ant-modal-confirm-content, 
.ant-modal-body');
+    this.modalContent = page.locator('.ant-modal-body');
+
+    this.okButton = page.locator('button:has-text("OK")');
+    this.cancelButton = page.locator('button:has-text("Cancel")');
+    this.runButton = page.locator('button:has-text("Run")');
+
+    this.welcomeTitle = page.getByRole('heading', { name: 'Welcome to 
Zeppelin!' });
   }
 
   async waitForPageLoad(): Promise<void> {
@@ -63,4 +83,51 @@ export class BasePage {
   async getElementText(locator: Locator): Promise<string> {
     return (await locator.textContent()) || '';
   }
+
+  async waitForFormLabels(labelTexts: string[], timeout = 10000): 
Promise<void> {
+    await this.page.waitForFunction(
+      texts => {
+        const labels = Array.from(document.querySelectorAll('nz-form-label'));
+        return texts.some(text => labels.some(l => 
l.textContent?.includes(text)));
+      },
+      labelTexts,
+      { timeout }
+    );
+  }
+
+  async waitForElementAttribute(
+    selector: string,
+    attribute: string,
+    exists: boolean = true,
+    timeout = 10000
+  ): Promise<void> {
+    const locator = this.page.locator(selector);
+    if (exists) {
+      await expect(locator).toHaveAttribute(attribute, { timeout });
+    } else {
+      await expect(locator).not.toHaveAttribute(attribute, { timeout });
+    }
+  }
+
+  async waitForRouterOutletChild(timeout = 10000): Promise<void> {
+    await expect(this.page.locator('zeppelin-workspace router-outlet + 
*')).toHaveCount(1, { timeout });
+  }
+
+  async fillAndVerifyInput(
+    locator: Locator,
+    value: string,
+    options?: { timeout?: number; clearFirst?: boolean }
+  ): Promise<void> {
+    const { timeout = 10000, clearFirst = true } = options || {};
+
+    await expect(locator).toBeVisible({ timeout });
+    await expect(locator).toBeEnabled({ timeout: 5000 });
+
+    if (clearFirst) {
+      await locator.clear();
+    }
+
+    await locator.fill(value);
+    await expect(locator).toHaveValue(value);
+  }
 }
diff --git a/zeppelin-web-angular/e2e/models/theme.page.ts 
b/zeppelin-web-angular/e2e/models/dark-mode-page.ts
similarity index 81%
rename from zeppelin-web-angular/e2e/models/theme.page.ts
rename to zeppelin-web-angular/e2e/models/dark-mode-page.ts
index 5285ac4590..98f77c8933 100644
--- a/zeppelin-web-angular/e2e/models/theme.page.ts
+++ b/zeppelin-web-angular/e2e/models/dark-mode-page.ts
@@ -11,36 +11,36 @@
  */
 
 import { expect, Locator, Page } from '@playwright/test';
+import { BasePage } from './base-page';
 
-export class ThemePage {
-  readonly page: Page;
+export class DarkModePage extends BasePage {
   readonly themeToggleButton: Locator;
   readonly rootElement: Locator;
 
   constructor(page: Page) {
-    this.page = page;
+    super(page);
     this.themeToggleButton = page.locator('zeppelin-theme-toggle button');
     this.rootElement = page.locator('html');
   }
 
   async toggleTheme() {
-    await this.themeToggleButton.click();
+    await this.themeToggleButton.click({ timeout: 15000 });
   }
 
   async assertDarkTheme() {
-    await expect(this.rootElement).toHaveClass(/dark/);
+    await expect(this.rootElement).toHaveClass(/dark/, { timeout: 10000 });
     await expect(this.rootElement).toHaveAttribute('data-theme', 'dark');
     await expect(this.themeToggleButton).toHaveText('dark_mode');
   }
 
   async assertLightTheme() {
-    await expect(this.rootElement).toHaveClass(/light/);
+    await expect(this.rootElement).toHaveClass(/light/, { timeout: 10000 });
     await expect(this.rootElement).toHaveAttribute('data-theme', 'light');
     await expect(this.themeToggleButton).toHaveText('light_mode');
   }
 
   async assertSystemTheme() {
-    await expect(this.themeToggleButton).toHaveText('smart_toy');
+    await expect(this.themeToggleButton).toHaveText('smart_toy', { timeout: 
60000 });
   }
 
   async setThemeInLocalStorage(theme: 'light' | 'dark' | 'system') {
diff --git a/zeppelin-web-angular/e2e/models/home-page.ts 
b/zeppelin-web-angular/e2e/models/home-page.ts
index 872784dfa0..52c39df8b3 100644
--- a/zeppelin-web-angular/e2e/models/home-page.ts
+++ b/zeppelin-web-angular/e2e/models/home-page.ts
@@ -11,18 +11,12 @@
  */
 
 import { expect, Locator, Page } from '@playwright/test';
-import { getCurrentPath, waitForUrlNotContaining } from '../utils';
 import { BasePage } from './base-page';
 
 export class HomePage extends BasePage {
-  readonly welcomeHeading: Locator;
   readonly notebookSection: Locator;
   readonly helpSection: Locator;
   readonly communitySection: Locator;
-  readonly createNewNoteButton: Locator;
-  readonly importNoteButton: Locator;
-  readonly searchInput: Locator;
-  readonly filterInput: Locator;
   readonly zeppelinLogo: Locator;
   readonly anonymousUserIndicator: Locator;
   readonly welcomeSection: Locator;
@@ -31,11 +25,12 @@ export class HomePage extends BasePage {
   readonly helpCommunityColumn: Locator;
   readonly welcomeDescription: Locator;
   readonly refreshNoteButton: Locator;
-  readonly refreshIcon: Locator;
-  readonly notebookList: Locator;
   readonly notebookHeading: Locator;
   readonly helpHeading: Locator;
   readonly communityHeading: Locator;
+  readonly createNoteModal: Locator;
+  readonly createNoteButton: Locator;
+  readonly notebookNameInput: Locator;
   readonly externalLinks: {
     documentation: Locator;
     mailingList: Locator;
@@ -52,27 +47,13 @@ export class HomePage extends BasePage {
       clearOutput: Locator;
       moveToTrash: Locator;
     };
-    folderActions: {
-      createNote: Locator;
-      renameFolder: Locator;
-      moveToTrash: Locator;
-    };
-    trashActions: {
-      restoreAll: Locator;
-      emptyAll: Locator;
-    };
   };
 
   constructor(page: Page) {
     super(page);
-    this.welcomeHeading = page.locator('h1', { hasText: 'Welcome to Zeppelin!' 
});
     this.notebookSection = page.locator('text=Notebook').first();
     this.helpSection = page.locator('text=Help').first();
     this.communitySection = page.locator('text=Community').first();
-    this.createNewNoteButton = page.locator('text=Create new Note');
-    this.importNoteButton = page.locator('text=Import Note');
-    this.searchInput = page.locator('textbox', { hasText: 'Search' });
-    this.filterInput = page.locator('input[placeholder*="Filter"]');
     this.zeppelinLogo = page.locator('text=Zeppelin').first();
     this.anonymousUserIndicator = page.locator('text=anonymous');
     this.welcomeSection = page.locator('.welcome');
@@ -81,11 +62,12 @@ export class HomePage extends BasePage {
     this.helpCommunityColumn = page.locator('[nz-col]').last();
     this.welcomeDescription = page.locator('.welcome').getByText('Zeppelin is 
web-based notebook');
     this.refreshNoteButton = page.locator('a.refresh-note');
-    this.refreshIcon = page.locator('a.refresh-note i[nz-icon]');
-    this.notebookList = page.locator('zeppelin-node-list');
     this.notebookHeading = this.notebookColumn.locator('h3');
     this.helpHeading = page.locator('h3').filter({ hasText: 'Help' });
     this.communityHeading = page.locator('h3').filter({ hasText: 'Community' 
});
+    this.createNoteModal = page.locator('div.ant-modal-content');
+    this.createNoteButton = this.createNoteModal.locator('button', { hasText: 
'Create' });
+    this.notebookNameInput = 
this.createNoteModal.locator('input[name="noteName"]');
 
     this.externalLinks = {
       documentation: page.locator('a[href*="zeppelin.apache.org/docs"]'),
@@ -103,67 +85,30 @@ export class HomePage extends BasePage {
         renameNote: page.locator('.file .operation a[nztooltiptitle*="Rename 
note"]'),
         clearOutput: page.locator('.file .operation a[nztooltiptitle*="Clear 
output"]'),
         moveToTrash: page.locator('.file .operation a[nztooltiptitle*="Move 
note to Trash"]')
-      },
-      folderActions: {
-        createNote: page.locator('.folder .operation a[nztooltiptitle*="Create 
new note"]'),
-        renameFolder: page.locator('.folder .operation 
a[nztooltiptitle*="Rename folder"]'),
-        moveToTrash: page.locator('.folder .operation a[nztooltiptitle*="Move 
folder to Trash"]')
-      },
-      trashActions: {
-        restoreAll: page.locator('.folder .operation 
a[nztooltiptitle*="Restore all"]'),
-        emptyAll: page.locator('.folder .operation a[nztooltiptitle*="Empty 
all"]')
       }
     };
   }
 
-  async navigateToHome(): Promise<void> {
-    await this.page.goto('/', { waitUntil: 'load' });
-    await this.waitForPageLoad();
-  }
-
   async navigateToLogin(): Promise<void> {
-    await this.page.goto('/#/login', { waitUntil: 'load' });
-    await this.waitForPageLoad();
+    await this.navigateToRoute('/login');
     // Wait for potential redirect to complete by checking URL change
-    await waitForUrlNotContaining(this.page, '#/login');
+    await this.waitForUrlNotContaining('#/login');
   }
 
   async isHomeContentDisplayed(): Promise<boolean> {
-    try {
-      await expect(this.welcomeHeading).toBeVisible();
-      return true;
-    } catch {
-      return false;
-    }
+    return this.welcomeTitle.isVisible();
   }
 
   async isAnonymousUser(): Promise<boolean> {
-    try {
-      await expect(this.anonymousUserIndicator).toBeVisible();
-      return true;
-    } catch {
-      return false;
-    }
+    return this.anonymousUserIndicator.isVisible();
   }
 
   async clickZeppelinLogo(): Promise<void> {
-    await this.zeppelinLogo.click();
-  }
-
-  async getCurrentURL(): Promise<string> {
-    return this.page.url();
-  }
-
-  getCurrentPath(): string {
-    return getCurrentPath(this.page);
-  }
-
-  async getPageTitle(): Promise<string> {
-    return this.page.title();
+    await this.zeppelinLogo.click({ timeout: 15000 });
   }
 
   async getWelcomeHeadingText(): Promise<string> {
-    const text = await this.welcomeHeading.textContent();
+    const text = await this.welcomeTitle.textContent();
     return text || '';
   }
 
@@ -173,65 +118,48 @@ export class HomePage extends BasePage {
   }
 
   async clickRefreshNotes(): Promise<void> {
-    await this.refreshNoteButton.click();
+    await this.refreshNoteButton.click({ timeout: 15000 });
   }
 
   async isNotebookListVisible(): Promise<boolean> {
-    return this.notebookList.isVisible();
+    return this.zeppelinNodeList.isVisible();
   }
 
   async clickCreateNewNote(): Promise<void> {
-    await this.nodeList.createNewNoteLink.click();
+    await this.nodeList.createNewNoteLink.click({ timeout: 15000 });
+    await this.createNoteModal.waitFor({ state: 'visible' });
   }
 
-  async clickImportNote(): Promise<void> {
-    await this.nodeList.importNoteLink.click();
-  }
+  async createNote(notebookName: string): Promise<void> {
+    await this.clickCreateNewNote();
 
-  async filterNotes(searchTerm: string): Promise<void> {
-    await this.nodeList.filterInput.fill(searchTerm);
-  }
+    // Wait for the modal form to be fully rendered with proper labels
+    await this.page.waitForSelector('nz-form-label', { timeout: 10000 });
 
-  async isRefreshIconSpinning(): Promise<boolean> {
-    const spinAttribute = await this.refreshIcon.getAttribute('nzSpin');
-    return spinAttribute === 'true' || spinAttribute === '';
-  }
+    await this.waitForFormLabels(['Note Name', 'Clone Note']);
 
-  async waitForRefreshToComplete(): Promise<void> {
-    await this.page.waitForFunction(
-      () => {
-        const icon = document.querySelector('a.refresh-note i[nz-icon]');
-        return icon && !icon.hasAttribute('nzSpin');
-      },
-      { timeout: 10000 }
-    );
+    // Fill and verify the notebook name input
+    await this.fillAndVerifyInput(this.notebookNameInput, notebookName);
+
+    // Click the 'Create' button in the modal
+    await expect(this.createNoteButton).toBeEnabled({ timeout: 5000 });
+    await this.createNoteButton.click({ timeout: 15000 });
+    await this.waitForPageLoad();
   }
 
-  async getDocumentationLinkHref(): Promise<string | null> {
-    return this.externalLinks.documentation.getAttribute('href');
+  async clickImportNote(): Promise<void> {
+    await this.nodeList.importNoteLink.click({ timeout: 15000 });
   }
 
-  async areExternalLinksVisible(): Promise<boolean> {
-    const links = [
-      this.externalLinks.documentation,
-      this.externalLinks.mailingList,
-      this.externalLinks.issuesTracking,
-      this.externalLinks.github
-    ];
-
-    for (const link of links) {
-      if (!(await link.isVisible())) {
-        return false;
-      }
-    }
-    return true;
+  async filterNotes(searchTerm: string): Promise<void> {
+    await this.nodeList.filterInput.fill(searchTerm, { timeout: 15000 });
   }
 
-  async isWelcomeSectionVisible(): Promise<boolean> {
-    return this.welcomeSection.isVisible();
+  async waitForRefreshToComplete(): Promise<void> {
+    await this.waitForElementAttribute('a.refresh-note i[nz-icon]', 'nzSpin', 
false);
   }
 
-  async isMoreInfoGridVisible(): Promise<boolean> {
-    return this.moreInfoGrid.isVisible();
+  async getDocumentationLinkHref(): Promise<string | null> {
+    return this.externalLinks.documentation.getAttribute('href');
   }
 }
diff --git a/zeppelin-web-angular/e2e/models/home-page.util.ts 
b/zeppelin-web-angular/e2e/models/home-page.util.ts
deleted file mode 100644
index 5a5a6ff210..0000000000
--- a/zeppelin-web-angular/e2e/models/home-page.util.ts
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *     http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { expect, Page } from '@playwright/test';
-import { getBasicPageMetadata } from '../utils';
-import { HomePage } from './home-page';
-
-export class HomePageUtil {
-  private homePage: HomePage;
-  private page: Page;
-
-  constructor(page: Page) {
-    this.page = page;
-    this.homePage = new HomePage(page);
-  }
-
-  async verifyAnonymousUserRedirectFromLogin(): Promise<{
-    isLoginUrlMaintained: boolean;
-    isHomeContentDisplayed: boolean;
-    isAnonymousUser: boolean;
-    currentPath: string;
-  }> {
-    await this.homePage.navigateToLogin();
-
-    const currentPath = this.homePage.getCurrentPath();
-    const isLoginUrlMaintained = currentPath.includes('#/login');
-    const isHomeContentDisplayed = await 
this.homePage.isHomeContentDisplayed();
-    const isAnonymousUser = await this.homePage.isAnonymousUser();
-
-    return {
-      isLoginUrlMaintained,
-      isHomeContentDisplayed,
-      isAnonymousUser,
-      currentPath
-    };
-  }
-
-  async verifyHomePageElements(): Promise<void> {
-    await expect(this.homePage.welcomeHeading).toBeVisible();
-    await expect(this.homePage.notebookSection).toBeVisible();
-    await expect(this.homePage.helpSection).toBeVisible();
-    await expect(this.homePage.communitySection).toBeVisible();
-  }
-
-  async verifyExternalLinks(): Promise<void> {
-    await expect(this.homePage.externalLinks.documentation).toBeVisible();
-    await expect(this.homePage.externalLinks.mailingList).toBeVisible();
-    await expect(this.homePage.externalLinks.issuesTracking).toBeVisible();
-    await expect(this.homePage.externalLinks.github).toBeVisible();
-  }
-
-  async testNavigationConsistency(): Promise<{
-    pathBeforeClick: string;
-    pathAfterClick: string;
-    homeContentMaintained: boolean;
-  }> {
-    const pathBeforeClick = this.homePage.getCurrentPath();
-
-    await this.homePage.clickZeppelinLogo();
-    await this.homePage.waitForPageLoad();
-
-    const pathAfterClick = this.homePage.getCurrentPath();
-    const homeContentMaintained = await this.homePage.isHomeContentDisplayed();
-
-    return {
-      pathBeforeClick,
-      pathAfterClick,
-      homeContentMaintained
-    };
-  }
-
-  async getHomePageMetadata(): Promise<{
-    title: string;
-    path: string;
-    isAnonymous: boolean;
-  }> {
-    const basicMetadata = await getBasicPageMetadata(this.page);
-    const isAnonymous = await this.homePage.isAnonymousUser();
-
-    return {
-      ...basicMetadata,
-      isAnonymous
-    };
-  }
-
-  async verifyWelcomeSection(): Promise<void> {
-    await expect(this.homePage.welcomeSection).toBeVisible();
-    await expect(this.homePage.welcomeHeading).toBeVisible();
-
-    const headingText = await this.homePage.getWelcomeHeadingText();
-    expect(headingText.trim()).toBe('Welcome to Zeppelin!');
-
-    const welcomeText = await this.homePage.welcomeDescription.textContent();
-    expect(welcomeText).toContain('web-based notebook');
-    expect(welcomeText).toContain('interactive data analytics');
-  }
-
-  async verifyNotebookSection(): Promise<void> {
-    await expect(this.homePage.notebookSection).toBeVisible();
-    await expect(this.homePage.notebookHeading).toBeVisible();
-    await expect(this.homePage.refreshNoteButton).toBeVisible();
-
-    // Wait for notebook list to load with timeout
-    await this.page.waitForSelector('zeppelin-node-list', { timeout: 10000 });
-    await expect(this.homePage.notebookList).toBeVisible();
-
-    // Additional wait for content to load
-    await this.page.waitForTimeout(1000);
-  }
-
-  async verifyNotebookRefreshFunctionality(): Promise<void> {
-    await this.homePage.clickRefreshNotes();
-
-    // Wait for refresh operation to complete
-    await this.page.waitForTimeout(2000);
-
-    // Ensure the notebook list is still visible after refresh
-    await expect(this.homePage.notebookList).toBeVisible();
-    const isStillVisible = await this.homePage.isNotebookListVisible();
-    expect(isStillVisible).toBe(true);
-  }
-
-  async verifyHelpSection(): Promise<void> {
-    await expect(this.homePage.helpSection).toBeVisible();
-    await expect(this.homePage.helpHeading).toBeVisible();
-  }
-
-  async verifyCommunitySection(): Promise<void> {
-    await expect(this.homePage.communitySection).toBeVisible();
-    await expect(this.homePage.communityHeading).toBeVisible();
-  }
-
-  async testExternalLinkTargets(): Promise<{
-    documentationHref: string | null;
-    mailingListHref: string | null;
-    issuesTrackingHref: string | null;
-    githubHref: string | null;
-  }> {
-    // Get the parent links that contain the text
-    const docLink = this.page.locator('a').filter({ hasText: 'Zeppelin 
documentation' });
-    const mailLink = this.page.locator('a').filter({ hasText: 'Mailing list' 
});
-    const issuesLink = this.page.locator('a').filter({ hasText: 'Issues 
tracking' });
-    const githubLink = this.page.locator('a').filter({ hasText: 'Github' });
-
-    return {
-      documentationHref: await docLink.getAttribute('href'),
-      mailingListHref: await mailLink.getAttribute('href'),
-      issuesTrackingHref: await issuesLink.getAttribute('href'),
-      githubHref: await githubLink.getAttribute('href')
-    };
-  }
-
-  async verifyNotebookActions(): Promise<void> {
-    await expect(this.homePage.nodeList.createNewNoteLink).toBeVisible();
-    await expect(this.homePage.nodeList.importNoteLink).toBeVisible();
-    await expect(this.homePage.nodeList.filterInput).toBeVisible();
-    await expect(this.homePage.nodeList.tree).toBeVisible();
-  }
-
-  async testNotebookRefreshLoadingState(): Promise<void> {
-    const refreshButton = this.page.locator('a.refresh-note');
-    const refreshIcon = this.page.locator('a.refresh-note i[nz-icon]');
-
-    await expect(refreshButton).toBeVisible();
-    await expect(refreshIcon).toBeVisible();
-
-    await this.homePage.clickRefreshNotes();
-
-    await this.page.waitForTimeout(500);
-
-    await expect(refreshIcon).toBeVisible();
-  }
-
-  async verifyCreateNewNoteWorkflow(): Promise<void> {
-    await this.homePage.clickCreateNewNote();
-
-    await this.page.waitForFunction(
-      () => {
-        return document.querySelector('zeppelin-note-create') !== null;
-      },
-      { timeout: 10000 }
-    );
-  }
-
-  async verifyImportNoteWorkflow(): Promise<void> {
-    await this.homePage.clickImportNote();
-
-    await this.page.waitForFunction(
-      () => {
-        return document.querySelector('zeppelin-note-import') !== null;
-      },
-      { timeout: 10000 }
-    );
-  }
-
-  async testFilterFunctionality(filterTerm: string): Promise<void> {
-    await this.homePage.filterNotes(filterTerm);
-
-    await this.page.waitForTimeout(1000);
-
-    const filteredResults = await this.page.locator('nz-tree .node').count();
-    expect(filteredResults).toBeGreaterThanOrEqual(0);
-  }
-
-  async verifyDocumentationVersionLink(): Promise<void> {
-    const href = await this.homePage.getDocumentationLinkHref();
-    expect(href).toContain('zeppelin.apache.org/docs');
-    expect(href).toMatch(/\/docs\/\d+\.\d+\.\d+(-SNAPSHOT)?\//);
-  }
-
-  async verifyAllExternalLinksTargetBlank(): Promise<void> {
-    const links = [
-      this.homePage.externalLinks.documentation,
-      this.homePage.externalLinks.mailingList,
-      this.homePage.externalLinks.issuesTracking,
-      this.homePage.externalLinks.github
-    ];
-
-    for (const link of links) {
-      const target = await link.getAttribute('target');
-      expect(target).toBe('_blank');
-    }
-  }
-}
diff --git a/zeppelin-web-angular/e2e/models/login-page.ts 
b/zeppelin-web-angular/e2e/models/login-page.ts
index cf9e003d77..7e89786883 100644
--- a/zeppelin-web-angular/e2e/models/login-page.ts
+++ b/zeppelin-web-angular/e2e/models/login-page.ts
@@ -17,37 +17,33 @@ export class LoginPage extends BasePage {
   readonly userNameInput: Locator;
   readonly passwordInput: Locator;
   readonly loginButton: Locator;
-  readonly welcomeTitle: Locator;
   readonly formContainer: Locator;
+  readonly errorMessage: Locator;
 
   constructor(page: Page) {
     super(page);
     this.userNameInput = page.getByRole('textbox', { name: 'User Name' });
     this.passwordInput = page.getByRole('textbox', { name: 'Password' });
     this.loginButton = page.getByRole('button', { name: 'Login' });
-    this.welcomeTitle = page.getByRole('heading', { name: 'Welcome to 
Zeppelin!' });
     this.formContainer = page.locator('form[nz-form]');
+    this.errorMessage = page.locator("text=The username and password that you 
entered don't match.").first();
   }
 
   async navigate(): Promise<void> {
-    await this.page.goto('/#/login');
-    await this.waitForPageLoad();
+    await this.navigateToRoute('/login');
   }
 
   async login(username: string, password: string): Promise<void> {
-    await this.userNameInput.fill(username);
-    await this.passwordInput.fill(password);
-    await this.loginButton.click();
+    await this.userNameInput.fill(username, { timeout: 15000 });
+    await this.passwordInput.fill(password, { timeout: 15000 });
+    await this.loginButton.click({ timeout: 15000 });
   }
 
   async waitForErrorMessage(): Promise<void> {
-    await this.page.waitForSelector("text=The username and password that you 
entered don't match.", { timeout: 5000 });
+    await this.errorMessage.waitFor({ state: 'visible', timeout: 5000 });
   }
 
   async getErrorMessageText(): Promise<string> {
-    return (
-      (await this.page.locator("text=The username and password that you 
entered don't match.").first().textContent()) ||
-      ''
-    );
+    return this.getElementText(this.errorMessage);
   }
 }
diff --git a/zeppelin-web-angular/e2e/models/notebook-repo-item.util.ts 
b/zeppelin-web-angular/e2e/models/notebook-repo-item.util.ts
new file mode 100644
index 0000000000..06cdab7ed2
--- /dev/null
+++ b/zeppelin-web-angular/e2e/models/notebook-repo-item.util.ts
@@ -0,0 +1,37 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { expect, Page } from '@playwright/test';
+import { NotebookRepoItemPage } from './notebook-repos-page';
+import { BasePage } from './base-page';
+
+export class NotebookRepoItemUtil extends BasePage {
+  private repoItemPage: NotebookRepoItemPage;
+
+  constructor(page: Page, repoName: string) {
+    super(page);
+    this.repoItemPage = new NotebookRepoItemPage(page, repoName);
+  }
+
+  async verifyDisplayMode(): Promise<void> {
+    await expect(this.repoItemPage.editButton).toBeVisible();
+    const isEditMode = await this.repoItemPage.isEditMode();
+    expect(isEditMode).toBe(false);
+  }
+
+  async verifyEditMode(): Promise<void> {
+    await expect(this.repoItemPage.saveButton).toBeVisible();
+    await expect(this.repoItemPage.cancelButton).toBeVisible();
+    const isEditMode = await this.repoItemPage.isEditMode();
+    expect(isEditMode).toBe(true);
+  }
+}
diff --git a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts 
b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts
index 66befc4d2b..3272df477d 100644
--- a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts
+++ b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts
@@ -15,26 +15,24 @@ import { waitForZeppelinReady } from '../utils';
 import { BasePage } from './base-page';
 
 export class NotebookReposPage extends BasePage {
-  readonly pageHeader: Locator;
   readonly pageDescription: Locator;
   readonly repositoryItems: Locator;
 
   constructor(page: Page) {
     super(page);
-    this.pageHeader = page.locator('zeppelin-page-header[title="Notebook 
Repository"]');
     this.pageDescription = page.locator("text=Manage your Notebook 
Repositories' settings.");
     this.repositoryItems = page.locator('zeppelin-notebook-repo-item');
   }
 
   async navigate(): Promise<void> {
-    await this.page.goto('/#/notebook-repos', { waitUntil: 'load' });
-    await this.page.waitForURL('**/#/notebook-repos', { timeout: 15000 });
+    await this.navigateToRoute('/notebook-repos', { timeout: 60000 });
+    await this.page.waitForURL('**/#/notebook-repos', { timeout: 60000 });
     await waitForZeppelinReady(this.page);
     await this.page.waitForLoadState('networkidle', { timeout: 15000 });
-    await this.page.waitForSelector('zeppelin-notebook-repo-item, 
zeppelin-page-header[title="Notebook Repository"]', {
-      state: 'visible',
-      timeout: 20000
-    });
+    await Promise.race([
+      this.zeppelinPageHeader.filter({ hasText: 'Notebook Repository' 
}).waitFor({ state: 'visible' }),
+      this.page.waitForSelector('zeppelin-notebook-repo-item', { state: 
'visible' })
+    ]);
   }
 
   async getRepositoryItemCount(): Promise<number> {
@@ -42,8 +40,7 @@ export class NotebookReposPage extends BasePage {
   }
 }
 
-export class NotebookRepoItemPage {
-  readonly page: Page;
+export class NotebookRepoItemPage extends BasePage {
   readonly repositoryCard: Locator;
   readonly repositoryName: Locator;
   readonly editButton: Locator;
@@ -53,7 +50,7 @@ export class NotebookRepoItemPage {
   readonly settingRows: Locator;
 
   constructor(page: Page, repoName: string) {
-    this.page = page;
+    super(page);
     this.repositoryCard = page.locator('nz-card').filter({ hasText: repoName 
});
     this.repositoryName = this.repositoryCard.locator('.ant-card-head-title');
     this.editButton = this.repositoryCard.locator('button:has-text("Edit")');
@@ -64,15 +61,15 @@ export class NotebookRepoItemPage {
   }
 
   async clickEdit(): Promise<void> {
-    await this.editButton.click();
+    await this.editButton.click({ timeout: 15000 });
   }
 
   async clickSave(): Promise<void> {
-    await this.saveButton.click();
+    await this.saveButton.click({ timeout: 15000 });
   }
 
   async clickCancel(): Promise<void> {
-    await this.cancelButton.click();
+    await this.cancelButton.click({ timeout: 15000 });
   }
 
   async isEditMode(): Promise<boolean> {
@@ -99,8 +96,8 @@ export class NotebookRepoItemPage {
   async selectSettingDropdown(settingName: string, optionValue: string): 
Promise<void> {
     const row = this.repositoryCard.locator('tbody tr').filter({ hasText: 
settingName });
     const select = row.locator('nz-select');
-    await select.click();
-    await this.page.locator(`nz-option[nzvalue="${optionValue}"]`).click();
+    await select.click({ timeout: 15000 });
+    await this.page.locator(`nz-option[nzvalue="${optionValue}"]`).click({ 
timeout: 15000 });
   }
 
   async getSettingInputValue(settingName: string): Promise<string> {
diff --git a/zeppelin-web-angular/e2e/models/notebook-repos-page.util.ts 
b/zeppelin-web-angular/e2e/models/notebook-repos-page.util.ts
deleted file mode 100644
index d2b0b1f204..0000000000
--- a/zeppelin-web-angular/e2e/models/notebook-repos-page.util.ts
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *     http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import { expect, Page } from '@playwright/test';
-import { NotebookReposPage, NotebookRepoItemPage } from 
'./notebook-repos-page';
-
-export class NotebookReposPageUtil {
-  private notebookReposPage: NotebookReposPage;
-  private page: Page;
-
-  constructor(page: Page) {
-    this.page = page;
-    this.notebookReposPage = new NotebookReposPage(page);
-  }
-
-  async verifyPageStructure(): Promise<void> {
-    await expect(this.notebookReposPage.pageHeader).toBeVisible();
-    await expect(this.notebookReposPage.pageDescription).toBeVisible();
-  }
-
-  async verifyRepositoryListDisplayed(): Promise<void> {
-    const count = await this.notebookReposPage.getRepositoryItemCount();
-    expect(count).toBeGreaterThan(0);
-  }
-
-  async verifyAllRepositoriesRendered(): Promise<number> {
-    const count = await this.notebookReposPage.getRepositoryItemCount();
-    expect(count).toBeGreaterThan(0);
-    return count;
-  }
-
-  async getRepositoryItem(repoName: string): Promise<NotebookRepoItemPage> {
-    return new NotebookRepoItemPage(this.page, repoName);
-  }
-
-  async verifyRepositoryCardDisplayed(repoName: string): Promise<void> {
-    const repoItem = await this.getRepositoryItem(repoName);
-    await expect(repoItem.repositoryCard).toBeVisible();
-    await expect(repoItem.repositoryName).toContainText(repoName);
-  }
-}
-
-export class NotebookRepoItemUtil {
-  private repoItemPage: NotebookRepoItemPage;
-
-  constructor(page: Page, repoName: string) {
-    this.repoItemPage = new NotebookRepoItemPage(page, repoName);
-  }
-
-  async verifyDisplayMode(): Promise<void> {
-    await expect(this.repoItemPage.editButton).toBeVisible();
-    const isEditMode = await this.repoItemPage.isEditMode();
-    expect(isEditMode).toBe(false);
-  }
-
-  async verifyEditMode(): Promise<void> {
-    await expect(this.repoItemPage.saveButton).toBeVisible();
-    await expect(this.repoItemPage.cancelButton).toBeVisible();
-    const isEditMode = await this.repoItemPage.isEditMode();
-    expect(isEditMode).toBe(true);
-  }
-
-  async enterEditMode(): Promise<void> {
-    await this.repoItemPage.clickEdit();
-    await this.verifyEditMode();
-  }
-
-  async exitEditModeByCancel(): Promise<void> {
-    await this.repoItemPage.clickCancel();
-    await this.verifyDisplayMode();
-  }
-
-  async exitEditModeBySave(): Promise<void> {
-    await this.repoItemPage.clickSave();
-    await this.verifyDisplayMode();
-  }
-
-  async verifySettingsDisplayed(): Promise<void> {
-    const settingCount = await this.repoItemPage.getSettingCount();
-    expect(settingCount).toBeGreaterThan(0);
-  }
-
-  async verifyInputTypeSettingInEditMode(settingName: string): Promise<void> {
-    const isVisible = await this.repoItemPage.isInputVisible(settingName);
-    expect(isVisible).toBe(true);
-  }
-
-  async verifyDropdownTypeSettingInEditMode(settingName: string): 
Promise<void> {
-    const isVisible = await this.repoItemPage.isDropdownVisible(settingName);
-    expect(isVisible).toBe(true);
-  }
-
-  async updateInputSetting(settingName: string, value: string): Promise<void> {
-    await this.repoItemPage.fillSettingInput(settingName, value);
-    const inputValue = await 
this.repoItemPage.getSettingInputValue(settingName);
-    expect(inputValue).toBe(value);
-  }
-
-  async updateDropdownSetting(settingName: string, optionValue: string): 
Promise<void> {
-    await this.repoItemPage.selectSettingDropdown(settingName, optionValue);
-  }
-
-  async verifySaveButtonDisabled(): Promise<void> {
-    const isEnabled = await this.repoItemPage.isSaveButtonEnabled();
-    expect(isEnabled).toBe(false);
-  }
-
-  async verifySaveButtonEnabled(): Promise<void> {
-    const isEnabled = await this.repoItemPage.isSaveButtonEnabled();
-    expect(isEnabled).toBe(true);
-  }
-
-  async verifyFormReset(settingName: string, originalValue: string): 
Promise<void> {
-    const currentValue = await this.repoItemPage.getSettingValue(settingName);
-    expect(currentValue.trim()).toBe(originalValue.trim());
-  }
-
-  async performCompleteEditWorkflow(settingName: string, newValue: string, 
isInput: boolean = true): Promise<void> {
-    await this.enterEditMode();
-    if (isInput) {
-      await this.updateInputSetting(settingName, newValue);
-    } else {
-      await this.updateDropdownSetting(settingName, newValue);
-    }
-    await this.verifySaveButtonEnabled();
-    await this.exitEditModeBySave();
-  }
-}
diff --git a/zeppelin-web-angular/e2e/models/notebook.util.ts 
b/zeppelin-web-angular/e2e/models/notebook.util.ts
index 5495a1dfef..00e8dbc183 100644
--- a/zeppelin-web-angular/e2e/models/notebook.util.ts
+++ b/zeppelin-web-angular/e2e/models/notebook.util.ts
@@ -11,6 +11,7 @@
  */
 
 import { expect, Page } from '@playwright/test';
+import { performLoginIfRequired, waitForZeppelinReady } from '../utils';
 import { BasePage } from './base-page';
 import { HomePage } from './home-page';
 
@@ -24,21 +25,20 @@ export class NotebookUtil extends BasePage {
 
   async createNotebook(notebookName: string): Promise<void> {
     await this.homePage.navigateToHome();
-    await this.homePage.createNewNoteButton.click();
 
-    // Wait for the modal to appear and fill the notebook name
-    const notebookNameInput = this.page.locator('input[name="noteName"]');
-    await expect(notebookNameInput).toBeVisible({ timeout: 10000 });
+    // Perform login if required
+    await performLoginIfRequired(this.page);
 
-    // Fill notebook name
-    await notebookNameInput.fill(notebookName);
+    // Wait for Zeppelin to be fully ready
+    await waitForZeppelinReady(this.page);
 
-    // Click the 'Create' button in the modal
-    const createButton = this.page.locator('button', { hasText: 'Create' });
-    await createButton.click();
+    // Wait for URL to not contain 'login' and for the notebook list to appear
+    await this.page.waitForFunction(
+      () => !window.location.href.includes('#/login') && 
document.querySelector('zeppelin-node-list') !== null,
+      { timeout: 30000 }
+    );
 
-    // Wait for the notebook to be created and navigate to it
-    await this.page.waitForURL(url => url.toString().includes('/notebook/'), { 
timeout: 30000 });
-    await this.waitForPageLoad();
+    await expect(this.homePage.zeppelinNodeList).toBeVisible({ timeout: 90000 
});
+    await this.homePage.createNote(notebookName);
   }
 }
diff --git a/zeppelin-web-angular/e2e/models/published-paragraph-page.ts 
b/zeppelin-web-angular/e2e/models/published-paragraph-page.ts
index 73f37b1798..0bc6997cfd 100644
--- a/zeppelin-web-angular/e2e/models/published-paragraph-page.ts
+++ b/zeppelin-web-angular/e2e/models/published-paragraph-page.ts
@@ -11,58 +11,36 @@
  */
 
 import { Locator, Page } from '@playwright/test';
+import { navigateToNotebookWithFallback } from '../utils';
 import { BasePage } from './base-page';
 
 export class PublishedParagraphPage extends BasePage {
-  readonly publishedParagraphContainer: Locator;
-  readonly dynamicForms: Locator;
   readonly paragraphResult: Locator;
-  readonly errorModal: Locator;
-  readonly errorModalTitle: Locator;
   readonly errorModalContent: Locator;
   readonly errorModalOkButton: Locator;
   readonly confirmationModal: Locator;
-  readonly modalTitle: Locator;
-  readonly runButton: Locator;
 
   constructor(page: Page) {
     super(page);
-    this.publishedParagraphContainer = 
page.locator('zeppelin-publish-paragraph');
-    this.dynamicForms = 
page.locator('zeppelin-notebook-paragraph-dynamic-forms');
     this.paragraphResult = page.locator('zeppelin-notebook-paragraph-result');
-    this.errorModal = page.locator('.ant-modal').last();
-    this.errorModalTitle = page.locator('.ant-modal-title');
     this.errorModalContent = this.page.locator('.ant-modal-body', { hasText: 
'Paragraph Not Found' }).last();
     this.errorModalOkButton = page.getByRole('button', { name: 'OK' }).last();
     this.confirmationModal = page.locator('div.ant-modal-confirm').last();
-    this.modalTitle = 
this.confirmationModal.locator('.ant-modal-confirm-title');
-    this.runButton = this.confirmationModal.locator('button', { hasText: 'Run' 
});
   }
 
   async navigateToNotebook(noteId: string): Promise<void> {
-    await this.page.goto(`/#/notebook/${noteId}`);
-    await this.waitForPageLoad();
+    await navigateToNotebookWithFallback(this.page, noteId);
   }
 
   async navigateToPublishedParagraph(noteId: string, paragraphId: string): 
Promise<void> {
-    await this.page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`);
-    await this.waitForPageLoad();
+    await this.navigateToRoute(`/notebook/${noteId}/paragraph/${paragraphId}`);
   }
 
   async getErrorModalContent(): Promise<string> {
-    return (await this.errorModalContent.textContent()) || '';
+    return await this.getElementText(this.errorModalContent);
   }
 
   async clickErrorModalOk(): Promise<void> {
-    await this.errorModalOkButton.click();
-  }
-
-  async getCurrentUrl(): Promise<string> {
-    return this.page.url();
-  }
-
-  async isOnHomePage(): Promise<boolean> {
-    const url = await this.getCurrentUrl();
-    return url.includes('/#/') && !url.includes('/notebook/');
+    await this.errorModalOkButton.click({ timeout: 15000 });
   }
 }
diff --git a/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts 
b/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts
index 8f91c02094..a10cce38da 100644
--- a/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts
+++ b/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts
@@ -10,230 +10,28 @@
  * limitations under the License.
  */
 
-import { expect, Page } from '@playwright/test';
-import { NotebookUtil } from './notebook.util';
+import { Page } from '@playwright/test';
+import { BasePage } from './base-page';
 import { PublishedParagraphPage } from './published-paragraph-page';
 
-export class PublishedParagraphTestUtil {
-  private page: Page;
+export class PublishedParagraphTestUtil extends BasePage {
   private publishedParagraphPage: PublishedParagraphPage;
-  private notebookUtil: NotebookUtil;
 
   constructor(page: Page) {
-    this.page = page;
+    super(page);
     this.publishedParagraphPage = new PublishedParagraphPage(page);
-    this.notebookUtil = new NotebookUtil(page);
   }
 
-  async verifyNonExistentParagraphError(validNoteId: string, 
invalidParagraphId: string): Promise<void> {
-    await 
this.publishedParagraphPage.navigateToPublishedParagraph(validNoteId, 
invalidParagraphId);
-
-    // Try different possible error modal texts
-    const possibleModals = [
-      this.page.locator('.ant-modal', { hasText: 'Paragraph Not Found' }),
-      this.page.locator('.ant-modal', { hasText: 'not found' }),
-      this.page.locator('.ant-modal', { hasText: 'Error' }),
-      this.page.locator('.ant-modal').filter({ hasText: /not 
found|error|paragraph/i })
-    ];
-
-    let modal;
-    for (const possibleModal of possibleModals) {
-      const count = await possibleModal.count();
-
-      for (let i = 0; i < count; i++) {
-        const m = possibleModal.nth(i);
-
-        if (await m.isVisible()) {
-          modal = m;
-          break;
-        }
-      }
-
-      if (modal) {
-        break;
-      }
-    }
-
-    if (!modal) {
-      // If no modal is found, check if we're redirected to home
-      await expect(this.page).toHaveURL(/\/#\/$/, { timeout: 10000 });
-      return;
-    }
-
-    await expect(modal).toBeVisible({ timeout: 10000 });
-
-    // Try to get content and check if available
-    try {
-      const content = await this.publishedParagraphPage.getErrorModalContent();
-      if (content && content.includes(invalidParagraphId)) {
-        expect(content).toContain(invalidParagraphId);
-      }
-    } catch {
-      throw Error('Content check failed, continue with OK button click');
-    }
-
-    await this.publishedParagraphPage.clickErrorModalOk();
-
-    // Wait for redirect to home page instead of checking modal state
-    await expect(this.page).toHaveURL(/\/#\/$/, { timeout: 10000 });
-
-    expect(await this.publishedParagraphPage.isOnHomePage()).toBe(true);
+  async navigateToPublishedParagraph(noteId: string, paragraphId: string): 
Promise<void> {
+    await this.publishedParagraphPage.navigateToPublishedParagraph(noteId, 
paragraphId);
   }
 
-  async verifyClickLinkThisParagraphBehavior(noteId: string, paragraphId: 
string): Promise<void> {
-    // 1. Navigate to the normal notebook view
-    await this.page.goto(`/#/notebook/${noteId}`);
-    await this.page.waitForLoadState('networkidle');
-
-    // 2. Find the correct paragraph result element and go up to the parent 
paragraph container
-    // First try with data-testid, then fallback to first paragraph if not 
found
-    let paragraphElement = 
this.page.locator(`zeppelin-notebook-paragraph[data-testid="${paragraphId}"]`);
-
-    if ((await paragraphElement.count()) === 0) {
-      // Fallback to first paragraph if specific ID not found
-      paragraphElement = 
this.page.locator('zeppelin-notebook-paragraph').first();
-    }
-
-    await expect(paragraphElement).toBeVisible({ timeout: 10000 });
-
-    // 3. Click the settings button to open the dropdown
-    const settingsButton = paragraphElement.locator('a[nz-dropdown]');
-    await settingsButton.click();
-
-    // 4. Click "Link this paragraph" in the dropdown menu
-    const linkParagraphButton = this.page.locator('li.list-item:has-text("Link 
this paragraph")');
-    await expect(linkParagraphButton).toBeVisible();
-
-    // 5. Handle the new page/tab that opens
-    const [newPage] = await Promise.all([this.page.waitForEvent('popup'), 
linkParagraphButton.click()]);
-    await newPage.waitForLoadState();
-
-    // 6. Verify the new page URL shows published paragraph (not redirected)
-    await expect(newPage).toHaveURL(new 
RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 10000 });
-
-    const codeEditor = 
newPage.locator('zeppelin-notebook-paragraph-code-editor');
-    await expect(codeEditor).toBeHidden();
-
-    const controlPanel = 
newPage.locator('zeppelin-notebook-paragraph-control');
-    await expect(controlPanel).toBeHidden();
+  async getErrorModalContent(): Promise<string> {
+    return this.publishedParagraphPage.getErrorModalContent();
   }
 
-  async createTestNotebook(): Promise<{ noteId: string; paragraphId: string }> 
{
-    const notebookName = `Test Notebook ${Date.now()}`;
-
-    // Use existing NotebookUtil to create notebook
-    await this.notebookUtil.createNotebook(notebookName);
-
-    // Extract noteId from URL
-    const url = this.page.url();
-    const noteIdMatch = url.match(/\/notebook\/([^\/\?]+)/);
-    if (!noteIdMatch) {
-      throw new Error(`Failed to extract notebook ID from URL: ${url}`);
-    }
-    const noteId = noteIdMatch[1];
-
-    // Get first paragraph ID
-    await this.page.locator('zeppelin-notebook-paragraph').first().waitFor({ 
state: 'visible', timeout: 10000 });
-    const paragraphContainer = 
this.page.locator('zeppelin-notebook-paragraph').first();
-    const dropdownTrigger = paragraphContainer.locator('a[nz-dropdown]');
-    await dropdownTrigger.click();
-
-    const paragraphLink = this.page.locator('li.paragraph-id a').first();
-    await paragraphLink.waitFor({ state: 'attached', timeout: 5000 });
-
-    const paragraphId = await paragraphLink.textContent();
-
-    if (!paragraphId || !paragraphId.startsWith('paragraph_')) {
-      throw new Error(`Failed to find a valid paragraph ID. Found: 
${paragraphId}`);
-    }
-
-    // Navigate back to home
-    await this.page.goto('/');
-    await this.page.waitForLoadState('networkidle');
-    await this.page.waitForSelector('text=Welcome to Zeppelin!', { timeout: 
5000 });
-
-    return { noteId, paragraphId };
-  }
-
-  async deleteTestNotebook(noteId: string): Promise<void> {
-    try {
-      // Navigate to home page
-      await this.page.goto('/');
-      await this.page.waitForLoadState('networkidle');
-
-      // Find the notebook in the tree by noteId and get its parent tree node
-      const notebookLink = this.page.locator(`a[href*="/notebook/${noteId}"]`);
-
-      if ((await notebookLink.count()) > 0) {
-        // Hover over the tree node to make delete button visible
-        const treeNode = 
notebookLink.locator('xpath=ancestor::nz-tree-node[1]');
-        await treeNode.hover();
-
-        // Wait a bit for hover effects
-        await this.page.waitForTimeout(1000);
-
-        // Try multiple selectors for the delete button
-        const deleteButtonSelectors = [
-          'a[nz-tooltip] i[nztype="delete"]',
-          'i[nztype="delete"]',
-          '[nz-popconfirm] i[nztype="delete"]',
-          'i.anticon-delete'
-        ];
-
-        let deleteClicked = false;
-        for (const selector of deleteButtonSelectors) {
-          const deleteButton = treeNode.locator(selector);
-          try {
-            if (await deleteButton.isVisible({ timeout: 2000 })) {
-              await deleteButton.click({ timeout: 5000 });
-              deleteClicked = true;
-              break;
-            }
-          } catch (e) {
-            // Continue to next selector
-            continue;
-          }
-        }
-
-        if (!deleteClicked) {
-          console.warn(`Delete button not found for notebook ${noteId}`);
-          return;
-        }
-
-        // Confirm deletion in popconfirm with timeout
-        try {
-          const confirmButton = this.page.locator('button:has-text("OK")');
-          await confirmButton.click({ timeout: 5000 });
-
-          // Wait for the notebook to be removed with timeout
-          await expect(treeNode).toBeHidden({ timeout: 10000 });
-        } catch (e) {
-          // If confirmation fails, try alternative OK button selectors
-          const altConfirmButtons = [
-            '.ant-popover button:has-text("OK")',
-            '.ant-popconfirm button:has-text("OK")',
-            'button.ant-btn-primary:has-text("OK")'
-          ];
-
-          for (const selector of altConfirmButtons) {
-            try {
-              const button = this.page.locator(selector);
-              if (await button.isVisible({ timeout: 1000 })) {
-                await button.click({ timeout: 3000 });
-                await expect(treeNode).toBeHidden({ timeout: 10000 });
-                break;
-              }
-            } catch (altError) {
-              // Continue to next selector
-              continue;
-            }
-          }
-        }
-      }
-    } catch (error) {
-      console.warn(`Failed to delete test notebook ${noteId}:`, error);
-      // Don't throw error to avoid failing the test cleanup
-    }
+  async clickErrorModalOk(): Promise<void> {
+    await this.publishedParagraphPage.clickErrorModalOk();
   }
 
   generateNonExistentIds(): { noteId: string; paragraphId: string } {
diff --git a/zeppelin-web-angular/e2e/models/workspace-page.ts 
b/zeppelin-web-angular/e2e/models/workspace-page.ts
index 57c0da8796..1fdcf9e5a7 100644
--- a/zeppelin-web-angular/e2e/models/workspace-page.ts
+++ b/zeppelin-web-angular/e2e/models/workspace-page.ts
@@ -14,19 +14,10 @@ import { Locator, Page } from '@playwright/test';
 import { BasePage } from './base-page';
 
 export class WorkspacePage extends BasePage {
-  readonly workspaceComponent: Locator;
-  readonly header: Locator;
   readonly routerOutlet: Locator;
 
   constructor(page: Page) {
     super(page);
-    this.workspaceComponent = page.locator('zeppelin-workspace');
-    this.header = page.locator('zeppelin-header');
     this.routerOutlet = page.locator('zeppelin-workspace router-outlet');
   }
-
-  async navigateToWorkspace(): Promise<void> {
-    await this.page.goto('/', { waitUntil: 'load' });
-    await this.waitForPageLoad();
-  }
 }
diff --git a/zeppelin-web-angular/e2e/models/workspace-page.util.ts 
b/zeppelin-web-angular/e2e/models/workspace-page.util.ts
index 7ff706f93a..fd6d9c3f45 100644
--- a/zeppelin-web-angular/e2e/models/workspace-page.util.ts
+++ b/zeppelin-web-angular/e2e/models/workspace-page.util.ts
@@ -11,54 +11,28 @@
  */
 
 import { expect, Page } from '@playwright/test';
-import { performLoginIfRequired, waitForZeppelinReady } from '../utils';
+import { BasePage } from './base-page';
 import { WorkspacePage } from './workspace-page';
 
-export class WorkspaceTestUtil {
-  private page: Page;
+export class WorkspaceUtil extends BasePage {
   private workspacePage: WorkspacePage;
 
   constructor(page: Page) {
-    this.page = page;
+    super(page);
     this.workspacePage = new WorkspacePage(page);
   }
 
-  async navigateAndWaitForLoad(): Promise<void> {
-    await this.workspacePage.navigateToWorkspace();
-    await waitForZeppelinReady(this.page);
-    await performLoginIfRequired(this.page);
-  }
-
-  async verifyWorkspaceLayout(): Promise<void> {
-    await expect(this.workspacePage.workspaceComponent).toBeVisible();
-    await expect(this.workspacePage.routerOutlet).toBeAttached();
-  }
-
   async verifyHeaderVisibility(shouldBeVisible: boolean): Promise<void> {
     if (shouldBeVisible) {
-      await expect(this.workspacePage.header).toBeVisible();
+      await expect(this.workspacePage.zeppelinHeader).toBeVisible();
     } else {
-      await expect(this.workspacePage.header).toBeHidden();
+      await expect(this.workspacePage.zeppelinHeader).toBeHidden();
     }
   }
 
-  async verifyWorkspaceContainer(): Promise<void> {
-    await expect(this.workspacePage.workspaceComponent).toBeVisible();
-    const contentElements = await this.page.locator('.content').count();
-    expect(contentElements).toBeGreaterThan(0);
-  }
-
   async verifyRouterOutletActivation(): Promise<void> {
     await expect(this.workspacePage.routerOutlet).toBeAttached();
-
-    await this.page.waitForFunction(
-      () => {
-        const workspace = document.querySelector('zeppelin-workspace');
-        const outlet = workspace?.querySelector('router-outlet');
-        return outlet && outlet.nextElementSibling !== null;
-      },
-      { timeout: 10000 }
-    );
+    await this.waitForRouterOutletChild();
   }
 
   async waitForComponentActivation(): Promise<void> {
diff --git a/zeppelin-web-angular/e2e/tests/app.spec.ts 
b/zeppelin-web-angular/e2e/tests/app.spec.ts
index 5a02c87f38..5d956c747f 100644
--- a/zeppelin-web-angular/e2e/tests/app.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/app.spec.ts
@@ -12,8 +12,7 @@
 
 import { expect, test } from '@playwright/test';
 import { BasePage } from '../models/base-page';
-import { LoginTestUtil } from '../models/login-page.util';
-import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from 
'../utils';
+import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES, 
performLoginIfRequired } from '../utils';
 
 test.describe('Zeppelin App Component', () => {
   addPageAnnotationBeforeEach(PAGES.APP);
@@ -23,6 +22,8 @@ test.describe('Zeppelin App Component', () => {
     basePage = new BasePage(page);
 
     await page.goto('/', { waitUntil: 'load' });
+    await waitForZeppelinReady(page);
+    await performLoginIfRequired(page);
   });
 
   test('should have correct component selector and structure', async ({ page 
}) => {
@@ -56,12 +57,8 @@ test.describe('Zeppelin App Component', () => {
 
   test('should display workspace after loading', async ({ page }) => {
     await waitForZeppelinReady(page);
-    const isShiroEnabled = await LoginTestUtil.isShiroEnabled();
-    if (isShiroEnabled) {
-      await expect(page.locator('zeppelin-login')).toBeVisible();
-    } else {
-      await expect(page.locator('zeppelin-workspace')).toBeVisible();
-    }
+    // After the `beforeEach` hook, which handles login, the workspace should 
be visible.
+    await expect(basePage.zeppelinWorkspace).toBeVisible();
   });
 
   test('should handle navigation events correctly', async ({ page }) => {
@@ -142,6 +139,7 @@ test.describe('Zeppelin App Component', () => {
 
   test('should maintain component integrity during navigation', async ({ page 
}) => {
     await waitForZeppelinReady(page);
+    await performLoginIfRequired(page);
 
     const zeppelinRoot = page.locator('zeppelin-root');
     const routerOutlet = zeppelinRoot.locator('router-outlet').first();
diff --git 
a/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts
 
b/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts
index 1c0905c282..5e73dc036d 100644
--- 
a/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts
@@ -11,10 +11,12 @@
  */
 
 import { expect, test } from '@playwright/test';
-import { HomePageUtil } from '../../models/home-page.util';
+import { BasePage } from '../../models/base-page';
+import { HomePage } from '../../models/home-page';
 import { LoginTestUtil } from '../../models/login-page.util';
 import {
   addPageAnnotationBeforeEach,
+  getBasicPageMetadata,
   getCurrentPath,
   waitForUrlNotContaining,
   waitForZeppelinReady,
@@ -24,7 +26,8 @@ import {
 test.describe('Anonymous User Login Redirect', () => {
   addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME);
 
-  let homePageUtil: HomePageUtil;
+  let homePage: HomePage;
+  let basePage: BasePage;
 
   test.beforeAll(async () => {
     const isShiroEnabled = await LoginTestUtil.isShiroEnabled();
@@ -34,74 +37,90 @@ test.describe('Anonymous User Login Redirect', () => {
   });
 
   test.beforeEach(async ({ page }) => {
-    homePageUtil = new HomePageUtil(page);
+    homePage = new HomePage(page);
+    basePage = new BasePage(page);
   });
 
   test.describe('Given an anonymous user is already logged in', () => {
     test.beforeEach(async ({ page }) => {
-      await page.goto('/', { waitUntil: 'load' });
+      await page.goto('/#/');
       await waitForZeppelinReady(page);
     });
 
-    test('When accessing login page directly, Then should redirect to home 
with proper URL change', async () => {
-      const redirectResult = await 
homePageUtil.verifyAnonymousUserRedirectFromLogin();
-
-      expect(redirectResult.isLoginUrlMaintained).toBe(false);
-      expect(redirectResult.isHomeContentDisplayed).toBe(true);
-      expect(redirectResult.isAnonymousUser).toBe(true);
-      expect(redirectResult.currentPath).toContain('#/');
-      expect(redirectResult.currentPath).not.toContain('#/login');
+    test('When accessing login page directly, Then should redirect to home 
with proper URL change', async ({
+      page
+    }) => {
+      await homePage.navigateToLogin();
+
+      const currentPath = getCurrentPath(page);
+      const isLoginUrlMaintained = currentPath.includes('#/login');
+      const isHomeContentDisplayed = await homePage.isHomeContentDisplayed();
+      const isAnonymousUser = await homePage.isAnonymousUser();
+
+      expect(isLoginUrlMaintained).toBe(false);
+      expect(isHomeContentDisplayed).toBe(true);
+      expect(isAnonymousUser).toBe(true);
+      expect(currentPath).toContain('#/');
+      expect(currentPath).not.toContain('#/login');
     });
 
     test('When accessing login page directly, Then should display all home 
page elements correctly', async ({
       page
     }) => {
-      await page.goto('/#/login', { waitUntil: 'load' });
+      await page.goto('/#/login');
       await waitForZeppelinReady(page);
       await page.waitForURL(url => !url.toString().includes('#/login'));
 
-      await homePageUtil.verifyHomePageElements();
+      await expect(homePage.welcomeTitle).toBeVisible();
+      await expect(homePage.notebookSection).toBeVisible();
+      await expect(homePage.helpSection).toBeVisible();
+      await expect(homePage.communitySection).toBeVisible();
     });
 
     test('When clicking Zeppelin logo after redirect, Then should maintain 
home URL and content', async ({ page }) => {
-      await page.goto('/#/login', { waitUntil: 'load' });
+      await page.goto('/#/login');
       await waitForZeppelinReady(page);
       await page.waitForURL(url => !url.toString().includes('#/login'));
 
-      const navigationResult = await homePageUtil.testNavigationConsistency();
+      const pathBeforeClick = getCurrentPath(page);
+      await homePage.clickZeppelinLogo();
+      await basePage.waitForPageLoad();
+      const pathAfterClick = getCurrentPath(page);
+      const homeContentMaintained = await homePage.isHomeContentDisplayed();
 
-      expect(navigationResult.pathBeforeClick).toContain('#/');
-      expect(navigationResult.pathBeforeClick).not.toContain('#/login');
-      expect(navigationResult.pathAfterClick).toContain('#/');
-      expect(navigationResult.homeContentMaintained).toBe(true);
+      expect(pathBeforeClick).toContain('#/');
+      expect(pathBeforeClick).not.toContain('#/login');
+      expect(pathAfterClick).toContain('#/');
+      expect(homeContentMaintained).toBe(true);
     });
 
     test('When accessing login page, Then should redirect and maintain 
anonymous user state', async ({ page }) => {
-      await page.goto('/#/login', { waitUntil: 'load' });
+      await page.goto('/#/login');
       await waitForZeppelinReady(page);
       await page.waitForURL(url => !url.toString().includes('#/login'));
 
-      const metadata = await homePageUtil.getHomePageMetadata();
+      const basicMetadata = await getBasicPageMetadata(page);
+      const isAnonymous = await homePage.isAnonymousUser();
 
-      expect(metadata.title).toContain('Zeppelin');
-      expect(metadata.path).toContain('#/');
-      expect(metadata.path).not.toContain('#/login');
-      expect(metadata.isAnonymous).toBe(true);
+      expect(basicMetadata.title).toContain('Zeppelin');
+      expect(basicMetadata.path).toContain('#/');
+      expect(basicMetadata.path).not.toContain('#/login');
+      expect(isAnonymous).toBe(true);
     });
 
     test('When accessing login page, Then should display welcome heading and 
main sections', async ({ page }) => {
-      await page.goto('/#/login', { waitUntil: 'load' });
+      await page.goto('/#/login');
       await waitForZeppelinReady(page);
       await page.waitForURL(url => !url.toString().includes('#/login'));
 
-      await expect(page.locator('h1', { hasText: 'Welcome to Zeppelin!' 
})).toBeVisible();
+      await expect(basePage.welcomeTitle).toBeVisible();
       await expect(page.locator('text=Notebook').first()).toBeVisible();
       await expect(page.locator('text=Help').first()).toBeVisible();
       await expect(page.locator('text=Community').first()).toBeVisible();
     });
 
     test('When accessing login page, Then should display notebook 
functionalities', async ({ page }) => {
-      await page.goto('/#/login', { waitUntil: 'load' });
+      await page.goto('/#/login');
       await waitForZeppelinReady(page);
       await page.waitForURL(url => !url.toString().includes('#/login'));
 
@@ -117,7 +136,7 @@ test.describe('Anonymous User Login Redirect', () => {
     test('When accessing login page, Then should display external links in 
help and community sections', async ({
       page
     }) => {
-      await page.goto('/#/login', { waitUntil: 'load' });
+      await page.goto('/#/login');
       await waitForZeppelinReady(page);
       await page.waitForURL(url => !url.toString().includes('#/login'));
 
@@ -143,33 +162,36 @@ test.describe('Anonymous User Login Redirect', () => {
     test('When navigating between home and login URLs, Then should maintain 
consistent user experience', async ({
       page
     }) => {
-      await page.goto('/', { waitUntil: 'load' });
+      await page.goto('/#/');
       await waitForZeppelinReady(page);
 
-      const homeMetadata = await homePageUtil.getHomePageMetadata();
+      const homeMetadata = await getBasicPageMetadata(page);
+      const isHomeAnonymous = await homePage.isAnonymousUser();
       expect(homeMetadata.path).toContain('#/');
-      expect(homeMetadata.isAnonymous).toBe(true);
+      expect(isHomeAnonymous).toBe(true);
 
-      await page.goto('/#/login', { waitUntil: 'load' });
+      await page.goto('/#/login');
       await waitForZeppelinReady(page);
       await page.waitForURL(url => !url.toString().includes('#/login'));
 
-      const loginMetadata = await homePageUtil.getHomePageMetadata();
+      const loginMetadata = await getBasicPageMetadata(page);
+      const isLoginAnonymous = await homePage.isAnonymousUser();
       expect(loginMetadata.path).toContain('#/');
       expect(loginMetadata.path).not.toContain('#/login');
-      expect(loginMetadata.isAnonymous).toBe(true);
+      expect(isLoginAnonymous).toBe(true);
 
-      const isHomeContentDisplayed = await 
homePageUtil.verifyAnonymousUserRedirectFromLogin();
-      expect(isHomeContentDisplayed.isHomeContentDisplayed).toBe(true);
+      await homePage.navigateToLogin();
+      const isHomeContentDisplayed = await homePage.isHomeContentDisplayed();
+      expect(isHomeContentDisplayed).toBe(true);
     });
 
     test('When multiple page loads occur on login URL, Then should 
consistently redirect to home', async ({ page }) => {
       for (let i = 0; i < 3; i++) {
-        await page.goto('/#/login', { waitUntil: 'load' });
+        await page.goto('/#/login');
         await waitForZeppelinReady(page);
         await waitForUrlNotContaining(page, '#/login');
 
-        await expect(page.locator('h1', { hasText: 'Welcome to Zeppelin!' 
})).toBeVisible();
+        await expect(basePage.welcomeTitle).toBeVisible();
         await expect(page.locator('text=anonymous')).toBeVisible();
 
         const path = getCurrentPath(page);
diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts 
b/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts
index f9f27d59e5..f41c00c544 100644
--- a/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts
@@ -12,13 +12,15 @@
 
 import { expect, test } from '@playwright/test';
 import { HomePage } from '../../models/home-page';
-import { HomePageUtil } from '../../models/home-page.util';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../utils';
 
 test.describe('Home Page - Core Elements', () => {
   addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME);
 
+  let homePage: HomePage;
+
   test.beforeEach(async ({ page }) => {
+    homePage = new HomePage(page);
     await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
@@ -26,10 +28,7 @@ test.describe('Home Page - Core Elements', () => {
 
   test.describe('Welcome Section', () => {
     test('should display welcome section with correct content', async ({ page 
}) => {
-      const homePageUtil = new HomePageUtil(page);
-
       await test.step('Given I am on the home page', async () => {
-        const homePage = new HomePage(page);
         await homePage.navigateToHome();
       });
 
@@ -38,13 +37,18 @@ test.describe('Home Page - Core Elements', () => {
       });
 
       await test.step('Then I should see the welcome section with correct 
content', async () => {
-        await homePageUtil.verifyWelcomeSection();
+        await expect(homePage.welcomeSection).toBeVisible();
+        await expect(homePage.welcomeTitle).toBeVisible();
+        const headingText = await homePage.getWelcomeHeadingText();
+        expect(headingText.trim()).toBe('Welcome to Zeppelin!');
+        await expect(homePage.welcomeDescription).toBeVisible();
+        const welcomeText = await homePage.welcomeDescription.textContent();
+        expect(welcomeText).toContain('web-based notebook');
+        expect(welcomeText).toContain('interactive data analytics');
       });
     });
 
-    test('should have proper welcome message structure', async ({ page }) => {
-      const homePage = new HomePage(page);
-
+    test('should have proper welcome message structure', async () => {
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
@@ -54,7 +58,7 @@ test.describe('Home Page - Core Elements', () => {
       });
 
       await test.step('Then I should see the welcome heading', async () => {
-        await expect(homePage.welcomeHeading).toBeVisible();
+        await expect(homePage.welcomeTitle).toBeVisible();
         const headingText = await homePage.getWelcomeHeadingText();
         expect(headingText.trim()).toBe('Welcome to Zeppelin!');
       });
@@ -70,10 +74,7 @@ test.describe('Home Page - Core Elements', () => {
 
   test.describe('Notebook Section', () => {
     test('should display notebook section with all components', async ({ page 
}) => {
-      const homePageUtil = new HomePageUtil(page);
-
       await test.step('Given I am on the home page', async () => {
-        const homePage = new HomePage(page);
         await homePage.navigateToHome();
       });
 
@@ -82,14 +83,15 @@ test.describe('Home Page - Core Elements', () => {
       });
 
       await test.step('Then I should see all notebook section components', 
async () => {
-        await homePageUtil.verifyNotebookSection();
+        await expect(homePage.notebookSection).toBeVisible();
+        await expect(homePage.notebookHeading).toBeVisible();
+        await expect(homePage.refreshNoteButton).toBeVisible();
+        await page.waitForSelector('zeppelin-node-list', { timeout: 10000 });
+        await expect(homePage.zeppelinNodeList).toBeVisible();
       });
     });
 
-    test('should have functional refresh notes button', async ({ page }) => {
-      const homePage = new HomePage(page);
-      const homePageUtil = new HomePageUtil(page);
-
+    test('should have functional refresh notes button', async () => {
       await test.step('Given I am on the home page with notebook section 
visible', async () => {
         await homePage.navigateToHome();
         await expect(homePage.refreshNoteButton).toBeVisible();
@@ -100,13 +102,14 @@ test.describe('Home Page - Core Elements', () => {
       });
 
       await test.step('Then the notebook list should still be visible', async 
() => {
-        await homePageUtil.verifyNotebookRefreshFunctionality();
+        await homePage.waitForRefreshToComplete();
+        await expect(homePage.zeppelinNodeList).toBeVisible();
+        const isStillVisible = await homePage.zeppelinNodeList.isVisible();
+        expect(isStillVisible).toBe(true);
       });
     });
 
     test('should display notebook list component', async ({ page }) => {
-      const homePage = new HomePage(page);
-
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
@@ -116,7 +119,7 @@ test.describe('Home Page - Core Elements', () => {
       });
 
       await test.step('Then I should see the notebook list component', async 
() => {
-        await expect(homePage.notebookList).toBeVisible();
+        await expect(homePage.zeppelinNodeList).toBeVisible();
         const isVisible = await homePage.isNotebookListVisible();
         expect(isVisible).toBe(true);
       });
@@ -125,10 +128,7 @@ test.describe('Home Page - Core Elements', () => {
 
   test.describe('Help Section', () => {
     test('should display help section with documentation link', async ({ page 
}) => {
-      const homePageUtil = new HomePageUtil(page);
-
       await test.step('Given I am on the home page', async () => {
-        const homePage = new HomePage(page);
         await homePage.navigateToHome();
       });
 
@@ -137,11 +137,11 @@ test.describe('Home Page - Core Elements', () => {
       });
 
       await test.step('Then I should see the help section', async () => {
-        await homePageUtil.verifyHelpSection();
+        await expect(homePage.helpSection).toBeVisible();
+        await expect(homePage.helpHeading).toBeVisible();
       });
 
       await test.step('And I should see the documentation link', async () => {
-        const homePage = new HomePage(page);
         await expect(homePage.externalLinks.documentation).toBeVisible();
       });
     });
@@ -149,10 +149,7 @@ test.describe('Home Page - Core Elements', () => {
 
   test.describe('Community Section', () => {
     test('should display community section with all links', async ({ page }) 
=> {
-      const homePageUtil = new HomePageUtil(page);
-
       await test.step('Given I am on the home page', async () => {
-        const homePage = new HomePage(page);
         await homePage.navigateToHome();
       });
 
@@ -161,11 +158,15 @@ test.describe('Home Page - Core Elements', () => {
       });
 
       await test.step('Then I should see the community section', async () => {
-        await homePageUtil.verifyCommunitySection();
+        await expect(homePage.communitySection).toBeVisible();
+        await expect(homePage.communityHeading).toBeVisible();
       });
 
       await test.step('And I should see all community links', async () => {
-        await homePageUtil.verifyExternalLinks();
+        await expect(homePage.externalLinks.documentation).toBeVisible();
+        await expect(homePage.externalLinks.mailingList).toBeVisible();
+        await expect(homePage.externalLinks.issuesTracking).toBeVisible();
+        await expect(homePage.externalLinks.github).toBeVisible();
       });
     });
   });
diff --git 
a/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts 
b/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts
index 1025a48e4f..fb3a56cbc2 100644
--- 
a/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts
@@ -11,54 +11,82 @@
  */
 
 import { expect, test } from '@playwright/test';
-import { HomePageUtil } from '../../models/home-page.util';
+import { HomePage } from '../../models/home-page';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../utils';
 
 addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME);
 
 test.describe('Home Page Enhanced Functionality', () => {
-  let homeUtil: HomePageUtil;
+  let homePage: HomePage;
 
   test.beforeEach(async ({ page }) => {
-    homeUtil = new HomePageUtil(page);
-    await page.goto('/');
+    homePage = new HomePage(page);
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
   });
 
   test.describe('Given documentation links are displayed', () => {
     test('When documentation link is checked Then should have correct version 
in URL', async () => {
-      await homeUtil.verifyDocumentationVersionLink();
+      const href = await homePage.getDocumentationLinkHref();
+      expect(href).toContain('zeppelin.apache.org/docs');
+      expect(href).toMatch(/\/docs\/\d+\.\d+\.\d+(-SNAPSHOT)?\//);
     });
 
     test('When external links are checked Then should all open in new tab', 
async () => {
-      await homeUtil.verifyAllExternalLinksTargetBlank();
+      const links = [
+        homePage.externalLinks.documentation,
+        homePage.externalLinks.mailingList,
+        homePage.externalLinks.issuesTracking,
+        homePage.externalLinks.github
+      ];
+
+      for (const link of links) {
+        const target = await link.getAttribute('target');
+        expect(target).toBe('_blank');
+      }
     });
   });
 
   test.describe('Given welcome section display', () => {
     test('When page loads Then should show welcome content with proper text', 
async () => {
-      await homeUtil.verifyWelcomeSection();
+      await expect(homePage.welcomeSection).toBeVisible();
+      await expect(homePage.welcomeTitle).toBeVisible();
+      const headingText = await homePage.getWelcomeHeadingText();
+      expect(headingText.trim()).toBe('Welcome to Zeppelin!');
+      await expect(homePage.welcomeDescription).toBeVisible();
+      const welcomeText = await homePage.welcomeDescription.textContent();
+      expect(welcomeText).toContain('web-based notebook');
+      expect(welcomeText).toContain('interactive data analytics');
     });
 
-    test('When welcome section is displayed Then should contain interactive 
elements', async () => {
-      await homeUtil.verifyNotebookSection();
+    test('When welcome section is displayed Then should contain interactive 
elements', async ({ page }) => {
+      await expect(homePage.notebookSection).toBeVisible();
+      await expect(homePage.notebookHeading).toBeVisible();
+      await expect(homePage.refreshNoteButton).toBeVisible();
+      await page.waitForSelector('zeppelin-node-list', { timeout: 10000 });
+      await expect(homePage.zeppelinNodeList).toBeVisible();
     });
   });
 
   test.describe('Given community section content', () => {
     test('When community section loads Then should display help and community 
headings', async () => {
-      await homeUtil.verifyHelpSection();
-      await homeUtil.verifyCommunitySection();
+      await expect(homePage.helpSection).toBeVisible();
+      await expect(homePage.helpHeading).toBeVisible();
+      await expect(homePage.communitySection).toBeVisible();
+      await expect(homePage.communityHeading).toBeVisible();
     });
 
     test('When external links are displayed Then should show correct targets', 
async () => {
-      const linkTargets = await homeUtil.testExternalLinkTargets();
+      const docHref = await 
homePage.externalLinks.documentation.getAttribute('href');
+      const mailHref = await 
homePage.externalLinks.mailingList.getAttribute('href');
+      const issuesHref = await 
homePage.externalLinks.issuesTracking.getAttribute('href');
+      const githubHref = await 
homePage.externalLinks.github.getAttribute('href');
 
-      
expect(linkTargets.documentationHref).toContain('zeppelin.apache.org/docs');
-      expect(linkTargets.mailingListHref).toContain('community.html');
-      expect(linkTargets.issuesTrackingHref).toContain('issues.apache.org');
-      expect(linkTargets.githubHref).toContain('github.com/apache/zeppelin');
+      expect(docHref).toContain('zeppelin.apache.org/docs');
+      expect(mailHref).toContain('community.html');
+      expect(issuesHref).toContain('issues.apache.org');
+      expect(githubHref).toContain('github.com/apache/zeppelin');
     });
   });
 });
diff --git 
a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts 
b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts
index 34e7e27de0..ce44eb967b 100644
--- a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts
@@ -12,23 +12,22 @@
 
 import { expect, test } from '@playwright/test';
 import { HomePage } from '../../models/home-page';
-import { HomePageUtil } from '../../models/home-page.util';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../utils';
 
 test.describe('Home Page - External Links', () => {
   addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME);
 
+  let homePage: HomePage;
+
   test.beforeEach(async ({ page }) => {
+    homePage = new HomePage(page);
     await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
   });
 
   test.describe('Documentation Link', () => {
-    test('should have correct documentation link with dynamic version', async 
({ page }) => {
-      const homePage = new HomePage(page);
-      const homePageUtil = new HomePageUtil(page);
-
+    test('should have correct documentation link with dynamic version', async 
() => {
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
@@ -38,9 +37,9 @@ test.describe('Home Page - External Links', () => {
       });
 
       await test.step('Then it should have the correct href pattern', async () 
=> {
-        const linkTargets = await homePageUtil.testExternalLinkTargets();
-        
expect(linkTargets.documentationHref).toContain('zeppelin.apache.org/docs');
-        expect(linkTargets.documentationHref).toContain('index.html');
+        const href = await 
homePage.externalLinks.documentation.getAttribute('href');
+        expect(href).toContain('zeppelin.apache.org/docs');
+        expect(href).toContain('index.html');
       });
 
       await test.step('And it should open in a new tab', async () => {
@@ -51,10 +50,7 @@ test.describe('Home Page - External Links', () => {
   });
 
   test.describe('Community Links', () => {
-    test('should have correct mailing list link', async ({ page }) => {
-      const homePage = new HomePage(page);
-      const homePageUtil = new HomePageUtil(page);
-
+    test('should have correct mailing list link', async () => {
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
@@ -64,8 +60,8 @@ test.describe('Home Page - External Links', () => {
       });
 
       await test.step('Then it should have the correct href', async () => {
-        const linkTargets = await homePageUtil.testExternalLinkTargets();
-        
expect(linkTargets.mailingListHref).toBe('http://zeppelin.apache.org/community.html');
+        const href = await 
homePage.externalLinks.mailingList.getAttribute('href');
+        expect(href).toBe('http://zeppelin.apache.org/community.html');
       });
 
       await test.step('And it should open in a new tab', async () => {
@@ -79,10 +75,7 @@ test.describe('Home Page - External Links', () => {
       });
     });
 
-    test('should have correct issues tracking link', async ({ page }) => {
-      const homePage = new HomePage(page);
-      const homePageUtil = new HomePageUtil(page);
-
+    test('should have correct issues tracking link', async () => {
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
@@ -92,10 +85,8 @@ test.describe('Home Page - External Links', () => {
       });
 
       await test.step('Then it should have the correct href', async () => {
-        const linkTargets = await homePageUtil.testExternalLinkTargets();
-        expect(linkTargets.issuesTrackingHref).toBe(
-          
'https://issues.apache.org/jira/projects/ZEPPELIN/issues/filter=allopenissues'
-        );
+        const href = await 
homePage.externalLinks.issuesTracking.getAttribute('href');
+        
expect(href).toBe('https://issues.apache.org/jira/projects/ZEPPELIN/issues/filter=allopenissues');
       });
 
       await test.step('And it should open in a new tab', async () => {
@@ -109,10 +100,7 @@ test.describe('Home Page - External Links', () => {
       });
     });
 
-    test('should have correct GitHub link', async ({ page }) => {
-      const homePage = new HomePage(page);
-      const homePageUtil = new HomePageUtil(page);
-
+    test('should have correct GitHub link', async () => {
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
@@ -122,8 +110,8 @@ test.describe('Home Page - External Links', () => {
       });
 
       await test.step('Then it should have the correct href', async () => {
-        const linkTargets = await homePageUtil.testExternalLinkTargets();
-        
expect(linkTargets.githubHref).toBe('https://github.com/apache/zeppelin');
+        const href = await homePage.externalLinks.github.getAttribute('href');
+        expect(href).toBe('https://github.com/apache/zeppelin');
       });
 
       await test.step('And it should open in a new tab', async () => {
@@ -139,9 +127,7 @@ test.describe('Home Page - External Links', () => {
   });
 
   test.describe('Link Verification', () => {
-    test('should have all external links with proper attributes', async ({ 
page }) => {
-      const homePage = new HomePage(page);
-
+    test('should have all external links with proper attributes', async () => {
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts 
b/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts
index b830f8ab03..e960c3c6cb 100644
--- a/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts
@@ -17,7 +17,10 @@ import { addPageAnnotationBeforeEach, 
performLoginIfRequired, waitForZeppelinRea
 test.describe('Home Page - Layout and Grid', () => {
   addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME);
 
+  let homePage: HomePage;
+
   test.beforeEach(async ({ page }) => {
+    homePage = new HomePage(page);
     await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
@@ -26,7 +29,6 @@ test.describe('Home Page - Layout and Grid', () => {
   test.describe('Responsive Grid Layout', () => {
     test('should display responsive grid structure', async ({ page }) => {
       await test.step('Given I am on the home page', async () => {
-        const homePage = new HomePage(page);
         await homePage.navigateToHome();
       });
 
@@ -35,9 +37,7 @@ test.describe('Home Page - Layout and Grid', () => {
       });
     });
 
-    test('should have proper column distribution', async ({ page }) => {
-      const homePage = new HomePage(page);
-
+    test('should have proper column distribution', async () => {
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
@@ -66,15 +66,12 @@ test.describe('Home Page - Layout and Grid', () => {
     });
 
     test('should maintain layout structure across different viewport sizes', 
async ({ page }) => {
-      const homePage = new HomePage(page);
-
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
 
       await test.step('When I resize to tablet view', async () => {
         await page.setViewportSize({ width: 768, height: 1024 });
-        await page.waitForTimeout(500);
       });
 
       await test.step('Then the grid should still be visible and functional', 
async () => {
@@ -85,7 +82,6 @@ test.describe('Home Page - Layout and Grid', () => {
 
       await test.step('When I resize to mobile view', async () => {
         await page.setViewportSize({ width: 375, height: 667 });
-        await page.waitForTimeout(500);
       });
 
       await test.step('Then the grid should adapt to mobile layout', async () 
=> {
@@ -104,8 +100,6 @@ test.describe('Home Page - Layout and Grid', () => {
 
   test.describe('Content Organization', () => {
     test('should organize content in logical sections', async ({ page }) => {
-      const homePage = new HomePage(page);
-
       await test.step('Given I am on the home page', async () => {
         await homePage.navigateToHome();
       });
diff --git 
a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts 
b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts
index 23a6888054..018bfbf40e 100644
--- a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts
@@ -11,16 +11,21 @@
  */
 
 import { expect, test } from '@playwright/test';
+import { HomePage } from '../../models/home-page';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../utils';
 
 addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME);
 
 test.describe('Home Page Note Operations', () => {
+  let homePage: HomePage;
+
   test.beforeEach(async ({ page }) => {
-    await page.goto('/');
+    homePage = new HomePage(page);
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
-    await page.waitForSelector('zeppelin-node-list', { timeout: 15000 });
+    const noteListLocator = page.locator('zeppelin-node-list');
+    await expect(noteListLocator).toBeVisible({ timeout: 15000 });
   });
 
   test.describe('Given note operations are available', () => {
@@ -31,9 +36,9 @@ test.describe('Home Page Note Operations', () => {
         const firstNote = page.locator('.node .file').first();
         await firstNote.hover();
 
-        await expect(page.locator('.file .operation a[nztooltiptitle*="Rename 
note"]').first()).toBeVisible();
-        await expect(page.locator('.file .operation a[nztooltiptitle*="Clear 
output"]').first()).toBeVisible();
-        await expect(page.locator('.file .operation a[nztooltiptitle*="Move 
note to Trash"]').first()).toBeVisible();
+        await 
expect(homePage.nodeList.noteActions.renameNote.first()).toBeVisible();
+        await 
expect(homePage.nodeList.noteActions.clearOutput.first()).toBeVisible();
+        await 
expect(homePage.nodeList.noteActions.moveToTrash.first()).toBeVisible();
       } else {
         console.log('No notes available for testing operations');
       }
@@ -50,22 +55,18 @@ test.describe('Home Page Note Operations', () => {
         const firstNote = page.locator('.node .file').first();
         await firstNote.hover();
 
-        const renameIcon = page.locator('.file .operation 
a[nztooltiptitle*="Rename note"]').first();
-        const clearIcon = page.locator('.file .operation 
a[nztooltiptitle*="Clear output"]').first();
-        const deleteIcon = page.locator('.file .operation 
a[nztooltiptitle*="Move note to Trash"]').first();
-
-        await expect(renameIcon).toBeVisible();
-        await expect(clearIcon).toBeVisible();
-        await expect(deleteIcon).toBeVisible();
+        await expect(homePage.nodeList.noteActions.renameNote).toBeVisible();
+        await expect(homePage.nodeList.noteActions.clearOutput).toBeVisible();
+        await expect(homePage.nodeList.noteActions.moveToTrash).toBeVisible();
 
         // Test tooltip visibility by hovering over each icon
-        await renameIcon.hover();
+        await homePage.nodeList.noteActions.renameNote.hover();
         await expect(page.locator('.ant-tooltip', { hasText: 'Rename note' 
})).toBeVisible();
 
-        await clearIcon.hover();
+        await homePage.nodeList.noteActions.clearOutput.hover();
         await expect(page.locator('.ant-tooltip', { hasText: 'Clear output' 
})).toBeVisible();
 
-        await deleteIcon.hover();
+        await homePage.nodeList.noteActions.moveToTrash.hover();
         await expect(page.locator('.ant-tooltip', { hasText: 'Move note to 
Trash' })).toBeVisible();
       }
     });
@@ -83,7 +84,7 @@ test.describe('Home Page Note Operations', () => {
         const noteItem = page.locator('.node .file').first();
         await noteItem.hover();
 
-        const renameButton = page.locator('.file .operation 
a[nztooltiptitle*="Rename note"]').first();
+        const renameButton = homePage.nodeList.noteActions.renameNote.first();
         await expect(renameButton).toBeVisible();
         await renameButton.click();
 
@@ -114,7 +115,7 @@ test.describe('Home Page Note Operations', () => {
         const noteItem = page.locator('.node .file').first();
         await noteItem.hover();
 
-        const clearButton = page.locator('.file .operation 
a[nztooltiptitle*="Clear output"]').first();
+        const clearButton = homePage.nodeList.noteActions.clearOutput.first();
         await expect(clearButton).toBeVisible();
         await clearButton.click();
 
@@ -133,7 +134,7 @@ test.describe('Home Page Note Operations', () => {
         const noteItem = page.locator('.node .file').first();
         await noteItem.hover();
 
-        const clearButton = page.locator('.file .operation 
a[nztooltiptitle*="Clear output"]').first();
+        const clearButton = homePage.nodeList.noteActions.clearOutput.first();
         await expect(clearButton).toBeVisible();
         await clearButton.click();
 
@@ -157,7 +158,7 @@ test.describe('Home Page Note Operations', () => {
         const noteItem = page.locator('.node .file').first();
         await noteItem.hover();
 
-        const deleteButton = page.locator('.file .operation 
a[nztooltiptitle*="Move note to Trash"]').first();
+        const deleteButton = homePage.nodeList.noteActions.moveToTrash.first();
         await expect(deleteButton).toBeVisible();
         await deleteButton.click();
 
@@ -176,7 +177,7 @@ test.describe('Home Page Note Operations', () => {
         const noteItem = page.locator('.node .file').first();
         await noteItem.hover();
 
-        const deleteButton = page.locator('.file .operation 
a[nztooltiptitle*="Move note to Trash"]').first();
+        const deleteButton = homePage.nodeList.noteActions.moveToTrash.first();
         await expect(deleteButton).toBeVisible();
         await deleteButton.click();
 
@@ -184,8 +185,6 @@ test.describe('Home Page Note Operations', () => {
         if (await confirmButton.isVisible()) {
           await confirmButton.click();
 
-          await page.waitForTimeout(2000);
-
           const trashFolder = page.locator('.node .folder').filter({ hasText: 
'Trash' });
           await expect(trashFolder).toBeVisible();
         }
diff --git 
a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts 
b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts
index c323573b28..3cb9725dcb 100644
--- a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts
@@ -10,59 +10,80 @@
  * limitations under the License.
  */
 
-import { test } from '@playwright/test';
-import { HomePageUtil } from '../../models/home-page.util';
+import { expect, test } from '@playwright/test';
+import { HomePage } from '../../models/home-page';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../utils';
 
 addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME);
 
 test.describe('Home Page Notebook Actions', () => {
-  let homeUtil: HomePageUtil;
+  let homePage: HomePage;
 
   test.beforeEach(async ({ page }) => {
-    homeUtil = new HomePageUtil(page);
-    await page.goto('/');
+    homePage = new HomePage(page);
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
   });
 
   test.describe('Given notebook list is displayed', () => {
     test('When page loads Then should show notebook actions', async () => {
-      await homeUtil.verifyNotebookActions();
+      await expect(homePage.nodeList.createNewNoteLink).toBeVisible();
+      await expect(homePage.nodeList.importNoteLink).toBeVisible();
+      await expect(homePage.nodeList.filterInput).toBeVisible();
+      await expect(homePage.nodeList.tree).toBeVisible();
     });
 
-    test('When refresh button is clicked Then should trigger reload with 
loading state', async () => {
-      await homeUtil.testNotebookRefreshLoadingState();
+    test('When refresh button is clicked Then should trigger reload with 
loading state', async ({ page }) => {
+      const refreshButton = page.locator('a.refresh-note');
+      const refreshIcon = page.locator('a.refresh-note i[nz-icon]');
+
+      await expect(refreshButton).toBeVisible();
+      await expect(refreshIcon).toBeVisible();
+
+      await homePage.clickRefreshNotes();
+
+      await page.waitForTimeout(500);
+
+      await expect(refreshIcon).toBeVisible();
     });
 
-    test('When filter is used Then should filter notebook list', async () => {
-      await homeUtil.testFilterFunctionality('test');
+    test('When filter is used Then should filter notebook list', async ({ page 
}) => {
+      // Note (ZEPPELIN-6386):
+      // The Notebook search filter in the New UI is currently too slow,
+      // so this test is temporarily skipped. The skip will be removed
+      // once the performance issue is resolved.
+      test.skip();
+      await homePage.filterNotes('test');
+      await page.waitForLoadState('networkidle', { timeout: 15000 });
+      const filteredResults = await page.locator('nz-tree .node').count();
+      expect(filteredResults).toBeGreaterThanOrEqual(0);
     });
   });
 
   test.describe('Given create new note action', () => {
-    test('When create new note is clicked Then should open note creation 
modal', async () => {
-      try {
-        await homeUtil.verifyCreateNewNoteWorkflow();
-      } catch (error) {
-        console.log('Note creation modal might not appear immediately');
-      }
+    test('When create new note is clicked Then should open note creation 
modal', async ({ page }) => {
+      await homePage.clickCreateNewNote();
+      await page.waitForSelector('zeppelin-note-create', { timeout: 10000 });
+      await expect(page.locator('zeppelin-note-create')).toBeVisible();
     });
   });
 
   test.describe('Given import note action', () => {
-    test('When import note is clicked Then should open import modal', async () 
=> {
-      try {
-        await homeUtil.verifyImportNoteWorkflow();
-      } catch (error) {
-        console.log('Import modal might not appear immediately');
-      }
+    test('When import note is clicked Then should open import modal', async ({ 
page }) => {
+      await homePage.clickImportNote();
+      await page.waitForSelector('zeppelin-note-import', { timeout: 10000 });
+      await expect(page.locator('zeppelin-note-import')).toBeVisible();
     });
   });
 
   test.describe('Given notebook refresh functionality', () => {
     test('When refresh is triggered Then should maintain notebook list 
visibility', async () => {
-      await homeUtil.verifyNotebookRefreshFunctionality();
+      await homePage.clickRefreshNotes();
+      await homePage.waitForRefreshToComplete();
+      await expect(homePage.zeppelinNodeList).toBeVisible();
+      const isStillVisible = await homePage.zeppelinNodeList.isVisible();
+      expect(isStillVisible).toBe(true);
     });
   });
 });
diff --git 
a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts 
b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts
index b3388cd087..2c35369bd0 100644
--- 
a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts
@@ -13,7 +13,14 @@
 import { expect, test } from '@playwright/test';
 import { PublishedParagraphPage } from 'e2e/models/published-paragraph-page';
 import { PublishedParagraphTestUtil } from 
'../../../models/published-paragraph-page.util';
-import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../../utils';
+import {
+  addPageAnnotationBeforeEach,
+  performLoginIfRequired,
+  waitForNotebookLinks,
+  waitForZeppelinReady,
+  PAGES,
+  createTestNotebook
+} from '../../../utils';
 
 test.describe('Published Paragraph', () => {
   addPageAnnotationBeforeEach(PAGES.WORKSPACE.PUBLISHED_PARAGRAPH);
@@ -24,24 +31,18 @@ test.describe('Published Paragraph', () => {
 
   test.beforeEach(async ({ page }) => {
     publishedParagraphPage = new PublishedParagraphPage(page);
-    await page.goto('/');
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
+    await waitForNotebookLinks(page);
 
-    // Handle the welcome modal if it appears
-    const cancelButton = page.locator('.ant-modal-root button', { hasText: 
'Cancel' });
-    if ((await cancelButton.count()) > 0) {
-      await cancelButton.click();
+    if ((await publishedParagraphPage.cancelButton.count()) > 0) {
+      await publishedParagraphPage.cancelButton.click();
+      await publishedParagraphPage.cancelButton.waitFor({ state: 'detached', 
timeout: 5000 });
     }
 
     testUtil = new PublishedParagraphTestUtil(page);
-    testNotebook = await testUtil.createTestNotebook();
-  });
-
-  test.afterEach(async () => {
-    if (testNotebook?.noteId) {
-      await testUtil.deleteTestNotebook(testNotebook.noteId);
-    }
+    testNotebook = await createTestNotebook(page);
   });
 
   test.describe('Error Handling', () => {
@@ -50,22 +51,33 @@ test.describe('Published Paragraph', () => {
 
       await 
publishedParagraphPage.navigateToPublishedParagraph(nonExistentIds.noteId, 
nonExistentIds.paragraphId);
 
+      // Directly assert that the modal appears and contains the expected text
       const modal = page.locator('.ant-modal:has-text("Notebook not 
found")').last();
-      const isModalVisible = await modal.isVisible({ timeout: 10000 });
+      await expect(modal).toBeVisible({ timeout: 10000 }); // Expect the modal 
to be visible
 
-      if (isModalVisible) {
-        const modalContent = await modal.textContent();
-        expect(modalContent?.toLowerCase()).toContain('not found');
-      } else {
-        await expect(page).toHaveURL(/\/#\/$/, { timeout: 5000 });
-      }
+      const modalContent = await modal.textContent();
+      expect(modalContent?.toLowerCase()).toContain('not found');
     });
 
-    test('should show error modal when paragraph does not exist in valid 
notebook', async () => {
+    test('should show error modal when paragraph does not exist in valid 
notebook', async ({ page }) => {
       const validNoteId = testNotebook.noteId;
       const nonExistentParagraphId = 
testUtil.generateNonExistentIds().paragraphId;
 
-      await testUtil.verifyNonExistentParagraphError(validNoteId, 
nonExistentParagraphId);
+      await testUtil.navigateToPublishedParagraph(validNoteId, 
nonExistentParagraphId);
+
+      // Expect a specific error modal
+      const errorModal = page.locator('.ant-modal', { hasText: /Paragraph Not 
Found|not found|Error/i });
+      await expect(errorModal).toBeVisible({ timeout: 10000 });
+
+      // Verify modal content includes the invalid paragraph ID
+      const content = await testUtil.getErrorModalContent();
+      expect(content).toBeDefined();
+      expect(content).toContain(nonExistentParagraphId);
+
+      await testUtil.clickErrorModalOk();
+
+      // Wait for redirect to home page
+      await expect(page).toHaveURL(/\/#\/$/, { timeout: 10000 });
     });
 
     test('should redirect to home page after error modal dismissal', async ({ 
page }) => {
@@ -77,8 +89,7 @@ test.describe('Published Paragraph', () => {
       const isModalVisible = await modal.isVisible();
 
       if (isModalVisible) {
-        const okButton = page.locator('button:has-text("OK"), 
button:has-text("확인"), [role="button"]:has-text("OK")');
-        await okButton.click();
+        await publishedParagraphPage.okButton.click();
 
         await expect(page).toHaveURL(/\/#\/$/, { timeout: 10000 });
       } else {
@@ -87,55 +98,193 @@ test.describe('Published Paragraph', () => {
     });
   });
 
-  test.describe('Valid Paragraph Display', () => {
-    test('should enter published paragraph by clicking', async () => {
-      await testUtil.verifyClickLinkThisParagraphBehavior(testNotebook.noteId, 
testNotebook.paragraphId);
+  test.describe('Navigation and URL Patterns', () => {
+    test('should enter published paragraph by clicking link', async ({ page }) 
=> {
+      const { noteId, paragraphId } = testNotebook;
+
+      // Navigate to the normal notebook view
+      await page.goto(`/#/notebook/${noteId}`);
+      await page.waitForLoadState('networkidle');
+
+      // Find the first paragraph
+      let paragraphElement = 
page.locator(`zeppelin-notebook-paragraph[data-testid="${paragraphId}"]`);
+      if ((await paragraphElement.count()) === 0) {
+        paragraphElement = page.locator('zeppelin-notebook-paragraph').first();
+      }
+
+      await expect(paragraphElement).toBeVisible({ timeout: 10000 });
+
+      // Click the settings button to open the dropdown
+      const settingsButton = paragraphElement.locator('a[nz-dropdown]');
+      await settingsButton.click();
+
+      // Click "Link this paragraph" in the dropdown menu
+      const linkParagraphButton = page.locator('li.list-item:has-text("Link 
this paragraph")');
+      await expect(linkParagraphButton).toBeVisible();
+
+      // Handle the new page/tab that opens
+      const [newPage] = await Promise.all([page.waitForEvent('popup'), 
linkParagraphButton.click()]);
+      await newPage.waitForLoadState();
+
+      // Verify the new page URL shows published paragraph
+      await expect(newPage).toHaveURL(new 
RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 10000 });
+
+      const codeEditor = 
newPage.locator('zeppelin-notebook-paragraph-code-editor');
+      await expect(codeEditor).toBeHidden();
+
+      const controlPanel = 
newPage.locator('zeppelin-notebook-paragraph-control');
+      await expect(controlPanel).toBeHidden();
     });
 
-    test('should enter published paragraph by URL', async ({ page }) => {
+    test('should enter published paragraph by direct URL navigation', async ({ 
page }) => {
       await 
page.goto(`/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}`);
       await page.waitForLoadState('networkidle');
       await 
expect(page).toHaveURL(`/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}`,
 {
         timeout: 10000
       });
     });
+
+    test('should allow running paragraph via confirmation modal in published 
mode', async ({ page }) => {
+      const { noteId, paragraphId } = testNotebook;
+
+      // Given: Navigate to a specific paragraph's published URL
+      await page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`);
+      await page.waitForLoadState('networkidle');
+
+      // Then: URL should correctly preserve both notebook and paragraph 
identifiers
+      await expect(page).toHaveURL(new 
RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 15000 });
+
+      // Verify URL contains the specific notebook and paragraph context
+      expect(page.url()).toContain(noteId);
+      expect(page.url()).toContain(paragraphId);
+
+      // Then: Published paragraph component should be loaded (indicating 
published mode is active)
+      const publishedContainer = page.locator('zeppelin-publish-paragraph');
+      await publishedContainer.waitFor({ state: 'attached', timeout: 10000 });
+
+      // Then: Confirmation modal should appear for paragraph execution
+      const modal = page.locator('.ant-modal');
+      await expect(modal).toBeVisible({ timeout: 20000 });
+
+      // Handle the execution confirmation to complete the published mode setup
+      await expect(publishedParagraphPage.runButton).toBeVisible();
+      await publishedParagraphPage.runButton.click();
+      await expect(modal).not.toBeVisible({ timeout: 10000 });
+
+      // Then: Published container should remain attached and page should be 
in published mode
+      await expect(publishedContainer).toBeAttached({ timeout: 10000 });
+
+      // Verify we're in published mode by checking for the published component
+      const isPublishedMode = await page.evaluate(() => 
document.querySelector('zeppelin-publish-paragraph') !== null);
+      expect(isPublishedMode).toBe(true);
+
+      const paragraphContainer = page.locator('zeppelin-publish-paragraph');
+
+      // Published component should be present
+      await expect(paragraphContainer).toBeAttached();
+    });
   });
 
-  test('should show confirmation modal and allow running the paragraph', async 
({ page }) => {
-    const { noteId, paragraphId } = testNotebook;
+  test.describe('Published Mode Functionality', () => {
+    test('should hide editing controls in published mode', async ({ page }) => 
{
+      const { noteId, paragraphId } = testNotebook;
+
+      await page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`);
+      await page.waitForLoadState('networkidle');
+
+      // In published mode, code editor and control panel should be hidden
+      const codeEditor = 
page.locator('zeppelin-notebook-paragraph-code-editor');
+      const controlPanel = page.locator('zeppelin-notebook-paragraph-control');
+
+      await expect(codeEditor).toBeHidden();
+      await expect(controlPanel).toBeHidden();
+    });
+  });
+
+  test.describe('Confirmation Modal and Execution', () => {
+    test('should show confirmation modal and allow running the paragraph', 
async ({ page }) => {
+      const { noteId, paragraphId } = testNotebook;
+
+      await publishedParagraphPage.navigateToNotebook(noteId);
 
-    await publishedParagraphPage.navigateToNotebook(noteId);
+      const paragraphElement = 
page.locator('zeppelin-notebook-paragraph').first();
+      const paragraphResult = 
paragraphElement.locator('zeppelin-notebook-paragraph-result');
 
-    const paragraphElement = 
page.locator('zeppelin-notebook-paragraph').first();
-    const paragraphResult = 
paragraphElement.locator('zeppelin-notebook-paragraph-result');
+      // Only clear output if result exists
+      if (await paragraphResult.isVisible()) {
+        const settingsButton = paragraphElement.locator('a[nz-dropdown]');
+        await settingsButton.click();
 
-    // Only clear output if result exists
-    if (await paragraphResult.isVisible()) {
+        const clearOutputButton = page.locator('li.list-item:has-text("Clear 
output")');
+        await clearOutputButton.click();
+        await expect(paragraphResult).toBeHidden();
+      }
+
+      await publishedParagraphPage.navigateToPublishedParagraph(noteId, 
paragraphId);
+
+      await expect(page).toHaveURL(new RegExp(`/paragraph/${paragraphId}`));
+
+      const modal = publishedParagraphPage.confirmationModal;
+      await expect(modal).toBeVisible();
+
+      // Check for the enhanced modal content
+      await expect(publishedParagraphPage.modalTitle).toHaveText('Run 
Paragraph?');
+
+      // Verify that the modal shows code preview
+      await 
expect(publishedParagraphPage.modalBody.locator('.ant-modal-confirm-content')).toContainText(
+        'This paragraph contains the following code:'
+      );
+      await 
expect(publishedParagraphPage.modalBody.locator('.ant-modal-confirm-content')).toContainText(
+        'Would you like to execute this code?'
+      );
+
+      // Click the Run button in the modal (OK button in confirmation modal)
+      const runButton = modal.locator('.ant-modal-confirm-btns 
.ant-btn-primary');
+      await expect(runButton).toBeVisible();
+      await runButton.click();
+      await expect(modal).toBeHidden();
+    });
+
+    test('should show confirmation modal for paragraphs without results', 
async ({ page }) => {
+      const { noteId, paragraphId } = testNotebook;
+
+      await publishedParagraphPage.navigateToNotebook(noteId);
+
+      const paragraphElement = 
page.locator('zeppelin-notebook-paragraph').first();
       const settingsButton = paragraphElement.locator('a[nz-dropdown]');
       await settingsButton.click();
 
       const clearOutputButton = page.locator('li.list-item:has-text("Clear 
output")');
       await clearOutputButton.click();
-      await expect(paragraphResult).toBeHidden();
-    }
+      await 
expect(paragraphElement.locator('[data-testid="paragraph-result"]')).toBeHidden();
 
-    await publishedParagraphPage.navigateToPublishedParagraph(noteId, 
paragraphId);
+      await publishedParagraphPage.navigateToPublishedParagraph(noteId, 
paragraphId);
 
-    const modal = publishedParagraphPage.confirmationModal;
-    await expect(modal).toBeVisible();
+      const modal = publishedParagraphPage.confirmationModal;
+      await expect(modal).toBeVisible();
 
-    // Check for the new enhanced modal content
-    await expect(publishedParagraphPage.modalTitle).toHaveText('Run 
Paragraph?');
+      // Check for the enhanced modal content
+      await expect(publishedParagraphPage.modalTitle).toContainText('Run 
Paragraph?');
 
-    // Verify that the modal shows code preview
-    const modalContent = 
publishedParagraphPage.confirmationModal.locator('.ant-modal-confirm-content');
-    await expect(modalContent).toContainText('This paragraph contains the 
following code:');
-    await expect(modalContent).toContainText('Would you like to execute this 
code?');
+      // Check that code preview is shown
+      await expect(publishedParagraphPage.modalBody.first()).toContainText(
+        'This paragraph contains the following code:'
+      );
+      await 
expect(publishedParagraphPage.modalBody.first()).toContainText('Would you like 
to execute this code?');
 
-    // Click the Run button in the modal (OK button in confirmation modal)
-    const runButton = modal.locator('.ant-modal-confirm-btns 
.ant-btn-primary');
-    await expect(runButton).toBeVisible();
-    await runButton.click();
-    await expect(modal).toBeHidden();
+      // Verify that the code preview area exists
+      const codePreview = publishedParagraphPage.modalBody
+        .locator('pre, code, .code-preview, .highlight, [class*="code"]')
+        .first();
+      await expect(codePreview).toBeVisible();
+
+      // Check for Run and Cancel buttons
+      await expect(publishedParagraphPage.runButton).toBeVisible();
+      await expect(publishedParagraphPage.cancelButton).toBeVisible();
+
+      // Click the Run button in the modal
+      await publishedParagraphPage.runButton.click();
+      await expect(modal).toBeHidden();
+    });
   });
 });
diff --git a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts 
b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts
index 2099180632..76e9f77e61 100644
--- a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts
@@ -11,79 +11,65 @@
  */
 
 import { expect, test } from '@playwright/test';
-import { ThemePage } from '../../models/theme.page';
+import { DarkModePage } from '../../models/dark-mode-page';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../utils';
 
 test.describe('Dark Mode Theme Switching', () => {
   addPageAnnotationBeforeEach(PAGES.SHARE.THEME_TOGGLE);
-  let themePage: ThemePage;
+  let darkModePage: DarkModePage;
 
   test.beforeEach(async ({ page }) => {
-    themePage = new ThemePage(page);
-    await page.goto('/');
+    darkModePage = new DarkModePage(page);
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
 
     // Handle authentication if shiro.ini exists
     await performLoginIfRequired(page);
 
     // Ensure a clean localStorage for each test
-    await themePage.clearLocalStorage();
+    await darkModePage.clearLocalStorage();
   });
 
-  test('Scenario: User can switch to dark mode and persistence is maintained', 
async ({ page, context }) => {
-    let currentPage = page;
-
+  test('Scenario: User can switch to dark mode and persistence is maintained', 
async ({ page }) => {
     // GIVEN: User is on the main page, which starts in 'system' mode by 
default (localStorage cleared).
     await test.step('GIVEN the page starts in system mode', async () => {
-      await themePage.assertSystemTheme(); // Robot icon for system theme
+      await darkModePage.assertSystemTheme(); // Robot icon for system theme
     });
 
     // WHEN: Explicitly set theme to light mode for the rest of the test.
     await test.step('WHEN the user explicitly sets theme to light mode', async 
() => {
-      await themePage.setThemeInLocalStorage('light');
+      await darkModePage.setThemeInLocalStorage('light');
+      await page.waitForTimeout(500);
+      // Reload the page to apply localStorage theme changes
       await page.reload();
       await waitForZeppelinReady(page);
-      await themePage.assertLightTheme(); // Now it should be light mode with 
sun icon
+      await darkModePage.assertLightTheme(); // Now it should be light mode 
with sun icon
     });
 
     // WHEN: User switches to dark mode by setting localStorage and reloading.
-    await test.step('WHEN the user switches to dark mode', async () => {
-      await themePage.setThemeInLocalStorage('dark');
-      const newPage = await context.newPage();
-      await newPage.goto(currentPage.url());
-      await waitForZeppelinReady(newPage);
-
-      // Update themePage to use newPage and verify dark mode
-      themePage = new ThemePage(newPage);
-      currentPage = newPage;
-      await themePage.assertDarkTheme();
-    });
-
-    // AND: User refreshes the page.
-    await test.step('AND the user refreshes the page', async () => {
-      await currentPage.reload();
-      await waitForZeppelinReady(currentPage);
-    });
-
-    // THEN: Dark mode is maintained after refresh.
-    await test.step('THEN dark mode is maintained after refresh', async () => {
-      await themePage.assertDarkTheme();
+    await test.step('WHEN the user explicitly sets theme to dark mode', async 
() => {
+      await darkModePage.setThemeInLocalStorage('dark');
+      await page.waitForTimeout(500);
+      // Reload the page to apply localStorage theme changes
+      await page.reload();
+      await waitForZeppelinReady(page);
+      await darkModePage.assertDarkTheme();
     });
 
     // AND: User clicks the toggle again to switch back to light mode.
     await test.step('AND the user clicks the toggle to switch back to light 
mode', async () => {
-      await themePage.toggleTheme();
+      await darkModePage.toggleTheme();
     });
 
     // THEN: The theme switches to system mode.
     await test.step('THEN the theme switches to system mode', async () => {
-      await themePage.assertSystemTheme();
+      await darkModePage.assertSystemTheme();
     });
   });
 
   test('Scenario: System Theme and Local Storage Interaction', async ({ page 
}) => {
     // Ensure localStorage is clear for each sub-scenario
-    await themePage.clearLocalStorage();
+    await darkModePage.clearLocalStorage();
 
     await test.step('GIVEN: No localStorage, System preference is Light', 
async () => {
       await page.emulateMedia({ colorScheme: 'light' });
@@ -91,44 +77,44 @@ test.describe('Dark Mode Theme Switching', () => {
       await waitForZeppelinReady(page);
       // When no explicit theme is set, it defaults to 'system' mode
       // Even in system mode with light preference, the icon should be robot
-      await expect(themePage.rootElement).toHaveClass(/light/);
-      await expect(themePage.rootElement).toHaveAttribute('data-theme', 
'light');
-      await themePage.assertSystemTheme(); // Should show robot icon
+      await expect(darkModePage.rootElement).toHaveClass(/light/);
+      await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 
'light');
+      await darkModePage.assertSystemTheme(); // Should show robot icon
     });
 
     await test.step('GIVEN: No localStorage, System preference is Dark 
(initial system state)', async () => {
-      await themePage.setThemeInLocalStorage('system');
+      await darkModePage.setThemeInLocalStorage('system');
       await page.goto('/');
       await waitForZeppelinReady(page);
-      await themePage.assertSystemTheme(); // Robot icon for system theme
+      await darkModePage.assertSystemTheme(); // Robot icon for system theme
     });
 
     await test.step("GIVEN: localStorage is 'dark', System preference is 
Light", async () => {
-      await themePage.setThemeInLocalStorage('dark');
+      await darkModePage.setThemeInLocalStorage('dark');
       await page.emulateMedia({ colorScheme: 'light' });
       await page.goto('/');
       await waitForZeppelinReady(page);
-      await themePage.assertDarkTheme(); // localStorage should override system
+      await darkModePage.assertDarkTheme(); // localStorage should override 
system
     });
 
     await test.step("GIVEN: localStorage is 'system', THEN: Emulate system 
preference change to Light", async () => {
-      await themePage.setThemeInLocalStorage('system');
+      await darkModePage.setThemeInLocalStorage('system');
       await page.emulateMedia({ colorScheme: 'light' });
       await page.goto('/');
       await waitForZeppelinReady(page);
-      await expect(themePage.rootElement).toHaveClass(/light/);
-      await expect(themePage.rootElement).toHaveAttribute('data-theme', 
'light');
-      await themePage.assertSystemTheme(); // Robot icon for system theme
+      await expect(darkModePage.rootElement).toHaveClass(/light/);
+      await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 
'light');
+      await darkModePage.assertSystemTheme(); // Robot icon for system theme
     });
 
     await test.step("GIVEN: localStorage is 'system', THEN: Emulate system 
preference change to Dark", async () => {
-      await themePage.setThemeInLocalStorage('system');
+      await darkModePage.setThemeInLocalStorage('system');
       await page.emulateMedia({ colorScheme: 'dark' });
       await page.goto('/');
       await waitForZeppelinReady(page);
-      await expect(themePage.rootElement).toHaveClass(/dark/);
-      await expect(themePage.rootElement).toHaveAttribute('data-theme', 
'dark');
-      await themePage.assertSystemTheme(); // Robot icon for system theme
+      await expect(darkModePage.rootElement).toHaveClass(/dark/);
+      await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 
'dark');
+      await darkModePage.assertSystemTheme(); // Robot icon for system theme
     });
   });
 });
diff --git 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts
 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts
index 342c67e7a8..6e887b1924 100644
--- 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts
@@ -22,7 +22,7 @@ test.describe('Notebook Repository Item - Display Mode', () 
=> {
   let firstRepoName: string;
 
   test.beforeEach(async ({ page }) => {
-    await page.goto('/');
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
     notebookReposPage = new NotebookReposPage(page);
diff --git 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts
 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts
index 13c870df38..1ee350c21d 100644
--- 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts
@@ -12,7 +12,7 @@
 
 import { expect, test } from '@playwright/test';
 import { NotebookReposPage, NotebookRepoItemPage } from 
'../../../models/notebook-repos-page';
-import { NotebookRepoItemUtil } from 
'../../../models/notebook-repos-page.util';
+import { NotebookRepoItemUtil } from '../../../models/notebook-repo-item.util';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../../utils';
 
 test.describe('Notebook Repository Item - Edit Mode', () => {
@@ -24,7 +24,7 @@ test.describe('Notebook Repository Item - Edit Mode', () => {
   let firstRepoName: string;
 
   test.beforeEach(async ({ page }) => {
-    await page.goto('/');
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
     notebookReposPage = new NotebookReposPage(page);
@@ -66,22 +66,13 @@ test.describe('Notebook Repository Item - Edit Mode', () => 
{
   });
 
   test('should reset form when cancel is clicked', async () => {
-    const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
-
     const firstRow = repoItemPage.settingRows.first();
     const settingName = (await firstRow.locator('td').first().textContent()) 
|| '';
     const originalValue = await repoItemPage.getSettingValue(settingName);
 
     await repoItemPage.clickEdit();
 
-    const isInputVisible = await repoItemPage.isInputVisible(settingName);
-    if (isInputVisible) {
-      await repoItemPage.fillSettingInput(settingName, 'temp-value');
-    }
+    await repoItemPage.fillSettingInput(settingName, 'temp-value');
 
     await repoItemPage.clickCancel();
 
diff --git 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts
 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts
index 51f5d232c1..aedf7e1675 100644
--- 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts
@@ -22,7 +22,7 @@ test.describe('Notebook Repository Item - Form Validation', 
() => {
   let firstRepoName: string;
 
   test.beforeEach(async ({ page }) => {
-    await page.goto('/');
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
     notebookReposPage = new NotebookReposPage(page);
@@ -34,58 +34,32 @@ test.describe('Notebook Repository Item - Form Validation', 
() => {
   });
 
   test('should disable save button when form is invalid', async () => {
-    const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
-
     await repoItemPage.clickEdit();
 
     const firstRow = repoItemPage.settingRows.first();
     const settingName = (await firstRow.locator('td').first().textContent()) 
|| '';
 
-    const isInputVisible = await repoItemPage.isInputVisible(settingName);
-    if (isInputVisible) {
-      await repoItemPage.fillSettingInput(settingName, '');
+    await repoItemPage.fillSettingInput(settingName, '');
 
-      const isSaveEnabled = await repoItemPage.isSaveButtonEnabled();
-      expect(isSaveEnabled).toBe(false);
-    } else {
-      test.skip();
-    }
+    const isSaveEnabled = await repoItemPage.isSaveButtonEnabled();
+    expect(isSaveEnabled).toBe(false);
   });
 
   test('should enable save button when form is valid', async () => {
-    const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
-
     await repoItemPage.clickEdit();
 
     const firstRow = repoItemPage.settingRows.first();
     const settingName = (await firstRow.locator('td').first().textContent()) 
|| '';
 
-    const isInputVisible = await repoItemPage.isInputVisible(settingName);
-    if (isInputVisible) {
-      const originalValue = await 
repoItemPage.getSettingInputValue(settingName);
-      await repoItemPage.fillSettingInput(settingName, originalValue || 
'valid-value');
+    const originalValue = await repoItemPage.getSettingInputValue(settingName);
+    await repoItemPage.fillSettingInput(settingName, originalValue || 
'valid-value');
 
-      const isSaveEnabled = await repoItemPage.isSaveButtonEnabled();
-      expect(isSaveEnabled).toBe(true);
-    } else {
-      test.skip();
-    }
+    const isSaveEnabled = await repoItemPage.isSaveButtonEnabled();
+    expect(isSaveEnabled).toBe(true);
   });
 
   test('should validate required fields on form controls', async () => {
     const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
 
     await repoItemPage.clickEdit();
 
diff --git 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts
 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts
index e25fbfd911..68cc608bb3 100644
--- 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts
@@ -22,7 +22,7 @@ test.describe('Notebook Repository Item - Settings', () => {
   let firstRepoName: string;
 
   test.beforeEach(async ({ page }) => {
-    await page.goto('/');
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
     notebookReposPage = new NotebookReposPage(page);
@@ -48,10 +48,6 @@ test.describe('Notebook Repository Item - Settings', () => {
 
   test('should show input controls for INPUT type settings in edit mode', 
async () => {
     const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
 
     await repoItemPage.clickEdit();
 
@@ -70,10 +66,6 @@ test.describe('Notebook Repository Item - Settings', () => {
 
   test('should show dropdown controls for DROPDOWN type settings in edit 
mode', async () => {
     const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
 
     await repoItemPage.clickEdit();
 
@@ -91,14 +83,9 @@ test.describe('Notebook Repository Item - Settings', () => {
 
   test('should update input value in edit mode', async () => {
     const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
 
     await repoItemPage.clickEdit();
 
-    let foundInput = false;
     for (let i = 0; i < settingRows; i++) {
       const row = repoItemPage.settingRows.nth(i);
       const settingName = (await row.locator('td').first().textContent()) || 
'';
@@ -109,23 +96,12 @@ test.describe('Notebook Repository Item - Settings', () => 
{
         await repoItemPage.fillSettingInput(settingName, testValue);
         const inputValue = await 
repoItemPage.getSettingInputValue(settingName);
         expect(inputValue).toBe(testValue);
-        foundInput = true;
         break;
       }
     }
-
-    if (!foundInput) {
-      test.skip();
-    }
   });
 
   test('should display setting name and value in display mode', async () => {
-    const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
-
     const firstRow = repoItemPage.settingRows.first();
     const nameCell = firstRow.locator('td').first();
     const valueCell = firstRow.locator('td').nth(1);
diff --git 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts
 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts
index a765eb82dd..52f3e42909 100644
--- 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts
@@ -12,7 +12,7 @@
 
 import { expect, test } from '@playwright/test';
 import { NotebookReposPage, NotebookRepoItemPage } from 
'../../../models/notebook-repos-page';
-import { NotebookRepoItemUtil } from 
'../../../models/notebook-repos-page.util';
+import { NotebookRepoItemUtil } from '../../../models/notebook-repo-item.util';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../../utils';
 
 test.describe('Notebook Repository Item - Edit Workflow', () => {
@@ -24,7 +24,7 @@ test.describe('Notebook Repository Item - Edit Workflow', () 
=> {
   let firstRepoName: string;
 
   test.beforeEach(async ({ page }) => {
-    await page.goto('/');
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
     notebookReposPage = new NotebookReposPage(page);
@@ -36,19 +36,14 @@ test.describe('Notebook Repository Item - Edit Workflow', 
() => {
     repoItemUtil = new NotebookRepoItemUtil(page, firstRepoName);
   });
 
-  test('should complete full edit workflow with save', async ({ page }) => {
+  test('should complete full edit workflow with save', async () => {
     const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
 
     await repoItemUtil.verifyDisplayMode();
 
     await repoItemPage.clickEdit();
     await repoItemUtil.verifyEditMode();
 
-    let foundSetting = false;
     for (let i = 0; i < settingRows; i++) {
       const row = repoItemPage.settingRows.nth(i);
       const settingName = (await row.locator('td').first().textContent()) || 
'';
@@ -57,33 +52,19 @@ test.describe('Notebook Repository Item - Edit Workflow', 
() => {
       if (isInputVisible) {
         const originalValue = await 
repoItemPage.getSettingInputValue(settingName);
         await repoItemPage.fillSettingInput(settingName, originalValue || 
'test-value');
-        foundSetting = true;
         break;
       }
     }
 
-    if (!foundSetting) {
-      test.skip();
-      return;
-    }
-
     const isSaveEnabled = await repoItemPage.isSaveButtonEnabled();
     expect(isSaveEnabled).toBe(true);
 
     await repoItemPage.clickSave();
 
-    await page.waitForTimeout(1000);
-
     await repoItemUtil.verifyDisplayMode();
   });
 
   test('should complete full edit workflow with cancel', async () => {
-    const settingRows = await repoItemPage.settingRows.count();
-    if (settingRows === 0) {
-      test.skip();
-      return;
-    }
-
     await repoItemUtil.verifyDisplayMode();
 
     const firstRow = repoItemPage.settingRows.first();
@@ -93,13 +74,7 @@ test.describe('Notebook Repository Item - Edit Workflow', () 
=> {
     await repoItemPage.clickEdit();
     await repoItemUtil.verifyEditMode();
 
-    const isInputVisible = await repoItemPage.isInputVisible(settingName);
-    if (isInputVisible) {
-      await repoItemPage.fillSettingInput(settingName, 'temp-modified-value');
-    } else {
-      test.skip();
-      return;
-    }
+    await repoItemPage.fillSettingInput(settingName, 'temp-modified-value');
 
     await repoItemPage.clickCancel();
     await repoItemUtil.verifyDisplayMode();
diff --git 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts
 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts
index 957a7a8a3d..747037ef47 100644
--- 
a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts
+++ 
b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts
@@ -12,26 +12,23 @@
 
 import { expect, test } from '@playwright/test';
 import { NotebookReposPage } from '../../../models/notebook-repos-page';
-import { NotebookReposPageUtil } from 
'../../../models/notebook-repos-page.util';
 import { addPageAnnotationBeforeEach, performLoginIfRequired, 
waitForZeppelinReady, PAGES } from '../../../utils';
 
 test.describe('Notebook Repository Page - Structure', () => {
   addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS);
 
   let notebookReposPage: NotebookReposPage;
-  let notebookReposUtil: NotebookReposPageUtil;
 
   test.beforeEach(async ({ page }) => {
-    await page.goto('/');
+    await page.goto('/#/');
     await waitForZeppelinReady(page);
     await performLoginIfRequired(page);
     notebookReposPage = new NotebookReposPage(page);
-    notebookReposUtil = new NotebookReposPageUtil(page);
     await notebookReposPage.navigate();
   });
 
   test('should display page header with correct title and description', async 
() => {
-    await expect(notebookReposPage.pageHeader).toBeVisible();
+    await expect(notebookReposPage.zeppelinPageHeader).toBeVisible();
     await expect(notebookReposPage.pageDescription).toBeVisible();
   });
 
@@ -42,10 +39,6 @@ test.describe('Notebook Repository Page - Structure', () => {
 
   test('should display all repository items', async () => {
     const count = await notebookReposPage.getRepositoryItemCount();
-    if (count === 0) {
-      test.skip();
-      return;
-    }
-    await notebookReposUtil.verifyAllRepositoriesRendered();
+    expect(count).toBeGreaterThan(0);
   });
 });
diff --git a/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts 
b/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts
index c6292cbaec..a3e42474c0 100644
--- a/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts
+++ b/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts
@@ -10,58 +10,57 @@
  * limitations under the License.
  */
 
-import { test } from '@playwright/test';
-import { WorkspaceTestUtil } from '../../models/workspace-page.util';
-import { addPageAnnotationBeforeEach, PAGES } from '../../utils';
+import { expect, test } from '@playwright/test';
+import { WorkspacePage } from 'e2e/models/workspace-page';
+import { WorkspaceUtil } from '../../models/workspace-page.util';
+import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, 
waitForZeppelinReady } from '../../utils';
 
 addPageAnnotationBeforeEach(PAGES.WORKSPACE.MAIN);
 
 test.describe('Workspace Main Component', () => {
-  let workspaceUtil: WorkspaceTestUtil;
+  let workspaceUtil: WorkspaceUtil;
+  let workspacePage: WorkspacePage;
 
   test.beforeEach(async ({ page }) => {
-    workspaceUtil = new WorkspaceTestUtil(page);
+    await page.goto('/#/');
+    await waitForZeppelinReady(page);
+    await performLoginIfRequired(page);
+
+    workspacePage = new WorkspacePage(page);
+    workspaceUtil = new WorkspaceUtil(page);
   });
 
   test.describe('Given user accesses workspace container', () => {
-    test('When workspace loads Then should display main container structure', 
async () => {
-      await workspaceUtil.navigateAndWaitForLoad();
+    test('When workspace loads Then should display main container structure', 
async ({ page }) => {
+      await expect(workspacePage.zeppelinWorkspace).toBeVisible();
+      await expect(workspacePage.routerOutlet).toBeAttached();
 
-      await workspaceUtil.verifyWorkspaceLayout();
-      await workspaceUtil.verifyWorkspaceContainer();
+      await expect(workspacePage.zeppelinWorkspace).toBeVisible();
+      const contentElements = await page.locator('.content').count();
+      expect(contentElements).toBeGreaterThan(0);
     });
 
     test('When workspace loads Then should display header component', async () 
=> {
-      await workspaceUtil.navigateAndWaitForLoad();
-
       await workspaceUtil.verifyHeaderVisibility(true);
     });
 
     test('When workspace loads Then should activate router outlet', async () 
=> {
-      await workspaceUtil.navigateAndWaitForLoad();
-
       await workspaceUtil.verifyRouterOutletActivation();
     });
 
     test('When component activates Then should trigger onActivate event', 
async () => {
-      await workspaceUtil.navigateAndWaitForLoad();
-
       await workspaceUtil.waitForComponentActivation();
     });
   });
 
   test.describe('Given workspace header visibility', () => {
     test('When not in publish mode Then should show header', async () => {
-      await workspaceUtil.navigateAndWaitForLoad();
-
       await workspaceUtil.verifyHeaderVisibility(true);
     });
   });
 
   test.describe('Given router outlet functionality', () => {
     test('When navigating to workspace Then should load child components', 
async () => {
-      await workspaceUtil.navigateAndWaitForLoad();
-
       await workspaceUtil.verifyRouterOutletActivation();
       await workspaceUtil.waitForComponentActivation();
     });
diff --git a/zeppelin-web-angular/e2e/utils.ts 
b/zeppelin-web-angular/e2e/utils.ts
index bc57c35352..dab04a1325 100644
--- a/zeppelin-web-angular/e2e/utils.ts
+++ b/zeppelin-web-angular/e2e/utils.ts
@@ -374,7 +374,7 @@ const navigateViaHomePageFallback = async (page: Page, 
baseNotebookName: string)
 };
 
 const extractFirstParagraphId = async (page: Page): Promise<string> => {
-  await page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 
'visible', timeout: 10000 });
+  await page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 
'visible', timeout: 20000 });
 
   const paragraphContainer = 
page.locator('zeppelin-notebook-paragraph').first();
   const dropdownTrigger = paragraphContainer.locator('a[nz-dropdown]');


Reply via email to