chromium/chrome/test/data/webui/whats_new/whats_new_app_test.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 {CommandHandlerRemote} from 'chrome://resources/js/browser_command.mojom-webui.js';
import {BrowserCommandProxy} from 'chrome://resources/js/browser_command/browser_command_proxy.js';
import {isChromeOS} from 'chrome://resources/js/platform.js';
import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {TestMock} from 'chrome://webui-test/test_mock.js';
import {eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js';
import {ModulePosition, ScrollDepth} from 'chrome://whats-new/whats_new.mojom-webui.js';
import {formatModuleName} from 'chrome://whats-new/whats_new_app.js';
import {WhatsNewProxyImpl} from 'chrome://whats-new/whats_new_proxy.js';

import {TestWhatsNewBrowserProxy} from './test_whats_new_browser_proxy.js';

const whatsNewURL = 'chrome://webui-test/whats_new/test.html';

function getUrlForFixture(filename: string, query?: string): string {
  if (query) {
    return `chrome://webui-test/whats_new/${filename}.html?${query}`;
  }
  return `chrome://webui-test/whats_new/${filename}.html`;
}

suite('WhatsNewAppTest', function() {
  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
  });

  test('with query parameters', async () => {
    const proxy = new TestWhatsNewBrowserProxy(whatsNewURL);
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '?auto=true');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);
    await proxy.handler.whenCalled('getServerUrl');
    await microtasksFinished();

    const iframe =
        whatsNewApp.shadowRoot!.querySelector<HTMLIFrameElement>('#content');
    assertTrue(!!iframe);
    // iframe has latest=true URL query parameter except on CrOS
    assertEquals(
        whatsNewURL + (isChromeOS ? '?latest=false' : '?latest=true'),
        iframe.src);
  });

  test('with version as query parameter', async () => {
    const proxy = new TestWhatsNewBrowserProxy(whatsNewURL + '?version=m98');
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '?auto=true');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);
    await proxy.handler.whenCalled('getServerUrl');
    await microtasksFinished();

    const iframe =
        whatsNewApp.shadowRoot!.querySelector<HTMLIFrameElement>('#content');
    assertTrue(!!iframe);
    // iframe has latest=true URL query parameter except on CrOS
    assertEquals(
        whatsNewURL + '?version=m98' +
            (isChromeOS ? '&latest=false' : '&latest=true'),
        iframe.src);
  });

  test('no query parameters', async () => {
    const proxy = new TestWhatsNewBrowserProxy(whatsNewURL);
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);
    await proxy.handler.whenCalled('getServerUrl');
    await microtasksFinished();

    const iframe =
        whatsNewApp.shadowRoot!.querySelector<HTMLIFrameElement>('#content');
    assertTrue(!!iframe);
    assertEquals(whatsNewURL + '?latest=false', iframe.src);
  });

  test('with legacy command format', async () => {
    const proxy = new TestWhatsNewBrowserProxy(
        getUrlForFixture('test_with_legacy_command_3'));
    WhatsNewProxyImpl.setInstance(proxy);
    const browserCommandHandler = TestMock.fromClass(CommandHandlerRemote);
    BrowserCommandProxy.getInstance().handler = browserCommandHandler;
    browserCommandHandler.setResultFor(
        'canExecuteCommand', Promise.resolve({canExecute: true}));
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    const whenMessage = eventToPromise('message', window);
    const commandId =
        await browserCommandHandler.whenCalled('canExecuteCommand');
    assertEquals(3, commandId);

    const {data} = await whenMessage;
    assertEquals(3, data.data.commandId);

    await proxy.handler.whenCalled('recordBrowserCommandExecuted');
    assertEquals(1, proxy.handler.getCallCount('recordBrowserCommandExecuted'));
  });

  test('with browser command format', async () => {
    const proxy =
        new TestWhatsNewBrowserProxy(getUrlForFixture('test_with_command_4'));
    WhatsNewProxyImpl.setInstance(proxy);
    const browserCommandHandler = TestMock.fromClass(CommandHandlerRemote);
    BrowserCommandProxy.getInstance().handler = browserCommandHandler;
    browserCommandHandler.setResultFor(
        'canExecuteCommand', Promise.resolve({canExecute: true}));
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    const whenMessage = eventToPromise('message', window);
    const commandId =
        await browserCommandHandler.whenCalled('canExecuteCommand');
    assertEquals(4, commandId);

    const {data} = await whenMessage;
    assertEquals('browser_command', data.data.event);
    assertEquals(4, data.data.commandId);

    await proxy.handler.whenCalled('recordBrowserCommandExecuted');
    assertEquals(1, proxy.handler.getCallCount('recordBrowserCommandExecuted'));
  });

  test('with page_load metrics from embedded page', async () => {
    const proxy = new TestWhatsNewBrowserProxy(
        getUrlForFixture('test_with_metrics_page_loaded'));
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    const isAutoOpen =
        await proxy.handler.whenCalled('recordVersionPageLoaded');
    assertEquals(false, isAutoOpen);

    const contentLoadedCallCount =
        proxy.handler.getCallCount('recordTimeToLoadContent');
    assertEquals(1, contentLoadedCallCount);
  });

  test('with module_impression metrics from embedded page', async () => {
    const proxy = new TestWhatsNewBrowserProxy(
        getUrlForFixture('test_with_metrics_module_impression'));
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    const moduleImpression =
        await proxy.handler.whenCalled('recordModuleImpression');
    assertEquals('ChromeFeature', moduleImpression[0]);
    assertEquals(ModulePosition.kUndefined, moduleImpression[1]);
  });

  test('with explore_more_toggled metrics from embedded page', async () => {
    const proxy = new TestWhatsNewBrowserProxy(
        getUrlForFixture('test_with_metrics_explore_more_toggled'));
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    let expanded = await proxy.handler.whenCalled('recordExploreMoreToggled');
    assertEquals(true, expanded);
    await proxy.handler.resetResolver('recordExploreMoreToggled');
    expanded = await proxy.handler.whenCalled('recordExploreMoreToggled');
    assertEquals(false, expanded);
  });

  test('with scroll_depth metrics from embedded page', async () => {
    const proxy = new TestWhatsNewBrowserProxy(
        getUrlForFixture('test_with_metrics_scroll_depth'));
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    const percentage = await proxy.handler.whenCalled('recordScrollDepth');
    assertEquals(ScrollDepth.k25, percentage);
  });

  test('with time_on_page metrics from embedded page', async () => {
    const proxy = new TestWhatsNewBrowserProxy(
        getUrlForFixture('test_with_metrics_time_on_page'));
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    const timeOnPage = await proxy.handler.whenCalled('recordTimeOnPage');
    // 3 million microseconds = 3 thousand milliseconds
    assertEquals(3n * 1000n * 1000n, timeOnPage.microseconds);
  });

  test('with module_click metrics from embedded page', async () => {
    const proxy = new TestWhatsNewBrowserProxy(
        getUrlForFixture('test_with_metrics_module_click'));
    WhatsNewProxyImpl.setInstance(proxy);
    window.history.replaceState({}, '', '/');
    const whatsNewApp = document.createElement('whats-new-app');
    document.body.appendChild(whatsNewApp);

    const clickedModule =
        await proxy.handler.whenCalled('recordModuleLinkClicked');
    assertEquals('FeatureWithLink', clickedModule[0]);
    assertEquals(ModulePosition.kSpotlight1, clickedModule[1]);
  });

  test('with different module name formats', async () => {
    // Formats legacy format correctly.
    assertEquals('ChromeFeature', formatModuleName('123-chrome-feature'));
    // Ignores modern format.
    assertEquals('ChromeFeature', formatModuleName('ChromeFeature'));

    // Edge-cases
    // Ignores when no hyphens present.
    assertEquals('chrome', formatModuleName('chrome'));
    // Ignores when starts with numbers, but does not contain hyphens.
    assertEquals('123feature', formatModuleName('123feature'));
    // Works when starts or ends with hyphen
    assertEquals('Feature', formatModuleName('feature-'));
    assertEquals('Feature', formatModuleName('-feature'));
    // Does not remove numbers within name.
    assertEquals('Chrome123Feature', formatModuleName('chrome-123-feature'));
  });
});