chromium/chrome/test/data/webui/cr_elements/cr_page_selector_test.ts

// Copyright 2024 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://resources/cr_elements/cr_page_selector/cr_page_selector.js';

import type {CrPageSelectorElement} from 'chrome://resources/cr_elements/cr_page_selector/cr_page_selector.js';
import {getTrustedHTML} from 'chrome://resources/js/static_types.js';
import {CrLitElement, html} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {eventToPromise, isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js';

suite('cr-page-selector', () => {
  let element: CrPageSelectorElement;

  setup(() => {
    document.body.innerHTML = getTrustedHTML`
      <cr-page-selector attr-for-selected="path">
        <div id="a" path="a">Page A</div>
        <div id="b" path="b">Page B</div>
        <div id="c" path="c">Page C</div>
      </cr-page-selector>
    `;
    element = document.querySelector('cr-page-selector')!;
  });

  test('Only selected is visible', async() => {
    element.selected = 'a';
    await element.updateComplete;

    assertTrue(!!document.body.querySelector('#a.selected'));
    assertTrue(isVisible(document.body.querySelector('#a')));
    assertFalse(isVisible(document.body.querySelector('#b')));
    assertFalse(isVisible(document.body.querySelector('#c')));

    element.selected = 'c';
    await element.updateComplete;
    assertTrue(!!document.body.querySelector('#c.selected'));
    assertFalse(isVisible(document.body.querySelector('#a')));
    assertFalse(isVisible(document.body.querySelector('#b')));
    assertTrue(isVisible(document.body.querySelector('#c')));
  });

  test('show-all', async () => {
    element.toggleAttribute('show-all', true);
    element.selected = 'a';
    await element.updateComplete;

    assertTrue(!!document.body.querySelector('#a.selected'));
    assertTrue(isVisible(document.body.querySelector('#a')));
    assertTrue(isVisible(document.body.querySelector('#b')));
    assertTrue(isVisible(document.body.querySelector('#c')));

    element.selected = 'c';
    await element.updateComplete;
    assertTrue(!!document.body.querySelector('#c.selected'));
    assertTrue(isVisible(document.body.querySelector('#a')));
    assertTrue(isVisible(document.body.querySelector('#b')));
    assertTrue(isVisible(document.body.querySelector('#c')));
  });

  test('Click does not select', async () => {
    element.selected = 'a';
    await element.updateComplete;

    const pageA = document.body.querySelector<HTMLElement>('#a');
    assertTrue(!!pageA);

    const whenClicked = new Promise<void>(resolve => {
      pageA.addEventListener('click', () => {
        element.selected = 'b';
        resolve();
      });
    });
    pageA.click();

    await whenClicked;
    await element.updateComplete;
    assertEquals('b', element.selected);
  });
});

class TestPageManager extends CrLitElement {
  static get is() {
    return 'test-page-manager';
  }

  static override get properties() {
    return {
      page: {type: String},
    };
  }

  page: string = '';

  override render() {
    return html`<cr-page-selector has-nested-slots attr-for-selected="path"
          .selected="${this.page}">
      <slot name="foo"></slot>
      <slot name="bar"></slot>
      <div id="z" path="z">Page Z</div>
    </cr-page-selector>`;
  }
}

customElements.define('test-page-manager', TestPageManager);

suite('cr-page-selector nested slots', () => {
  let element: TestPageManager;

  setup(() => {
    document.body.innerHTML = getTrustedHTML`
      <test-page-manager>
        <div id="a" path="a" slot="foo">Page A</div>
        <div id="b" path="b" slot="foo">Page B</div>
        <div id="c" path="c" slot="bar">Page C</div>
      </test-page-manager>
    `;
    const manager =
        document.querySelector<TestPageManager>('test-page-manager');
    assertTrue(!!manager);
    element = manager;
  });

  test('Only selected is visible', async () => {
    element.page = 'a';
    await microtasksFinished();

    assertTrue(isVisible(element.querySelector('#a.selected')));
    assertFalse(isVisible(element.querySelector('#b')));
    assertFalse(isVisible(element.querySelector('#c')));
    assertFalse(isVisible(element.shadowRoot!.querySelector('#z')));

    element.page = 'c';
    await microtasksFinished();
    assertTrue(isVisible(element.querySelector('#c.selected')));
    assertFalse(isVisible(element.querySelector('#a')));
    assertFalse(isVisible(element.querySelector('#b')));
    assertFalse(isVisible(element.shadowRoot!.querySelector('#z')));

    element.page = 'z';
    await microtasksFinished();
    assertTrue(isVisible(element.shadowRoot!.querySelector('#z.selected')));
    assertFalse(isVisible(element.querySelector('#a')));
    assertFalse(isVisible(element.querySelector('#b')));
    assertFalse(isVisible(element.querySelector('#c')));

    element.page = 'd';
    await microtasksFinished();
    // Nothing is selected.
    assertFalse(!!element.querySelector('.selected'));
    assertFalse(isVisible(element.querySelector('#a')));
    assertFalse(isVisible(element.querySelector('#b')));
    assertFalse(isVisible(element.querySelector('#c')));
    assertFalse(isVisible(element.shadowRoot!.querySelector('#z')));

    // Make sure the slotchange event for the nested slot triggers
    // iron-items-changed.
    const div = document.createElement('div');
    div.setAttribute('path', 'd');
    div.id = 'd';
    div.slot = 'bar';
    div.textContent = 'Page D';
    element.appendChild(div);
    await eventToPromise('iron-items-changed', element);
    await microtasksFinished();

    // Verify the selected item is now visible.
    assertTrue(isVisible(element.querySelector('#d.selected')));
    assertFalse(isVisible(element.querySelector('#a')));
    assertFalse(isVisible(element.querySelector('#b')));
    assertFalse(isVisible(element.querySelector('#c')));
    assertFalse(isVisible(element.shadowRoot!.querySelector('#z')));

    // Make sure the slotchange event for the non-nested slot triggers
    // iron-items-changed.
    const divY = document.createElement('div');
    divY.setAttribute('path', 'y');
    divY.id = 'y';
    divY.textContent = 'Page Y';
    const selector = element.shadowRoot!.querySelector('cr-page-selector');
    assertTrue(!!selector);
    selector.appendChild(divY);
    await eventToPromise('iron-items-changed', element);

    // Select page Y.
    element.page = 'y';
    await microtasksFinished();

    assertTrue(isVisible(element.shadowRoot!.querySelector('#y.selected')));
    assertFalse(isVisible(element.querySelector('#a')));
    assertFalse(isVisible(element.querySelector('#b')));
    assertFalse(isVisible(element.querySelector('#c')));
    assertFalse(isVisible(element.querySelector('#d')));
    assertFalse(isVisible(element.shadowRoot!.querySelector('#z')));
  });
});