chromium/chrome/test/data/webui/chromeos/shimless_rma/onboarding_network_page_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 'chrome://shimless-rma/shimless_rma.js';

import {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
import {NetworkConfigElement} from 'chrome://resources/ash/common/network/network_config.js';
import {NetworkListElement} from 'chrome://resources/ash/common/network/network_list.js';
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js';
import {assert} from 'chrome://resources/js/assert.js';
import {NetworkStateProperties} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
import {ConnectionStateType, NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
import {SET_NEXT_BUTTON_LABEL} from 'chrome://shimless-rma/events.js';
import {fakeNetworks} from 'chrome://shimless-rma/fake_data.js';
import {FakeShimlessRmaService} from 'chrome://shimless-rma/fake_shimless_rma_service.js';
import {setNetworkConfigServiceForTesting, setShimlessRmaServiceForTesting} from 'chrome://shimless-rma/mojo_interface_provider.js';
import {OnboardingNetworkPage} from 'chrome://shimless-rma/onboarding_network_page.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
import {FakeNetworkConfig} from 'chrome://webui-test/chromeos/fake_network_config_mojom.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';

suite('onboardingNetworkPageTest', function() {
  let component: OnboardingNetworkPage|null = null;

  let shimlessRmaService: FakeShimlessRmaService|null = null;

  let networkConfigService: FakeNetworkConfig|null = null;

  const networkListSelector = '#networkList';
  const networkConfigSelector = '#networkConfig';
  const connectButtonSelector = '#connectButton';
  const networkDialogSelector = '#dialog';

  setup(() => {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    shimlessRmaService = new FakeShimlessRmaService();
    setShimlessRmaServiceForTesting(shimlessRmaService);
    networkConfigService = new FakeNetworkConfig();
    setNetworkConfigServiceForTesting(networkConfigService);
  });

  teardown(() => {
    component?.remove();
    component = null;
    shimlessRmaService = null;
    networkConfigService = null;
  });

  function initializeOnboardingNetworkPage(): Promise<void> {
    assert(!component);
    component = document.createElement(OnboardingNetworkPage.is);
    assert(component);
    document.body.appendChild(component);
    return flushTasks();
  }

  function openNetworkConfigDialog(): Promise<void> {
    assert(component);
    // TODO (b/333120446): Use NetworkListElement directly instead of
    // HTMLElement once available.
    const networkList =
        strictQuery(networkListSelector, component.shadowRoot, HTMLElement) as
        NetworkListElement;
    const network = networkList.networks[1] as NetworkStateProperties;
    component.showConfigForTesting(
        network.type,
        /* empty guid since network_config.js is not mocked */ '',
        /* name= */ 'eth0');
    return flushTasks();
  }

  // Verify the component renders.
  test('ComponentRenders', async () => {
    await initializeOnboardingNetworkPage();
    assert(component);
    const networkList =
        strictQuery(networkListSelector, component.shadowRoot, HTMLElement) as
        NetworkListElement;
    assert(networkList);
  });

  // Verify the network list populates with networks.
  test('PopulatesNetworkList', async () => {
    assert(networkConfigService);
    networkConfigService.addNetworksForTest(fakeNetworks);
    await initializeOnboardingNetworkPage();

    assert(component);
    const networkList =
        strictQuery(networkListSelector, component.shadowRoot, HTMLElement) as
        NetworkListElement;
    assert(networkList);
    assertEquals('eth0_guid', networkList.networks[0]!.guid);
    assertEquals('wifi0_guid', networkList.networks[1]!.guid);
  });

  // Verify after a successful network selection the connect sections are
  // disabled.
  test('NetworkSelectionDialog', async () => {
    assert(networkConfigService);
    networkConfigService.addNetworksForTest(fakeNetworks);
    await initializeOnboardingNetworkPage();

    assert(component);
    const networkList =
        strictQuery(networkListSelector, component.shadowRoot, HTMLElement) as
        NetworkListElement;
    networkList.dispatchEvent(
        new CustomEvent('selected', {detail: networkList.networks[1]}));
    await flushTasks();

    const networkConfig =
        strictQuery(networkConfigSelector, component.shadowRoot, HTMLElement) as
        NetworkConfigElement;
    assert(networkConfig);
    assertFalse(networkConfig.enableConnect);
    assertTrue(strictQuery(
                   connectButtonSelector, component.shadowRoot, CrButtonElement)
                   .disabled);
  });

  // Verify the connect button starts disabled until the network config enables
  // it.
  test('DialogConnectButtonBindsToDialog', async () => {
    assert(networkConfigService);
    networkConfigService.addNetworksForTest(fakeNetworks);
    await initializeOnboardingNetworkPage();
    await openNetworkConfigDialog();

    assert(component);
    const connectButton = strictQuery(
        connectButtonSelector, component.shadowRoot, CrButtonElement);
    assertTrue(connectButton.disabled);

    const networkConfig =
        strictQuery(networkConfigSelector, component.shadowRoot, HTMLElement) as
        NetworkConfigElement;
    networkConfig.enableConnect = true;
    await flushTasks();

    assertFalse(connectButton.disabled);
  });

  // Verify the network dialog can be closed.
  test('DialogCloses', async () => {
    assert(networkConfigService);
    networkConfigService.addNetworksForTest(fakeNetworks);
    await initializeOnboardingNetworkPage();

    assert(component);
    const dialog = strictQuery(
        networkDialogSelector, component.shadowRoot, CrDialogElement);
    assertFalse(dialog.open);
    await openNetworkConfigDialog();

    assertTrue(strictQuery(
                   networkDialogSelector, component.shadowRoot, CrDialogElement)
                   .open);
    const cancelButton =
        strictQuery('#cancelButton', component.shadowRoot, CrButtonElement);
    assertFalse(cancelButton.disabled);

    cancelButton.click();
    await flushTasks();

    assertFalse(dialog.open);
  });

  // Verify the network dialog can be re-opened after connecting to a network.
  test('DialogReopensAfterHittingConnect', async () => {
    assert(networkConfigService);
    networkConfigService.addNetworksForTest(fakeNetworks);
    await initializeOnboardingNetworkPage();
    assert(component);
    const networkList =
        strictQuery(networkListSelector, component.shadowRoot, HTMLElement) as
        NetworkListElement;

    // Add fake unconnected wifi.
    const fakeWiFi = OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi');
    fakeWiFi.connectionState = ConnectionStateType.kNotConnected;
    networkConfigService.addNetworksForTest([fakeWiFi]);
    component.refreshNetworks();
    await flushTasks();

    // Open network dialog.
    const network = networkList.networks[networkList.networks.length - 1] as
        NetworkStateProperties;

    const dialog = strictQuery(
        networkDialogSelector, component.shadowRoot, CrDialogElement);
    assertFalse(dialog.open);
    component.showConfigForTesting(network.type, network.guid, network.name);
    assertTrue(dialog.open);
    await flushTasks();

    // Select a network.
    networkList.dispatchEvent(new CustomEvent('selected', {detail: network}));

    // Click connect button and dialog will be closed.
    const connectButton = strictQuery(
        connectButtonSelector, component.shadowRoot, CrButtonElement);
    assertFalse(connectButton.hidden);
    connectButton.click();
    component.refreshNetworks();
    await flushTasks();
    assertFalse(dialog.open);

    // Reopen the same dialog.
    const dialog2 = strictQuery(
        networkDialogSelector, component.shadowRoot, CrDialogElement);
    assertFalse(dialog2.open);
    component.showConfigForTesting(network.type, network.guid, network.name);
    assertTrue(dialog2.open);
  });

  // Verify a connected network can be disconnected.
  test('DisconnectNetwork', async () => {
    assert(networkConfigService);
    networkConfigService.addNetworksForTest(fakeNetworks);
    await initializeOnboardingNetworkPage();
    assert(component);
    const networkList =
        strictQuery(networkListSelector, component.shadowRoot, HTMLElement) as
        NetworkListElement;

    // Add fake connected wifi.
    const fakeWiFi = OncMojo.getDefaultNetworkState(NetworkType.kWiFi, 'wifi');
    fakeWiFi.connectionState = ConnectionStateType.kConnected;
    networkConfigService.addNetworksForTest([fakeWiFi]);
    component.refreshNetworks();
    await flushTasks();

    // fake WiFi connectionState should be 'Connected'.
    const network = networkList.networks[networkList.networks.length - 1] as
        NetworkStateProperties;
    assert(network);
    assertEquals(network.connectionState, ConnectionStateType.kConnected);

    // Select a network.
    networkList.dispatchEvent(new CustomEvent('selected', {detail: network}));

    // Show the 'disconnect' button instead of 'connect'.
    const connectButton = strictQuery(
        connectButtonSelector, component.shadowRoot, CrButtonElement);
    const disconnectButton =
        strictQuery('#disconnectButton', component.shadowRoot, CrButtonElement);
    assertTrue(connectButton.hidden);
    assertFalse(disconnectButton.hidden);

    disconnectButton.click();
    component.refreshNetworks();
    await flushTasks();
    assertEquals(network.connectionState, ConnectionStateType.kNotConnected);
  });

  // Verify next button shows 'Skip' when not connected to a network.
  test('SetSkipButtonWhenNotConnected', async () => {
    assert(networkConfigService);
    networkConfigService.addNetworksForTest(fakeNetworks);

    // Reset the component.
    component = document.createElement(OnboardingNetworkPage.is);
    const skipButtonLabelEvent =
        eventToPromise(SET_NEXT_BUTTON_LABEL, component);
    let buttonLabelKey;
    component.addEventListener(SET_NEXT_BUTTON_LABEL, (e: CustomEvent) => {
      buttonLabelKey = e.detail;
    });

    document.body.appendChild(component);
    await flushTasks();
    await skipButtonLabelEvent;
    assertEquals('skipButtonLabel', buttonLabelKey);

    // Connect to a network and expect the next button label event.
    const nextButtonLabelEvent =
        eventToPromise(SET_NEXT_BUTTON_LABEL, component);
    const ethernetConnected =
        OncMojo.getDefaultNetworkState(NetworkType.kEthernet, 'ethernet');
    ethernetConnected.connectionState = ConnectionStateType.kOnline;
    networkConfigService.addNetworksForTest([ethernetConnected]);

    component.refreshNetworks();
    await flushTasks();
    await nextButtonLabelEvent;
    assertEquals('nextButtonLabel', buttonLabelKey);
  });

  // Verify the network list is disabled when `allButtonsDisabled` is set.
  test('DisableNetworkList', async () => {
    await initializeOnboardingNetworkPage();

    assert(component);
    const networkList =
        strictQuery(networkListSelector, component.shadowRoot, HTMLElement) as
        NetworkListElement;
    assertEquals(undefined, networkList.disabled);
    component.allButtonsDisabled = true;
    assertTrue(networkList.disabled);
  });

  // Verify `trackConfiguredNetworks()` is called in page initialization;
  test('TrackConfiguredNetworksCalled', async () => {
    await initializeOnboardingNetworkPage();

    assert(shimlessRmaService);
    assertTrue(shimlessRmaService.getTrackConfiguredNetworks());
  });
});