chromium/chrome/test/data/webui/chromeos/personalization_app/ambient_preview_large_element_test.ts

// Copyright 2023 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://personalization/strings.m.js';

import {AmbientObserver, AmbientPreviewLargeElement, Paths, PersonalizationRouterElement, TopicSource} from 'chrome://personalization/js/personalization_app.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {TestMock} from 'chrome://webui-test/test_mock.js';

import {baseSetup, initElement, teardownElement} from './personalization_app_test_utils.js';
import {TestAmbientProvider} from './test_ambient_interface_provider.js';
import {TestPersonalizationStore} from './test_personalization_store.js';


suite('AmbientPreviewLargeElementTest', function() {
  let ambientPreviewLargeElement: AmbientPreviewLargeElement|null;
  let ambientProvider: TestAmbientProvider;
  let personalizationStore: TestPersonalizationStore;
  const routerOriginal = PersonalizationRouterElement.instance;
  const routerMock = TestMock.fromClass(PersonalizationRouterElement);

  setup(() => {
    const mocks = baseSetup();
    ambientProvider = mocks.ambientProvider;
    personalizationStore = mocks.personalizationStore;
    AmbientObserver.initAmbientObserverIfNeeded();
    PersonalizationRouterElement.instance = () => routerMock;
  });

  teardown(async () => {
    await teardownElement(ambientPreviewLargeElement);
    ambientPreviewLargeElement = null;
    AmbientObserver.shutdown();
    PersonalizationRouterElement.instance = routerOriginal;
  });

  test(
      'displays zero state message when ambient mode is disabled', async () => {
        loadTimeData.overrideValues({isAmbientModeAllowed: true});
        personalizationStore.data.ambient.albums = ambientProvider.albums;
        personalizationStore.data.ambient.topicSource = TopicSource.kArtGallery;
        personalizationStore.data.ambient.ambientModeEnabled = false;
        personalizationStore.data.ambient.previews = ambientProvider.previews;
        ambientPreviewLargeElement = initElement(AmbientPreviewLargeElement);
        personalizationStore.notifyObservers();
        await waitAfterNextRender(ambientPreviewLargeElement);

        const messageContainer =
            ambientPreviewLargeElement.shadowRoot!.getElementById(
                'messageContainer');
        assertTrue(!!messageContainer);
        const textSpan = messageContainer.querySelector<HTMLSpanElement>(
            '#turnOnDescription');
        assertTrue(!!textSpan);
        assertEquals(
            ambientPreviewLargeElement.i18n(
                'ambientModeMainPageZeroStateMessageV2'),
            textSpan.innerText.trim());
      });

  test(
      'clicks turn on button enables ambient mode and navigates to ambient subpage',
      async () => {
        personalizationStore.data.ambient.albums = ambientProvider.albums;
        personalizationStore.data.ambient.topicSource = TopicSource.kArtGallery;
        personalizationStore.data.ambient.ambientModeEnabled = false;
        personalizationStore.data.ambient.previews = ambientProvider.previews;
        ambientPreviewLargeElement = initElement(AmbientPreviewLargeElement);
        personalizationStore.notifyObservers();
        await waitAfterNextRender(ambientPreviewLargeElement);

        const messageContainer =
            ambientPreviewLargeElement.shadowRoot!.getElementById(
                'messageContainer');
        assertTrue(!!messageContainer);
        const button = messageContainer.querySelector('cr-button');
        assertTrue(!!button);

        personalizationStore.setReducersEnabled(true);
        button.click();
        assertTrue(personalizationStore.data.ambient.ambientModeEnabled);

        const original = PersonalizationRouterElement.instance;
        const goToRoutePromise = new Promise<[Paths, Object]>(resolve => {
          PersonalizationRouterElement.instance = () => {
            return {
              goToRoute(path: Paths, queryParams: Object = {}) {
                resolve([path, queryParams]);
                PersonalizationRouterElement.instance = original;
              },
            } as PersonalizationRouterElement;
          };
        });
        const [path, queryParams] = await goToRoutePromise;
        assertEquals(Paths.AMBIENT, path);
        assertDeepEquals({}, queryParams);
      });

  test('click big image preview goes to ambient subpage', async () => {
    personalizationStore.data.ambient = {
      ...personalizationStore.data.ambient,
      albums: ambientProvider.albums,
      topicSource: TopicSource.kArtGallery,
      ambientModeEnabled: true,
      previews: ambientProvider.previews,
    };
    ambientPreviewLargeElement = initElement(AmbientPreviewLargeElement);
    personalizationStore.notifyObservers();
    await waitAfterNextRender(ambientPreviewLargeElement);

    const original = PersonalizationRouterElement.instance;
    const goToRoutePromise = new Promise<[Paths, Object]>(resolve => {
      PersonalizationRouterElement.instance = () => {
        return {
          goToRoute(path: Paths, queryParams: Object = {}) {
            resolve([path, queryParams]);
            PersonalizationRouterElement.instance = original;
          },
        } as PersonalizationRouterElement;
      };
    });

    ambientPreviewLargeElement.shadowRoot!
        .querySelector<HTMLImageElement>('.preview-image.clickable')!.click();

    const [path, queryParams] = await goToRoutePromise;

    assertEquals(Paths.AMBIENT, path, 'navigates to ambient subpage');
    assertDeepEquals({}, queryParams, 'no query params set');
  });

  test('shows 2 or 3 preview images', async () => {
    loadTimeData.overrideValues({isAmbientModeAllowed: true});
    personalizationStore.data.ambient = {
      ...personalizationStore.data.ambient,
      albums: ambientProvider.albums,
      topicSource: TopicSource.kArtGallery,
      ambientModeEnabled: true,
      previews: ambientProvider.previews,
    };
    ambientPreviewLargeElement = initElement(AmbientPreviewLargeElement);
    personalizationStore.notifyObservers();
    await waitAfterNextRender(ambientPreviewLargeElement);

    assertEquals(
        'http://test_url2',
        ambientPreviewLargeElement.shadowRoot!
            .querySelector<HTMLImageElement>(
                '#imageContainer .preview-image')!.getAttribute('auto-src'),
        'large container shows album preview image from first selected album');

    const thumbnailContainer =
        ambientPreviewLargeElement.shadowRoot!.getElementById(
            'thumbnailContainer');
    assertTrue(!!thumbnailContainer, 'thumbnailContainer exists');

    let thumbnailImages =
        thumbnailContainer.querySelectorAll<HTMLImageElement>('img');
    assertDeepEquals(
        [
          'http://preview0',
          'http://preview1',
        ],
        Array.from(thumbnailImages).map(img => img.getAttribute('auto-src')),
        'first two preview images are shown for kArtGallery');

    personalizationStore.data.ambient.topicSource = TopicSource.kGooglePhotos;
    personalizationStore.notifyObservers();
    await waitAfterNextRender(ambientPreviewLargeElement);

    thumbnailImages =
        thumbnailContainer.querySelectorAll<HTMLImageElement>('img');
    assertDeepEquals(
        [
          'http://preview0',
          'http://preview1',
          'http://preview2',
        ],
        Array.from(thumbnailImages).map(img => img.getAttribute('auto-src')),
        'first three preview images are shown for kGooglePhotos');
  });

  test('click ambient thumbnail goes to ambient subpage', async () => {
    personalizationStore.data.ambient = {
      ...personalizationStore.data.ambient,
      albums: ambientProvider.albums,
      topicSource: TopicSource.kArtGallery,
      ambientModeEnabled: true,
      previews: ambientProvider.previews,
    };
    ambientPreviewLargeElement = initElement(AmbientPreviewLargeElement);
    personalizationStore.notifyObservers();
    await waitAfterNextRender(ambientPreviewLargeElement);

    const original = PersonalizationRouterElement.instance;
    const goToRoutePromise = new Promise<[Paths, Object]>(resolve => {
      PersonalizationRouterElement.instance = () => {
        return {
          goToRoute(path: Paths, queryParams: Object = {
            scrollTo: 'topic-source-list',
          }) {
            resolve([path, queryParams]);
            PersonalizationRouterElement.instance = original;
          },
        } as PersonalizationRouterElement;
      };
    });

    ambientPreviewLargeElement.shadowRoot!.getElementById(
                                              'thumbnailContainer')!.click();

    const [path, queryParams] = await goToRoutePromise;

    assertEquals(Paths.AMBIENT, path, 'navigates to ambient subpage');
    assertDeepEquals(
        {scrollTo: 'topic-source-list'}, queryParams, 'query params set');
  });

  test('displays not available message for non-allowed user', async () => {
    // Disable `isAmbientModeAllowed` to mock an enterprise controlled user.
    loadTimeData.overrideValues({isAmbientModeAllowed: false});

    personalizationStore.data.ambient.albums = ambientProvider.albums;
    personalizationStore.data.ambient.topicSource = TopicSource.kArtGallery;
    personalizationStore.data.ambient.ambientModeEnabled = false;
    personalizationStore.data.ambient.previews = ambientProvider.previews;
    ambientPreviewLargeElement = initElement(AmbientPreviewLargeElement);
    personalizationStore.notifyObservers();
    await waitAfterNextRender(ambientPreviewLargeElement);

    const messageContainer =
        ambientPreviewLargeElement.shadowRoot!.getElementById(
            'messageContainer');
    assertTrue(!!messageContainer);
    const textSpan =
        messageContainer.querySelector<HTMLSpanElement>('#turnOnDescription');
    assertTrue(!!textSpan);
    assertEquals(
        ambientPreviewLargeElement.i18n(
            'ambientModeMainPageEnterpriseUserMessage'),
        textSpan.innerText.trim());
  });
});