Files
paseo/packages/app/e2e/browser/keyboard-chord-modifier-step.spec.ts
T
paseo-bot[bot] 9a3f3a0dc6 fix(app): complete a multi-step shortcut whose second step holds a modifier (#5272)
A recorded sequence like Ctrl+K Ctrl+J never fired. Pressing a modifier
emits a keydown for the modifier key itself before the combo that holds
it, so a chord waiting on its second step saw a bare `Control` first.
That keydown matches no combo, and the resolver's fall-through reset the
chord to step 0, leaving the following Ctrl+J to resolve as a first step
and match nothing. A second step with no modifier was unaffected, which
is why Ctrl+K J worked.

A modifier keydown is the prefix of a combo, never a combo of its own, so
the resolver now ignores it and leaves the chord where it is. The capture
path already held that rule in `keyboardEventToComboString`; this exports
the predicate behind it rather than adding a second notion of what a
modifier key is.

Closes #5265
2026-09-23 14:46:33 +02:00

45 lines
1.6 KiB
TypeScript

import type { Page } from "@playwright/test";
import { expect, test } from "../support/fixtures";
import { gotoAppShell } from "../support/helpers/app";
// Where Settings → Keyboard shortcuts persists a rebound shortcut.
const OVERRIDE_STORAGE_KEY = "@paseo:keyboard-shortcut-overrides";
const COMMAND_CENTER_BINDING = "command-center-toggle-ctrl-k-non-mac";
async function rebindCommandCenter(page: Page, combo: string): Promise<void> {
await page.addInitScript(
([key, bindingId, value]) => {
window.localStorage.setItem(key, JSON.stringify({ [bindingId]: value }));
},
[OVERRIDE_STORAGE_KEY, COMMAND_CENTER_BINDING, combo] as const,
);
await gotoAppShell(page);
await expect(page.getByTestId("sidebar-search")).toBeVisible({ timeout: 30_000 });
}
async function expectCommandCenterOpen(page: Page): Promise<void> {
await expect(page.getByTestId("command-center-panel")).toBeVisible({ timeout: 10_000 });
}
test.describe("Multi-step shortcut", () => {
test("completes a chord whose second step is a bare key", async ({ page }) => {
await rebindCommandCenter(page, "Ctrl+K J");
await page.keyboard.press("Control+k");
await page.keyboard.press("j");
await expectCommandCenterOpen(page);
});
// Releasing Ctrl between the steps makes the browser emit a bare `Control`
// keydown before `Ctrl+J`, which used to reset the chord to its first step.
test("completes a chord whose second step carries a modifier", async ({ page }) => {
await rebindCommandCenter(page, "Ctrl+K Ctrl+J");
await page.keyboard.press("Control+k");
await page.keyboard.press("Control+j");
await expectCommandCenterOpen(page);
});
});