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


##########
zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts:
##########
@@ -0,0 +1,82 @@
+/*
+ * 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 } from '@playwright/test';
+import { HomePage } from '../../../models/home-page';
+import { NoteCreateModal } from '../../../models/note-create-modal';
+import { NoteCreateModalUtil } from '../../../models/note-create-modal.util';
+import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, 
waitForZeppelinReady } from '../../../utils';
+
+test.describe('Note Create Modal', () => {
+  let homePage: HomePage;
+  let noteCreateModal: NoteCreateModal;
+  let noteCreateUtil: NoteCreateModalUtil;
+
+  addPageAnnotationBeforeEach(PAGES.SHARE.NOTE_CREATE);
+
+  test.beforeEach(async ({ page }) => {
+    homePage = new HomePage(page);
+    noteCreateModal = new NoteCreateModal(page);
+    noteCreateUtil = new NoteCreateModalUtil(noteCreateModal);
+
+    await page.goto('/');
+    await waitForZeppelinReady(page);
+    await performLoginIfRequired(page);
+
+    await homePage.clickCreateNewNote();
+    await page.waitForSelector('input[name="noteName"]');
+  });
+
+  test('Given user clicks Create New Note, When modal opens, Then modal should 
display all required elements', async () => {
+    await noteCreateUtil.verifyModalIsOpen();
+    await expect(noteCreateModal.interpreterDropdown).toBeVisible();
+    await noteCreateUtil.verifyFolderCreationInfo();
+  });
+
+  test('Given Create Note modal is open, When checking default note name, Then 
auto-generated name should follow pattern', async () => {
+    await noteCreateUtil.verifyDefaultNoteName(/Untitled Note \d+/);
+  });
+
+  test('Given Create Note modal is open, When entering custom note name and 
creating, Then new note should be created successfully', async ({
+    page
+  }) => {
+    const uniqueName = `Test Note ${Date.now()}`;
+    await noteCreateModal.setNoteName(uniqueName);
+    await noteCreateModal.clickCreate();
+
+    await page.waitForURL(/notebook\//);
+    expect(page.url()).toContain('notebook/');
+  });
+
+  test('Given Create Note modal is open, When entering note name with folder 
path, Then note should be created in folder', async ({
+    page
+  }) => {
+    const folderPath = `/TestFolder/SubFolder`;
+    const noteName = `Note ${Date.now()}`;
+    const fullPath = `${folderPath}/${noteName}`;
+
+    await noteCreateModal.setNoteName(fullPath);
+    await noteCreateModal.clickCreate();
+
+    await page.waitForURL(/notebook\//);
+    expect(page.url()).toContain('notebook/');
+  });

Review Comment:
   It would be better if we could verify the note name and path.



##########
zeppelin-web-angular/e2e/models/node-list-page.ts:
##########
@@ -0,0 +1,176 @@
+/*
+ * 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 { Locator, Page } from '@playwright/test';
+import { BasePage } from './base-page';
+
+export class NodeListPage extends BasePage {
+  readonly nodeListContainer: Locator;
+  readonly importNoteButton: Locator;
+  readonly createNewNoteButton: Locator;
+  readonly filterInput: Locator;
+  readonly treeView: Locator;
+  readonly folders: Locator;
+  readonly notes: Locator;
+  readonly trashFolder: Locator;
+
+  constructor(page: Page) {
+    super(page);
+    this.nodeListContainer = page.locator('zeppelin-node-list');
+    this.importNoteButton = page.getByText('Import Note', { exact: true 
}).first();
+    this.createNewNoteButton = page.getByText('Create new Note', { exact: true 
}).first();
+    this.filterInput = page.locator('zeppelin-node-list 
input[placeholder*="Filter"]');
+    this.treeView = page.locator('zeppelin-node-list nz-tree');
+    this.folders = page.locator('nz-tree-node').filter({ has: 
page.locator('.ant-tree-node-content-wrapper .folder') });
+    this.notes = page.locator('nz-tree-node').filter({ has: 
page.locator('.ant-tree-node-content-wrapper .file') });
+    this.trashFolder = page.locator('nz-tree-node').filter({ hasText: '~Trash' 
});
+  }
+
+  async clickImportNote(): Promise<void> {
+    await this.importNoteButton.click();
+  }
+
+  async clickCreateNewNote(): Promise<void> {
+    await this.createNewNoteButton.click();
+  }
+
+  async filterNotes(searchTerm: string): Promise<void> {
+    await this.filterInput.fill(searchTerm);
+  }
+
+  async clearFilter(): Promise<void> {
+    await this.filterInput.clear();
+  }
+
+  async getFolderByName(folderName: string): Locator {
+    return this.page.locator('nz-tree-node').filter({ hasText: folderName 
}).first();
+  }
+
+  async getNoteByName(noteName: string): Locator {

Review Comment:
   ```suggestion
     getNoteByName(noteName: string): Locator {
   ```



##########
zeppelin-web-angular/e2e/models/node-list-page.ts:
##########
@@ -0,0 +1,176 @@
+/*
+ * 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 { Locator, Page } from '@playwright/test';
+import { BasePage } from './base-page';
+
+export class NodeListPage extends BasePage {
+  readonly nodeListContainer: Locator;
+  readonly importNoteButton: Locator;
+  readonly createNewNoteButton: Locator;
+  readonly filterInput: Locator;
+  readonly treeView: Locator;
+  readonly folders: Locator;
+  readonly notes: Locator;
+  readonly trashFolder: Locator;
+
+  constructor(page: Page) {
+    super(page);
+    this.nodeListContainer = page.locator('zeppelin-node-list');
+    this.importNoteButton = page.getByText('Import Note', { exact: true 
}).first();
+    this.createNewNoteButton = page.getByText('Create new Note', { exact: true 
}).first();
+    this.filterInput = page.locator('zeppelin-node-list 
input[placeholder*="Filter"]');
+    this.treeView = page.locator('zeppelin-node-list nz-tree');
+    this.folders = page.locator('nz-tree-node').filter({ has: 
page.locator('.ant-tree-node-content-wrapper .folder') });
+    this.notes = page.locator('nz-tree-node').filter({ has: 
page.locator('.ant-tree-node-content-wrapper .file') });
+    this.trashFolder = page.locator('nz-tree-node').filter({ hasText: '~Trash' 
});
+  }
+
+  async clickImportNote(): Promise<void> {
+    await this.importNoteButton.click();
+  }
+
+  async clickCreateNewNote(): Promise<void> {
+    await this.createNewNoteButton.click();
+  }
+
+  async filterNotes(searchTerm: string): Promise<void> {
+    await this.filterInput.fill(searchTerm);
+  }
+
+  async clearFilter(): Promise<void> {
+    await this.filterInput.clear();
+  }
+
+  async getFolderByName(folderName: string): Locator {

Review Comment:
   ```suggestion
     getFolderByName(folderName: string): Locator {
   ```



##########
zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts:
##########
@@ -0,0 +1,111 @@
+/*
+ * 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 } from '@playwright/test';
+import { HomePage } from '../../../models/home-page';
+import { NoteImportModal } from '../../../models/note-import-modal';
+import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, 
waitForZeppelinReady } from '../../../utils';
+
+test.describe('Note Import Modal', () => {
+  let homePage: HomePage;
+  let noteImportModal: NoteImportModal;
+
+  addPageAnnotationBeforeEach(PAGES.SHARE.NOTE_IMPORT);
+
+  test.beforeEach(async ({ page }) => {
+    homePage = new HomePage(page);
+    noteImportModal = new NoteImportModal(page);
+
+    await page.goto('/');
+    await waitForZeppelinReady(page);
+    await performLoginIfRequired(page);
+
+    await homePage.clickImportNote();
+    await page.waitForSelector('input[name="noteImportName"]');
+  });
+
+  test('Given user clicks Import Note, When modal opens, Then modal should 
display all required elements', async () => {
+    await expect(noteImportModal.modal).toBeVisible();
+    await expect(noteImportModal.modalTitle).toBeVisible();
+    await expect(noteImportModal.importAsInput).toBeVisible();
+    await expect(noteImportModal.jsonFileTab).toBeVisible();
+    await expect(noteImportModal.urlTab).toBeVisible();
+  });
+
+  test('Given Import Note modal is open, When viewing default tab, Then JSON 
File tab should be selected', async () => {
+    const isJsonTabSelected = await noteImportModal.isJsonFileTabSelected();
+    expect(isJsonTabSelected).toBe(true);
+
+    await expect(noteImportModal.uploadArea).toBeVisible();
+    await expect(noteImportModal.uploadText).toBeVisible();
+  });
+
+  test('Given Import Note modal is open, When switching to URL tab, Then URL 
input should be visible', async () => {
+    await noteImportModal.switchToUrlTab();
+
+    const isUrlTabSelected = await noteImportModal.isUrlTabSelected();
+    expect(isUrlTabSelected).toBe(true);
+
+    await expect(noteImportModal.urlInput).toBeVisible();
+    await expect(noteImportModal.importNoteButton).toBeVisible();
+  });
+
+  test('Given URL tab is selected, When URL is empty, Then import button 
should be disabled', async () => {
+    await noteImportModal.switchToUrlTab();
+
+    const isDisabled = await noteImportModal.isImportNoteButtonDisabled();
+    expect(isDisabled).toBe(true);
+  });
+
+  test('Given URL tab is selected, When entering URL, Then import button 
should be enabled', async () => {
+    await noteImportModal.switchToUrlTab();
+    await noteImportModal.setImportUrl('https://example.com/note.json');
+
+    const isDisabled = await noteImportModal.isImportNoteButtonDisabled();
+    expect(isDisabled).toBe(false);
+  });
+
+  test('Given Import Note modal is open, When entering import name, Then name 
should be set', async () => {
+    const importName = `Imported Note ${Date.now()}`;
+    await noteImportModal.setImportAsName(importName);
+
+    const actualName = await noteImportModal.getImportAsName();
+    expect(actualName).toBe(importName);
+  });
+
+  test('Given JSON File tab is selected, When viewing file size limit, Then 
limit should be displayed', async () => {
+    const fileSizeLimit = await noteImportModal.getFileSizeLimit();
+    expect(fileSizeLimit).toBeTruthy();
+    expect(fileSizeLimit.length).toBeGreaterThan(0);
+  });
+
+  test('Given Import Note modal is open, When clicking close button, Then 
modal should close', async () => {
+    await noteImportModal.close();
+    await expect(noteImportModal.modal).not.toBeVisible();
+  });
+
+  test('Given URL tab is selected, When entering invalid URL and clicking 
import, Then error should be displayed', async ({
+    page
+  }) => {
+    await noteImportModal.switchToUrlTab();
+    await noteImportModal.setImportUrl('invalid-url');
+    await noteImportModal.clickImportNote();
+
+    await page.waitForTimeout(2000);
+
+    const hasError = await noteImportModal.isErrorAlertVisible();
+    if (hasError) {
+      const errorMessage = await noteImportModal.getErrorMessage();
+      expect(errorMessage).toBeTruthy();
+    }

Review Comment:
   Is there any reason for this to be verified conditionally?



-- 
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