chromium/chrome/test/data/webui/side_panel/bookmarks/power_bookmarks_edit_dialog_test.ts

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_edit_dialog.js';

import {BookmarksApiProxyImpl} from 'chrome://bookmarks-side-panel.top-chrome/bookmarks_api_proxy.js';
import type {PowerBookmarksEditDialogElement} from 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_edit_dialog.js';
import {PowerBookmarksService} from 'chrome://bookmarks-side-panel.top-chrome/power_bookmarks_service.js';
import type {CrInputElement} from 'chrome://resources/cr_elements/cr_input/cr_input.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {assertEquals} from 'chrome://webui-test/chai_assert.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';

import {TestBookmarksApiProxy} from './test_bookmarks_api_proxy.js';
import {TestPowerBookmarksDelegate} from './test_power_bookmarks_delegate.js';

suite('SidePanelPowerBookmarksEditDialogTest', () => {
  let powerBookmarksEditDialog: PowerBookmarksEditDialogElement;
  let bookmarksApi: TestBookmarksApiProxy;
  let delegate: TestPowerBookmarksDelegate;
  let service: PowerBookmarksService;

  const folders: chrome.bookmarks.BookmarkTreeNode[] = [
    {
      id: '2',
      parentId: '0',
      title: 'Other Bookmarks',
      children: [
        {
          id: '3',
          parentId: '2',
          title: 'First child bookmark',
          url: 'http://child/bookmark/1/',
          dateAdded: 1,
        },
        {
          id: '4',
          parentId: '2',
          title: 'Second child bookmark',
          url: 'http://child/bookmark/2/',
          dateAdded: 3,
        },
        {
          id: '5',
          parentId: '2',
          title: 'Child folder',
          dateAdded: 2,
          children: [
            {
              id: '6',
              parentId: '5',
              title: 'Nested bookmark',
              url: 'http://nested/bookmark/',
              dateAdded: 4,
            },
          ],
        },
        {
          id: '6',
          parentId: '2',
          title: 'Child folder 2',
          dateAdded: 1,
          children: [],
        },
      ],
    },
  ];

  setup(async () => {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;

    bookmarksApi = new TestBookmarksApiProxy();
    bookmarksApi.setFolders(structuredClone(folders));
    BookmarksApiProxyImpl.setInstance(bookmarksApi);

    delegate = new TestPowerBookmarksDelegate();
    service = new PowerBookmarksService(delegate);
    service.startListening();

    loadTimeData.overrideValues({
      allBookmarks: 'All Bookmarks',
    });

    powerBookmarksEditDialog =
        document.createElement('power-bookmarks-edit-dialog');
    document.body.appendChild(powerBookmarksEditDialog);

    await delegate.whenCalled('onBookmarksLoaded');
  });

  test('ShowsCorrectRowCount', async () => {
    const topLevelBookmarks = service.getTopLevelBookmarks();
    powerBookmarksEditDialog.showDialog(
        [],
        topLevelBookmarks,
        [topLevelBookmarks[0]!],
        false,
    );

    const ironList =
        powerBookmarksEditDialog.shadowRoot!.querySelector('iron-list');
    const rows = ironList!.items!;
    // Shows folders apart from itself/descendants
    assertEquals(rows.length, 1);
  });

  test('ShowsActiveFolderName', () => {
    const topLevelBookmarks = service.getTopLevelBookmarks();
    powerBookmarksEditDialog.showDialog(
        [],
        topLevelBookmarks,
        [topLevelBookmarks[0]!],
        false,
    );

    const titleElement =
        powerBookmarksEditDialog.shadowRoot!.querySelector('h2');
    assertEquals(
        titleElement!.textContent!.includes(
            loadTimeData.getString('allBookmarks')),
        true);
  });

  test('SavesChanges', async () => {
    let saveCount = 0;
    let savedName;
    let savedUrl;
    let savedParent;
    let savedNewFolderCount = 0;
    powerBookmarksEditDialog.addEventListener('save', ((e: CustomEvent) => {
                                                        saveCount++;
                                                        savedName =
                                                            e.detail.name;
                                                        savedUrl = e.detail.url;
                                                        savedParent =
                                                            e.detail.folderId;
                                                        savedNewFolderCount =
                                                            e.detail.newFolders
                                                                .length;
                                                      }) as EventListener);

    const topLevelBookmarks = service.getTopLevelBookmarks();
    powerBookmarksEditDialog.showDialog(
        [],
        topLevelBookmarks,
        [topLevelBookmarks[3]!],
        false,
    );

    const newFolderButton: HTMLElement =
        powerBookmarksEditDialog.shadowRoot!.querySelector('#newFolderButton')!;
    newFolderButton.click();

    const nameInput: CrInputElement =
        powerBookmarksEditDialog.shadowRoot!.querySelector('#nameInput')!;
    nameInput.inputElement.value = 'Modified value';
    nameInput.inputElement.dispatchEvent(
        new CustomEvent('input', {composed: true, bubbles: true}));
    await eventToPromise('value-changed', nameInput);

    const saveButton: HTMLElement =
        powerBookmarksEditDialog.shadowRoot!.querySelector('.action-button')!;
    saveButton.click();

    assertEquals(saveCount, 1);
    assertEquals(savedName, 'Modified value');
    assertEquals(savedUrl, 'http://child/bookmark/1/');
    // Adding a new folder should automatically select that folder.
    assertEquals(savedParent, 'tmp_new_folder_0');
    assertEquals(savedNewFolderCount, 1);
  });

  test('DoesNotSaveInvalidUrls', async () => {
    let saveCount = 0;
    powerBookmarksEditDialog.addEventListener('save', (() => {
                                                        saveCount++;
                                                      }) as EventListener);

    const topLevelBookmarks = service.getTopLevelBookmarks();
    powerBookmarksEditDialog.showDialog(
        [],
        topLevelBookmarks,
        [topLevelBookmarks[3]!],
        false,
    );

    const newFolderButton: HTMLElement =
        powerBookmarksEditDialog.shadowRoot!.querySelector('#newFolderButton')!;
    newFolderButton.click();

    const urlInput: CrInputElement =
        powerBookmarksEditDialog.shadowRoot!.querySelector('#urlInput')!;
    urlInput.inputElement.value = 'notavalidurl.2';
    urlInput.inputElement.dispatchEvent(
        new CustomEvent('input', {composed: true, bubbles: true}));
    await eventToPromise('value-changed', urlInput);

    const saveButton: HTMLElement =
        powerBookmarksEditDialog.shadowRoot!.querySelector('.action-button')!;
    saveButton.click();

    // Wait for the urlInput to update for validation, and wait one more cycle
    // to ensure we catch the save event if it occurs.
    await urlInput.updateComplete;
    await new Promise(resolve => setTimeout(resolve, 1));

    assertEquals(saveCount, 0);
  });
});