chromium/ui/file_manager/file_manager/foreground/js/ui/banners/state_banner_unittest.ts

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

import './state_banner.js';

import type {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
import {getTrustedHTML} from 'chrome://resources/js/static_types.js';
import {assertEquals} from 'chrome://webui-test/chromeos/chai_assert.js';

import {crInjectTypeAndInit} from '../../../../common/js/cr_ui.js';
import {waitUntil} from '../../../../common/js/test_error_reporting.js';
import {getLastVisitedURL} from '../../../../common/js/util.js';
import {Command} from '../command.js';

import type {StateBanner} from './state_banner.js';

let stateBanner: StateBanner;

/**
 * Mocks out the chrome.fileManagerPrivate.openSettingsSubpage function to
 * enable interrogation of the subpage that was invoked.
 * @returns {{ restore: function(), getSubpage: (function(): string)}}
 */
function mockOpenSettingsSubpage() {
  const actualOpenSettingsSubpage =
      chrome.fileManagerPrivate.openSettingsSubpage;
  let subpage: string;
  chrome.fileManagerPrivate.openSettingsSubpage = (settingsSubpage: string) => {
    subpage = settingsSubpage;
  };
  const restore = () => {
    chrome.fileManagerPrivate.openSettingsSubpage = actualOpenSettingsSubpage;
  };
  const getSubpage = () => {
    return subpage;
  };
  return {restore, getSubpage};
}

export function setUp() {
  document.body.innerHTML = getTrustedHTML`
    <state-banner>
      <span slot="text">Banner title</span>
      <button slot="extra-button" href="http://test.com">
        Test Banner
      </button>
    </state-banner>
  `;
  stateBanner = document.body.querySelector<StateBanner>('state-banner')!;
}

/**
 * Test that the additional button can be set and the link is visited when the
 * button is clicked.
 */
export async function testAdditionalButtonCanBeClicked() {
  stateBanner.querySelector<CrButtonElement>('[slot="extra-button"]')!.click();
  assertEquals(getLastVisitedURL(), 'http://test.com');
}

/**
 * Test that the default configuration is set on the state banners to ensure
 * any overridden banners have sensible configuration.
 */
export function testStateBannerDefaults() {
  // Ensure the default allowed volume type is empty. This ensures any
  // banners that don't override this property do not show by default.
  assertEquals(stateBanner.allowedVolumes().length, 0);
}

/**
 * Test that extra buttons with a ChromeOS settings href utilise the
 * chrome.fileManagerPrivate.openSettingsSubpage appropriately. The prefix
 * chrome://os-settings/ should be stripped and the subpage passed through.
 */
export async function testChromeOsSettingsLink() {
  const mockSettingsSubpage = mockOpenSettingsSubpage();
  const subpage = 'test/settings/subpage';
  document.body.innerHTML = getTrustedHTML`
    <state-banner>
      <span slot="text">Banner title</span>
      <button slot="extra-button"
          href="chrome://os-settings/test/settings/subpage">
        Test Button
      </button>
    </state-banner>
  `;
  stateBanner = document.body.querySelector<StateBanner>('state-banner')!;
  stateBanner.querySelector<CrButtonElement>('[slot="extra-button"]')!.click();
  assertEquals(mockSettingsSubpage.getSubpage(), subpage);
  mockSettingsSubpage.restore();
}

/**
 * Test that a href with no subpage, still calls visitURL as there is no
 * internal method to make the chrome://os-settings/ page appear except for
 * link capturing.
 */
export async function testChromeOsSettingsNoSubpageLink() {
  const osSettingsLink = 'chrome://os-settings/';
  document.body.innerHTML = getTrustedHTML`
    <state-banner>
      <span slot="text">Banner title</span>
      <button slot="extra-button" href="chrome://os-settings/">
        Test Button
      </button>
    </state-banner>
  `;
  stateBanner = document.body.querySelector<StateBanner>('state-banner')!;
  stateBanner.querySelector<CrButtonElement>('[slot="extra-button"]')!.click();
  assertEquals(getLastVisitedURL(), osSettingsLink);
}

/**
 * Test that an extra-button with a command triggers an Event of the correct
 * type.
 */
export async function testCommandsCanBeUsedForExtraButtons(done: () => void) {
  document.body.innerHTML = getTrustedHTML`
    <command id="format">
      <state-banner>
        <span slot="text">Banner title</span>
        <button slot="extra-button" command="#format">
          Test Button
        </button>
      </state-banner>
  `;
  crInjectTypeAndInit(document.querySelector<Command>('command')!, Command);

  // Add a listener to wait for the #format command to be received and keep
  // track of the event it received. Given the actual command is not properly
  // setup in the unittest environment, the event bubbles up to the body and
  // we can listen for it there.
  let commandReceived = false;
  let commandEvent: Event|null = null;
  document.body.addEventListener('command', (e) => {
    commandReceived = true;
    commandEvent = e;
  });

  // Click the extra button with a command associated with it.
  stateBanner = document.body.querySelector<StateBanner>('state-banner')!;
  stateBanner.querySelector<CrButtonElement>('[slot="extra-button"]')!.click();

  // Wait until the command has been received.
  await waitUntil(() => commandReceived === true);

  // Assert the event type received is a command.
  assertEquals(commandEvent!.type, 'command');

  done();
}