shortcuts: Migrate tests to TS Part 3

Bug: b/242549183
Test: browser_tests --gtest_filter=ShortcutCustomizationApp*
Change-Id: I89b265a4167431a113202a533b2e423771d71298
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3861196
Commit-Queue: Michael Checo <michaelcheco@google.com>
Reviewed-by: Jimmy Gong <jimmyxgong@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1041878}
diff --git a/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts b/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts
index c45d088..8a57887 100644
--- a/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts
+++ b/ash/webui/shortcut_customization_ui/resources/accelerator_view.ts
@@ -472,4 +472,10 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'accelerator-view': AcceleratorViewElement;
+  }
+}
+
 customElements.define(AcceleratorViewElement.is, AcceleratorViewElement);
diff --git a/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts b/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts
index b2b0c17..69a62e8 100644
--- a/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts
+++ b/ash/webui/shortcut_customization_ui/resources/shortcut_customization_app.ts
@@ -200,5 +200,11 @@
   }
 }
 
+declare global {
+  interface HTMLElementTagNameMap {
+    'shortcut-customization-app': ShortcutCustomizationAppElement;
+  }
+}
+
 customElements.define(
     ShortcutCustomizationAppElement.is, ShortcutCustomizationAppElement);
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn b/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
index 9bb1a201..50ce7f3 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/BUILD.gn
@@ -23,11 +23,11 @@
     "accelerator_edit_view_test.ts",
     "accelerator_lookup_manager_test.ts",
     "accelerator_row_test.ts",
-    "accelerator_subsection_test.js",
-    "accelerator_view_test.js",
-    "fake_shortcut_provider_test.js",
-    "shortcut_customization_test.js",
-    "shortcut_customization_test_util.js",
+    "accelerator_subsection_test.ts",
+    "accelerator_view_test.ts",
+    "fake_shortcut_provider_test.ts",
+    "shortcut_customization_test.ts",
+    "shortcut_customization_test_util.ts",
   ]
   deps = [ "//ash/webui/shortcut_customization_ui/resources:build_ts" ]
   extra_deps = [ "../..:generate_definitions" ]
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.ts
index 03997a3..af0f1fb 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.ts
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_edit_dialog_test.ts
@@ -33,12 +33,12 @@
     const acceleratorInfo1: AcceleratorInfo = createUserAccelerator(
         Modifier.CONTROL | Modifier.SHIFT,
         /*key=*/ 71,
-        /*key_display=*/ 'g');
+        /*keyDisplay=*/ 'g');
 
     const acceleratorInfo2: AcceleratorInfo = createUserAccelerator(
         Modifier.CONTROL,
         /*key=*/ 67,
-        /*key_display=*/ 'c');
+        /*keyDisplay=*/ 'c');
 
     const accelerators = [acceleratorInfo1, acceleratorInfo2];
 
@@ -92,12 +92,12 @@
     const acceleratorInfo1: AcceleratorInfo = createUserAccelerator(
         Modifier.CONTROL | Modifier.SHIFT,
         /*key=*/ 71,
-        /*key_display=*/ 'g');
+        /*keyDisplay=*/ 'g');
 
     const acceleratorInfo2: AcceleratorInfo = createUserAccelerator(
         Modifier.CONTROL | Modifier.SHIFT,
         /*key=*/ 67,
-        /*key_display=*/ 'c');
+        /*keyDisplay=*/ 'c');
 
     const acceleratorInfos = [acceleratorInfo1, acceleratorInfo2];
     const description = 'test shortcut';
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.ts
similarity index 64%
rename from chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.js
rename to chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.ts
index 4288035..797010c 100644
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.js
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_subsection_test.ts
@@ -9,45 +9,42 @@
 import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
 import {AcceleratorSubsectionElement} from 'chrome://shortcut-customization/accelerator_subsection.js';
 import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
 import {assertEquals} from 'chrome://webui-test/chai_assert.js';
 import {flushTasks} from 'chrome://webui-test/test_util.js';
 
 import {createUserAccelerator} from './shortcut_customization_test_util.js';
 
 suite('acceleratorSubsectionTest', function() {
-  /** @type {?AcceleratorSubsectionElement} */
-  let sectionElement = null;
+  let sectionElement: AcceleratorSubsectionElement|null = null;
 
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
+  let manager: AcceleratorLookupManager|null = null;
 
   setup(() => {
     manager = AcceleratorLookupManager.getInstance();
-    manager.setAcceleratorLookup(fakeAcceleratorConfig);
-    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
+    manager!.setAcceleratorLookup(fakeAcceleratorConfig);
+    manager!.setAcceleratorLayoutLookup(fakeLayoutInfo);
 
-    sectionElement = /** @type {!AcceleratorSubsectionElement} */ (
-        document.createElement('accelerator-subsection'));
+    sectionElement = document.createElement('accelerator-subsection');
     document.body.appendChild(sectionElement);
   });
 
   teardown(() => {
-    manager.reset();
-    sectionElement.remove();
+    if (manager) {
+      manager!.reset();
+    }
+    sectionElement!.remove();
     sectionElement = null;
   });
 
   // TODO(jimmyxgong): Update this test after retrieving accelerators is
   // implemented for a subsection.
   test('LoadsBasicSection', async () => {
-    /** @type {!AcceleratorInfo} */
     const acceleratorInfo1 = createUserAccelerator(
         Modifier.CONTROL | Modifier.SHIFT,
         /*key=*/ 71,
         /*keyDisplay=*/ 'g');
 
-    /** @type {!AcceleratorInfo} */
     const acceleratorInfo2 = createUserAccelerator(
         Modifier.CONTROL | Modifier.SHIFT,
         /*key=*/ 67,
@@ -57,36 +54,39 @@
     const description = 'test shortcut';
     const title = 'test title';
 
-    sectionElement.title = title;
-    sectionElement.acceleratorContainer = [{
+    sectionElement!.title = title;
+    sectionElement!.acceleratorContainer = [{
       description: description,
       acceleratorInfos: accelerators,
+      source: AcceleratorSource.ASH,
+      action: 0,
     }];
 
     await flush();
     assertEquals(
         title,
-        sectionElement.shadowRoot.querySelector('#title').textContent.trim());
+        sectionElement!.shadowRoot!.querySelector(
+                                       '#title')!.textContent!.trim());
   });
 
   test('LoadCategoryAndConfirmDescriptions', async () => {
     const expectedTitle = 'test title';
-    sectionElement.title = expectedTitle;
-    sectionElement.category = /*Chromeos*/ 0;
-    sectionElement.subcategory = /*Window Management*/ 0;
+    sectionElement!.title = expectedTitle;
+    sectionElement!.category = /*Chromeos*/ 0;
+    sectionElement!.subcategory = /*Window Management*/ 0;
 
     await flushTasks();
 
     const rowListElement =
-        sectionElement.shadowRoot.querySelectorAll('accelerator-row');
+        sectionElement!.shadowRoot!.querySelectorAll('accelerator-row');
 
     // First accelerator-row corresponds to 'Snap Window Left'.
     assertEquals(
-        manager.getAcceleratorName(/*source=*/ 0, /*action=*/ 0),
-        rowListElement[0].description);
+        manager!.getAcceleratorName(/*source=*/ 0, /*action=*/ 0)!,
+        rowListElement[0]!.description);
     // Second accelerator-row corresponds to 'Snap Window Right'.
     assertEquals(
-        manager.getAcceleratorName(/*source=*/ 0, /*action=*/ 1),
-        rowListElement[1].description);
+        manager!.getAcceleratorName(/*source=*/ 0, /*action=*/ 1)!,
+        rowListElement[1]!.description);
   });
 });
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.js
deleted file mode 100644
index 9c537d88..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.js
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://shortcut-customization/accelerator_view.js';
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
-import {AcceleratorViewElement, ViewState} from 'chrome://shortcut-customization/accelerator_view.js';
-import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {AcceleratorSource, AcceleratorState, AcceleratorType, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
-
-import {createDefaultAccelerator, createUserAccelerator} from './shortcut_customization_test_util.js';
-
-suite('acceleratorViewTest', function() {
-  /** @type {?AcceleratorViewElement} */
-  let viewElement = null;
-
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
-
-  setup(() => {
-    manager = AcceleratorLookupManager.getInstance();
-    manager.setAcceleratorLookup(fakeAcceleratorConfig);
-    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
-
-    viewElement = /** @type {!AcceleratorViewElement} */ (
-        document.createElement('accelerator-view'));
-    document.body.appendChild(viewElement);
-  });
-
-  teardown(() => {
-    manager.reset();
-
-    viewElement.remove();
-    viewElement = null;
-  });
-
-  test('LoadsBasicAccelerator', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createUserAccelerator(
-        Modifier.CONTROL | Modifier.SHIFT,
-        /*key=*/ 71,
-        /*keyDisplay=*/ 'g');
-
-
-    viewElement.acceleratorInfo = acceleratorInfo;
-    await flush();
-    const keys = viewElement.shadowRoot.querySelectorAll('input-key');
-    // Three keys: shift, control, g
-    assertEquals(3, keys.length);
-
-    assertEquals(
-        'shift', keys[0].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'ctrl', keys[1].shadowRoot.querySelector('#key').textContent.trim());
-    assertEquals(
-        'g', keys[2].shadowRoot.querySelector('#key').textContent.trim());
-  });
-
-  test('EditableAccelerator', async () => {
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createDefaultAccelerator(
-        Modifier.ALT,
-        /*key=*/ 221,
-        /*keyDisplay=*/ ']');
-
-    viewElement.acceleratorInfo = acceleratorInfo;
-    viewElement.source = AcceleratorSource.ASH;
-    viewElement.action = 1;
-    await flush();
-    // Enable the edit view.
-    viewElement.viewState = ViewState.EDIT;
-
-    await flush();
-
-    const ctrlKey = viewElement.shadowRoot.querySelector('#ctrlKey');
-    const altKey = viewElement.shadowRoot.querySelector('#altKey');
-    const shiftKey = viewElement.shadowRoot.querySelector('#shiftKey');
-    const metaKey = viewElement.shadowRoot.querySelector('#searchKey');
-    const pendingKey = viewElement.shadowRoot.querySelector('#pendingKey');
-
-    // By default, no keys should be registered.
-    assertEquals('not-selected', ctrlKey.keyState);
-    assertEquals('not-selected', altKey.keyState);
-    assertEquals('not-selected', shiftKey.keyState);
-    assertEquals('not-selected', metaKey.keyState);
-    assertEquals('not-selected', pendingKey.keyState);
-    assertEquals('key', pendingKey.key);
-
-    // Simulate Ctrl + Alt + e.
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: 'e',
-      keyCode: '69',
-      code: 'KeyE',
-      ctrlKey: true,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flush();
-
-    assertEquals('modifier-selected', ctrlKey.keyState);
-    assertEquals('modifier-selected', altKey.keyState);
-    assertEquals('not-selected', shiftKey.keyState);
-    assertEquals('not-selected', metaKey.keyState);
-    assertEquals('alpha-numeric-selected', pendingKey.keyState);
-    assertEquals('e', pendingKey.key);
-  });
-});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts
new file mode 100644
index 0000000..a8bf1b2
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/accelerator_view_test.ts
@@ -0,0 +1,119 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://shortcut-customization/accelerator_view.js';
+import 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
+import {AcceleratorViewElement, ViewState} from 'chrome://shortcut-customization/accelerator_view.js';
+import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
+import {InputKeyElement, KeyInputState} from 'chrome://shortcut-customization/input_key.js';
+import {AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+import {createDefaultAccelerator, createUserAccelerator} from './shortcut_customization_test_util.js';
+
+suite('acceleratorViewTest', function() {
+  let viewElement: AcceleratorViewElement|null = null;
+
+  let manager: AcceleratorLookupManager|null = null;
+
+  setup(() => {
+    manager = AcceleratorLookupManager.getInstance();
+    manager.setAcceleratorLookup(fakeAcceleratorConfig);
+    manager.setAcceleratorLayoutLookup(fakeLayoutInfo);
+
+    viewElement = document.createElement('accelerator-view');
+    document.body.appendChild(viewElement);
+  });
+
+  teardown(() => {
+    if (manager) {
+      manager.reset();
+    }
+
+    viewElement!.remove();
+    viewElement = null;
+  });
+
+  function getInputKey(selector: string): InputKeyElement {
+    const element = viewElement!.shadowRoot!.querySelector(selector);
+    assertTrue(!!element);
+    return element as InputKeyElement;
+  }
+
+  test('LoadsBasicAccelerator', async () => {
+    const acceleratorInfo = createUserAccelerator(
+        Modifier.CONTROL | Modifier.SHIFT,
+        /*key=*/ 71,
+        /*keyDisplay=*/ 'g');
+
+
+    viewElement!.acceleratorInfo = acceleratorInfo;
+    await flush();
+    const keys = viewElement!.shadowRoot!.querySelectorAll('input-key');
+    // Three keys: shift, control, g
+    assertEquals(3, keys.length);
+
+    assertEquals(
+        'shift',
+        keys[0]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'ctrl',
+        keys[1]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+    assertEquals(
+        'g', keys[2]!.shadowRoot!.querySelector('#key')!.textContent!.trim());
+  });
+
+  test('EditableAccelerator', async () => {
+    const acceleratorInfo = createDefaultAccelerator(
+        Modifier.ALT,
+        /*key=*/ 221,
+        /*keyDisplay=*/ ']');
+
+    viewElement!.acceleratorInfo = acceleratorInfo;
+    viewElement!.source = AcceleratorSource.ASH;
+    viewElement!.action = 1;
+    await flush();
+    // Enable the edit view.
+    viewElement!.viewState = ViewState.EDIT;
+
+    await flush();
+
+    const ctrlKey = getInputKey('#ctrlKey');
+    const altKey = getInputKey('#altKey');
+    const shiftKey = getInputKey('#shiftKey');
+    const metaKey = getInputKey('#searchKey');
+    const pendingKey = getInputKey('#pendingKey');
+
+    // By default, no keys should be registered.
+    assertEquals(KeyInputState.NOT_SELECTED, ctrlKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, altKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, shiftKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, metaKey.keyState);
+    assertEquals(KeyInputState.NOT_SELECTED, pendingKey.keyState);
+    assertEquals('key', pendingKey.key);
+
+    // Simulate Ctrl + Alt + e.
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: 'e',
+      keyCode: 69,
+      code: 'KeyE',
+      ctrlKey: true,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flush();
+
+    assertEquals('modifier-selected', ctrlKey.keyState);
+    assertEquals('modifier-selected', altKey.keyState);
+    assertEquals('not-selected', shiftKey.keyState);
+    assertEquals('not-selected', metaKey.keyState);
+    assertEquals('alpha-numeric-selected', pendingKey.keyState);
+    assertEquals('e', pendingKey.key);
+  });
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.js
deleted file mode 100644
index 0d83aea..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.js
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
-import {FakeShortcutProvider} from 'chrome://shortcut-customization/fake_shortcut_provider.js';
-import {AcceleratorConfigResult, AcceleratorSource, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-
-suite('fakeShortcutProviderTest', function() {
-  /** @type {?FakeShortcutProvider} */
-  let provider = null;
-
-  setup(() => {
-    provider = new FakeShortcutProvider();
-  });
-
-  teardown(() => {
-    provider = null;
-  });
-
-  test('GetAllAcceleratorConfigEmpty', () => {
-    /** @type {!AcceleratorConfig} */
-    const expected = new Map();
-    provider.setFakeAcceleratorConfig(expected);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(expected, result);
-    });
-  });
-
-  test('GetAllAcceleratorConfigDefaultFake', () => {
-    // TODO(zentaro): Remove this test once real data is ready.
-    const expected = new Map();
-    provider.setFakeAcceleratorConfig(fakeAcceleratorConfig);
-    return provider.getAllAcceleratorConfig().then((result) => {
-      assertDeepEquals(fakeAcceleratorConfig, result);
-    });
-  });
-
-  test('GetLayoutInfoEmpty', () => {
-    /** @type {!LayoutInfoList} */
-    const expected = [];
-    provider.setFakeLayoutInfo(expected);
-    return provider.getLayoutInfo().then((result) => {
-      assertDeepEquals(expected, result);
-    });
-  });
-
-  test('GetLayoutInfoDefaultFake', () => {
-    // TODO(zentaro): Remove this test once real data is ready.
-    provider.setFakeLayoutInfo(fakeLayoutInfo);
-    return provider.getLayoutInfo().then((result) => {
-      assertDeepEquals(fakeLayoutInfo, result);
-    });
-  });
-
-  test('IsMutableDefaultFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    // AcceleratorSource.ASH is a mutable source.
-    return provider.isMutable(AcceleratorSource.ASH).then((result) => {
-      assertTrue(result);
-      // AcceleratorSource.BROWSER is not a mutable source
-      return provider.isMutable(AcceleratorSource.BROWSER).then((result) => {
-        assertFalse(result);
-      });
-    });
-  });
-
-  test('AddUserAcceleratorFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    const acceleratorKeys = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 79,
-      keyDisplay: 'o',
-    });
-    return provider
-        .addUserAccelerator(
-            AcceleratorSource.ASH, /**action=*/ 0, acceleratorKeys)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-
-  test('ReplaceAcceleratorFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    const oldAcceleratorKeys = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 79,
-      keyDisplay: 'o',
-    });
-
-    const newAcceleratorKeys = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 80,
-      keyDisplay: 'p',
-    });
-
-    return provider
-        .replaceAccelerator(
-            AcceleratorSource.ASH, /**action=*/ 0, oldAcceleratorKeys,
-            newAcceleratorKeys)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-
-  test('RemoveAcceleratorFake', () => {
-    // TODO(jimmyxgong): Remove this test once real data is ready.
-    const accel = /** @type {!AcceleratorKeys} */ ({
-      modifiers: Modifier.SHIFT,
-      key: 79,
-      keyDisplay: 'o',
-    });
-
-    return provider
-        .removeAccelerator(AcceleratorSource.ASH, /**action=*/ 0, accel)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-
-  test('RestoreAllDefaultsFake', () => {
-    return provider.restoreAllDefaults().then((result) => {
-      assertEquals(AcceleratorConfigResult.SUCCESS, result);
-    });
-  });
-
-  test('RestoreActionDefaultsFake', () => {
-    return provider.restoreActionDefaults(AcceleratorSource.ASH, 0)
-        .then((result) => {
-          assertEquals(AcceleratorConfigResult.SUCCESS, result);
-        });
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
new file mode 100644
index 0000000..d2b98cb
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/fake_shortcut_provider_test.ts
@@ -0,0 +1,105 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://webui-test/mojo_webui_test_support.js';
+
+import {fakeAcceleratorConfig, fakeLayoutInfo} from 'chrome://shortcut-customization/fake_data.js';
+import {FakeShortcutProvider} from 'chrome://shortcut-customization/fake_shortcut_provider.js';
+import {AcceleratorConfigResult, AcceleratorSource, LayoutInfoList} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+
+suite('fakeShortcutProviderTest', function() {
+  let provider: FakeShortcutProvider|null = null;
+
+  setup(() => {
+    provider = new FakeShortcutProvider();
+  });
+
+  teardown(() => {
+    provider = null;
+  });
+
+  function getProvider(): FakeShortcutProvider {
+    assertTrue(!!provider);
+    return provider as FakeShortcutProvider;
+  }
+  test('GetAllAcceleratorConfigEmpty', () => {
+    const expected = new Map();
+    getProvider().setFakeAcceleratorConfig(expected);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(expected, result);
+    });
+  });
+
+  test('GetAllAcceleratorConfigDefaultFake', () => {
+    // TODO(zentaro): Remove this test once real data is ready.
+    getProvider().setFakeAcceleratorConfig(fakeAcceleratorConfig);
+    return getProvider().getAllAcceleratorConfig().then((result) => {
+      assertDeepEquals(fakeAcceleratorConfig, result);
+    });
+  });
+
+  test('GetLayoutInfoEmpty', () => {
+    const expected: LayoutInfoList = [];
+    getProvider().setFakeLayoutInfo(expected);
+    return getProvider().getLayoutInfo().then((result) => {
+      assertDeepEquals(expected, result);
+    });
+  });
+
+  test('GetLayoutInfoDefaultFake', () => {
+    // TODO(zentaro): Remove this test once real data is ready.
+    getProvider().setFakeLayoutInfo(fakeLayoutInfo);
+    return getProvider().getLayoutInfo().then((result) => {
+      assertDeepEquals(fakeLayoutInfo, result);
+    });
+  });
+
+  test('IsMutableDefaultFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    // AcceleratorSource.ASH is a mutable source.
+    return getProvider().isMutable(AcceleratorSource.ASH).then((result) => {
+      assertTrue(result);
+      // AcceleratorSource.BROWSER is not a mutable source
+      return getProvider()
+          .isMutable(AcceleratorSource.BROWSER)
+          .then((result) => {
+            assertFalse(result);
+          });
+    });
+  });
+
+  test('AddUserAcceleratorFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    return getProvider().addUserAccelerator().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('ReplaceAcceleratorFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    return getProvider().replaceAccelerator().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('RemoveAcceleratorFake', () => {
+    // TODO(jimmyxgong): Remove this test once real data is ready.
+    return getProvider().removeAccelerator().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('RestoreAllDefaultsFake', () => {
+    return getProvider().restoreAllDefaults().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+
+  test('RestoreActionDefaultsFake', () => {
+    return getProvider().restoreActionDefaults().then((result) => {
+      assertEquals(AcceleratorConfigResult.SUCCESS, result);
+    });
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.js b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.js
deleted file mode 100644
index bb93cc36..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.js
+++ /dev/null
@@ -1,371 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://shortcut-customization/shortcut_customization_app.js';
-import 'chrome://webui-test/mojo_webui_test_support.js';
-
-import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
-import {AcceleratorSubsectionElement} from 'chrome://shortcut-customization/accelerator_subsection.js';
-import {fakeAcceleratorConfig, fakeLayoutInfo, fakeSubCategories} from 'chrome://shortcut-customization/fake_data.js';
-import {getShortcutProvider, setShortcutProviderForTesting} from 'chrome://shortcut-customization/mojo_interface_provider.js';
-import {ShortcutCustomizationAppElement} from 'chrome://shortcut-customization/shortcut_customization_app.js';
-import {Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
-import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
-import {flushTasks} from 'chrome://webui-test/test_util.js';
-
-import {createUserAccelerator} from './shortcut_customization_test_util.js';
-
-suite('shortcutCustomizationAppTest', function() {
-  /** @type {?ShortcutCustomizationAppElement} */
-  let page = null;
-
-  /** @type {?AcceleratorLookupManager} */
-  let manager = null;
-
-  setup(() => {
-    manager = AcceleratorLookupManager.getInstance();
-
-    page = /** @type {!ShortcutCustomizationAppElement} */ (
-        document.createElement('shortcut-customization-app'));
-    document.body.appendChild(page);
-  });
-
-  teardown(() => {
-    manager.reset();
-    page.remove();
-    page = null;
-  });
-
-  /**
-   * @param {string} subpageId
-   * @return {!Array<!AcceleratorSubsectionElement>}
-   */
-  function getSubsections(subpageId) {
-    const navPanel = page.shadowRoot.querySelector('navigation-view-panel');
-    const navBody = navPanel.shadowRoot.querySelector('#navigationBody');
-    const subPage = navBody.querySelector(`#${subpageId}`);
-    return subPage.shadowRoot.querySelectorAll('accelerator-subsection');
-  }
-
-  /**
-   * @param {number} subsectionIndex
-   */
-  async function openDialogForAcceleratorInSubsection(subsectionIndex) {
-    // The edit dialog should not be stamped and visible.
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertFalse(!!editDialog);
-
-    const subSections = getSubsections('chromeos-page-id');
-    const accelerators =
-        subSections[subsectionIndex].shadowRoot.querySelectorAll(
-            'accelerator-row');
-
-    // Click on the first accelerator, expect the edit dialog to open.
-    accelerators[0].click();
-    await flushTasks();
-  }
-
-  test('LoadFakeChromeOSPage', async () => {
-    await flushTasks();
-
-    const subSections = getSubsections('chromeos-page-id');
-    const expectedLayouts = manager.getSubcategories(/**ChromeOS*/ 0);
-    // Two subsections for ChromeOS (Window Management + Virtual Desks).
-    assertEquals(expectedLayouts.size, subSections.length);
-
-    const keyIterator = expectedLayouts.keys();
-    // Assert subsection title (Window management) matches expected value from
-    // fake lookup.
-    const windowManagementValue = keyIterator.next().value;
-    assertEquals(
-        fakeSubCategories.get(windowManagementValue), subSections[0].title);
-    // Asert 2 accelerators are loaded for Window Management.
-    assertEquals(
-        expectedLayouts.get(windowManagementValue).length,
-        subSections[0].acceleratorContainer.length);
-
-    // Assert subsection title (Virtual Desks) matches expected value from
-    // fake lookup.
-    const virtualDesksValue = keyIterator.next().value;
-    assertEquals(
-        fakeSubCategories.get(virtualDesksValue), subSections[1].title);
-    // Asert 2 accelerators are loaded for Virtual Desks.
-    assertEquals(
-        expectedLayouts.get(virtualDesksValue).length,
-        subSections[1].acceleratorContainer.length);
-  });
-
-  test('LoadFakeBrowserPage', async () => {
-    await flushTasks();
-
-    const navPanel = page.shadowRoot.querySelector('navigation-view-panel');
-    const navSelector = navPanel.shadowRoot.querySelector('#navigationSelector')
-                            .querySelector('navigation-selector');
-    const navMenuItems =
-        navSelector.shadowRoot.querySelector('#navigationSelectorMenu')
-            .querySelectorAll('.navigation-item');
-    // Index[1] represents the Browser subpage.
-    navMenuItems[1].click();
-
-    await flushTasks();
-
-    const subSections = getSubsections('browser-page-id');
-    const expectedLayouts = manager.getSubcategories(/**Browser*/ 1);
-    // One subsection for the Browser (Tabs).
-    assertEquals(expectedLayouts.size, subSections.length);
-
-    const keyIterator = expectedLayouts.keys().next();
-    // Assert subsection names match name lookup (Tabs).
-    assertEquals(
-        fakeSubCategories.get(keyIterator.value), subSections[0].title);
-    // Assert only 1 accelerator is within Tabs.
-    assertEquals(
-        expectedLayouts.get(keyIterator.value).length,
-        subSections[0].acceleratorContainer.length);
-  });
-
-  test('OpenDialogFromAccelerator', async () => {
-    await flushTasks();
-
-    // The edit dialog should not be stamped and visible.
-    let editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertFalse(!!editDialog);
-
-    const subSections = getSubsections('chromeos-page-id');
-    const accelerators =
-        subSections[0].shadowRoot.querySelectorAll('accelerator-row');
-    // Only two accelerators rows for "Window Management".
-    assertEquals(2, accelerators.length);
-    // Click on the first accelerator, expect the edit dialog to open.
-    accelerators[0].click();
-    await flushTasks();
-    editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-  });
-
-  test('DialogOpensOnEvent', async () => {
-    await flushTasks();
-
-    // The edit dialog should not be stamped and visible.
-    let editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertFalse(!!editDialog);
-
-    const nav = page.shadowRoot.querySelector('navigation-view-panel');
-
-    /** @type {!AcceleratorInfo} */
-    const acceleratorInfo = createUserAccelerator(
-        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: /**@type {!Object}*/ (
-          {description: 'test', accelerators: [acceleratorInfo]}),
-    }));
-    await flushTasks();
-
-    // Requery dialog.
-    editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Close the dialog.
-    const dialog = editDialog.shadowRoot.querySelector('#editDialog');
-    dialog.close();
-    await flushTasks();
-
-    assertFalse(dialog.open);
-  });
-
-  test('ReplaceAccelerator', async () => {
-    await flushTasks();
-
-    // Open dialog for first accelerator in View Desk subsection.
-    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Grab the first accelerator from Virtual Desks subsection.
-    let editView = editDialog.shadowRoot.querySelector('cr-dialog')
-                       .querySelectorAll('accelerator-edit-view')[0];
-
-    // Click on edit button.
-    editView.shadowRoot.querySelector('#editButton').click();
-
-    await flushTasks();
-
-    let accelViewElement =
-        editView.shadowRoot.querySelector('#acceleratorItem');
-
-    // Assert no error has occurred prior to pressing a shortcut.
-    assertFalse(editView.hasError);
-
-    // 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);
-
-    // 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();
-
-    // Requery the view element.
-    editView = editDialog.shadowRoot.querySelector('cr-dialog')
-                   .querySelectorAll('accelerator-edit-view')[0];
-    accelViewElement = editView.shadowRoot.querySelector('#acceleratorItem');
-
-    // Assert that the accelerator was updated with the new shortcut (Alt + ']')
-    const actualAccelerator = accelViewElement.acceleratorInfo.accelerator;
-    assertEquals(Modifier.ALT, actualAccelerator.modifiers);
-    assertEquals(221, actualAccelerator.key);
-    assertEquals(']', actualAccelerator.keyDisplay);
-  });
-
-  test('AddAccelerator', async () => {
-    await flushTasks();
-
-    // Open dialog for first accelerator in View Desk subsection.
-    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Grab the first accelerator from Virtual Desks subsection.
-    let 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').click();
-
-    await flushTasks();
-
-    const editElement =
-        editDialog.shadowRoot.querySelector('#pendingAccelerator');
-
-    // Assert no error has occurred prior to pressing a shortcut.
-    assertFalse(editElement.hasError);
-
-    const viewElement =
-        editElement.shadowRoot.querySelector('#acceleratorItem');
-
-    // Alt + ']' is a conflict, expect the error message to appear.
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: ']',
-      keyCode: '221',
-      code: 'Key]',
-      ctrlKey: false,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-
-    assertTrue(editElement.hasError);
-
-    // Press the shortcut again, this time it will add and remove the preexsting
-    // accelerator.
-    viewElement.dispatchEvent(new KeyboardEvent('keydown', {
-      key: ']',
-      keyCode: '221',
-      code: 'Key]',
-      ctrlKey: false,
-      altKey: true,
-      shiftKey: false,
-      metaKey: false,
-    }));
-
-    await flushTasks();
-
-    // Requery all accelerators.
-    dialogAccels = editDialog.shadowRoot.querySelector('cr-dialog')
-                       .querySelectorAll('accelerator-edit-view');
-    // Expect 2 accelerators now.
-    assertEquals(2, dialogAccels.length);
-    const newAccel = dialogAccels[1];
-
-    const actualAccelerator =
-        newAccel.shadowRoot.querySelector('#acceleratorItem')
-            .acceleratorInfo.accelerator;
-    assertEquals(Modifier.ALT, actualAccelerator.modifiers);
-    assertEquals(221, actualAccelerator.key);
-    assertEquals(']', actualAccelerator.keyDisplay);
-  });
-
-  test('RemoveAccelerator', async () => {
-    await flushTasks();
-
-    // Open dialog for first accelerator in View Desk subsection.
-    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
-    const editDialog = page.shadowRoot.querySelector('#editDialog');
-    assertTrue(!!editDialog);
-
-    // Grab the first accelerator from Virtual Desks subsection.
-    let acceleratorList = editDialog.shadowRoot.querySelector('cr-dialog')
-                              .querySelectorAll('accelerator-edit-view');
-    assertEquals(1, acceleratorList.length);
-    const editView = acceleratorList[0];
-
-    // Click on remove button.
-    editView.shadowRoot.querySelector('#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 removed.
-    assertEquals(0, acceleratorList.length);
-  });
-
-  test('RestoreAllButton', async () => {
-    await flushTasks();
-
-    let restoreDialog = page.shadowRoot.querySelector('#restoreDialog');
-    // Expect the dialog to not appear initially.
-    assertFalse(!!restoreDialog);
-
-    // Click on the Restore all button.
-    const restoreButton = page.shadowRoot.querySelector('#restoreAllButton');
-    restoreButton.click();
-
-    await flushTasks();
-
-    // Requery the dialog.
-    restoreDialog = page.shadowRoot.querySelector('#restoreDialog');
-    assertTrue(restoreDialog.open);
-
-    // Click on Cancel button.
-    restoreDialog.querySelector('#cancelButton').click();
-
-    await flushTasks();
-
-    restoreDialog = page.shadowRoot.querySelector('#restoreDialog');
-    assertFalse(!!restoreDialog);
-  });
-});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
new file mode 100644
index 0000000..773db64
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test.ts
@@ -0,0 +1,406 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://shortcut-customization/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 {AcceleratorEditViewElement} from 'chrome://shortcut-customization/accelerator_edit_view.js';
+import {AcceleratorLookupManager} from 'chrome://shortcut-customization/accelerator_lookup_manager.js';
+import {AcceleratorRowElement} from 'chrome://shortcut-customization/accelerator_row.js';
+import {AcceleratorSubsectionElement} from 'chrome://shortcut-customization/accelerator_subsection.js';
+import {AcceleratorViewElement} from 'chrome://shortcut-customization/accelerator_view.js';
+import {fakeSubCategories} from 'chrome://shortcut-customization/fake_data.js';
+import {ShortcutCustomizationAppElement} from 'chrome://shortcut-customization/shortcut_customization_app.js';
+import {AcceleratorInfo, AcceleratorKeys, LayoutInfoList, Modifier} from 'chrome://shortcut-customization/shortcut_types.js';
+import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
+import {flushTasks} from 'chrome://webui-test/test_util.js';
+
+import {createUserAccelerator} from './shortcut_customization_test_util.js';
+
+suite('shortcutCustomizationAppTest', function() {
+  let page: ShortcutCustomizationAppElement|null = null;
+
+  let manager: AcceleratorLookupManager|null = null;
+
+  setup(() => {
+    manager = AcceleratorLookupManager.getInstance();
+
+    page = document.createElement('shortcut-customization-app');
+    document.body.appendChild(page);
+  });
+
+  teardown(() => {
+    if (manager) {
+      manager.reset();
+    }
+    if (page) {
+      page.remove();
+    }
+    page = 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(subpageId: string):
+      NodeListOf<AcceleratorSubsectionElement> {
+    const navPanel =
+        getPage().shadowRoot!.querySelector('navigation-view-panel');
+    const navBody = navPanel!!.shadowRoot!.querySelector('#navigationBody');
+    const subPage = navBody!.querySelector(`#${subpageId}`);
+    return subPage!.shadowRoot!.querySelectorAll('accelerator-subsection');
+  }
+
+  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('chromeos-page-id');
+    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();
+  }
+
+  test('LoadFakeChromeOSPage', async () => {
+    await flushTasks();
+
+    const subSections = getSubsections('chromeos-page-id');
+    const expectedLayouts = getManager().getSubcategories(/**ChromeOS*/ 0);
+    // Two subsections for ChromeOS (Window Management + Virtual Desks).
+    assertEquals(expectedLayouts!.size, subSections!.length);
+
+    const keyIterator = expectedLayouts!.keys();
+    // Assert subsection title (Window management) matches expected value from
+    // fake lookup.
+    const windowManagementValue = keyIterator.next().value;
+    assertEquals(
+        (fakeSubCategories.get(windowManagementValue) as string),
+        subSections[0]!.title);
+    // Asert 2 accelerators are loaded for Window Management.
+    assertEquals(
+        (expectedLayouts!.get(windowManagementValue) as LayoutInfoList).length,
+        subSections[0]!.acceleratorContainer!.length);
+
+    // Assert subsection title (Virtual Desks) matches expected value from
+    // fake lookup.
+    const virtualDesksValue = keyIterator.next().value;
+    assertEquals(
+        fakeSubCategories.get(virtualDesksValue), subSections[1]!.title);
+    // Asert 2 accelerators are loaded for Virtual Desks.
+    assertEquals(
+        (expectedLayouts!.get(virtualDesksValue) as LayoutInfoList).length,
+        subSections[1]!.acceleratorContainer!.length);
+  });
+
+  test('LoadFakeBrowserPage', async () => {
+    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>;
+    // Index[1] represents the Browser subgetPage().
+    navMenuItems[1]!.click();
+
+    await flushTasks();
+
+    const subSections = getSubsections('browser-page-id');
+    const expectedLayouts = getManager().getSubcategories(/**Browser*/ 1);
+    // One subsection for the Browser (Tabs).
+    assertEquals(expectedLayouts!.size, subSections!.length);
+
+    const keyIterator = expectedLayouts!.keys().next();
+    // Assert subsection names match name lookup (Tabs).
+    assertEquals(
+        fakeSubCategories.get(keyIterator.value), subSections[0]!.title);
+    // Assert only 1 accelerator is within Tabs.
+    assertEquals(
+        (expectedLayouts!.get(keyIterator.value) as LayoutInfoList).length,
+        subSections[0]!.acceleratorContainer.length);
+  });
+
+  test('OpenDialogFromAccelerator', async () => {
+    await flushTasks();
+
+    // The edit dialog should not be stamped and visible.
+    let editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertFalse(!!editDialog);
+
+    const subSections = getSubsections('chromeos-page-id');
+    const accelerators =
+        subSections[0]!.shadowRoot!.querySelectorAll('accelerator-row');
+    // Only two accelerators rows for "Window Management".
+    assertEquals(2, 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 () => {
+    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 = createUserAccelerator(
+        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 () => {
+    await flushTasks();
+
+    // Open dialog for first accelerator in View Desk subsection.
+    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
+    const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertTrue(!!editDialog);
+
+    // Grab the first accelerator from Virtual Desks subsection.
+    let 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();
+
+    let accelViewElement =
+        editView.shadowRoot!.querySelector('#acceleratorItem');
+
+    // Assert no error has occurred prior to pressing a shortcut.
+    assertFalse(editView.hasError);
+
+    // 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);
+
+    // 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();
+
+    // Requery the view element.
+    editView =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view')[0] as AcceleratorEditViewElement;
+    accelViewElement = editView.shadowRoot!.querySelector('#acceleratorItem');
+
+    // Assert that the accelerator was updated with the new shortcut (Alt + ']')
+    const acceleratorInfo =
+        (accelViewElement as AcceleratorViewElement).acceleratorInfo as
+        AcceleratorInfo;
+    const actualAccelerator = acceleratorInfo.accelerator as AcceleratorKeys;
+    assertEquals(Modifier.ALT, actualAccelerator!.modifiers);
+    assertEquals(221, actualAccelerator!.key);
+    assertEquals(']', actualAccelerator!.keyDisplay);
+  });
+
+  test('AddAccelerator', async () => {
+    await flushTasks();
+
+    // Open dialog for first accelerator in View Desk subsection.
+    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
+    const editDialog = getPage().shadowRoot!.querySelector('#editDialog');
+    assertTrue(!!editDialog);
+
+    // Grab the first accelerator from Virtual Desks subsection.
+    let 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');
+
+    // Alt + ']' is a conflict, expect the error message to appear.
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: ']',
+      keyCode: 221,
+      code: 'Key]',
+      ctrlKey: false,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+
+    assertTrue(editElement.hasError);
+
+    // Press the shortcut again, this time it will add and remove the preexsting
+    // accelerator.
+    viewElement!.dispatchEvent(new KeyboardEvent('keydown', {
+      key: ']',
+      keyCode: 221,
+      code: 'Key]',
+      ctrlKey: false,
+      altKey: true,
+      shiftKey: false,
+      metaKey: false,
+    }));
+
+    await flushTasks();
+
+    // Requery all accelerators.
+    dialogAccels =
+        editDialog!.shadowRoot!.querySelector('cr-dialog')!.querySelectorAll(
+            'accelerator-edit-view');
+    // Expect 2 accelerators now.
+    assertEquals(2, dialogAccels!.length);
+    const newAccel = dialogAccels[1];
+
+    const actualAccelerator =
+        (newAccel!.shadowRoot!.querySelector('#acceleratorItem') as
+         AcceleratorViewElement)
+            .acceleratorInfo!.accelerator;
+    assertEquals(Modifier.ALT, actualAccelerator!.modifiers);
+    assertEquals(221, actualAccelerator!.key);
+    assertEquals(']', actualAccelerator!.keyDisplay);
+  });
+
+  test('RemoveAccelerator', async () => {
+    await flushTasks();
+
+    // Open dialog for first accelerator in View Desk subsection.
+    await openDialogForAcceleratorInSubsection(/*View Desk*/ 1);
+    const editDialog = getDialog('#editDialog');
+    assertTrue(!!editDialog);
+
+    // Grab the first accelerator from Virtual Desks 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 removed.
+    assertEquals(0, acceleratorList!.length);
+  });
+
+  test('RestoreAllButton', async () => {
+    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);
+
+    // Click on Cancel button.
+    const cancelButton =
+        restoreDialog!.querySelector('#cancelButton') as CrButtonElement;
+    cancelButton.click();
+
+    await flushTasks();
+
+    restoreDialog = getDialog('#restoreDialog');
+    assertFalse(!!restoreDialog);
+  });
+});
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.js b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.js
deleted file mode 100644
index 41219014..0000000
--- a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.js
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {AcceleratorState, AcceleratorType} from 'chrome://shortcut-customization/shortcut_types.js';
-
-/**
- * @param {number} modifier
- * @param {number} keycode
- * @param {string} keyDisplay
- * @param {?boolean} locked
- * @return {!AcceleratorInfo}
- */
-export function createDefaultAccelerator(
-    modifier, keycode, keyDisplay, locked = false) {
-  return /** @type {!AcceleratorInfo} */ ({
-    accelerator: /** @type {!AcceleratorKeys} */ ({
-      modifiers: modifier,
-      key: keycode,
-      keyDisplay: keyDisplay,
-    }),
-    type: AcceleratorType.DEFAULT,
-    state: AcceleratorState.ENABLED,
-    locked: locked,
-  });
-}
-
-/**
- * @param {number} modifier
- * @param {number} keycode
- * @param {string} keyDisplay
- * @param {?boolean} locked
- * @return {!AcceleratorInfo}
- */
-export function createUserAccelerator(
-    modifier, keycode, keyDisplay, locked = false) {
-  return /** @type {!AcceleratorInfo} */ ({
-    accelerator: /** @type {!AcceleratorKeys} */ ({
-      modifiers: modifier,
-      key: keycode,
-      keyDisplay: keyDisplay,
-    }),
-    type: AcceleratorType.USER_DEFINED,
-    state: AcceleratorState.ENABLED,
-    locked: locked,
-  });
-}
diff --git a/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.ts b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.ts
new file mode 100644
index 0000000..03dae00
--- /dev/null
+++ b/chrome/test/data/webui/chromeos/shortcut_customization/shortcut_customization_test_util.ts
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {AcceleratorInfo, AcceleratorState, AcceleratorType} from 'chrome://shortcut-customization/shortcut_types.js';
+
+export function createDefaultAccelerator(
+    modifier: number, keycode: number, keyDisplay: string,
+    locked = false): AcceleratorInfo {
+  return {
+    accelerator: {
+      modifiers: modifier,
+      key: keycode,
+      keyDisplay: keyDisplay,
+    },
+    type: AcceleratorType.DEFAULT,
+    state: AcceleratorState.ENABLED,
+    locked: locked,
+  };
+}
+
+export function createUserAccelerator(
+    modifier: number, keycode: number, keyDisplay: string,
+    locked = false): AcceleratorInfo {
+  return {
+    accelerator: {
+      modifiers: modifier,
+      key: keycode,
+      keyDisplay: keyDisplay,
+    },
+    type: AcceleratorType.USER_DEFINED,
+    state: AcceleratorState.ENABLED,
+    locked: locked,
+  };
+}