chromium/chrome/test/data/webui/new_tab_page/modules/v2/file_suggestion/module_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 {FileSuggestionHandlerRemote} from 'chrome://new-tab-page/file_suggestion.mojom-webui.js';
import type {DisableModuleEvent, DismissModuleEvent, FileSuggestionModuleElement} from 'chrome://new-tab-page/lazy_load.js';
import {FileProxy, fileSuggestionDescriptor} from 'chrome://new-tab-page/lazy_load.js';
import type {CrAutoImgElement} from 'chrome://new-tab-page/new_tab_page.js';
import {$$} from 'chrome://new-tab-page/new_tab_page.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import type {TestMock} from 'chrome://webui-test/test_mock.js';
import {eventToPromise, isVisible, microtasksFinished} from 'chrome://webui-test/test_util.js';

import {installMock} from '../../../test_support.js';

suite('FileSuggestionV2Module', () => {
  let handler: TestMock<FileSuggestionHandlerRemote>;

  setup(() => {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    handler = installMock(FileSuggestionHandlerRemote, FileProxy.setHandler);
  });

  test('shows all retrieved files on render', async () => {
    const data = {
      files: [
        {
          justificationText: 'Edited last week',
          title: 'Foo',
          id: '123',
          mimeType: 'application/vnd.google-apps.spreadsheet',
          itemUrl: {url: 'https://foo.com'},
        },
        {
          justificationText: 'Edited yesterday',
          title: 'Bar',
          id: '132',
          mimeType: 'application/vnd.google-apps.document',
          itemUrl: {url: 'https://bar.com'},
        },
        {
          justificationText: 'Created today',
          title: 'Baz',
          id: '213',
          mimeType: 'application/vnd.google-apps.presentation',
          itemUrl: {url: 'https://baz.com'},
        },
        {
          justificationText: 'Created yesterday',
          title: 'Qux',
          id: '231',
          mimeType: 'application/vnd.google-apps.presentation',
          itemUrl: {url: 'https://qux.com'},
        },
        {
          justificationText: 'Edited last week',
          title: 'FooBar',
          id: '312',
          mimeType: 'application/vnd.google-apps.spreadsheet',
          itemUrl: {url: 'https://foo.com'},
        },
        {
          justificationText: 'Edited yesterday',
          title: 'BazQux',
          id: '321',
          mimeType: 'application/vnd.google-apps.document',
          itemUrl: {url: 'https://bar.com'},
        },
      ],
    };
    handler.setResultFor('getFiles', Promise.resolve(data));

    const module =
        await fileSuggestionDescriptor.initialize(0) as FileSuggestionModuleElement;
    assertTrue(!!module);
    document.body.append(module);
    await handler.whenCalled('getFiles');
    await microtasksFinished();
    const items = Array.from(module.shadowRoot!.querySelectorAll('.file'));

    assertTrue(isVisible(module.$.files));
    assertEquals(6, items.length);
  });

  test('parses file data correctly', async () => {
    const data = {
      files: [
        {
          justificationText: 'Edited last week',
          title: 'Foo',
          id: '123',
          mimeType: 'application/vnd.google-apps.spreadsheet',
          itemUrl: {url: 'https://foo.com'},
        },
        {
          justificationText: 'Edited yesterday',
          title: 'Bar',
          id: '132',
          mimeType: 'application/vnd.google-apps.document',
          itemUrl: {url: 'https://bar.com'},
        },
      ],
    };
    handler.setResultFor('getFiles', Promise.resolve(data));

    const module =
        await fileSuggestionDescriptor.initialize(0) as FileSuggestionModuleElement;
    assertTrue(!!module);
    document.body.append(module);
    await handler.whenCalled('getFiles');
    await microtasksFinished();
    const items = Array.from(module.shadowRoot!.querySelectorAll('.file'));
    const urls =
        module.shadowRoot!.querySelectorAll<HTMLAnchorElement>('.file');

    assertTrue(isVisible(module.$.files));
    assertEquals(2, items.length);
    assertEquals(
        'Bar',
        items[1]!.querySelector<HTMLElement>('.file-title')!.textContent);
    assertEquals(
        'Edited yesterday',
        items[1]!.querySelector<HTMLElement>('.file-description')!.textContent);
    assertEquals(
        'https://drive-thirdparty.googleusercontent.com/32/type/application/vnd.google-apps.spreadsheet',
        items[0]!.querySelector<CrAutoImgElement>('.file-icon')!.autoSrc);
    assertEquals(
        'https://drive-thirdparty.googleusercontent.com/32/type/application/vnd.google-apps.document',
        items[1]!.querySelector<CrAutoImgElement>('.file-icon')!.autoSrc);
    assertEquals('https://foo.com/', urls[0]!.href);
    assertEquals('https://bar.com/', urls[1]!.href);
  });

  test('module does not render if there are no files', async () => {
    handler.setResultFor('getFiles', Promise.resolve({files: []}));

    const module = await fileSuggestionDescriptor.initialize(0);
    await handler.whenCalled('getFiles');
    assertFalse(!!module);
  });

  test('clicking the info button opens the ntp info dialog box', async () => {
    // Arrange.
    const data = {
      files: [
        {
          justificationText: 'Edited yesterday',
          title: 'Abc',
          id: '012',
          mimeType: 'application/vnd.google-apps.presentation',
          itemUrl: {url: 'https://abc.com'},
        },
      ],
    };
    handler.setResultFor('getFiles', Promise.resolve(data));
    const driveModule =
        await fileSuggestionDescriptor.initialize(0) as FileSuggestionModuleElement;
    assertTrue(!!driveModule);
    document.body.append(driveModule);
    await microtasksFinished();

    // Act.
    const infoButton = driveModule.$.moduleHeaderElementV2.shadowRoot!
                           .querySelector<HTMLElement>('#info');
    assertTrue(!!infoButton);
    infoButton.click();
    await microtasksFinished();

    // Assert.
    assertTrue(!!$$(driveModule, 'ntp-info-dialog'));
  });

  test(
      'clicking the disable button sets the correct toast message',
      async () => {
        // Arrange.
        const data = {
          files: [
            {
              justificationText: 'Edited yesterday',
              title: 'Abc',
              id: '012',
              mimeType: 'application/vnd.google-apps.presentation',
              itemUrl: {url: 'https://abc.com'},
            },
          ],
        };
        handler.setResultFor('getFiles', Promise.resolve(data));
        const driveModule =
            await fileSuggestionDescriptor.initialize(0) as FileSuggestionModuleElement;
        document.body.append(driveModule);
        await microtasksFinished();

        // Act.
        const whenFired = eventToPromise('disable-module', driveModule);
        const disableButton = driveModule.$.moduleHeaderElementV2.shadowRoot!
                                  .querySelector<HTMLElement>('#disable');
        assertTrue(!!disableButton);
        disableButton.click();

        // Assert.
        const event: DisableModuleEvent = await whenFired;
        assertEquals(
            'You won\'t see Drive files on this page again',
            event.detail.message);
      });

  test('backend is notified when module is dismissed or restored', async () => {
    // Arrange.
    const data = {
      files: [
        {
          justificationText: '',
          title: '',
          id: '',
          mimeType: '',
          itemUrl: {url: ''},
        },
      ],
    };
    handler.setResultFor('getFiles', Promise.resolve(data));
    const moduleElement =
        await fileSuggestionDescriptor.initialize(0) as FileSuggestionModuleElement;
    assertTrue(!!moduleElement);
    document.body.append(moduleElement);
    await microtasksFinished();

    // Act.
    const whenFired = eventToPromise('dismiss-module-instance', moduleElement);
    const dismissButton = moduleElement.$.moduleHeaderElementV2.shadowRoot!
                              .querySelector<HTMLElement>('#dismiss');
    assertTrue(!!dismissButton);
    dismissButton.click();

    // Assert.
    const event: DismissModuleEvent = await whenFired;
    assertEquals('Files hidden', event.detail.message);
    assertTrue(!!event.detail.restoreCallback);
    assertEquals(1, handler.getCallCount('dismissModule'));

    // Act.
    event.detail.restoreCallback!();

    // Assert.
    assertEquals(1, handler.getCallCount('restoreModule'));
  });
});