Skip unrelated required checks without losing their names (#2542)
* fix(ci): skip unrelated required checks cleanly Matrix jobs had to start no-op runners to preserve interpolated required-check names. Static named jobs let GitHub report genuine skipped conclusions while keeping those names stable. * fix(ci): gate changes to install patching script * fix(ci): route cross-package test contracts narrowly * fix(ci): keep routed contracts merge-blocking * fix(server): exclude nested test utilities from builds * fix(ci): cover app-owned native and browser domains * refactor(ci): align tests with runtime domains Own browser specs, desktop specs, and Electron-only app code by stable directories so PR routing does not depend on filename conventions. Keep desktop integration coverage inside the required desktop check. * fix(ci): keep routing and desktop suites isolated The routing regression must run before dependency installation, and desktop Vitest must not collect Playwright-owned specs. * fix(ci): isolate desktop e2e runtime * perf(test): isolate Playwright workers * perf(test): parallelize Playwright within specs * fix(test): keep Playwright file scheduling * fix(test): share dynamic Metro fixture * fix(test): preserve own-host restart fixtures * fix(ci): preserve routed contracts after rebase * Stabilize Playwright wheel-scroll assertions
This commit is contained in:
@@ -1,322 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildBrowserKeyboardPolicy,
|
||||
parseBrowserShortcutInput,
|
||||
shouldPublishBrowserShortcutPolicy,
|
||||
} from "./browser-shortcuts";
|
||||
import { buildEffectiveBindings, resolveKeyboardShortcut } from "./keyboard-shortcuts";
|
||||
|
||||
describe("buildBrowserKeyboardPolicy", () => {
|
||||
it("publishes only chord starts while no browser chord is pending", () => {
|
||||
const bindings = buildEffectiveBindings({
|
||||
"workspace-tab-new-ctrl-t-non-mac": "Ctrl+Y",
|
||||
"workspace-terminal-new-ctrl-shift-t-non-mac": "Ctrl+F12 Ctrl+F11",
|
||||
});
|
||||
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: false, isDesktop: true });
|
||||
|
||||
expect(policy.prefixes).toContainEqual({
|
||||
alt: false,
|
||||
code: "KeyY",
|
||||
control: true,
|
||||
key: "y",
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
expect(policy.prefixes).toContainEqual({
|
||||
alt: false,
|
||||
code: "F12",
|
||||
control: true,
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
expect(policy.prefixes).not.toContainEqual({
|
||||
alt: false,
|
||||
code: "F11",
|
||||
control: true,
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("publishes a chord continuation only after its browser start crosses the boundary", () => {
|
||||
const bindings = buildEffectiveBindings({
|
||||
"workspace-terminal-new-ctrl-shift-t-non-mac": "Ctrl+F12 Ctrl+F11",
|
||||
});
|
||||
const chordIndex = bindings.findIndex(
|
||||
(binding) => binding.id === "workspace-terminal-new-ctrl-shift-t-non-mac",
|
||||
);
|
||||
|
||||
const policy = buildBrowserKeyboardPolicy({
|
||||
bindings,
|
||||
chordState: { candidateIndices: [chordIndex], step: 1, timeoutId: null },
|
||||
isMac: false,
|
||||
isDesktop: true,
|
||||
});
|
||||
|
||||
expect(policy.prefixes).toEqual([
|
||||
{
|
||||
alt: false,
|
||||
code: "F11",
|
||||
control: true,
|
||||
meta: false,
|
||||
shift: false,
|
||||
},
|
||||
]);
|
||||
expect(policy.menuPrefixes).toContainEqual({
|
||||
alt: false,
|
||||
code: "KeyW",
|
||||
control: true,
|
||||
key: "w",
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
|
||||
const result = resolveKeyboardShortcut({
|
||||
event: {
|
||||
altKey: false,
|
||||
code: "F11",
|
||||
ctrlKey: true,
|
||||
key: "F11",
|
||||
metaKey: false,
|
||||
repeat: false,
|
||||
shiftKey: false,
|
||||
},
|
||||
context: {
|
||||
commandCenterOpen: false,
|
||||
focusScope: "browser",
|
||||
isDesktop: true,
|
||||
isMac: false,
|
||||
},
|
||||
chordState: { candidateIndices: [chordIndex], step: 1, timeoutId: null },
|
||||
onChordReset: () => undefined,
|
||||
bindings,
|
||||
});
|
||||
|
||||
expect(result.match?.action).toBe("workspace.terminal.new");
|
||||
});
|
||||
|
||||
it("rejects an entire chord when a continuation cannot cross the browser boundary", () => {
|
||||
const bindings = buildEffectiveBindings({
|
||||
"settings-toggle-ctrl-comma-non-mac": "Ctrl+F10 F9",
|
||||
});
|
||||
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: false, isDesktop: true });
|
||||
|
||||
expect(policy.prefixes).not.toContainEqual({
|
||||
alt: false,
|
||||
code: "F10",
|
||||
control: true,
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
expect(policy.prefixes).not.toContainEqual({
|
||||
alt: false,
|
||||
code: "F9",
|
||||
control: false,
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("publishes Mod bindings for the current shortcut platform", () => {
|
||||
const bindings = buildEffectiveBindings({
|
||||
"workspace-tab-new-cmd-t-mac": "Mod+Y",
|
||||
});
|
||||
|
||||
expect(
|
||||
buildBrowserKeyboardPolicy({ bindings, isMac: true, isDesktop: true }).prefixes,
|
||||
).toContainEqual({
|
||||
alt: false,
|
||||
code: "KeyY",
|
||||
control: false,
|
||||
key: "y",
|
||||
meta: true,
|
||||
shift: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps Ctrl+W out of the window menu after the tab-close shortcut is remapped", () => {
|
||||
const bindings = buildEffectiveBindings({
|
||||
"workspace-tab-close-current-ctrl-w-non-mac": "Ctrl+Y",
|
||||
});
|
||||
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: false, isDesktop: true });
|
||||
|
||||
expect(policy.prefixes).not.toContainEqual({
|
||||
alt: false,
|
||||
code: "KeyW",
|
||||
control: true,
|
||||
key: "w",
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
expect(policy.menuPrefixes).toContainEqual({
|
||||
alt: false,
|
||||
code: "KeyW",
|
||||
control: true,
|
||||
key: "w",
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("leaves macOS browser back and forward shortcuts in the guest", () => {
|
||||
const bindings = buildEffectiveBindings({});
|
||||
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: true, isDesktop: true });
|
||||
|
||||
for (const code of ["BracketLeft", "BracketRight"]) {
|
||||
expect(policy.prefixes).not.toContainEqual({
|
||||
alt: false,
|
||||
code,
|
||||
control: false,
|
||||
key: code === "BracketLeft" ? "[" : "]",
|
||||
meta: true,
|
||||
shift: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("marks editable-only exclusions for enforcement inside the guest", () => {
|
||||
const bindings = buildEffectiveBindings({});
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: true, isDesktop: true });
|
||||
|
||||
expect(policy.prefixes).toContainEqual({
|
||||
alt: false,
|
||||
code: "ArrowLeft",
|
||||
control: false,
|
||||
editable: false,
|
||||
meta: true,
|
||||
shift: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not publish plain browser keys", () => {
|
||||
const bindings = buildEffectiveBindings({});
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: false, isDesktop: true });
|
||||
|
||||
expect(policy.prefixes).not.toContainEqual({
|
||||
alt: false,
|
||||
code: "Enter",
|
||||
control: false,
|
||||
meta: false,
|
||||
shift: false,
|
||||
});
|
||||
expect(policy.prefixes).not.toContainEqual({
|
||||
alt: false,
|
||||
code: "Slash",
|
||||
control: false,
|
||||
meta: false,
|
||||
shift: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("publishes Cmd+B with its logical key for non-QWERTY layouts", () => {
|
||||
const bindings = buildEffectiveBindings({});
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: true, isDesktop: true });
|
||||
|
||||
expect(policy.prefixes).toContainEqual({
|
||||
alt: false,
|
||||
code: "KeyB",
|
||||
control: false,
|
||||
key: "b",
|
||||
meta: true,
|
||||
shift: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("publishes the physical code needed for macOS Option shortcuts", () => {
|
||||
const bindings = buildEffectiveBindings({});
|
||||
const policy = buildBrowserKeyboardPolicy({ bindings, isMac: true, isDesktop: true });
|
||||
|
||||
expect(policy.prefixes).toContainEqual({
|
||||
alt: true,
|
||||
code: "KeyT",
|
||||
control: false,
|
||||
key: "t",
|
||||
meta: true,
|
||||
shift: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldPublishBrowserShortcutPolicy", () => {
|
||||
it("restores the initial browser policy when a host key resets a pending chord", () => {
|
||||
expect(
|
||||
shouldPublishBrowserShortcutPolicy({
|
||||
isBrowserInput: false,
|
||||
previousChordState: { candidateIndices: [1], step: 1, timeoutId: null },
|
||||
nextChordState: { candidateIndices: [], step: 0, timeoutId: null },
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseBrowserShortcutInput", () => {
|
||||
it("normalizes browser shortcut input without losing its identity", () => {
|
||||
expect(
|
||||
parseBrowserShortcutInput({
|
||||
browserId: "browser-1",
|
||||
key: "t",
|
||||
code: "KeyT",
|
||||
meta: false,
|
||||
control: true,
|
||||
shift: false,
|
||||
alt: false,
|
||||
}),
|
||||
).toEqual({
|
||||
browserId: "browser-1",
|
||||
key: "t",
|
||||
code: "KeyT",
|
||||
metaKey: false,
|
||||
ctrlKey: true,
|
||||
shiftKey: false,
|
||||
altKey: false,
|
||||
repeat: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps browser identities exact", () => {
|
||||
expect(
|
||||
parseBrowserShortcutInput({
|
||||
browserId: " browser-1 ",
|
||||
key: "t",
|
||||
code: "KeyT",
|
||||
meta: false,
|
||||
control: true,
|
||||
shift: false,
|
||||
alt: false,
|
||||
}),
|
||||
).toMatchObject({ browserId: " browser-1 " });
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "a missing browser identity",
|
||||
payload: {
|
||||
key: "t",
|
||||
code: "KeyT",
|
||||
meta: false,
|
||||
control: true,
|
||||
shift: false,
|
||||
alt: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "a malformed repeat flag",
|
||||
payload: {
|
||||
browserId: "browser-1",
|
||||
key: "t",
|
||||
code: "KeyT",
|
||||
meta: false,
|
||||
control: true,
|
||||
shift: false,
|
||||
alt: false,
|
||||
repeat: "yes",
|
||||
},
|
||||
},
|
||||
])("rejects $name", ({ payload }) => {
|
||||
expect(parseBrowserShortcutInput(payload)).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -1,211 +0,0 @@
|
||||
import {
|
||||
type ChordState,
|
||||
matchesKeyboardShortcutContext,
|
||||
type KeyboardShortcutInput,
|
||||
type ParsedShortcutBinding,
|
||||
} from "./keyboard-shortcuts";
|
||||
import type { KeyCombo } from "./shortcut-string";
|
||||
|
||||
export interface BrowserShortcutPrefix {
|
||||
alt: boolean;
|
||||
code: string;
|
||||
codeFallback?: true;
|
||||
control: boolean;
|
||||
editable?: false;
|
||||
key?: string;
|
||||
meta: boolean;
|
||||
repeat?: false;
|
||||
shift: boolean;
|
||||
shiftedKey?: string;
|
||||
}
|
||||
|
||||
export interface BrowserShortcutInput extends KeyboardShortcutInput {
|
||||
browserId: string;
|
||||
}
|
||||
|
||||
export interface BrowserKeyboardPolicy {
|
||||
menuPrefixes: BrowserShortcutPrefix[];
|
||||
prefixes: BrowserShortcutPrefix[];
|
||||
}
|
||||
|
||||
interface BrowserShortcutPolicyInput {
|
||||
bindings: readonly ParsedShortcutBinding[];
|
||||
chordState?: ChordState;
|
||||
isMac: boolean;
|
||||
isDesktop: boolean;
|
||||
}
|
||||
|
||||
export function shouldPublishBrowserShortcutPolicy(input: {
|
||||
isBrowserInput: boolean;
|
||||
nextChordState: ChordState;
|
||||
previousChordState: ChordState;
|
||||
}): boolean {
|
||||
return (
|
||||
input.isBrowserInput || (input.previousChordState.step > 0 && input.nextChordState.step === 0)
|
||||
);
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export function parseBrowserShortcutInput(value: unknown): BrowserShortcutInput | null {
|
||||
if (!isRecord(value)) {
|
||||
return null;
|
||||
}
|
||||
const { browserId, code, key } = value;
|
||||
if (typeof browserId !== "string" || browserId.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (typeof code !== "string" || typeof key !== "string") {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
typeof value.alt !== "boolean" ||
|
||||
typeof value.control !== "boolean" ||
|
||||
typeof value.meta !== "boolean" ||
|
||||
typeof value.shift !== "boolean" ||
|
||||
(value.repeat !== undefined && typeof value.repeat !== "boolean")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
browserId,
|
||||
key,
|
||||
code,
|
||||
altKey: value.alt,
|
||||
ctrlKey: value.control,
|
||||
metaKey: value.meta,
|
||||
shiftKey: value.shift,
|
||||
repeat: value.repeat ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
function prefixFromCombo(
|
||||
combo: KeyCombo,
|
||||
isMac: boolean,
|
||||
editable: false | undefined,
|
||||
): BrowserShortcutPrefix | null {
|
||||
const prefix: BrowserShortcutPrefix = {
|
||||
alt: combo.alt === true,
|
||||
code: combo.code,
|
||||
control: combo.ctrl === true || (!isMac && combo.mod === true),
|
||||
meta: combo.meta === true || (isMac && combo.mod === true),
|
||||
shift: combo.shift === true,
|
||||
};
|
||||
if (combo.codeFallback === true) {
|
||||
prefix.codeFallback = true;
|
||||
}
|
||||
if (editable === false) {
|
||||
prefix.editable = false;
|
||||
}
|
||||
if (combo.key) {
|
||||
prefix.key = combo.key;
|
||||
}
|
||||
if (combo.repeat === false) {
|
||||
prefix.repeat = false;
|
||||
}
|
||||
if (combo.shiftedKey) {
|
||||
prefix.shiftedKey = combo.shiftedKey;
|
||||
}
|
||||
return prefix.meta || prefix.control || prefix.alt ? prefix : null;
|
||||
}
|
||||
|
||||
function isBrowserNativeNavigationPrefix(prefix: BrowserShortcutPrefix, isMac: boolean): boolean {
|
||||
return (
|
||||
isMac &&
|
||||
prefix.meta &&
|
||||
!prefix.control &&
|
||||
!prefix.alt &&
|
||||
!prefix.shift &&
|
||||
(prefix.code === "BracketLeft" || prefix.code === "BracketRight")
|
||||
);
|
||||
}
|
||||
|
||||
function canCrossBrowserBoundary(binding: ParsedShortcutBinding, isMac: boolean): boolean {
|
||||
return binding.parsedChord.every((combo) => {
|
||||
const prefix = prefixFromCombo(combo, isMac, binding.when?.editable);
|
||||
return prefix !== null && !isBrowserNativeNavigationPrefix(prefix, isMac);
|
||||
});
|
||||
}
|
||||
|
||||
function prefixKey(prefix: BrowserShortcutPrefix): string {
|
||||
return [
|
||||
prefix.code,
|
||||
prefix.key ?? "",
|
||||
prefix.shiftedKey ?? "",
|
||||
prefix.codeFallback ?? "",
|
||||
prefix.editable ?? "",
|
||||
prefix.control,
|
||||
prefix.meta,
|
||||
prefix.alt,
|
||||
prefix.shift,
|
||||
prefix.repeat ?? "",
|
||||
].join(":");
|
||||
}
|
||||
|
||||
function buildBrowserShortcutPrefixes(input: BrowserShortcutPolicyInput): BrowserShortcutPrefix[] {
|
||||
const prefixes = new Map<string, BrowserShortcutPrefix>();
|
||||
const context = {
|
||||
isMac: input.isMac,
|
||||
isDesktop: input.isDesktop,
|
||||
focusScope: "browser" as const,
|
||||
commandCenterOpen: false,
|
||||
};
|
||||
|
||||
const candidates =
|
||||
input.chordState && input.chordState.step > 0
|
||||
? input.chordState.candidateIndices
|
||||
: input.bindings.map((_, index) => index);
|
||||
const step = input.chordState?.step ?? 0;
|
||||
|
||||
for (const index of candidates) {
|
||||
const binding = input.bindings[index];
|
||||
if (!binding) {
|
||||
continue;
|
||||
}
|
||||
if (!matchesKeyboardShortcutContext(binding.when, context)) {
|
||||
continue;
|
||||
}
|
||||
if (!canCrossBrowserBoundary(binding, input.isMac)) {
|
||||
continue;
|
||||
}
|
||||
const combo = binding.parsedChord[step];
|
||||
if (!combo) {
|
||||
continue;
|
||||
}
|
||||
const prefix = prefixFromCombo(combo, input.isMac, binding.when?.editable);
|
||||
if (!prefix) {
|
||||
continue;
|
||||
}
|
||||
prefixes.set(prefixKey(prefix), prefix);
|
||||
}
|
||||
|
||||
return [...prefixes.values()];
|
||||
}
|
||||
|
||||
export function buildBrowserKeyboardPolicy(
|
||||
input: BrowserShortcutPolicyInput,
|
||||
): BrowserKeyboardPolicy {
|
||||
const idlePrefixes = buildBrowserShortcutPrefixes({ ...input, chordState: undefined });
|
||||
const prefixes =
|
||||
input.chordState && input.chordState.step > 0
|
||||
? buildBrowserShortcutPrefixes(input)
|
||||
: idlePrefixes;
|
||||
const menuPrefixes = [...idlePrefixes];
|
||||
if (!input.isMac) {
|
||||
const closeWindowGuard: BrowserShortcutPrefix = {
|
||||
alt: false,
|
||||
code: "KeyW",
|
||||
control: true,
|
||||
key: "w",
|
||||
meta: false,
|
||||
shift: false,
|
||||
};
|
||||
if (!menuPrefixes.some((prefix) => prefixKey(prefix) === prefixKey(closeWindowGuard))) {
|
||||
menuPrefixes.push(closeWindowGuard);
|
||||
}
|
||||
}
|
||||
return { menuPrefixes, prefixes };
|
||||
}
|
||||
Reference in New Issue
Block a user