chromium/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_validation_gif_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 {EmojiGroupElement, EmojiPickerApiProxy, EmojiPickerApp, GIF_VALIDATION_DATE, TRENDING} from 'chrome://emoji-picker/emoji_picker.js';
import {assert} from 'chrome://resources/js/assert.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals} from 'chrome://webui-test/chai_assert.js';

import {assertEmojiImageAlt, initialiseEmojiPickerForTest, waitForCondition} from './emoji_picker_test_util.js';
import {TestEmojiPickerApiProxy} from './test_emoji_picker_api_proxy.js';

function historyGroupSelector(category: string) {
  return `[data-group="${category}-history"] > ` +
      `emoji-group[category="${category}"]`;
}

function subcategoryGroupSelector(category: string, subcategory: string) {
  return `[data-group="${subcategory}"] > ` +
      `emoji-group[category="${category}"]`;
}

suite(`emoji-picker-validation-gif`, () => {
  const oneByOneGif =
      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
  const oneByTwoGif =
      'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAQAAAAziH6sAAAADklEQVR42mNk+M/I8B8ABQoCAV5AcKEAAAAASUVORK5CYII=';

  // The name left of - is the position of the GIF initially.
  // The name right of - is the position of the GIF after history GIFs have
  // been validated.
  const historyGifs = {
    history: [
      {
        base: {
          visualContent: {
            id: '0',
            url: {
              full: {
                url: oneByTwoGif,
              },
              preview: {
                url: oneByTwoGif,
              },
            },
            previewSize: {width: 1, height: 2},
          },
          name: 'Left 1 - Invalid',
        },
        alternates: [],
      },
      {
        base: {
          visualContent: {
            id: '1',
            url: {
              full: {
                url: oneByOneGif,
              },
              preview: {
                url: oneByOneGif,
              },
            },
            previewSize: {width: 1, height: 1},
          },
          name: 'Right 1 - Left 1',
        },
        alternates: [],
      },
      {
        base: {
          visualContent: {
            id: '2',
            url: {
              full: {
                url: oneByTwoGif,
              },
              preview: {
                url: oneByTwoGif,
              },
            },
            previewSize: {width: 1, height: 2},
          },
          name: 'Right 2 - Right 1',
        },
        alternates: [],
      },
      {
        base: {
          visualContent: {
            id: 3,
            url: {
              full: {
                url: oneByTwoGif,
              },
              preview: {
                url: oneByTwoGif,
              },
            },
            previewSize: {width: 1, height: 2},
          },
          name: 'Left 2 - Invalid',
        },
        alternates: [],
      },
      {
        base: {
          visualContent: {
            id: '4',
            url: {
              full: {
                url: oneByTwoGif,
              },
              preview: {
                url: oneByTwoGif,
              },
            },
            previewSize: {width: 1, height: 2},
          },
          name: 'Right 3 - Left 2',
        },
        alternates: [],
      },
    ],
    preference: {},
  };

  EmojiPickerApiProxy.setInstance(new TestEmojiPickerApiProxy());

  let emojiPicker: EmojiPickerApp;
  let findInEmojiPicker: (...path: string[]) => HTMLElement | null;
  let waitUntilFindInEmojiPicker: (...path: string[]) => Promise<HTMLElement>;
  let scrollToBottom: () => void;
  const categoryList = ['emoji', 'symbol', 'emoticon', 'gif'];
  let categoryIndex: number;

  setup(async () => {
    const newPicker = initialiseEmojiPickerForTest(false, [
      {key: GIF_VALIDATION_DATE, value: new Date(0).toJSON()},
      {key: 'gif-recently-used', value: JSON.stringify(historyGifs)},
    ]);
    emojiPicker = newPicker.emojiPicker;
    findInEmojiPicker = newPicker.findInEmojiPicker;
    waitUntilFindInEmojiPicker = newPicker.waitUntilFindInEmojiPicker;
    const readyPromise = newPicker.readyPromise;
    scrollToBottom = newPicker.scrollToBottom;
    await readyPromise;

    categoryIndex = categoryList.indexOf('gif');
  });


  test(
      `recently used gif group should contain the ` +
          `correct gifs after it is has been validated.`,
      async () => {
        await emojiPicker.updateIncognitoState(false);

        // Whilst history originally had 5 GIFs, there should now only be 3
        // valid GIFs.
        const recentlyUsedEmoji = findInEmojiPicker(historyGroupSelector(
            'gif'))!.shadowRoot!.querySelectorAll('emoji-image');

        assertEquals(3, recentlyUsedEmoji.length);

        // Check display is correct and the correct GIFs have been deleted.
        const leftColResults =
            findInEmojiPicker(historyGroupSelector('gif'))!.shadowRoot!
                .querySelectorAll<HTMLImageElement>(
                    'div.left-column > emoji-image');
        assertEquals(leftColResults.length, 2);
        assertEmojiImageAlt(leftColResults[0], 'Right 1 - Left 1');
        assertEmojiImageAlt(leftColResults[1], 'Right 3 - Left 2');

        const rightColResults =
            findInEmojiPicker(historyGroupSelector('gif'))!.shadowRoot!
                .querySelectorAll<HTMLImageElement>(
                    'div.right-column > emoji-image');
        assertEquals(rightColResults.length, 1);
        assert(rightColResults[0], 'Right 2 - Right 1');
      });

  test(
      'Trending appends GIFs correctly via scrolling when' +
          ' recently used group exists',
      async () => {
        await emojiPicker.updateIncognitoState(false);

        const categoryButton =
            findInEmojiPicker('emoji-search')!.shadowRoot!
                .querySelectorAll('emoji-category-button')
                ?.[categoryIndex]!.shadowRoot!.querySelector('cr-icon-button')!;
        categoryButton.click();
        flush();

        const recentlyUsedEmoji =
            (await waitUntilFindInEmojiPicker(historyGroupSelector(
                'gif')))!.shadowRoot!.querySelectorAll('emoji-image');

        assertEquals(3, recentlyUsedEmoji.length);

        const trendingId =
            emojiPicker.categoriesGroupElements
                .find((group: EmojiGroupElement) => group.name === TRENDING)
                ?.groupId;

        // Scroll to Trending subcategory.
        emojiPicker.shadowRoot!
            .querySelector(`div[data-group="${trendingId}"]`)
            ?.scrollIntoView();

        await waitForCondition(
            () => emojiPicker.activeInfiniteGroupId === trendingId,
            'wait for new group to be active');

        const group = await waitUntilFindInEmojiPicker(subcategoryGroupSelector(
            'gif',
            emojiPicker.activeInfiniteGroupId!,
            ));

        const gifResults1 = group!.shadowRoot!.querySelectorAll('emoji-image');
        assertEquals(gifResults1.length, 6);

        // Check display is correct.
        const leftColResults1 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.left-column > emoji-image');
        assertEquals(leftColResults1.length, 3);
        assertEmojiImageAlt(leftColResults1[0], 'Trending Left 1');
        assertEmojiImageAlt(leftColResults1[1], 'Trending Left 2');
        assertEmojiImageAlt(leftColResults1[2], 'Trending Left 3');

        const rightColResults1 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.right-column > emoji-image');
        assertEquals(rightColResults1.length, 3);
        assertEmojiImageAlt(rightColResults1[0], 'Trending Right 1');
        assertEmojiImageAlt(rightColResults1[1], 'Trending Right 2');
        assertEmojiImageAlt(rightColResults1[2], 'Trending Right 3');

        scrollToBottom();

        await waitForCondition(
            () => group?.shadowRoot?.querySelectorAll('emoji-image').length ===
                12,
            'wait for emoji picker to scroll and render new Gifs');

        const gifResults2 = group!.shadowRoot!.querySelectorAll('emoji-image');
        assertEquals(gifResults2.length, 12);

        // Check display is correct.
        const leftColResults2 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.left-column > emoji-image');
        assertEquals(leftColResults2.length, 6);
        assertEmojiImageAlt(leftColResults2[0], 'Trending Left 1');
        assertEmojiImageAlt(leftColResults2[1], 'Trending Left 2');
        assertEmojiImageAlt(leftColResults2[2], 'Trending Left 3');
        assertEmojiImageAlt(leftColResults2[3], 'Trending Left 4');
        assertEmojiImageAlt(leftColResults2[4], 'Trending Left 5');
        assertEmojiImageAlt(leftColResults2[5], 'Trending Left 6');

        const rightColResults2 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.right-column > emoji-image');
        assertEquals(rightColResults2.length, 6);
        assertEmojiImageAlt(rightColResults2[0], 'Trending Right 1');
        assertEmojiImageAlt(rightColResults2[1], 'Trending Right 2');
        assertEmojiImageAlt(rightColResults2[2], 'Trending Right 3');
        assertEmojiImageAlt(rightColResults2[3], 'Trending Right 4');
        assertEmojiImageAlt(rightColResults2[4], 'Trending Right 5');
        assertEmojiImageAlt(rightColResults2[5], 'Trending Right 6');
      });

  test(
      'Trending appends GIFs correctly via selecting group' +
          ' when recently used group exists',
      async () => {
        await emojiPicker.updateIncognitoState(false);

        const categoryButton =
            findInEmojiPicker('emoji-search')!.shadowRoot!
                .querySelectorAll('emoji-category-button')
                ?.[categoryIndex]!.shadowRoot!.querySelector<HTMLElement>(
                    'cr-icon-button');
        categoryButton!.click();
        flush();

        const recentlyUsedEmoji =
            (await waitUntilFindInEmojiPicker(historyGroupSelector(
                'gif')))!.shadowRoot!.querySelectorAll('emoji-image');

        assertEquals(3, recentlyUsedEmoji.length);

        const trendingId =
            emojiPicker.categoriesGroupElements
                .find((group: EmojiGroupElement) => group.name === TRENDING)
                ?.groupId;

        const trendingSubcategoryButton = (await waitUntilFindInEmojiPicker(
            `#tabs text-group-button[data-group="${
                trendingId}"]`))!.shadowRoot!.querySelector('cr-button');

        trendingSubcategoryButton!.click();
        await flush();

        await waitForCondition(
            () => emojiPicker.activeInfiniteGroupId === trendingId,
            'wait for new group to be active');

        const group = await waitUntilFindInEmojiPicker(subcategoryGroupSelector(
            'gif',
            emojiPicker.activeInfiniteGroupId!,
            ));

        await waitForCondition(
            () =>
                group!.shadowRoot!.querySelectorAll('emoji-image').length === 6,
            'wait for trending GIFs');

        const gifResults1 = group!.shadowRoot!.querySelectorAll('emoji-image');
        assertEquals(gifResults1.length, 6);

        // Check display is correct.
        const leftColResults1 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.left-column > emoji-image');
        assertEquals(leftColResults1.length, 3);
        assertEmojiImageAlt(leftColResults1[0], 'Trending Left 1');
        assertEmojiImageAlt(leftColResults1[1], 'Trending Left 2');
        assertEmojiImageAlt(leftColResults1[2], 'Trending Left 3');

        const rightColResults1 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.right-column > emoji-image');
        assertEquals(rightColResults1.length, 3);
        assertEmojiImageAlt(rightColResults1[0], 'Trending Right 1');
        assertEmojiImageAlt(rightColResults1[1], 'Trending Right 2');
        assertEmojiImageAlt(rightColResults1[2], 'Trending Right 3');



        scrollToBottom();

        // Wait for Emoji Picker to scroll and render new GIFs.
        await waitForCondition(
            () => group!.shadowRoot!.querySelectorAll('emoji-image').length ===
                12,
            'failed to wait for new GIFs to render');

        const gifResults2 = group!.shadowRoot!.querySelectorAll('emoji-image');
        assertEquals(gifResults2.length, 12);

        // Check display is correct.
        const leftColResults2 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.left-column > emoji-image');
        assertEquals(leftColResults2.length, 6);
        assertEmojiImageAlt(leftColResults2[0], 'Trending Left 1');
        assertEmojiImageAlt(leftColResults2[1], 'Trending Left 2');
        assertEmojiImageAlt(leftColResults2[2], 'Trending Left 3');
        assertEmojiImageAlt(leftColResults2[3], 'Trending Left 4');
        assertEmojiImageAlt(leftColResults2[4], 'Trending Left 5');
        assertEmojiImageAlt(leftColResults2[5], 'Trending Left 6');

        const rightColResults2 =
            group!.shadowRoot!.querySelectorAll<HTMLImageElement>(
                'div.right-column > emoji-image');
        assertEquals(rightColResults2.length, 6);
        assertEmojiImageAlt(rightColResults2[0], 'Trending Right 1');
        assertEmojiImageAlt(rightColResults2[1], 'Trending Right 2');
        assertEmojiImageAlt(rightColResults2[2], 'Trending Right 3');
        assertEmojiImageAlt(rightColResults2[3], 'Trending Right 4');
        assertEmojiImageAlt(rightColResults2[4], 'Trending Right 5');
        assertEmojiImageAlt(rightColResults2[5], 'Trending Right 6');
      });
});