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

// Copyright 2019 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 {PrintPreviewModelElement, PrintPreviewPinSettingsElement} from 'chrome://print/print_preview.js';
import {State} 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 {fakeDataBind} from 'chrome://webui-test/polymer_test_util.js';

import {triggerInputEvent} from './print_preview_test_utils.js';

suite('PinSettingsTest', function() {
  let pinSection: PrintPreviewPinSettingsElement;

  let model: PrintPreviewModelElement;

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    model = document.createElement('print-preview-model');
    document.body.appendChild(model);
    model.set('settings.pin.available', true);
    model.set('settings.pin.value', false);
    model.set('settings.pinValue.available', true);
    model.set('settings.pinValue.value', '');

    pinSection = document.createElement('print-preview-pin-settings');
    pinSection.settings = model.settings;
    pinSection.state = State.READY;
    pinSection.disabled = false;
    fakeDataBind(model, pinSection, 'settings');
    document.body.appendChild(pinSection);
    flush();
  });

  // Pin settings observes |state| which may change
  // regardless of pin availability, When the pin printing enforced by policy
  // the checkbox will be true and the initial pin is empty which is invalid
  // In this scenario setSettingValid assert will fail because the input is
  // invalid and the pin printing is unavailable. This test make sure there is
  // check for avaiablity before calling setSettingValid
  // Regression test for https://crbug.com/1321118
  test('pin settings unavailable with invalid input', async () => {
    pinSection.state = State.NOT_READY;
    model.set('settings.pin.available', false);
    model.set('settings.pin.value', true);
    model.set('settings.pinValue.available', false);
    pinSection.state = State.READY;
  });

  // Tests that checking the box or entering the pin value updates the
  // setting.
  test('enter valid pin value', async () => {
    const checkbox = pinSection.shadowRoot!.querySelector('cr-checkbox')!;
    const collapse = pinSection.shadowRoot!.querySelector('cr-collapse')!;
    assertFalse(checkbox.checked);
    assertFalse(collapse.opened);
    assertFalse(pinSection.getSettingValue('pin'));
    assertFalse(pinSection.getSetting('pin').setFromUi);
    assertEquals('', pinSection.getSettingValue('pinValue'));

    checkbox.checked = true;
    checkbox.dispatchEvent(
        new CustomEvent('change', {bubbles: true, composed: true}));
    assertTrue(collapse.opened);
    assertTrue(pinSection.getSettingValue('pin'));
    assertTrue(pinSection.getSetting('pin').setFromUi);
    assertEquals('', pinSection.getSettingValue('pinValue'));

    const input = pinSection.shadowRoot!.querySelector('cr-input')!;
    await input.updateComplete;
    assertEquals('', input.value);
    assertFalse(pinSection.getSetting('pinValue').setFromUi);

    // Verify that entering the pin value in the input sets the setting.
    await triggerInputEvent(input, '0000', pinSection);
    assertTrue(pinSection.getSettingValue('pin'));
    assertEquals('0000', pinSection.getSettingValue('pinValue'));
    assertTrue(pinSection.getSetting('pinValue').setFromUi);
    assertEquals(true, pinSection.isPinValid);
  });

  // Tests that entering non-digit pin value updates the validity of the
  // setting.
  test('enter non-digit pin value', async () => {
    const checkbox = pinSection.shadowRoot!.querySelector('cr-checkbox')!;
    checkbox.checked = true;
    checkbox.dispatchEvent(
        new CustomEvent('change', {bubbles: true, composed: true}));
    const input = pinSection.shadowRoot!.querySelector('cr-input')!;

    // Verify that entering the non-digit pin value in the input updates the
    // setting validity and doesn't update its value.
    await triggerInputEvent(input, 'aaaa', pinSection);
    assertTrue(pinSection.getSettingValue('pin'));
    assertEquals('', pinSection.getSettingValue('pinValue'));
    assertEquals(false, pinSection.isPinValid);

    // Check that checkbox and input are still enabled so user can correct
    // invalid input.
    assertEquals(false, checkbox.disabled);
    assertEquals(false, input.disabled);
  });


  // Tests that entering too short pin value updates the validity of the
  // setting.
  test('enter too short pin value', async () => {
    const checkbox = pinSection.shadowRoot!.querySelector('cr-checkbox')!;
    checkbox.checked = true;
    checkbox.dispatchEvent(
        new CustomEvent('change', {bubbles: true, composed: true}));
    const input = pinSection.shadowRoot!.querySelector('cr-input')!;

    // Verify that entering too short pin value in the input updates the
    // setting validity and doesn't update its value.
    await triggerInputEvent(input, '000', pinSection);
    assertTrue(pinSection.getSettingValue('pin'));
    assertEquals('', pinSection.getSettingValue('pinValue'));
    assertEquals(false, pinSection.isPinValid);

    // Check that checkbox and input are still enabled so user can correct
    // invalid input.
    assertEquals(false, checkbox.disabled);
    assertEquals(false, input.disabled);
  });

  // Tests that entering empty pin value updates the validity of the
  // setting.
  test('enter empty pin value', async () => {
    const checkbox = pinSection.shadowRoot!.querySelector('cr-checkbox')!;
    checkbox.checked = true;
    checkbox.dispatchEvent(
        new CustomEvent('change', {bubbles: true, composed: true}));
    const input = pinSection.shadowRoot!.querySelector('cr-input')!;

    // Verify that initial pin value is empty and the setting is invalid.
    assertTrue(pinSection.getSettingValue('pin'));
    assertEquals('', pinSection.getSettingValue('pinValue'));
    assertEquals(false, pinSection.isPinValid);

    // Verify that entering the pin value in the input sets the setting.
    await triggerInputEvent(input, '0000', pinSection);
    assertTrue(pinSection.getSettingValue('pin'));
    assertEquals('0000', pinSection.getSettingValue('pinValue'));
    assertEquals(true, pinSection.isPinValid);

    // Verify that entering empty pin value in the input updates the
    // setting validity and its value.
    await triggerInputEvent(input, '', pinSection);
    assertTrue(pinSection.getSettingValue('pin'));
    assertEquals('', pinSection.getSettingValue('pinValue'));
    assertEquals(false, pinSection.isPinValid);

    // Check that checkbox and input are still enabled so user can correct
    // invalid input.
    assertEquals(false, checkbox.disabled);
    assertEquals(false, input.disabled);

    // Check that after unchecking the checkbox the pin value is valid again.
    checkbox.checked = false;
    checkbox.dispatchEvent(
        new CustomEvent('change', {bubbles: true, composed: true}));
    assertEquals(true, pinSection.isPinValid);
  });

  // Tests that if settings are enforced by enterprise policy the
  // appropriate UI is disabled.
  test('disabled by policy', async () => {
    const checkbox = pinSection.shadowRoot!.querySelector('cr-checkbox')!;
    assertFalse(checkbox.disabled);

    pinSection.setSetting('pin', true);
    const input = pinSection.shadowRoot!.querySelector('cr-input')!;
    assertFalse(input.disabled);

    model.set('settings.pin.setByPolicy', true);
    await input.updateComplete;
    assertTrue(checkbox.disabled);
    assertFalse(input.disabled);
  });
});