// Copyright 2024 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://compare/product_selection_menu.js';
import type {ProductSelectionMenuElement} from 'chrome://compare/product_selection_menu.js';
import {BrowserProxyImpl} from 'chrome://resources/cr_components/commerce/browser_proxy.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {stringToMojoUrl} from 'chrome://resources/js/mojo_type_util.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {TestMock} from 'chrome://webui-test/test_mock.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';
import {$$, assertNotStyle, assertStyle} from './test_support.js';
suite('ProductSelectionMenuTest', () => {
const shoppingServiceApi = TestMock.fromClass(BrowserProxyImpl);
async function createMenu(): Promise<ProductSelectionMenuElement> {
const menu = document.createElement('product-selection-menu');
menu.selectedUrl = 'https://current-selection.com';
document.body.appendChild(menu);
await flushTasks();
return menu;
}
function initUrlInfos() {
initProductTabUrlInfos();
initRecentlyViewedTabUrlInfos();
}
function initProductTabUrlInfos(productTabs = [{
title: 'title',
url: stringToMojoUrl('http://example.com'),
}]) {
shoppingServiceApi.setResultFor(
'getUrlInfosForProductTabs', Promise.resolve({urlInfos: productTabs}));
}
function initRecentlyViewedTabUrlInfos(
recentlyViewedTabs = [{
title: 'title2',
url: stringToMojoUrl('http://example2.com'),
}]) {
shoppingServiceApi.setResultFor(
'getUrlInfosForRecentlyViewedTabs',
Promise.resolve({urlInfos: recentlyViewedTabs}));
}
setup(async () => {
shoppingServiceApi.reset();
document.body.innerHTML = window.trustedTypes!.emptyHTML;
BrowserProxyImpl.setInstance(shoppingServiceApi);
loadTimeData.overrideValues({
suggestedTabs: 'suggestions',
recentlyViewedTabs: 'recently viewed tabs',
});
});
test('empty state shown', async () => {
initRecentlyViewedTabUrlInfos([]);
initProductTabUrlInfos([]);
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
assertEquals(0, menu.sections.length);
assertNotStyle($$(menu, '#empty')!, 'display', 'none');
assertFalse(!!$$(menu, '.section-title'));
});
test('Product tabs shown', async () => {
initRecentlyViewedTabUrlInfos([]);
const title = 'title';
const url = stringToMojoUrl('http://example.com');
const productTabs = [{
title: title,
url: url,
}];
initProductTabUrlInfos(productTabs);
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
assertStyle($$(menu, '#empty')!, 'display', 'none');
const sectionTitles = menu.shadowRoot!.querySelectorAll('.section-title');
assertEquals(1, sectionTitles.length);
assertEquals('suggestions', sectionTitles[0]!.textContent);
// Ensure the number of open tab list items is equal to the number of open
// tabs.
assertEquals(1, menu.sections.length);
const menuOpenTabEntries = menu.sections[0]!.entries;
assertEquals(productTabs.length, menuOpenTabEntries.length);
assertEquals(title, menuOpenTabEntries[0]!.title);
assertEquals(url.url, menuOpenTabEntries[0]!.url);
});
test('recently viewed tabs shown', async () => {
initProductTabUrlInfos([]);
const title = 'title2';
const url = stringToMojoUrl('http://example2.com');
const recentlyViewedTabs = [{
title: title,
url: url,
}];
initRecentlyViewedTabUrlInfos(recentlyViewedTabs);
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
assertStyle($$(menu, '#empty')!, 'display', 'none');
const sectionTitles = menu.shadowRoot!.querySelectorAll('.section-title');
assertEquals(1, sectionTitles.length);
assertEquals('recently viewed tabs', sectionTitles[0]!.textContent);
// Ensure the number of recently viewed list items is equal to the number
// of recently viewed tabs.
assertEquals(1, menu.sections.length);
const recentlyViewedTabEntries = menu.sections[0]!.entries;
assertEquals(recentlyViewedTabs.length, recentlyViewedTabEntries.length);
assertEquals(title, recentlyViewedTabEntries[0]!.title);
assertEquals(url.url, recentlyViewedTabEntries[0]!.url);
});
test('both open and recently viewed tabs shown', async () => {
const title1 = 'title1';
const url = stringToMojoUrl('http://example.com');
const productTabs = [{
title: title1,
url: url,
}];
initProductTabUrlInfos(productTabs);
const title2 = 'title2';
const recentlyViewedTabs = [{
title: title2,
url: url,
}];
initRecentlyViewedTabUrlInfos(recentlyViewedTabs);
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
assertStyle($$(menu, '#empty')!, 'display', 'none');
const sectionTitles = menu.shadowRoot!.querySelectorAll('.section-title');
assertEquals(2, sectionTitles.length);
assertEquals('suggestions', sectionTitles[0]!.textContent);
assertEquals('recently viewed tabs', sectionTitles[1]!.textContent);
assertEquals(2, menu.sections.length);
const menuOpenTabEntries = menu.sections[0]!.entries;
assertEquals(productTabs.length, menuOpenTabEntries.length);
assertEquals(title1, menuOpenTabEntries[0]!.title);
assertEquals(url.url, menuOpenTabEntries[0]!.url);
const recentlyViewedTabEntries = menu.sections[1]!.entries;
assertEquals(recentlyViewedTabs.length, recentlyViewedTabEntries.length);
assertEquals(title2, recentlyViewedTabEntries[0]!.title);
assertEquals(url.url, recentlyViewedTabEntries[0]!.url);
});
test('abbreviates URLs', async () => {
initUrlInfos();
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
const listElement =
menu.$.menu.get().querySelector<HTMLElement>('.dropdown-item');
assertTrue(!!listElement);
const tabUrl =
listElement.shadowRoot!.querySelector<HTMLElement>('.description-text');
assertTrue(!!tabUrl);
assertEquals('example.com', tabUrl.textContent);
});
test('excludes current selection', async () => {
initRecentlyViewedTabUrlInfos([]);
const titleString = 'title';
const productTabs = [
{
title: titleString,
url: stringToMojoUrl('https://example.com'),
},
{
title: titleString,
url: stringToMojoUrl('https://current-selection.com'),
},
];
initProductTabUrlInfos(productTabs);
const menu = await createMenu();
menu.selectedUrl = 'https://current-selection.com';
menu.showAt(document.body);
await flushTasks();
const listElements =
menu.$.menu.get().querySelectorAll<HTMLElement>('.dropdown-item');
assertEquals(2, listElements.length);
const tabUrl = listElements[0]!.shadowRoot!.querySelector<HTMLElement>(
'.description-text');
assertTrue(!!tabUrl);
assertEquals('example.com', tabUrl.textContent);
});
test('excludes excluded urls', async () => {
const titleString = 'title';
const excludedUrlString1 = 'https://excluded-url-1.com';
const excludedUrlString2 = 'https://excluded-url-2.com';
const recentlyViewedTabs = [
{
title: titleString,
url: stringToMojoUrl(excludedUrlString1),
},
];
initRecentlyViewedTabUrlInfos(recentlyViewedTabs);
const productTabs = [
{
title: titleString,
url: stringToMojoUrl('https://example.com'),
},
{
title: titleString,
url: stringToMojoUrl(excludedUrlString2),
},
];
initProductTabUrlInfos(productTabs);
const menu = await createMenu();
menu.excludedUrls = [excludedUrlString1, excludedUrlString2];
menu.showAt(document.body);
await flushTasks();
const listElements =
menu.$.menu.get().querySelectorAll<HTMLElement>('.dropdown-item');
assertEquals(2, listElements.length);
const tabUrl = listElements[0]!.shadowRoot!.querySelector<HTMLElement>(
'.description-text');
assertTrue(!!tabUrl);
assertEquals('example.com', tabUrl.textContent);
});
test('fires selector event', async () => {
initUrlInfos();
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
const crActionMenu = menu.$.menu.get();
assertTrue(crActionMenu.open);
const listElement =
crActionMenu.querySelector<HTMLElement>('.dropdown-item');
assertTrue(!!listElement);
const eventPromise = eventToPromise('selected-url-change', menu);
listElement.click();
const event = await eventPromise;
assertTrue(!!event);
assertEquals('http://example.com', event.detail.url);
assertFalse(crActionMenu.open);
});
test('fires removal event', async () => {
initUrlInfos();
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
const crActionMenu = menu.$.menu.get();
assertTrue(crActionMenu.open);
const removeButton = crActionMenu.querySelector<HTMLElement>('#remove');
assertTrue(!!removeButton);
const eventPromise = eventToPromise('remove-url', menu);
removeButton.click();
const event = await eventPromise;
assertTrue(!!event);
assertFalse(crActionMenu.open);
});
test('updates when infos change', async () => {
initRecentlyViewedTabUrlInfos([]);
initProductTabUrlInfos([]);
const menu = await createMenu();
menu.showAt(document.body);
await flushTasks();
assertFalse(!!$$(menu, '.section-title'));
const title = 'title';
const url = stringToMojoUrl('http://example.com');
const productTabs = [{
title: title,
url: url,
}];
initProductTabUrlInfos(productTabs);
menu.showAt(document.body);
await flushTasks();
const sectionTitles = menu.shadowRoot!.querySelectorAll('.section-title');
assertEquals(1, sectionTitles.length);
assertEquals('suggestions', sectionTitles[0]!.textContent);
const menuOpenTabEntries = menu.sections[0]!.entries;
assertEquals(productTabs.length, menuOpenTabEntries.length);
assertEquals(title, menuOpenTabEntries[0]!.title);
assertEquals(url.url, menuOpenTabEntries[0]!.url);
});
});