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

// Copyright 2021 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 {GooglePhotosAlbum, GooglePhotosEnablementState, GooglePhotosPhoto, Paths, PersonalizationRouterElement, setTransitionsEnabled} from 'chrome://personalization/js/personalization_app.js';
import {SeaPenTemplateId} from 'chrome://resources/ash/common/sea_pen/sea_pen_generated.mojom-webui.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';

import {baseSetup, initElement} from './personalization_app_test_utils.js';
import {TestPersonalizationStore} from './test_personalization_store.js';
import {TestWallpaperProvider} from './test_wallpaper_interface_provider.js';

suite('PersonalizationRouterElementTest', function() {
  let personalizationStore: TestPersonalizationStore;
  let wallpaperProvider: TestWallpaperProvider;

  setup(() => {
    const mocks = baseSetup();
    personalizationStore = mocks.personalizationStore;
    wallpaperProvider = mocks.wallpaperProvider;

    // Disables page transition by default.
    setTransitionsEnabled(false);
  });

  test('will show ambient subpage if allowed', async () => {
    loadTimeData.overrideValues({'isAmbientModeAllowed': true});
    const routerElement = initElement(PersonalizationRouterElement);
    PersonalizationRouterElement.instance().goToRoute(Paths.AMBIENT);
    await waitAfterNextRender(routerElement);

    const mainElement =
        routerElement.shadowRoot!.querySelector('personalization-main');
    assertTrue(!!mainElement);
    assertEquals(getComputedStyle(mainElement).display, 'none');

    const ambientSubpage =
        routerElement.shadowRoot!.querySelector('ambient-subpage');
    assertTrue(!!ambientSubpage);
    assertNotEquals(getComputedStyle(ambientSubpage).display, 'none');
  });

  test('will not show ambient subpage if disallowed', async () => {
    loadTimeData.overrideValues({'isAmbientModeAllowed': false});
    const routerElement = initElement(PersonalizationRouterElement);
    PersonalizationRouterElement.instance().goToRoute(Paths.AMBIENT);
    await waitAfterNextRender(routerElement);

    const mainElement =
        routerElement.shadowRoot!.querySelector('personalization-main');
    assertTrue(!!mainElement);
    assertNotEquals(getComputedStyle(mainElement).display, 'none');

    const ambientSubpage =
        routerElement.shadowRoot!.querySelector('ambient-subpage');
    assertFalse(!!ambientSubpage);
  });

  test('returns to root page when wrong path is keyed in', async () => {
    loadTimeData.overrideValues({'isAmbientModeAllowed': true});
    const routerElement = initElement(PersonalizationRouterElement);
    routerElement.goToRoute('/wrongpath' as Paths, {});
    await waitAfterNextRender(routerElement);

    // Due to the wrong path, only shows root page.
    const mainElement =
        routerElement.shadowRoot!.querySelector('personalization-main');
    assertTrue(!!mainElement);
    assertNotEquals(getComputedStyle(mainElement).display, 'none');

    // No breadcrumb element, ambient subpage, user subpage and wallpaper
    // subpage are shown.
    const breadcrumbElement =
        routerElement.shadowRoot!.querySelector('personalization-breadcrumb');
    assertFalse(!!breadcrumbElement);

    const ambientSubpage =
        routerElement.shadowRoot!.querySelector('ambient-subpage');
    assertFalse(!!ambientSubpage);

    const userSubpage = routerElement.shadowRoot!.querySelector('user-subpage');
    assertFalse(!!userSubpage);

    const wallpaperSubpage =
        routerElement.shadowRoot!.querySelector('wallpaper-subpage');
    assertFalse(!!wallpaperSubpage);
  });

  test('puts googlePhotosAlbumIsShared query param in url', async () => {
    loadTimeData.overrideValues({isGooglePhotosSharedAlbumsEnabled: true});
    const isSharedParam = 'googlePhotosAlbumIsShared';
    const sharedAlbum: GooglePhotosAlbum = {
      id: 'aaa',
      isShared: true,
      photoCount: 5,
      preview: {url: ''},
      timestamp: {internalValue: 0n},
      title: 'fake album',
    };
    const ownedAlbum = {...sharedAlbum, id: 'bbb', isShared: false};

    const photo: GooglePhotosPhoto = {
      id: '9bd1d7a3-f995-4445-be47-53c5b58ce1cb',
      dedupKey: '2d0d1595-14af-4471-b2db-b9c8eae3a491',
      name: 'foo',
      date: {data: []},
      url: {url: 'foo.com'},
      location: 'home',
    };
    wallpaperProvider.setGooglePhotosSharedAlbums([sharedAlbum]);
    wallpaperProvider.setGooglePhotosAlbums([ownedAlbum]);
    wallpaperProvider.setGooglePhotosEnabled(
        GooglePhotosEnablementState.kEnabled);
    wallpaperProvider.setGooglePhotosPhotosByAlbumId(sharedAlbum.id, [photo]);
    wallpaperProvider.setGooglePhotosPhotosByAlbumId(ownedAlbum.id, [photo]);

    personalizationStore.setReducersEnabled(true);

    // Start at root page.
    const routerElement = initElement(PersonalizationRouterElement);
    await waitAfterNextRender(routerElement);

    // Navigate to wallpaper collections list.
    routerElement.goToRoute(Paths.COLLECTIONS);
    await wallpaperProvider.whenCalled('fetchGooglePhotosEnabled');

    // Navigate to google photos page.
    routerElement.goToRoute(Paths.GOOGLE_PHOTOS_COLLECTION);
    await wallpaperProvider.whenCalled('fetchGooglePhotosSharedAlbums');

    let params = new URLSearchParams(location.search);
    assertFalse(params.has(isSharedParam), 'param not set yet');

    // Select a shared album should put the param in query string.
    routerElement.selectGooglePhotosAlbum(sharedAlbum);
    await waitAfterNextRender(routerElement);

    params = new URLSearchParams(location.search);
    assertTrue(params.has(isSharedParam), 'param exists');
    assertEquals('true', params.get(isSharedParam), 'true value set');

    // Select owned album removes the param.
    routerElement.selectGooglePhotosAlbum(ownedAlbum);
    await waitAfterNextRender(routerElement);

    params = new URLSearchParams(location.search);
    assertFalse(params.has(isSharedParam), 'param no longer exists');
    assertEquals(null, params.get(isSharedParam), 'does not exist so null');
  });

  test('hides SeaPen from ineligible users', async () => {
    loadTimeData.overrideValues({isSeaPenEnabled: false});

    const routerElement = initElement(PersonalizationRouterElement, {});

    for (const path of [Paths.SEA_PEN_COLLECTION, Paths.SEA_PEN_RESULTS]) {
      PersonalizationRouterElement.instance().goToRoute(path);
      await waitAfterNextRender(routerElement);

      // Due to the forbidden path, only shows root page.
      const mainElement =
          routerElement.shadowRoot!.querySelector('personalization-main');
      assertTrue(!!mainElement, 'main element exists');
      assertNotEquals(
          getComputedStyle(mainElement).display, 'none',
          'main element is shown');

      const seaPenRouterElement =
          routerElement.shadowRoot!.querySelector('sea-pen-router');
      assertFalse(!!seaPenRouterElement, 'sea-pen-router does not exist');
    }
  });

  test('shows SeaPen for eligible users', async () => {
    loadTimeData.overrideValues({isSeaPenEnabled: true});

    const routerElement = initElement(PersonalizationRouterElement);
    await waitAfterNextRender(routerElement);

    let seaPenRouterElement =
        routerElement.shadowRoot!.querySelector('sea-pen-router');
    assertFalse(!!seaPenRouterElement, 'sea-pen-router does not exist');

    routerElement.goToRoute(Paths.SEA_PEN_COLLECTION);
    await waitAfterNextRender(routerElement);

    const mainElement =
        routerElement.shadowRoot!.querySelector('personalization-main');
    assertTrue(!!mainElement);
    assertEquals(
        getComputedStyle(mainElement).display, 'none',
        'main element is hidden');

    seaPenRouterElement =
        routerElement.shadowRoot!.querySelector('sea-pen-router');
    assertTrue(!!seaPenRouterElement, 'sea-pen-router now exists');
    assertNotEquals(
        getComputedStyle(seaPenRouterElement).display, 'none',
        'sea-pen-router is shown');
  });

  test('shows wallpaper selected in SeaPen', async () => {
    loadTimeData.overrideValues({isSeaPenEnabled: true});

    const routerElement = initElement(PersonalizationRouterElement);
    await waitAfterNextRender(routerElement);

    routerElement.goToRoute(Paths.SEA_PEN_COLLECTION);
    await waitAfterNextRender(routerElement);

    const seaPenRouterElement =
        routerElement.shadowRoot!.querySelector('sea-pen-router');
    assertTrue(!!seaPenRouterElement, 'sea-pen-router now exists');
    assertNotEquals(
        getComputedStyle(seaPenRouterElement).display, 'none',
        'sea-pen-router is shown');

    const wallpaperSelected =
        routerElement.shadowRoot!.getElementById('wallpaperSelected');
    assertTrue(!!wallpaperSelected);
    assertNotEquals(
        getComputedStyle(wallpaperSelected).display, 'none',
        'sea-pen-router shows wallpaper-selected');
  });

  test('hides wallpaper selected on non root path sea pen', async () => {
    loadTimeData.overrideValues(
        {isSeaPenEnabled: true, isSeaPenTextInputEnabled: true});

    const routerElement = initElement(PersonalizationRouterElement);
    await waitAfterNextRender(routerElement);

    routerElement.goToRoute(Paths.SEA_PEN_RESULTS, {
      seaPenTemplateId: SeaPenTemplateId.kFlower.toString(),
    });
    await waitAfterNextRender(routerElement);

    const seaPenRouterElement =
        routerElement.shadowRoot!.querySelector('sea-pen-router');
    assertTrue(!!seaPenRouterElement, 'sea-pen-router now exists');
    assertNotEquals(
        getComputedStyle(seaPenRouterElement).display, 'none',
        'sea-pen-router is shown');

    // No wallpaper-selected in Template results page.
    assertFalse(
        !!routerElement.shadowRoot!.getElementById('wallpaperSelected'),
        'wallpaper-selected should not be displayed in template results page');

    // No wallpaper-selected in Freeform subpage.
    routerElement.goToRoute(Paths.SEA_PEN_FREEFORM);
    await waitAfterNextRender(routerElement);
    assertFalse(
        !!routerElement.shadowRoot!.getElementById('wallpaperSelected'),
        'wallpaper-selected should not be displayed in freeform page');
  });

  test('supports transition animation', async () => {
    const routerElement = initElement(PersonalizationRouterElement);
    setTransitionsEnabled(true);
    await waitAfterNextRender(routerElement);

    // Forces transition to execute.
    await routerElement.goToRoute(Paths.COLLECTIONS);
    await waitAfterNextRender(routerElement);

    const wallpaperSubpage =
        routerElement.shadowRoot!.querySelector('wallpaper-subpage');
    assertTrue(!!wallpaperSubpage, 'wallpaper-subpage now exists');
  });
});