chromium/chrome/test/data/webui/chromeos/shimless_rma/reimaging_firmware_update_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 {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
import {PromiseResolver} from 'chrome://resources/ash/common/promise_resolver.js';
import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js';
import {assert} from 'chrome://resources/js/assert.js';
import {FakeShimlessRmaService} from 'chrome://shimless-rma/fake_shimless_rma_service.js';
import {setShimlessRmaServiceForTesting} from 'chrome://shimless-rma/mojo_interface_provider.js';
import {UpdateRoFirmwarePage} from 'chrome://shimless-rma/reimaging_firmware_update_page.js';
import {ShimlessRma} from 'chrome://shimless-rma/shimless_rma.js';
import {StateResult, UpdateRoFirmwareStatus} from 'chrome://shimless-rma/shimless_rma.mojom-webui.js';
import {assertEquals, assertFalse} from 'chrome://webui-test/chromeos/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';

suite('reimagingFirmwareUpdatePageTest', function() {
  // ShimlessRma is needed to handle the 'transition-state' event used when
  // the firmware update is complete.
  let shimlessRmaComponent: ShimlessRma|null = null;

  let component: UpdateRoFirmwarePage|null = null;

  const service: FakeShimlessRmaService = new FakeShimlessRmaService();

  setup(() => {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    setShimlessRmaServiceForTesting(service);
  });

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

  function initializeReimagingFirmwareUpdatePage(): Promise<void> {
    assert(!shimlessRmaComponent);
    shimlessRmaComponent = document.createElement(ShimlessRma.is);
    assert(shimlessRmaComponent);
    document.body.appendChild(shimlessRmaComponent);

    assert(!component);
    component = document.createElement(UpdateRoFirmwarePage.is);
    assert(component);
    document.body.appendChild(component);

    return flushTasks();
  }

  // Verify initialize page.
  test('RoFirmwareUpdatePageInitializes', async () => {
    await initializeReimagingFirmwareUpdatePage();

    assert(component);
    const updateStatus =
        strictQuery('#firmwareUpdateStatus', component.shadowRoot, HTMLElement);
    assertFalse(updateStatus.hidden);
    assertEquals('', updateStatus.textContent!.trim());
  });

  // Verify unplugging the USB while still updating won't trigger update
  // complete transition.
  test('UnplugUsbWhileUpdating', async () => {
    await initializeReimagingFirmwareUpdatePage();

    const resolver = new PromiseResolver<{stateResult: StateResult}>();
    let callCount = 0;
    service.roFirmwareUpdateComplete = () => {
      ++callCount;
      return resolver.promise;
    };

    // Simulate unplugging the USB and expect no complete call.
    service.triggerExternalDiskObserver(
        /* detected= */ false, /* delayMs= */ 0);
    await flushTasks();
    assertEquals(0, callCount);

    // Simulate unplugging the USB from an updating state and still expect
    // no complete call.
    service.triggerUpdateRoFirmwareObserver(
        UpdateRoFirmwareStatus.kUpdating, /* delayMs= */ 0);
    service.triggerExternalDiskObserver(
        /* detected= */ false, /* delayMs= */ 0);
    await flushTasks();
    assertEquals(0, callCount);
  });

  // Verify unplugging the USB when the update is complete triggers the update
  // complete transition.
  test('UnplugUsbWhileComplete', async () => {
    service.triggerUpdateRoFirmwareObserver(
        UpdateRoFirmwareStatus.kUpdating, /* delayMs= */ 0);
    await initializeReimagingFirmwareUpdatePage();

    assert(component);
    const firmwareTitle =
        strictQuery('#titleText', component.shadowRoot, HTMLElement);
    assertEquals(
        loadTimeData.getString('firmwareUpdateInstallImageTitleText'),
        firmwareTitle.textContent!.trim());

    let callCount = 0;
    const resolver = new PromiseResolver<{stateResult: StateResult}>();
    service.roFirmwareUpdateComplete = () => {
      ++callCount;
      return resolver.promise;
    };

    // Complete the update.
    service.triggerUpdateRoFirmwareObserver(
        UpdateRoFirmwareStatus.kComplete, /* delayMs= */ 0);
    await flushTasks();

    // Make sure that the transition doesn't happen until the USB is
    // unplugged.
    assertEquals(0, callCount);

    // Confirm the page title changes after firmware install completes.
    assertEquals(
        loadTimeData.getString('firmwareUpdateInstallCompleteTitleText'),
        firmwareTitle.textContent!.trim());

    // Unplug the USB and verify that the transition happened.
    service.triggerExternalDiskObserver(
        /* detected= */ false, /* delayMs= */ 0);
    await flushTasks();
    assertEquals(1, callCount);
  });
});