chromium/chrome/test/data/webui/chromeos/settings/nearby_share_page/nearby_share_receive_dialog_test.ts

// Copyright 2020 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://os-settings/lazy_load.js';

import {NearbyShareReceiveDialogElement} from 'chrome://os-settings/lazy_load.js';
import {CrCardRadioButtonElement, CrDialogElement, NearbyProgressElement, setContactManagerForTesting, setNearbyShareSettingsForTesting, setReceiveManagerForTesting} from 'chrome://os-settings/os_settings.js';
import {DataUsage, FastInitiationNotificationState, Visibility} from 'chrome://resources/mojo/chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom-webui.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertFalse, assertNull, assertStringContains, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {FakeContactManager} from 'chrome://webui-test/nearby_share/shared/fake_nearby_contact_manager.js';
import {FakeNearbyShareSettings} from 'chrome://webui-test/nearby_share/shared/fake_nearby_share_settings.js';
import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {isChildVisible, isVisible} from 'chrome://webui-test/test_util.js';

import {FakeReceiveManager} from '../fake_receive_manager.js';

suite('<nearby-share-receive-dialog>', () => {
  let dialog: NearbyShareReceiveDialogElement;
  let fakeReceiveManager: FakeReceiveManager;
  let fakeContactManager: FakeContactManager;
  let fakeSettings: FakeNearbyShareSettings;

  /**
   * This allows both sub-suites to share the same setup logic but with a
   * different enabled state which changes the routing of the first view.
   * @param enabled The value of the enabled setting.
   * @param isOnboardingComplete The value of the
   *     isOnboardingComplete setting.
   */
  function sharedSetup(enabled: boolean, isOnboardingComplete: boolean): void {
    fakeReceiveManager = new FakeReceiveManager();
    fakeContactManager = new FakeContactManager();
    fakeSettings = new FakeNearbyShareSettings();

    setReceiveManagerForTesting(fakeReceiveManager);
    setContactManagerForTesting(fakeContactManager);
    setNearbyShareSettingsForTesting(fakeSettings);

    fakeSettings.setEnabled(enabled);
    fakeSettings.setIsOnboardingComplete(isOnboardingComplete);

    dialog = document.createElement('nearby-share-receive-dialog');
    dialog.settings = {
      enabled,
      isOnboardingComplete,
      visibility: Visibility.kUnknown,
      fastInitiationNotificationState:
          FastInitiationNotificationState.MIN_VALUE,
      isFastInitiationHardwareSupported: false,
      deviceName: '',
      dataUsage: DataUsage.kUnknown,
      allowedContacts: [],
    };
    dialog.isSettingsRetreived = true;
    document.body.appendChild(dialog);
    flush();
  }

  /**
   * @param page page element name
   * @param button button selector (i.e. #actionButton)
   */
  function getButton(page: string, button: string): HTMLButtonElement {
    const element = dialog.shadowRoot!.querySelector(page);
    assertTrue(!!element);
    const template = element.shadowRoot!.querySelector('nearby-page-template');
    assertTrue(!!template);
    const actionButton =
        template.shadowRoot!.querySelector<HTMLButtonElement>(button);
    assertTrue(!!actionButton);
    return actionButton;
  }

  suite('EnabledTests', () => {
    setup(async () => {
      sharedSetup(/*enabled=*/ true, /*isOnboardingComplete=*/ true);
      dialog.showHighVisibilityPage(/*shutoffTimeoutInSeconds=*/ 5 * 60);
      flush();
      await waitAfterNextRender(dialog);
    });

    teardown(() => {
      dialog.remove();
    });

    test('show high visibility page, get a target, accept', async () => {
      // When attached we enter high visibility mode by default
      assertTrue(isVisible(dialog.shadowRoot!.querySelector(
          'nearby-share-high-visibility-page')));
      assertFalse(isVisible(
          dialog.shadowRoot!.querySelector('nearby-share-confirm-page')));
      // If a share target comes in, we show it.
      const target =
          fakeReceiveManager.simulateShareTargetArrival('testName', '1234');
      const confirmPage =
          dialog.shadowRoot!.querySelector('nearby-share-confirm-page');
      assertTrue(!!confirmPage);
      flush();

      const progressIcon =
          confirmPage.shadowRoot!.querySelector<NearbyProgressElement>(
              '#progressIcon');
      assertTrue(!!progressIcon);
      assertTrue(!!progressIcon.shareTarget);
      assertEquals(target.name, progressIcon.shareTarget.name);
      const connectionToken =
          confirmPage.shadowRoot!.querySelector('#connectionToken');
      assertTrue(!!connectionToken);
      assertStringContains(connectionToken.textContent!, '1234');
      assertTrue(isChildVisible(confirmPage, 'nearby-preview'));

      const page =
          confirmPage.shadowRoot!.querySelector('nearby-page-template');
      assertTrue(!!page);
      const button =
          page.shadowRoot!.querySelector<HTMLButtonElement>('#actionButton');
      assertTrue(!!button);
      button.click();
      const shareTargetId = await fakeReceiveManager.whenCalled('accept');
      assertEquals(target.id, shareTargetId);
    });

    test('show high visibility page, get a target, reject', async () => {
      // When attached we enter high visibility mode by default
      assertTrue(isVisible(dialog.shadowRoot!.querySelector(
          'nearby-share-high-visibility-page')));
      assertFalse(isVisible(
          dialog.shadowRoot!.querySelector('nearby-share-confirm-page')));
      // If a share target comes in, we show it.
      const target =
          fakeReceiveManager.simulateShareTargetArrival('testName', '1234');
      const confirmPage =
          dialog.shadowRoot!.querySelector('nearby-share-confirm-page');
      assertTrue(!!confirmPage);
      flush();

      const progressIcon =
          confirmPage.shadowRoot!.querySelector<NearbyProgressElement>(
              '#progressIcon');
      assertTrue(!!progressIcon);
      assertTrue(!!progressIcon.shareTarget);
      assertEquals(target.name, progressIcon.shareTarget.name);
      const connectionToken =
          confirmPage.shadowRoot!.querySelector('#connectionToken');
      assertTrue(!!connectionToken);
      assertStringContains(connectionToken.textContent!, '1234');
      assertTrue(isChildVisible(confirmPage, 'nearby-preview'));

      const page =
          confirmPage.shadowRoot!.querySelector('nearby-page-template');
      assertTrue(!!page);
      const button =
          page.shadowRoot!.querySelector<HTMLButtonElement>('#cancelButton');
      assertTrue(!!button);
      button.click();
      const shareTargetId = await fakeReceiveManager.whenCalled('reject');
      assertEquals(target.id, shareTargetId);
    });

    test(
        'show high visibility page, unregister surface, closes dialog',
        async () => {
          // When attached we enter high visibility mode by default
          assertTrue(isVisible(dialog.shadowRoot!.querySelector(
              'nearby-share-high-visibility-page')));
          assertFalse(isVisible(
              dialog.shadowRoot!.querySelector('nearby-share-confirm-page')));
          // If a share target comes in, we show it.
          await fakeReceiveManager.unregisterForegroundReceiveSurface();
          flush();
          assertTrue(dialog.get('closing_'));
          assertFalse(isVisible(dialog.shadowRoot!.querySelector('cr-dialog')));
        });

    test(
        'OnTransferUpdate, unregister surface, does not close dialog',
        async () => {
          // When attached we enter high visibility mode by default
          assertTrue(isVisible(dialog.shadowRoot!.querySelector(
              'nearby-share-high-visibility-page')));
          assertFalse(isVisible(
              dialog.shadowRoot!.querySelector('nearby-share-confirm-page')));
          fakeReceiveManager.simulateShareTargetArrival('testName', '1234');
          flush();
          assertFalse(dialog.get('closing_'));
          await fakeReceiveManager.unregisterForegroundReceiveSurface();
          flush();
          assertFalse(dialog.get('closing_'));
        });

    test('onStartAdvertisingFailure shows an error', async () => {
      assertTrue(isVisible(dialog.shadowRoot!.querySelector(
          'nearby-share-high-visibility-page')));
      const highVisibilityPage =
          dialog.shadowRoot!.querySelector('nearby-share-high-visibility-page');
      assertTrue(!!highVisibilityPage);
      assertNull(highVisibilityPage.shadowRoot!.querySelector('#errorTitle'));

      dialog.onStartAdvertisingFailure();
      await waitAfterNextRender(dialog);

      const errorTitle =
          highVisibilityPage.shadowRoot!.querySelector('#errorTitle');
      assertTrue(!!errorTitle && errorTitle.textContent!.length > 0);
    });
  });

  suite('DisabledTests', () => {
    setup(() => {
      sharedSetup(/*enabled=*/ false, /*isOnboardingComplete=*/ false);
    });

    teardown(() => {
      dialog.remove();
    });

    test('when disabled, one-page onboarding is shown first', async () => {
      dialog.showHighVisibilityPage(60);
      await waitAfterNextRender(dialog);

      assertFalse(isVisible(
          dialog.shadowRoot!.querySelector('nearby-onboarding-page')));
      assertTrue(isVisible(
          dialog.shadowRoot!.querySelector('nearby-onboarding-one-page')));
      // Finish onboarding
      getButton('nearby-onboarding-one-page', '#actionButton').click();

      await waitAfterNextRender(dialog);

      assertTrue(dialog.settings.enabled);
      assertEquals(Visibility.kAllContacts, dialog.settings.visibility);
      assertTrue(isVisible(dialog.shadowRoot!.querySelector(
          'nearby-share-high-visibility-page')));
    });

    test('when showing onboarding, close when complete.', async () => {
      dialog.showOnboarding();
      await waitAfterNextRender(dialog);

      assertFalse(isVisible(
          dialog.shadowRoot!.querySelector('nearby-onboarding-page')));
      assertTrue(isVisible(
          dialog.shadowRoot!.querySelector('nearby-onboarding-one-page')));
      // Select visibility button and advance to the next page.
      const page =
          dialog.shadowRoot!.querySelector('nearby-onboarding-one-page');
      assertTrue(!!page);
      const button = page.shadowRoot!.querySelector<HTMLButtonElement>(
          '#visibilityButton');
      assertTrue(!!button);
      button.click();

      await waitAfterNextRender(dialog);

      assertTrue(isVisible(
          dialog.shadowRoot!.querySelector('nearby-visibility-page')));
      // All contacts should be selected and confirm should close the dialog.
      fakeContactManager.completeDownload();

      const contactElement =
          dialog.shadowRoot!.querySelector('nearby-visibility-page');
      assertTrue(!!contactElement);
      const contactVisibilityElement =
          contactElement.shadowRoot!.querySelector('nearby-contact-visibility');
      assertTrue(!!contactVisibilityElement);
      const allContacts =
          contactVisibilityElement.shadowRoot!
              .querySelector<CrCardRadioButtonElement>('#contacts');
      assertTrue(!!allContacts);
      assertTrue(allContacts.checked);
      getButton('nearby-visibility-page', '#actionButton').click();

      assertTrue(dialog.get('closing_'));

      await waitAfterNextRender(dialog);

      const element =
          dialog.shadowRoot!.querySelector<CrDialogElement>('#dialog');
      assertTrue(!!element);
      assertFalse(element.open);
    });
  });
});