chromium/chrome/test/data/webui/cr_elements/cr_radio_button_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.

// clang-format off
import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.js';

import type {CrRadioButtonElement} from 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.js';
import {assertEquals, assertNotEquals, assertFalse, assertTrue, assertLT, assertGT} from 'chrome://webui-test/chai_assert.js';
import {microtasksFinished} from 'chrome://webui-test/test_util.js';
// clang-format on

suite('cr-radio-button', function() {
  let radioButton: CrRadioButtonElement;

  setup(function() {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    radioButton = document.createElement('cr-radio-button');
    document.body.appendChild(radioButton);
  });

  function assertStyle(element: Element, name: string, expected: string) {
    const actual = getComputedStyle(element).getPropertyValue(name).trim();
    assertEquals(expected, actual);
  }

  function assertNotStyle(element: Element, name: string, not: string) {
    const actual = getComputedStyle(element).getPropertyValue(name).trim();
    assertNotEquals(not, actual);
  }

  function assertChecked() {
    assertTrue(radioButton.hasAttribute('checked'));
    assertEquals('true', radioButton.$.button.getAttribute('aria-checked'));
    assertNotStyle(
        radioButton.shadowRoot!.querySelector('.disc')!, 'background-color',
        'rgba(0, 0, 0, 0)');
  }

  function assertNotChecked() {
    assertFalse(radioButton.hasAttribute('checked'));
    assertEquals('false', radioButton.$.button.getAttribute('aria-checked'));
    assertStyle(
        radioButton.shadowRoot!.querySelector('.disc')!, 'background-color',
        'rgba(0, 0, 0, 0)');
    assertStyle(
        radioButton.shadowRoot!.querySelector('.disc')!, 'background-color',
        'rgba(0, 0, 0, 0)');
  }

  function assertDisabled() {
    assertTrue(radioButton.hasAttribute('disabled'));
    assertEquals('true', radioButton.$.button.getAttribute('aria-disabled'));
    assertStyle(radioButton, 'pointer-events', 'none');
    assertStyle(radioButton, 'opacity', '1');
  }

  function assertNotDisabled() {
    assertFalse(radioButton.hasAttribute('disabled'));
    assertEquals('false', radioButton.$.button.getAttribute('aria-disabled'));
    assertStyle(radioButton, 'opacity', '1');
  }

  // Setting selection by mouse/keyboard is cr-radio-group's job, so
  // these tests simply set states programatically and make sure the element
  // is visually correct.
  test('Checked', async () => {
    assertNotChecked();
    radioButton.checked = true;
    await microtasksFinished();
    assertChecked();
    radioButton.checked = false;
    await microtasksFinished();
    assertNotChecked();
  });

  test('Disabled', async () => {
    assertNotDisabled();
    radioButton.disabled = true;
    await microtasksFinished();
    assertDisabled();
    radioButton.disabled = false;
    await microtasksFinished();
    assertNotChecked();
  });

  test('Ripple', function() {
    function getRipple() {
      return radioButton.shadowRoot!.querySelector('cr-ripple');
    }

    assertFalse(!!getRipple());
    radioButton.dispatchEvent(
        new CustomEvent('up', {bubbles: true, composed: true}));
    const ripple = getRipple();
    assertTrue(!!ripple);
    assertFalse(ripple.holdDown);
  });

  test('Label Hidden', async () => {
    // Having no label set hides label.
    assertStyle(
        radioButton.shadowRoot!.querySelector('#label')!, 'display', 'none');

    // Setting label shows label.
    radioButton.label = 'foo';
    await microtasksFinished();
    assertNotStyle(
        radioButton.shadowRoot!.querySelector('#label')!, 'display', 'none');
    assertNotStyle(
        radioButton.shadowRoot!.querySelector('#label')!, 'clip',
        'rect(0px, 0px, 0px, 0px)');
    assertEquals(radioButton.$.button.getAttribute('aria-labelledby'), 'label');
    assertEquals(
        radioButton.shadowRoot!.querySelector('#label')!.textContent!.trim(),
        'foo');

    // Setting hideLabelText true clips label from screen reader.
    radioButton.hideLabelText = true;
    await microtasksFinished();
    assertStyle(
        radioButton.shadowRoot!.querySelector('#label')!, 'clip',
        'rect(0px, 0px, 0px, 0px)');
    assertEquals(radioButton.$.button.getAttribute('aria-labelledby'), 'label');
    assertEquals(
        radioButton.shadowRoot!.querySelector('#label')!.textContent!.trim(),
        'foo');
  });

  test('Label First', () => {
    const button = radioButton.$.button;
    let buttonRect = button.getBoundingClientRect();
    const labelWrapper = radioButton.shadowRoot!.querySelector('#labelWrapper');
    assertTrue(!!labelWrapper);

    let labelWrapperRect = labelWrapper.getBoundingClientRect();
    assertLT(buttonRect.left, labelWrapperRect.left);

    radioButton.classList.add('label-first');
    buttonRect = button.getBoundingClientRect();
    labelWrapperRect = labelWrapper.getBoundingClientRect();
    assertGT(buttonRect.left, labelWrapperRect.left);
  });
});