chromium/chrome/test/data/webui/extensions/manager_test.ts

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

import type {ChromeEvent} from '/tools/typescript/definitions/chrome_event.js';
import type {ExtensionsManagerElement} from 'chrome://extensions/extensions.js';
import {navigation, Page, Service} from 'chrome://extensions/extensions.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';

interface ChromeEventWithDispatch extends
    ChromeEvent<(data: chrome.developerPrivate.EventData) => void> {
  dispatch<E>(obj: E): void;
}

suite('ExtensionManagerTest', function() {
  let manager: ExtensionsManagerElement;

  function assertViewActive(tagName: string) {
    assertTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`));
  }

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    manager = document.createElement('extensions-manager');
    document.body.appendChild(manager);

    // Wait for the first view to be active before starting tests, if one is
    // not active already. Sometimes, on Mac with native HTML imports
    // disabled, no views are active at this point.
    return manager.$.viewManager.querySelector('.active') ?
        Promise.resolve() :
        eventToPromise('view-enter-start', manager);
  });

  function getExtensions(): chrome.developerPrivate.ExtensionInfo[] {
    return manager.shadowRoot!.querySelector(
                                  'extensions-item-list')!.extensions;
  }

  function getApps(): chrome.developerPrivate.ExtensionInfo[] {
    return manager.shadowRoot!.querySelector('extensions-item-list')!.apps;
  }

  test('ItemListVisibility', function() {
    function getExtensionByName(name: string):
        chrome.developerPrivate.ExtensionInfo|null {
      return getExtensions().find(el => el.name === name) || null;
    }

    const extension = getExtensionByName('My extension 1');
    assertTrue(!!extension);

    const list = manager.$['items-list'];

    function listHasItemWithName(name: string): boolean {
      return list.extensions.some(el => el.name === name);
    }

    assertTrue(listHasItemWithName('My extension 1'));

    const target = Service.getInstance().getItemStateChangedTarget() as
        ChromeEventWithDispatch;

    target.dispatch<chrome.developerPrivate.EventData>({
      event_type: chrome.developerPrivate.EventType.UNINSTALLED,
      item_id: extension.id,
    });
    flush();
    assertFalse(listHasItemWithName('My extension 1'));

    target.dispatch<chrome.developerPrivate.EventData>({
      event_type: chrome.developerPrivate.EventType.INSTALLED,
      item_id: extension.id,
      extensionInfo: extension,
    });
    flush();
    assertTrue(listHasItemWithName('My extension 1'));
  });

  test('SplitItems', function() {
    function hasExtensionWithName(name: string): boolean {
      return getExtensions().some(el => el.name === name);
    }

    function hasAppWithName(name: string): boolean {
      return getApps().some(el => el.name === name);
    }

    // Test that we properly split up the items into two sections.
    assertTrue(hasExtensionWithName('My extension 1'));
    assertTrue(hasAppWithName('Platform App Test: minimal platform app'));
    assertTrue(hasAppWithName('hosted_app'));
    assertTrue(hasAppWithName('Packaged App Test'));
  });

  test('ChangePages', function() {
    // We start on the item list.
    manager.shadowRoot!.querySelector(
                           'extensions-sidebar')!.$.sectionsExtensions.click();
    flush();
    assertViewActive('extensions-item-list');

    // Switch: item list -> keyboard shortcuts.
    manager.shadowRoot!.querySelector(
                           'extensions-sidebar')!.$.sectionsShortcuts.click();
    flush();
    assertViewActive('extensions-keyboard-shortcuts');

    // Switch: item list -> detail view.
    const item =
        manager.$['items-list'].shadowRoot!.querySelector('extensions-item');
    assertTrue(!!item);
    const detailsButton =
        item.shadowRoot!.querySelector<HTMLElement>('#detailsButton');
    assertTrue(!!detailsButton);
    detailsButton.click();
    flush();
    assertViewActive('extensions-detail-view');

    // Switch: detail view -> keyboard shortcuts.
    manager.shadowRoot!.querySelector(
                           'extensions-sidebar')!.$.sectionsShortcuts.click();
    flush();
    assertViewActive('extensions-keyboard-shortcuts');

    // We get back on the item list.
    manager.shadowRoot!.querySelector(
                           'extensions-sidebar')!.$.sectionsExtensions.click();
    flush();
    assertViewActive('extensions-item-list');
  });

  test('CloseDrawerOnNarrowModeExit', async function() {
    manager.$.toolbar.narrow = true;
    const toolbar = manager.$.toolbar.$.toolbar;
    await toolbar.updateComplete;
    toolbar.shadowRoot!.querySelector<HTMLElement>('#menuButton')!.click();

    await eventToPromise('cr-drawer-opened', manager);
    const drawer = manager.shadowRoot!.querySelector('cr-drawer');
    assertTrue(!!drawer);

    manager.$.toolbar.narrow = false;
    await eventToPromise('close', drawer);
  });

  test('PageTitleUpdate', function() {
    assertEquals('Extensions', document.title);

    // Open details view with a valid ID.
    navigation.navigateTo(
        {page: Page.DETAILS, extensionId: 'ldnnhddmnhbkjipkidpdiheffobcpfmf'});
    flush();
    assertEquals('Extensions - My extension 1', document.title);

    // Navigate back to the list view and check the page title.
    navigation.navigateTo({page: Page.LIST});
    flush();
    assertEquals('Extensions', document.title);
  });

  test('NavigateToSitePermissionsFail', function() {
    assertFalse(manager.enableEnhancedSiteControls);

    // Try to open the site permissions page.
    navigation.navigateTo({page: Page.SITE_PERMISSIONS});
    flush();

    // Should be re-routed to the main page with enableEnhancedSiteControls
    // set to false.
    assertViewActive('extensions-item-list');

    // Try to open the site permissions all-sites page.
    navigation.navigateTo({page: Page.SITE_PERMISSIONS_ALL_SITES});
    flush();

    // Should be re-routed to the main page.
    assertViewActive('extensions-item-list');
  });

  test('NavigateToSitePermissionsSuccess', function() {
    // Set the enableEnhancedSiteControls flag to true.
    manager.enableEnhancedSiteControls = true;
    flush();

    // Try to open the site permissions page. The navigation should succeed
    // with enableEnhancedSiteControls set to true.
    navigation.navigateTo({page: Page.SITE_PERMISSIONS});
    flush();
    assertViewActive('extensions-site-permissions');

    // Try to open the site permissions all-sites page. The navigation
    // should succeed.
    navigation.navigateTo({page: Page.SITE_PERMISSIONS_ALL_SITES});
    flush();
    assertViewActive('extensions-site-permissions-by-site');
  });
});