chromium/chrome/test/data/webui/print_preview/destination_item_test_cros.ts

// Copyright 2020 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 {PrintPreviewDestinationListItemElement} from 'chrome://print/print_preview.js';
import {Destination, DestinationOrigin, getTrustedHTML, NativeLayerCrosImpl, PrinterStatusReason, PrinterStatusSeverity} from 'chrome://print/print_preview.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 {MockController} from 'chrome://webui-test/mock_controller.js';
import {waitBeforeNextRender} from 'chrome://webui-test/polymer_test_util.js';

import {NativeLayerCrosStub} from './native_layer_cros_stub.js';
import {FakeMediaQueryList} from './print_preview_test_utils.js';

suite('DestinationItemTestCros', function() {
  let listItem: PrintPreviewDestinationListItemElement;

  let nativeLayerCros: NativeLayerCrosStub;

  let mockController: MockController;

  let fakePrefersColorSchemeMediaQueryList: FakeMediaQueryList;

  function setNativeLayerPrinterStatusMap() {
    [{
      printerId: 'One',
      statusReasons: [{
        reason: PrinterStatusReason.NO_ERROR,
        severity: PrinterStatusSeverity.UNKNOWN_SEVERITY,
      }],
      timestamp: 0,
    },
     {
       printerId: 'Two',
       statusReasons: [{
         reason: PrinterStatusReason.OUT_OF_INK,
         severity: PrinterStatusSeverity.ERROR,
       }],
       timestamp: 0,
     },
     {
       printerId: 'Three',
       statusReasons: [
         {
           reason: PrinterStatusReason.PRINTER_UNREACHABLE,
           severity: PrinterStatusSeverity.ERROR,
         },
       ],
       timestamp: 0,
     },
     {
       printerId: 'Four',
       statusReasons: [{
         reason: PrinterStatusReason.UNKNOWN_REASON,
         severity: PrinterStatusSeverity.ERROR,
       }],
       timestamp: 0,
     }]
        .forEach(
            status => nativeLayerCros.addPrinterStatusToMap(
                status.printerId, status));
  }

  // Mocks calls to window.matchMedia, returning false by default.
  function configureMatchMediaMock() {
    mockController = new MockController();
    const matchMediaMock =
        mockController.createFunctionMock(window, 'matchMedia');
    fakePrefersColorSchemeMediaQueryList =
        new FakeMediaQueryList('(prefers-color-scheme: dark)');
    matchMediaMock.returnValue = fakePrefersColorSchemeMediaQueryList;
    assertFalse(window.matchMedia('(prefers-color-scheme: dark)').matches);
  }

  function createTestDestination(printerId: string): Destination {
    return new Destination(
        printerId, DestinationOrigin.CROS, `Destination ${printerId}`,
        {description: 'ABC'});
  }

  setup(function() {
    // Mock configuration needs to happen before element added to UI to
    // ensure iron-media-query uses mock.
    configureMatchMediaMock();

    document.body.innerHTML = getTrustedHTML`
          <print-preview-destination-list-item id="listItem">
          </print-preview-destination-list-item>`;

    // Stub out native layer.
    nativeLayerCros = new NativeLayerCrosStub();
    NativeLayerCrosImpl.setInstance(nativeLayerCros);
    setNativeLayerPrinterStatusMap();

    listItem =
        document.body.querySelector<PrintPreviewDestinationListItemElement>(
            '#listItem')!;
    listItem.destination = new Destination(
        'One', DestinationOrigin.CROS, 'Destination One', {description: 'ABC'});
    flush();
  });

  teardown(function() {
    mockController.reset();
  });

  test(
      'NewStatusUpdatesIcon', function() {
        const icon = listItem.shadowRoot!.querySelector('iron-icon')!;
        assertEquals('print-preview:printer-status-grey', icon.icon);

        return listItem.destination.requestPrinterStatus().then(() => {
          assertEquals('print-preview:printer-status-green', icon.icon);
        });
      });

  test(
      'ChangingDestinationUpdatesIcon', function() {
        const icon = listItem.shadowRoot!.querySelector('iron-icon')!;
        assertEquals('print-preview:printer-status-grey', icon.icon);

        listItem.destination = new Destination(
            'Two', DestinationOrigin.CROS, 'Destination Two',
            {description: 'ABC'});

        return waitBeforeNextRender(listItem).then(() => {
          assertEquals('print-preview:printer-status-orange', icon.icon);
        });
      });

  // Tests that the printer stauts icon is only notified to update if the
  // destination key in the printer status response matches the current
  // destination.
  test(
      'OnlyUpdateMatchingDestination', function() {
        const icon = listItem.shadowRoot!.querySelector('iron-icon')!;
        assertEquals('print-preview:printer-status-grey', icon.icon);
        const firstDestinationStatusRequestPromise =
            listItem.destination.requestPrinterStatus();

        // Simulate destination_list updating and switching the destination
        // after the request for the original destination was already sent out.
        listItem.destination = new Destination(
            'Two', DestinationOrigin.CROS, 'Destination Two',
            {description: 'ABC'});

        return firstDestinationStatusRequestPromise.then(() => {
          // PrinterState should stay the same because the destination in the
          // status request response doesn't match.
          assertEquals('print-preview:printer-status-grey', icon.icon);
        });
      });

  // Verifies expected icon displays for given status.
  test('PrinterIconMapsToPrinterStatus', async function() {
    const icon = listItem.shadowRoot!.querySelector('iron-icon')!;
    // Before destination status request icon should be grey.
    assertEquals('print-preview:printer-status-grey', icon.icon);

    // Verify destination with `PrinterStatusReason.NO_ERROR` uses a green
    // icon.
    listItem.destination = createTestDestination('One');
    await listItem.destination.requestPrinterStatus();
    assertEquals('print-preview:printer-status-green', icon.icon);

    // Verify destination with PrinterStatusReason that is not
    // `PRINTER_UNREACHABLE`, `NO_ERROR`, or unknown uses a orange icon.
    listItem.destination = createTestDestination('Two');
    await listItem.destination.requestPrinterStatus();
    assertEquals('print-preview:printer-status-orange', icon.icon);

    // Verify destination with `PrinterStatusReason.PRINTER_UNREACHABLE`
    // uses a red icon.
    listItem.destination = createTestDestination('Three');
    await listItem.destination.requestPrinterStatus();
    assertEquals('print-preview:printer-status-red', icon.icon);

    // Verify destination with `PrinterStatusReason.UNKNOWN_REASON` uses a
    // green icon.
    listItem.destination = createTestDestination('Four');
    await listItem.destination.requestPrinterStatus();
    assertEquals('print-preview:printer-status-green', icon.icon);
  });

  // Verifies expected hidden state and class applied to status text depending
  // on PrinterStatusReason.
  test('PrinterConnectionStatusClass', async function() {
    const connectionText: HTMLElement =
        listItem.shadowRoot!.querySelector<HTMLElement>('.connection-status')!;
    // Before destination status is empty and connection text is hidden.
    assertTrue(connectionText.hidden);

    // Verify destination with `PrinterStatusReason.NO_ERROR` connection
    // text hidden.
    listItem.destination = createTestDestination('One');
    await listItem.destination.requestPrinterStatus();
    assertTrue(connectionText.hidden);

    // Verify destination with PrinterStatusReason that is not `NO_ERROR`,
    // null, or `UNKNOWN_REASON` uses orange connection text.
    listItem.destination = createTestDestination('Two');
    await listItem.destination.requestPrinterStatus();
    assertFalse(connectionText.hidden);
    assertTrue(connectionText.classList.contains('status-orange'));

    // Verify destination with `PrinterStatusReason.PRINTER_UNREACHABLE`
    // uses red connection text.
    listItem.destination = createTestDestination('Three');
    await listItem.destination.requestPrinterStatus();
    assertFalse(connectionText.hidden);
    assertTrue(connectionText.classList.contains('status-red'));

    // Verify destination with `PrinterStatusReason.UNKNOWN_REASON`
    // connections text is hidden.
    listItem.destination = createTestDestination('Four');
    await listItem.destination.requestPrinterStatus();
    assertTrue(connectionText.hidden);
  });
});