fix(simulation): normalize named key presses (#37523)
This commit is contained in:
parent
677526d72e
commit
3fc06accbd
2 changed files with 49 additions and 3 deletions
|
|
@ -1,7 +1,14 @@
|
||||||
import { tmpdir } from "node:os"
|
import { tmpdir } from "node:os"
|
||||||
import { extname, join, resolve } from "node:path"
|
import { extname, join, resolve } from "node:path"
|
||||||
import type { CliRenderer, Renderable } from "@opentui/core"
|
import type { CliRenderer, Renderable } from "@opentui/core"
|
||||||
import { createMockKeys, createMockMouse, type MockInput, type MockMouse } from "@opentui/core/testing"
|
import {
|
||||||
|
createMockKeys,
|
||||||
|
createMockMouse,
|
||||||
|
KeyCodes,
|
||||||
|
type KeyInput,
|
||||||
|
type MockInput,
|
||||||
|
type MockMouse,
|
||||||
|
} from "@opentui/core/testing"
|
||||||
import { Config, Effect, FileSystem } from "effect"
|
import { Config, Effect, FileSystem } from "effect"
|
||||||
import type { SimulationProtocol } from "../protocol"
|
import type { SimulationProtocol } from "../protocol"
|
||||||
import { SimulationRenderer } from "./renderer"
|
import { SimulationRenderer } from "./renderer"
|
||||||
|
|
@ -26,6 +33,15 @@ type RenderBuffer = {
|
||||||
|
|
||||||
const decoder = new TextDecoder()
|
const decoder = new TextDecoder()
|
||||||
|
|
||||||
|
function isKeyCode(key: string): key is keyof typeof KeyCodes {
|
||||||
|
return Object.hasOwn(KeyCodes, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyInput(key: string): KeyInput {
|
||||||
|
const named = key.toUpperCase()
|
||||||
|
return isKeyCode(named) ? named : key
|
||||||
|
}
|
||||||
|
|
||||||
function children(renderable: Renderable) {
|
function children(renderable: Renderable) {
|
||||||
return renderable.getChildren().filter((child): child is Renderable => "num" in child)
|
return renderable.getChildren().filter((child): child is Renderable => "num" in child)
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +170,7 @@ export const execute = Effect.fn("SimulationActions.execute")(function* (harness
|
||||||
yield* Effect.tryPromise(() => harness.mockInput.typeText(action.text))
|
yield* Effect.tryPromise(() => harness.mockInput.typeText(action.text))
|
||||||
break
|
break
|
||||||
case "ui.press":
|
case "ui.press":
|
||||||
harness.mockInput.pressKey(action.key, action.modifiers)
|
harness.mockInput.pressKey(keyInput(action.key), action.modifiers)
|
||||||
break
|
break
|
||||||
case "ui.enter":
|
case "ui.enter":
|
||||||
harness.mockInput.pressEnter()
|
harness.mockInput.pressEnter()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { expect, test } from "bun:test"
|
import { expect, test } from "bun:test"
|
||||||
import { matches } from "../src/frontend/actions"
|
import { Effect } from "effect"
|
||||||
|
import { execute, type Harness, matches } from "../src/frontend/actions"
|
||||||
|
|
||||||
test("matches literal screen text", () => {
|
test("matches literal screen text", () => {
|
||||||
const harness = { screen: () => "OpenCode [ready].*" }
|
const harness = { screen: () => "OpenCode [ready].*" }
|
||||||
|
|
@ -9,3 +10,32 @@ test("matches literal screen text", () => {
|
||||||
expect(matches(harness, "OpenCode.*ready")).toBe(false)
|
expect(matches(harness, "OpenCode.*ready")).toBe(false)
|
||||||
expect(matches(harness, "opencode")).toBe(false)
|
expect(matches(harness, "opencode")).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("normalizes named keys for OpenTUI", async () => {
|
||||||
|
const pressed: Array<readonly [string, object | undefined]> = []
|
||||||
|
const harness = {
|
||||||
|
renderer: {
|
||||||
|
root: { getChildren: () => [] },
|
||||||
|
currentFocusedRenderable: undefined,
|
||||||
|
currentFocusedEditor: undefined,
|
||||||
|
},
|
||||||
|
mockInput: {
|
||||||
|
pressKey: (key: string, modifiers?: object) => pressed.push([key, modifiers]),
|
||||||
|
},
|
||||||
|
renderOnce: async () => {},
|
||||||
|
} as unknown as Harness
|
||||||
|
|
||||||
|
await Effect.runPromise(
|
||||||
|
execute(harness, {
|
||||||
|
type: "ui.press",
|
||||||
|
key: "escape",
|
||||||
|
modifiers: { ctrl: true },
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
await Effect.runPromise(execute(harness, { type: "ui.press", key: "x" }))
|
||||||
|
|
||||||
|
expect(pressed).toEqual([
|
||||||
|
["ESCAPE", { ctrl: true }],
|
||||||
|
["x", undefined],
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue