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

// Copyright 2018 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 {CrButtonElement, Destination, NativeInitialSettings, PrintPreviewAppElement} from 'chrome://print/print_preview.js';
import {MeasurementSystemUnitType, NativeLayerImpl, PluginProxyImpl, State, whenReady} from 'chrome://print/print_preview.js';
import {assert} from 'chrome://resources/js/assert.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {waitBeforeNextRender} from 'chrome://webui-test/polymer_test_util.js';

// <if expr="is_chromeos">
import {setNativeLayerCrosInstance} from './native_layer_cros_stub.js';
// </if>
import {NativeLayerStub} from './native_layer_stub.js';
import {getCddTemplate, getDefaultMediaSize, getDefaultOrientation} from './print_preview_test_utils.js';
import {TestPluginProxy} from './test_plugin_proxy.js';

suite('InvalidSettingsTest', function() {
  let page: PrintPreviewAppElement;

  let nativeLayer: NativeLayerStub;

  const initialSettings: NativeInitialSettings = {
    isInKioskAutoPrintMode: false,
    isInAppKioskMode: false,
    thousandsDelimiter: ',',
    decimalDelimiter: '.',
    unitType: MeasurementSystemUnitType.IMPERIAL,
    previewModifiable: true,
    destinationsManaged: false,
    previewIsFromArc: false,
    documentTitle: 'title',
    documentHasSelection: true,
    shouldPrintSelectionOnly: false,
    uiLocale: 'en-us',
    printerName: 'FooDevice',
    pdfPrinterDisabled: false,
    serializedAppStateStr: null,
    serializedDefaultDestinationSelectionRulesStr: null,
  };

  setup(function() {
    nativeLayer = new NativeLayerStub();
    NativeLayerImpl.setInstance(nativeLayer);
    // <if expr="is_chromeos">
    setNativeLayerCrosInstance();
    // </if>
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
  });

  /**
   * Initializes the page with initial settings and local destinations
   * given by |initialSettings| and |localDestinationInfos|. Also creates
   * the fake plugin. Moved out of setup so tests can set those parameters
   * differently.
   */
  function createPage() {
    nativeLayer.setInitialSettings(initialSettings);
    nativeLayer.setLocalDestinations([
      {printerName: 'FooName', deviceName: 'FooDevice'},
      {printerName: 'BarName', deviceName: 'BarDevice'},
    ]);
    PluginProxyImpl.setInstance(new TestPluginProxy());

    page = document.createElement('print-preview-app');
    document.body.appendChild(page);
    page.$.documentInfo.init(true, false, 'title', false);
  }

  // Tests that when a printer cannot be communicated with correctly the
  // preview area displays an invalid printer error message and printing
  // is disabled. Verifies that the user can recover from this error by
  // selecting a different, valid printer.
  test('invalid settings error', function() {
    createPage();
    const barDevice = getCddTemplate('BarDevice');
    nativeLayer.setLocalDestinationCapabilities(barDevice);

    // FooDevice is the default printer, so will be selected for the initial
    // preview request.
    nativeLayer.setInvalidPrinterId('FooDevice');

    // Expected message
    const expectedMessage = 'The selected printer is not available or not ' +
        'installed correctly.  Check your printer or try selecting another ' +
        'printer.';

    // Get references to relevant elements.
    const previewAreaEl = page.$.previewArea;
    const overlay =
        previewAreaEl.shadowRoot!.querySelector('.preview-area-overlay-layer')!;
    const messageEl =
        previewAreaEl.shadowRoot!.querySelector('.preview-area-message')!;
    const sidebar = page.shadowRoot!.querySelector('print-preview-sidebar')!;
    let printButton: CrButtonElement;
    const destinationSettings = sidebar.shadowRoot!.querySelector(
        'print-preview-destination-settings')!;

    return waitBeforeNextRender(page)
        .then(() => {
          const parentElement =
              sidebar.shadowRoot!.querySelector('print-preview-button-strip')!;
          printButton =
              parentElement.shadowRoot!.querySelector<CrButtonElement>(
                  '.action-button')!;

          return Promise.all([
            whenReady(),
            nativeLayer.whenCalled('getInitialSettings'),
          ]);
        })
        .then(function() {
          destinationSettings.getDestinationStoreForTest()
              .startLoadAllDestinations();
          // Wait for the preview request.
          return Promise.all([
            nativeLayer.whenCalled('getPrinterCapabilities'),
            nativeLayer.whenCalled('getPreview'),
          ]);
        })
        .then(function() {
          // Print preview should have failed with invalid settings, since
          // FooDevice was set as an invalid printer.
          assertFalse(overlay.classList.contains('invisible'));
          assertTrue(messageEl.textContent!.includes(expectedMessage));
          assertEquals(State.ERROR, page.state);

          // Verify that the print button is disabled
          assertTrue(printButton.disabled);

          // Select should still be enabled so that the user can select a
          // new printer.
          assertFalse(destinationSettings.$.destinationSelect.disabled);

          // Reset
          nativeLayer.reset();

          // Select a new destination
          const barDestination =
              destinationSettings.getDestinationStoreForTest()
                  .destinations()
                  .find((d: Destination) => d.id === 'BarDevice');
          assert(barDestination);
          destinationSettings.getDestinationStoreForTest().selectDestination(
              barDestination);

          // Wait for the preview to be updated.
          return nativeLayer.whenCalled('getPreview');
        })
        .then(function() {
          // Message should be gone.
          assertTrue(overlay.classList.contains('invisible'));
          assertFalse(messageEl.textContent!.includes(expectedMessage));

          // Has active print button and successfully 'prints', indicating
          assertFalse(printButton.disabled);
          assertEquals(State.READY, page.state);
          printButton.click();
          // This should result in a call to print.
          return nativeLayer.whenCalled('doPrint');
        })
        .then(
            /**
             * @param {string} printTicket The print ticket print() was
             *     called for.
             */
            function(printTicket) {
              // Sanity check some printing argument values.
              const ticket = JSON.parse(printTicket);
              assertEquals(barDevice.printer!.deviceName, ticket.deviceName);
              assertEquals(
                  getDefaultOrientation(barDevice) === 'LANDSCAPE',
                  ticket.landscape);
              assertEquals(1, ticket.copies);
              const mediaDefault = getDefaultMediaSize(barDevice);
              assertEquals(
                  mediaDefault.width_microns, ticket.mediaSize.width_microns);
              assertEquals(
                  mediaDefault.height_microns, ticket.mediaSize.height_microns);
              return nativeLayer.whenCalled('dialogClose');
            });
  });
});