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

// Copyright 2017 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_view_manager/cr_view_manager.js';
import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.js';
import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render_lit.js';

import type {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
import {getTrustedHTML} from 'chrome://resources/js/static_types.js';
import {CrLitElement, html as litHtml} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {PolymerElement, html as polymerHtml} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {isChildVisible} from 'chrome://webui-test/test_util.js';
// clang-format on


let viewManager: CrViewManagerElement;
let parent: HTMLElement;

function assertViewVisible(id: string, expectIsVisible: boolean) {
  assertEquals(
      expectIsVisible,
      isChildVisible(viewManager, `#${id}`, /*checkLightDom=*/ true));
}

suite('CrElementsViewManagerTest', function() {
  // Initialize an cr-view-manager inside a parent div before
  // each test.
  setup(function() {
    document.body.innerHTML = getTrustedHTML`
        <div id="parent">
          <cr-view-manager id="viewManager">
            <div slot="view" id="viewOne">view 1</div>
            <div slot="view" id="viewTwo">view 2</div>
            <div slot="view" id="viewThree">view 3</div>
          </cr-view-manager>
        </div>
      `;
    parent = document.body.querySelector('#parent')!;
    viewManager = document.body.querySelector('#viewManager')!;
  });

  test('visibility', async function() {
    assertViewVisible('viewOne', false);
    assertViewVisible('viewTwo', false);
    assertViewVisible('viewThree', false);

    await viewManager.switchView('viewOne');
    assertViewVisible('viewOne', true);
    assertViewVisible('viewTwo', false);
    assertViewVisible('viewThree', false);

    await viewManager.switchView('viewThree');
    assertViewVisible('viewOne', false);
    assertViewVisible('viewTwo', false);
    assertViewVisible('viewThree', true);
  });

  test('event firing', async function() {
    const viewOne = viewManager.querySelector('#viewOne')!;

    let fired = new Set();
    let bubbled = new Set();

    ['view-enter-start',
     'view-enter-finish',
     'view-exit-start',
     'view-exit-finish',
    ].forEach(type => {
      parent.addEventListener(type, () => {
        bubbled.add(type);
      });
      viewOne.addEventListener(type, () => {
        fired.add(type);
      });
    });

    /**
     * @param eventName The event to check
     * @param expectFired Whether the event should have fired.
     */
    function verifyEventFiredAndBubbled(
        eventName: string, expectFired: boolean) {
      assertEquals(expectFired, fired.has(eventName));
      assertEquals(expectFired, bubbled.has(eventName));
    }

    // Initial switch has no animation.
    viewManager.switchView('viewOne');
    // view-enter-start and view-enter-finish are fired synchronously when
    // there's no animation.
    verifyEventFiredAndBubbled('view-enter-start', true);
    verifyEventFiredAndBubbled('view-enter-finish', true);

    const exitPromises = viewManager.switchView('viewTwo');
    verifyEventFiredAndBubbled('view-exit-start', true);
    // view-exit-finish is waiting on the animation.
    verifyEventFiredAndBubbled('view-exit-finish', false);

    await exitPromises;
    verifyEventFiredAndBubbled('view-exit-finish', true);

    fired = new Set();
    bubbled = new Set();

    // Switching back has an animation this time.
    const enterPromises = viewManager.switchView('viewOne');
    verifyEventFiredAndBubbled('view-enter-start', true);
    verifyEventFiredAndBubbled('view-enter-finish', false);
    await enterPromises;
    verifyEventFiredAndBubbled('view-enter-finish', true);
  });
});

suite('CrLazyRenderInCrViewManagerTest', function() {
  class TestApp extends PolymerElement {
    static get is() {
      return 'test-app';
    }

    static get template() {
      return polymerHtml`
        <cr-view-manager id="viewManager">
          <div slot="view" id="viewOne">view one</div>
          <cr-lazy-render id="lazy">
            <template>
              <div slot="view" id="lazyView"></div>
            </template>
          </cr-lazy-render>
        </cr-view-manager>`;
    }
  }

  class TestAppLit extends CrLitElement {
    static get is() {
      return 'test-app-lit';
    }

    override render() {
      return litHtml`
        <cr-view-manager id="viewManager">
          <div slot="view" id="viewOne">view one</div>
          <cr-lazy-render-lit id="lazy"
              .template="${
          () => litHtml`<div slot="view" id="lazyView"></div>`}">
          </cr-lazy-render-lit>
        </cr-view-manager>`;
    }
  }

  customElements.define(TestApp.is, TestApp);
  customElements.define(TestAppLit.is, TestAppLit);

  function setupTest(isLit: boolean) {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    const testApp = isLit ? document.createElement('test-app-lit') :
                            document.createElement('test-app');
    document.body.appendChild(testApp);

    viewManager = testApp.shadowRoot!.querySelector('#viewManager')!;
    assertTrue(!!viewManager);
  }

  test('switch to cr-lazy-render view', async function() {
    setupTest(/*isLit=*/ false);

    assertViewVisible('viewOne', false);
    assertViewVisible('lazyView', false);

    await viewManager.switchView('viewOne');
    assertViewVisible('viewOne', true);
    assertViewVisible('lazyView', false);

    await viewManager.switchView('lazy');
    assertViewVisible('viewOne', false);
    assertViewVisible('lazyView', true);
  });

  test('switch to cr-lazy-render-lit view', async function() {
    setupTest(/*isLit=*/ true);

    assertViewVisible('viewOne', false);
    assertViewVisible('lazyView', false);

    await viewManager.switchView('viewOne');
    assertViewVisible('viewOne', true);
    assertViewVisible('lazyView', false);

    await viewManager.switchView('lazy');
    assertViewVisible('viewOne', false);
    assertViewVisible('lazyView', true);
  });
});