tbonelee commented on code in PR #5101:
URL: https://github.com/apache/zeppelin/pull/5101#discussion_r2460323004


##########
zeppelin-web-angular/e2e/models/notebook-action-bar-page.util.ts:
##########
@@ -0,0 +1,193 @@
+/*
+ * 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 { NotebookActionBarPage } from './notebook-action-bar-page';
+
+export class NotebookActionBarUtil {
+  private page: Page;
+  private actionBarPage: NotebookActionBarPage;
+
+  constructor(page: Page) {
+    this.page = page;
+    this.actionBarPage = new NotebookActionBarPage(page);
+  }
+
+  async verifyTitleEditingFunctionality(expectedTitle?: string): Promise<void> 
{
+    await expect(this.actionBarPage.titleEditor).toBeVisible();
+    const titleText = await this.actionBarPage.getTitleText();
+    expect(titleText).toBeDefined();
+    expect(titleText.length).toBeGreaterThan(0);
+
+    if (expectedTitle) {
+      expect(titleText).toContain(expectedTitle);
+    }
+  }
+
+  async verifyRunAllWorkflow(): Promise<void> {
+    await expect(this.actionBarPage.runAllButton).toBeVisible();
+    await expect(this.actionBarPage.runAllButton).toBeEnabled();
+
+    await this.actionBarPage.clickRunAll();
+
+    // Check if confirmation dialog appears (it might not in some 
configurations)
+    try {
+      // Try multiple possible confirmation dialog selectors
+      const confirmSelector = this.page
+        .locator('nz-popconfirm button:has-text("OK"), .ant-popconfirm 
button:has-text("OK"), button:has-text("OK")')
+        .first();
+      await expect(confirmSelector).toBeVisible({ timeout: 2000 });
+      await confirmSelector.click();
+      await expect(confirmSelector).not.toBeVisible();
+    } catch (error) {
+      // If no confirmation dialog appears, that's also valid behavior
+      console.log('Run all executed without confirmation dialog');
+    }
+  }
+
+  async verifyCodeVisibilityToggle(): Promise<void> {
+    await expect(this.actionBarPage.showHideCodeButton).toBeVisible();
+    await expect(this.actionBarPage.showHideCodeButton).toBeEnabled();
+
+    await this.actionBarPage.toggleCodeVisibility();
+
+    // Verify the button is still functional after click
+    await expect(this.actionBarPage.showHideCodeButton).toBeEnabled();
+  }
+
+  async verifyOutputVisibilityToggle(): Promise<void> {
+    await expect(this.actionBarPage.showHideOutputButton).toBeVisible();
+    await expect(this.actionBarPage.showHideOutputButton).toBeEnabled();
+
+    await this.actionBarPage.toggleOutputVisibility();
+
+    // Verify the button is still functional after click
+    await expect(this.actionBarPage.showHideOutputButton).toBeEnabled();
+  }

Review Comment:
   How about verifying the icon change as well? I'm not sure this is reliable, 
`nz-button` seems to set the `data-icon` attribute on the `svg` to the `nzType` 
value. We could assert that attribute and confirm it updates when the button is 
clicked.



##########
zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts:
##########
@@ -0,0 +1,1056 @@
+/*
+ * 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 test, { expect, Locator, Page } from '@playwright/test';
+import { BasePage } from './base-page';
+
+export class NotebookKeyboardPage extends BasePage {
+  readonly codeEditor: Locator;
+  readonly paragraphContainer: Locator;
+  readonly firstParagraph: Locator;
+  readonly runButton: Locator;
+  readonly paragraphResult: Locator;
+  readonly newParagraphButton: Locator;
+  readonly interpreterSelector: Locator;
+  readonly interpreterDropdown: Locator;
+  readonly autocompletePopup: Locator;
+  readonly autocompleteItems: Locator;
+  readonly paragraphTitle: Locator;
+  readonly editorLines: Locator;
+  readonly cursorLine: Locator;
+  readonly settingsButton: Locator;
+  readonly clearOutputOption: Locator;
+  readonly deleteButton: Locator;
+
+  constructor(page: Page) {
+    super(page);
+    this.codeEditor = page.locator('.monaco-editor .monaco-mouse-cursor-text');
+    this.paragraphContainer = page.locator('zeppelin-notebook-paragraph');
+    this.firstParagraph = this.paragraphContainer.first();
+    this.runButton = page.locator('button[title="Run this paragraph"], 
button:has-text("Run")');
+    this.paragraphResult = page.locator('[data-testid="paragraph-result"]');
+    this.newParagraphButton = page.locator('button:has-text("Add Paragraph"), 
.new-paragraph-button');
+    this.interpreterSelector = page.locator('.interpreter-selector');
+    this.interpreterDropdown = 
page.locator('nz-select[ng-reflect-nz-placeholder="Interpreter"]');
+    this.autocompletePopup = page.locator('.monaco-editor .suggest-widget');
+    this.autocompleteItems = page.locator('.monaco-editor .suggest-widget 
.monaco-list-row');
+    this.paragraphTitle = page.locator('.paragraph-title');
+    this.editorLines = page.locator('.monaco-editor .view-lines');
+    this.cursorLine = page.locator('.monaco-editor .current-line');
+    this.settingsButton = page.locator('a[nz-dropdown]');
+    this.clearOutputOption = page.locator('li.list-item:has-text("Clear 
output")');
+    this.deleteButton = page.locator('button:has-text("Delete"), 
.delete-paragraph-button');
+  }
+
+  async navigateToNotebook(noteId: string): Promise<void> {
+    if (!noteId) {
+      console.error('noteId is undefined or null. Cannot navigate to 
notebook.');

Review Comment:
   It seems better to throw an error right away when `noteId` is falsy, since 
that implies an earlier-step issue, so we don't end up silencing it. WDYT?



##########
zeppelin-web-angular/e2e/models/notebook-action-bar-page.util.ts:
##########
@@ -0,0 +1,193 @@
+/*
+ * 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 { NotebookActionBarPage } from './notebook-action-bar-page';
+
+export class NotebookActionBarUtil {
+  private page: Page;
+  private actionBarPage: NotebookActionBarPage;
+
+  constructor(page: Page) {
+    this.page = page;
+    this.actionBarPage = new NotebookActionBarPage(page);
+  }
+
+  async verifyTitleEditingFunctionality(expectedTitle?: string): Promise<void> 
{
+    await expect(this.actionBarPage.titleEditor).toBeVisible();
+    const titleText = await this.actionBarPage.getTitleText();
+    expect(titleText).toBeDefined();
+    expect(titleText.length).toBeGreaterThan(0);
+
+    if (expectedTitle) {
+      expect(titleText).toContain(expectedTitle);
+    }
+  }

Review Comment:
   If we're keeping this method name, the test should assert the editing 
behavior, not just element presence. Otherwise, consider renaming it to reflect 
what it currently does.



##########
zeppelin-web-angular/e2e/models/notebook-action-bar-page.util.ts:
##########
@@ -0,0 +1,193 @@
+/*
+ * 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 { NotebookActionBarPage } from './notebook-action-bar-page';
+
+export class NotebookActionBarUtil {
+  private page: Page;
+  private actionBarPage: NotebookActionBarPage;
+
+  constructor(page: Page) {
+    this.page = page;
+    this.actionBarPage = new NotebookActionBarPage(page);
+  }
+
+  async verifyTitleEditingFunctionality(expectedTitle?: string): Promise<void> 
{
+    await expect(this.actionBarPage.titleEditor).toBeVisible();
+    const titleText = await this.actionBarPage.getTitleText();
+    expect(titleText).toBeDefined();
+    expect(titleText.length).toBeGreaterThan(0);
+
+    if (expectedTitle) {
+      expect(titleText).toContain(expectedTitle);
+    }
+  }
+
+  async verifyRunAllWorkflow(): Promise<void> {
+    await expect(this.actionBarPage.runAllButton).toBeVisible();
+    await expect(this.actionBarPage.runAllButton).toBeEnabled();
+
+    await this.actionBarPage.clickRunAll();
+
+    // Check if confirmation dialog appears (it might not in some 
configurations)
+    try {
+      // Try multiple possible confirmation dialog selectors
+      const confirmSelector = this.page
+        .locator('nz-popconfirm button:has-text("OK"), .ant-popconfirm 
button:has-text("OK"), button:has-text("OK")')
+        .first();
+      await expect(confirmSelector).toBeVisible({ timeout: 2000 });
+      await confirmSelector.click();
+      await expect(confirmSelector).not.toBeVisible();
+    } catch (error) {
+      // If no confirmation dialog appears, that's also valid behavior
+      console.log('Run all executed without confirmation dialog');
+    }

Review Comment:
   Rather than catching and continuing, could we refactor (e.g., split methods) 
so that cases which should fail actually fail? Same note for the other similar 
try/catch blocks.



##########
zeppelin-web-angular/e2e/global-teardown.ts:
##########
@@ -17,6 +17,63 @@ async function globalTeardown() {
 
   LoginTestUtil.resetCache();
   console.log('✅ Test cache cleared');
+
+  // Clean up test notebooks that may have been left behind due to test 
failures
+  await cleanupTestNotebooks();
+}
+
+async function cleanupTestNotebooks() {

Review Comment:
   We need authorizations to use Rest APIs. How about using test notebook 
directory?
   
   
https://github.com/apache/zeppelin/blob/0a768bcc07a4b691df51eda8f26cc013e8773612/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java#L982
   
   Maybe we could set `ZEPPELIN_NOTEBOOK_DIR` environment variable, and let e2e 
script to use this to clean up test notebooks.



##########
zeppelin-web-angular/e2e/models/notebook-action-bar-page.util.ts:
##########
@@ -0,0 +1,193 @@
+/*
+ * 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 { NotebookActionBarPage } from './notebook-action-bar-page';
+
+export class NotebookActionBarUtil {
+  private page: Page;
+  private actionBarPage: NotebookActionBarPage;
+
+  constructor(page: Page) {
+    this.page = page;
+    this.actionBarPage = new NotebookActionBarPage(page);
+  }
+
+  async verifyTitleEditingFunctionality(expectedTitle?: string): Promise<void> 
{
+    await expect(this.actionBarPage.titleEditor).toBeVisible();
+    const titleText = await this.actionBarPage.getTitleText();
+    expect(titleText).toBeDefined();
+    expect(titleText.length).toBeGreaterThan(0);
+
+    if (expectedTitle) {
+      expect(titleText).toContain(expectedTitle);
+    }
+  }
+
+  async verifyRunAllWorkflow(): Promise<void> {
+    await expect(this.actionBarPage.runAllButton).toBeVisible();
+    await expect(this.actionBarPage.runAllButton).toBeEnabled();
+
+    await this.actionBarPage.clickRunAll();
+
+    // Check if confirmation dialog appears (it might not in some 
configurations)
+    try {
+      // Try multiple possible confirmation dialog selectors
+      const confirmSelector = this.page
+        .locator('nz-popconfirm button:has-text("OK"), .ant-popconfirm 
button:has-text("OK"), button:has-text("OK")')
+        .first();
+      await expect(confirmSelector).toBeVisible({ timeout: 2000 });
+      await confirmSelector.click();
+      await expect(confirmSelector).not.toBeVisible();
+    } catch (error) {
+      // If no confirmation dialog appears, that's also valid behavior
+      console.log('Run all executed without confirmation dialog');
+    }
+  }
+
+  async verifyCodeVisibilityToggle(): Promise<void> {
+    await expect(this.actionBarPage.showHideCodeButton).toBeVisible();
+    await expect(this.actionBarPage.showHideCodeButton).toBeEnabled();
+
+    await this.actionBarPage.toggleCodeVisibility();
+
+    // Verify the button is still functional after click
+    await expect(this.actionBarPage.showHideCodeButton).toBeEnabled();
+  }
+
+  async verifyOutputVisibilityToggle(): Promise<void> {
+    await expect(this.actionBarPage.showHideOutputButton).toBeVisible();
+    await expect(this.actionBarPage.showHideOutputButton).toBeEnabled();
+
+    await this.actionBarPage.toggleOutputVisibility();
+
+    // Verify the button is still functional after click
+    await expect(this.actionBarPage.showHideOutputButton).toBeEnabled();
+  }
+
+  async verifyClearOutputWorkflow(): Promise<void> {
+    await expect(this.actionBarPage.clearOutputButton).toBeVisible();
+    await expect(this.actionBarPage.clearOutputButton).toBeEnabled();
+
+    await this.actionBarPage.clickClearOutput();
+
+    // Check if confirmation dialog appears (it might not in some 
configurations)
+    try {
+      // Try multiple possible confirmation dialog selectors
+      const confirmSelector = this.page
+        .locator('nz-popconfirm button:has-text("OK"), .ant-popconfirm 
button:has-text("OK"), button:has-text("OK")')
+        .first();
+      await expect(confirmSelector).toBeVisible({ timeout: 2000 });
+      await confirmSelector.click();
+      await expect(confirmSelector).not.toBeVisible();
+    } catch (error) {
+      // If no confirmation dialog appears, that's also valid behavior
+      console.log('Clear output executed without confirmation dialog');
+    }

Review Comment:
   The same comment as the above one.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to