blob: 4185856a80c532d1d804290f0f55961517ce78b9 [file] [log] [blame]
// 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://shortcut-customization/js/shortcut_customization_app.js';
import 'chrome://webui-test/mojo_webui_test_support.js';
import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js';
import {CrDialogElement} from 'chrome://resources/cr_elements/cr_dialog/cr_dialog.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {AcceleratorEditViewElement} from 'chrome://shortcut-customization/js/accelerator_edit_view.js';
import {AcceleratorLookupManager} from 'chrome://shortcut-customization/js/accelerator_lookup_manager.js';
import {AcceleratorRowElement} from 'chrome://shortcut-customization/js/accelerator_row.js';
import {AcceleratorSubsectionElement} from 'chrome://shortcut-customization/js/accelerator_subsection.js';
import {AcceleratorViewElement} from 'chrome://shortcut-customization/js/accelerator_view.js';
import {fakeAcceleratorConfig, fakeLayoutInfo, fakeSearchResults} from 'chrome://shortcut-customization/js/fake_data.js';
import {FakeShortcutProvider} from 'chrome://shortcut-customization/js/fake_shortcut_provider.js';
import {setShortcutProviderForTesting, setUseFakeProviderForTesting} from 'chrome://shortcut-customization/js/mojo_interface_provider.js';
import {FakeShortcutSearchHandler} from 'chrome://shortcut-customization/js/search/fake_shortcut_search_handler.js';
import {setShortcutSearchHandlerForTesting} from 'chrome://shortcut-customization/js/search/shortcut_search_handler.js';
import {ShortcutCustomizationAppElement} from 'chrome://shortcut-customization/js/shortcut_customization_app.js';
import {AcceleratorCategory, AcceleratorConfig, AcceleratorConfigResult, AcceleratorSource, AcceleratorState, AcceleratorSubcategory, AcceleratorType, LayoutInfo, LayoutStyle, Modifier, MojoLayoutInfo, TextAcceleratorPartType} from 'chrome://shortcut-customization/js/shortcut_types.js';
import {getSubcategoryNameStringId} from 'chrome://shortcut-customization/js/shortcut_utils.js';
import {AcceleratorResultData} from 'chrome://shortcut-customization/mojom-webui/ash/webui/shortcut_customization_ui/mojom/shortcut_customization.mojom-webui.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks, waitAfterNextRender} from 'chrome://webui-test/polymer_test_util.js';
import {isVisible} from 'chrome://webui-test/test_util.js';
import {createUserAcceleratorInfo} from './shortcut_customization_test_util.js';
// Converts a JS string to mojo_base::mojom::String16 object.
function strToMojoString16(str: string): {data: number[]} {
const arr = [];
for (let i = 0; i < str.length; i++) {
arr[i] = str.charCodeAt(i);
}
return {data: arr};
}
function initShortcutCustomizationAppElement():
ShortcutCustomizationAppElement {
const element = document.createElement('shortcut-customization-app');
document.body.appendChild(element);
flush();
return element;
}
suite('shortcutCustomizationAppTest', function() {
let page: ShortcutCustomizationAppElement|null = null;
let manager: AcceleratorLookupManager|null = null;
let provider: FakeShortcutProvider;
let handler: FakeShortcutSearchHandler;
const jellyDisabledCssUrl =
'chrome://resources/chromeos/colors/cros_styles.css';
let linkEl: HTMLLinkElement|null = null;
setup(() => {
manager = AcceleratorLookupManager.getInstance();
// Set up provider.
setUseFakeProviderForTesting(true);
provider = new FakeShortcutProvider();
provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
provider.setFakeAcceleratorLayoutInfos(fakeLayoutInfo);
provider.setFakeHasLauncherButton(true);
setShortcutProviderForTesting(provider);
// Set up SearchHandler.
handler = new FakeShortcutSearchHandler();
handler.setFakeSearchResult(fakeSearchResults);
setShortcutSearchHandlerForTesting(handler);
// Setup link element for dynamic/jelly color tests.
linkEl = document.createElement('link');
linkEl.href = jellyDisabledCssUrl;
document.head.appendChild(linkEl);
});
teardown(() => {
provider.reset();
if (manager) {
manager.reset();
}
if (page) {
page.remove();
}
page = null;
if (linkEl) {
document.head.removeChild(linkEl);
}
linkEl = null;
});
function getManager(): AcceleratorLookupManager {
assertTrue(!!manager);
return manager as AcceleratorLookupManager;
}
function getPage(): ShortcutCustomizationAppElement {
assertTrue(!!page);
return page as ShortcutCustomizationAppElement;
}
function getDialog(selector: string) {
return getPage().shadowRoot!.querySelector(selector) as CrDialogElement;
}
function getSubsections(category: AcceleratorCategory):
NodeListOf<AcceleratorSubsectionElement> {
const navPanel =
getPage().shadowRoot!.querySelector('navigation-view-panel');
const navBody = navPanel!!.shadowRoot!.querySelector('#navigationBody');
const subPageId = `category-${category}`;
const subPage = navBody!.querySelector(`#${subPageId}`);
assertTrue(!!subPage, `Expected subpage with id ${subPageId} to exist.`);
return subPage!.shadowRoot!.querySelectorAll('accelerator-subsection');
}
function getLinkEl(): HTMLLinkElement {
assertTrue(!!linkEl);
return linkEl as HTMLLinkElement;
}
async function openDialogForAcceleratorInSubsection(subsectionIndex: number) {
// The edit dialog should not be stamped and visible.
const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertFalse(!!editDialog);
const subSections = getSubsections(AcceleratorCategory.kWindowsAndDesks);
const accelerators =
subSections[subsectionIndex]!.shadowRoot!.querySelectorAll(
'accelerator-row') as NodeListOf<AcceleratorRowElement>;
// Click on the first accelerator, expect the edit dialog to open.
accelerators[0]!.click();
await flushTasks();
}
function triggerOnAcceleratorUpdated(): Promise<void> {
provider.triggerOnAcceleratorUpdated();
return flushTasks();
}
test('LoadFakeWindowsAndDesksPage', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
const actualSubsections =
getSubsections(AcceleratorCategory.kWindowsAndDesks);
const expectedLayouts =
getManager().getSubcategories(AcceleratorCategory.kWindowsAndDesks);
// Two subsections for this category based on the data in fake_data.ts.
assertEquals(expectedLayouts!.size, actualSubsections!.length);
const keyIterator = expectedLayouts!.keys();
// Assert subsection title matches expected value from fake lookup.
const expectedFirstSubcat: AcceleratorSubcategory =
keyIterator.next().value;
assertEquals(
page.i18n(getSubcategoryNameStringId(expectedFirstSubcat)),
actualSubsections[0]!.title);
// Asert 2 accelerators are loaded for first subcategory.
assertEquals(
(expectedLayouts!.get(expectedFirstSubcat) as LayoutInfo[]).length,
actualSubsections[0]!.accelRowDataArray!.length);
// Assert subsection title matches expected value from fake lookup.
const expectedSecondSubcat: AcceleratorSubcategory =
keyIterator.next().value;
assertEquals(
page.i18n(getSubcategoryNameStringId(expectedSecondSubcat)),
actualSubsections[1]!.title);
// Assert 2 accelerators are loaded for the second subcategory.
assertEquals(
(expectedLayouts!.get(expectedSecondSubcat) as LayoutInfo[]).length,
actualSubsections[1]!.accelRowDataArray!.length);
});
test('LoadFakeBrowserPage', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
const navPanel =
getPage().shadowRoot!.querySelector('navigation-view-panel');
const navSelector =
navPanel!.shadowRoot!.querySelector('#navigationSelector')!
.querySelector('navigation-selector');
const navMenuItems =
navSelector!.shadowRoot!.querySelector('#navigationSelectorMenu')!
.querySelectorAll('.navigation-item') as NodeListOf<HTMLDivElement>;
navMenuItems[1]!.click();
await flushTasks();
const actualSubsections = getSubsections(AcceleratorCategory.kBrowser);
const expectedLayouts =
getManager().getSubcategories(AcceleratorCategory.kBrowser);
assertEquals(expectedLayouts!.size, actualSubsections!.length);
const keyIterator = expectedLayouts!.keys().next();
// Assert subsection names match name lookup.
assertEquals(
page.i18n(getSubcategoryNameStringId(keyIterator.value)),
actualSubsections[0]!.title);
// Assert only 1 accelerator is within this subsection.
assertEquals(
(expectedLayouts!.get(keyIterator.value) as LayoutInfo[]).length,
actualSubsections[0]!.accelRowDataArray.length);
});
test('OpenDialogFromAccelerator', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
// The edit dialog should not be stamped and visible.
let editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertFalse(!!editDialog);
const subSections = getSubsections(AcceleratorCategory.kWindowsAndDesks);
const accelerators =
subSections[0]!.shadowRoot!.querySelectorAll('accelerator-row');
// Only three accelerators rows for this subsection.
assertEquals(3, accelerators.length);
// Click on the first accelerator, expect the edit dialog to open.
accelerators[0]!.click();
await flushTasks();
editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertTrue(!!editDialog);
});
test('DialogOpensOnEvent', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
// The edit dialog should not be stamped and visible.
let editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertFalse(!!editDialog);
const nav = getPage().shadowRoot!.querySelector('navigation-view-panel');
const acceleratorInfo = createUserAcceleratorInfo(
Modifier.SHIFT,
/*key=*/ 67,
/*keyDisplay=*/ 'c');
// Simulate the trigger event to display the dialog.
nav!.dispatchEvent(new CustomEvent('show-edit-dialog', {
bubbles: true,
composed: true,
detail: {description: 'test', accelerators: [acceleratorInfo]},
}));
await flushTasks();
// Requery dialog.
editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertTrue(!!editDialog);
// Close the dialog.
const dialog =
editDialog!.shadowRoot!.querySelector('#editDialog') as CrDialogElement;
dialog.close();
await flushTasks();
assertFalse(dialog.open);
});
test('ReplaceAccelerator', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
// Open dialog for first accelerator in second subsection.
await openDialogForAcceleratorInSubsection(1);
const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertTrue(!!editDialog);
// Grab the first accelerator from the second subsection.
const editView =
editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
'accelerator-edit-view')[0] as AcceleratorEditViewElement;
// Click on edit button.
(editView!.shadowRoot!.querySelector('#editButton') as CrButtonElement)
.click();
await flushTasks();
const accelViewElement =
editView.shadowRoot!.querySelector('#acceleratorItem');
// Assert no error has occurred prior to pressing a shortcut.
assertFalse(editView.hasError);
// Set the fake mojo return call.
const fakeResult: AcceleratorResultData = {
result: AcceleratorConfigResult.kConflictCanOverride,
shortcutName: strToMojoString16('TestConflictName'),
};
provider.setFakeReplaceAcceleratorResult(fakeResult);
// Alt + ']' is a conflict, expect the error message to appear.
accelViewElement!.dispatchEvent(new KeyboardEvent('keydown', {
key: ']',
keyCode: 221,
code: 'Key]',
ctrlKey: false,
altKey: true,
shiftKey: false,
metaKey: false,
}));
await flushTasks();
assertTrue(editView.hasError);
const fakeResult2: AcceleratorResultData = {
result: AcceleratorConfigResult.kSuccess,
shortcutName: undefined,
};
provider.setFakeReplaceAcceleratorResult(fakeResult2);
// Press the shortcut again, this time it will replace the preexsting
// accelerator.
accelViewElement!.dispatchEvent(new KeyboardEvent('keydown', {
key: ']',
keyCode: 221,
code: 'Key]',
ctrlKey: false,
altKey: true,
shiftKey: false,
metaKey: false,
}));
await flushTasks();
const updatedEditView =
editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
'accelerator-edit-view')[0] as AcceleratorEditViewElement;
assertFalse(updatedEditView.hasError);
});
test('AddAccelerator', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
// Open dialog for first accelerator in second subsection.
await openDialogForAcceleratorInSubsection(1);
const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertTrue(!!editDialog);
// Grab the first accelerator from second subsection.
const dialogAccels =
editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
'accelerator-edit-view');
// Expect only 1 accelerator initially.
assertEquals(1, dialogAccels!.length);
// Click on add button.
(editDialog!.shadowRoot!.querySelector('#addAcceleratorButton') as
CrButtonElement)
.click();
await flushTasks();
const editElement =
editDialog!.shadowRoot!.querySelector('#pendingAccelerator') as
AcceleratorEditViewElement;
// Assert no error has occurred prior to pressing a shortcut.
assertFalse(editElement.hasError);
const viewElement =
editElement!.shadowRoot!.querySelector('#acceleratorItem');
// Set the fake mojo return call.
const fakeResult: AcceleratorResultData = {
result: AcceleratorConfigResult.kConflictCanOverride,
shortcutName: strToMojoString16('TestConflictName'),
};
provider.setFakeAddAcceleratorResult(fakeResult);
// Dispatch an add event, this should fail as it has a failure state.
viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
key: ']',
keyCode: 221,
code: 'Key]',
ctrlKey: false,
altKey: true,
shiftKey: false,
metaKey: false,
}));
await flushTasks();
assertTrue(editElement.hasError);
const expected_error_message =
'Shortcut is used by TestConflictName. Press a new shortcut or press ' +
'the same one again to use it for this action instead.';
assertEquals(
expected_error_message,
editElement!.shadowRoot!.querySelector('#acceleratorInfoText')!
.textContent!.trim());
// Press the shortcut again, this time with another error state.
const fakeResult2: AcceleratorResultData = {
result: AcceleratorConfigResult.kConflict,
shortcutName: strToMojoString16('TestConflictName'),
};
provider.setFakeAddAcceleratorResult(fakeResult2);
viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
key: ']',
keyCode: 221,
code: 'Key]',
ctrlKey: false,
altKey: true,
shiftKey: false,
metaKey: false,
}));
await flushTasks();
const expected_error_message2 =
'Shortcut is used by TestConflictName. Press a new shortcut to ' +
'replace.';
assertEquals(
expected_error_message2,
editElement!.shadowRoot!.querySelector('#acceleratorInfoText')!
.textContent!.trim());
assertTrue(editElement.hasError);
// Press the shortcut again, this time with another success state.
const fakeResult3: AcceleratorResultData = {
result: AcceleratorConfigResult.kSuccess,
shortcutName: undefined,
};
provider.setFakeAddAcceleratorResult(fakeResult3);
viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
key: ']',
keyCode: 221,
code: 'Key]',
ctrlKey: false,
altKey: true,
shiftKey: false,
metaKey: false,
}));
await flushTasks();
assertFalse(editElement.hasError);
});
test('AddAcceleratorMaximumAccelerators', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
// Open dialog for first accelerator in second subsection.
await openDialogForAcceleratorInSubsection(1);
const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
assertTrue(!!editDialog);
// Grab the first accelerator from second subsection.
const dialogAccels =
editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
'accelerator-edit-view');
// Expect only 1 accelerator initially.
assertEquals(1, dialogAccels!.length);
// Click on add button.
(editDialog!.shadowRoot!.querySelector('#addAcceleratorButton') as
CrButtonElement)
.click();
await flushTasks();
const editElement =
editDialog!.shadowRoot!.querySelector('#pendingAccelerator') as
AcceleratorEditViewElement;
// Assert no error has occurred prior to pressing a shortcut.
assertFalse(editElement.hasError);
const viewElement =
editElement!.shadowRoot!.querySelector('#acceleratorItem');
// Set the fake mojo return call.
const fakeResult: AcceleratorResultData = {
result: AcceleratorConfigResult.kMaximumAcceleratorsReached,
shortcutName: undefined,
};
provider.setFakeAddAcceleratorResult(fakeResult);
// Dispatch an add event, this should fail as it has a failure state.
viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
key: ']',
keyCode: 221,
code: 'Key]',
ctrlKey: false,
altKey: true,
shiftKey: false,
metaKey: false,
}));
await flushTasks();
assertTrue(editElement.hasError);
});
test('DisableDefaultAccelerator', async () => {
page = initShortcutCustomizationAppElement();
await flushTasks();
// Open dialog for first accelerator in second subsection.
await openDialogForAcceleratorInSubsection(1);
const editDialog = getDialog('#editDialog');
assertTrue(!!editDialog);
// Grab the first accelerator from second subsection.
let acceleratorList =
editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
'accelerator-edit-view');
assertEquals(1, acceleratorList!.length);
const editView = acceleratorList[0] as AcceleratorEditViewElement;
// Click on remove button.
const deleteButton =
editView!.shadowRoot!.querySelector('#deleteButton') as CrButtonElement;
deleteButton.click();
await flushTasks();
// Requery the accelerator elements.
acceleratorList =
editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
'accelerator-edit-view');
// Expect that the accelerator has now been disabled but not removed.
acceleratorList =
editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
'accelerator-edit-view');
assertEquals(1, acceleratorList!.length);
const accelViewElement =
acceleratorList[0]!.shadowRoot!.querySelector('#acceleratorItem');
const acceleratorInfo =
(accelViewElement as AcceleratorViewElement).acceleratorInfo;
assertEquals(AcceleratorState.kDisabledByUser, acceleratorInfo.state);
});
test('RestoreAllButton', async () => {
loadTimeData.overrideValues({isCustomizationEnabled: true});
page = initShortcutCustomizationAppElement();
await flushTasks();
let restoreDialog = getDialog('#restoreDialog');
// Expect the dialog to not appear initially.
assertFalse(!!restoreDialog);
// Click on the Restore all button.
const restoreButton = getPage().shadowRoot!.querySelector(
'#restoreAllButton') as CrButtonElement;
restoreButton!.click();
await flushTasks();
// Requery the dialog.
restoreDialog = getDialog('#restoreDialog');
assertTrue(restoreDialog!.open);
const confirmButton =
restoreDialog!.querySelector('#confirmButton') as CrButtonElement;
confirmButton.click();
await flushTasks();
// Confirm dialog is now closed.
restoreDialog = getDialog('#restoreDialog');
assertFalse(!!restoreDialog);
// Re-open the Restore All dialog.
restoreButton!.click();
await flushTasks();
restoreDialog = getDialog('#restoreDialog');
assertTrue(restoreDialog!.open);
// Click on Cancel button.
const cancelButton =
restoreDialog!.querySelector('#cancelButton') as CrButtonElement;
cancelButton.click();
await flushTasks();
restoreDialog = getDialog('#restoreDialog');
assertFalse(!!restoreDialog);
});
test('RestoreAllButtonShownWithFlag', async () => {
loadTimeData.overrideValues({isCustomizationEnabled: true});
page = initShortcutCustomizationAppElement();
waitAfterNextRender(getPage());
await flushTasks();
const restoreButton = getPage().shadowRoot!.querySelector(
'#restoreAllButton') as CrButtonElement;
await flushTasks();
assertTrue(isVisible(restoreButton));
});
test('RestoreAllButtonHiddenWithoutFlag', async () => {
loadTimeData.overrideValues({isCustomizationEnabled: false});
page = initShortcutCustomizationAppElement();
waitAfterNextRender(getPage());
await flushTasks();
const restoreButton = getPage().shadowRoot!.querySelector(
'#restoreAllButton') as CrButtonElement;
await flushTasks();
assertFalse(isVisible(restoreButton));
});
test('CurrentPageChangesWhenURLIsUpdated', async () => {
loadTimeData.overrideValues({isCustomizationEnabled: false});
page = initShortcutCustomizationAppElement();
waitAfterNextRender(getPage());
await flushTasks();
// At first, the selected page should be the first page.
// For the fake data, Windows & Desks is the first page.
assertEquals(
`category-${AcceleratorCategory.kWindowsAndDesks}`,
page.$.navigationPanel.selectedItem.id);
// Notify the app that the route has changed, and the selected page should
// change too.
let url = new URL('chrome://shortcut-customization');
url.searchParams.append('action', '0');
url.searchParams.append(
'category', AcceleratorCategory.kBrowser.toString());
page.onRouteChanged(url);
await flushTasks();
assertEquals(
`category-${AcceleratorCategory.kBrowser}`,
page.$.navigationPanel.selectedItem.id);
// If we notify with a URL that doesn't contain the correct params, the
// selected page should not change.
url = new URL('chrome://shortcut-customization');
page.onRouteChanged(url);
await flushTasks();
assertEquals(
`category-${AcceleratorCategory.kBrowser}`,
page.$.navigationPanel.selectedItem.id);
// If we notify with a URL that contains extra params, the selected page
// should change.
url = new URL('chrome://shortcut-customization');
url.searchParams.append('action', '0');
url.searchParams.append(
'category', AcceleratorCategory.kWindowsAndDesks.toString());
url.searchParams.append('fake-param', 'fake-value');
page.onRouteChanged(url);
await flushTasks();
assertEquals(
`category-${AcceleratorCategory.kWindowsAndDesks}`,
page.$.navigationPanel.selectedItem.id);
});
test('IsJellyEnabledForShortcutCustomization_DisabledKeepsCSS', async () => {
loadTimeData.overrideValues({
isJellyEnabledForShortcutCustomization: false,
});
page = initShortcutCustomizationAppElement();
await flushTasks();
assertTrue(getLinkEl().href.includes(jellyDisabledCssUrl));
});
test('IsJellyEnabledForShortcutCustomization_EnabledUpdatesCSS', async () => {
loadTimeData.overrideValues({
isJellyEnabledForShortcutCustomization: true,
});
page = initShortcutCustomizationAppElement();
await flushTasks();
assertTrue(getLinkEl().href.includes('chrome://theme/colors.css'));
});
test('TextAcceleratorLookupUpdatesCorrectly', async () => {
// Set up test to only have one shortcut.
const testLayoutInfo: MojoLayoutInfo[] = [
{
category: AcceleratorCategory.kWindowsAndDesks,
subCategory: AcceleratorSubcategory.kWindows,
description: strToMojoString16('Go to windows 1 through 8'),
style: LayoutStyle.kText,
source: AcceleratorSource.kAmbient,
action: 1,
},
];
provider.setFakeAcceleratorLayoutInfos(testLayoutInfo);
page = initShortcutCustomizationAppElement();
waitAfterNextRender(getPage());
await flushTasks();
// This config is constructed to match the generated mojo type for an
// accelerator configuration. `layoutProperties` is an union type, so
// we do not have an undefined `standardAccelerator`.
const testAcceleratorConfig: AcceleratorConfig = {
[AcceleratorSource.kAmbient]: {
[1]: [{
type: AcceleratorType.kDefault,
state: AcceleratorState.kEnabled,
locked: true,
layoutProperties: {
textAccelerator: {
parts: [
{
text: strToMojoString16('ctrl'),
type: TextAcceleratorPartType.kModifier,
},
{
text: strToMojoString16(' + '),
type: TextAcceleratorPartType.kDelimiter,
},
{
text: strToMojoString16('1 '),
type: TextAcceleratorPartType.kKey,
},
{
text: strToMojoString16('through '),
type: TextAcceleratorPartType.kPlainText,
},
{
text: strToMojoString16('8'),
type: TextAcceleratorPartType.kKey,
},
],
},
},
}],
},
};
// Cycle tabs accelerator from kAmbient[1].
const expectedCycleTabsAction = 1;
let textLookup = getManager().getTextAcceleratorInfos(
AcceleratorSource.kAmbient, expectedCycleTabsAction);
assertEquals(1, textLookup.length);
// Now simulate an update.
provider.setFakeAcceleratorsUpdated([testAcceleratorConfig]);
provider.setFakeHasLauncherButton(true);
await triggerOnAcceleratorUpdated();
await provider.getAcceleratorsUpdatedPromiseForTesting();
// After a call to `onAcceleratorsUpdated` we should still expect to have
// one text accelerator.
textLookup = getManager().getTextAcceleratorInfos(
AcceleratorSource.kAmbient, expectedCycleTabsAction);
assertEquals(1, textLookup.length);
});
test('LaunchOldKeyboardSettings', async () => {
loadTimeData.overrideValues({
isInputDeviceSettingsSplitEnabled: false,
});
page = initShortcutCustomizationAppElement();
await flushTasks();
const actualLink =
getPage()
.shadowRoot!.querySelector('#keyboardSettingsLinkContainer')!
.querySelector('#keyboardSettingsLink') as HTMLLinkElement;
assertEquals('chrome://os-settings/keyboard-overlay', actualLink.href);
});
test('LaunchNewKeyboardSettings', async () => {
loadTimeData.overrideValues({
isInputDeviceSettingsSplitEnabled: true,
});
page = initShortcutCustomizationAppElement();
await flushTasks();
const actualLink =
getPage()
.shadowRoot!.querySelector('#keyboardSettingsLinkContainer')!
.querySelector('#keyboardSettingsLink') as HTMLLinkElement;
assertEquals('chrome://os-settings/per-device-keyboard', actualLink.href);
});
});