keymap.test.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /** @jsxImportSource @opentui/solid */
  2. import { testRender } from "@opentui/solid"
  3. import { expect, test } from "bun:test"
  4. import { ConfigProvider } from "../src/config"
  5. import { Keymap } from "../src/context/keymap"
  6. import { createTuiResolvedConfig } from "./fixture/tui-runtime"
  7. test("legacy page key aliases compile as page keys", async () => {
  8. let read = () => ({ up: "", down: "" })
  9. function Harness() {
  10. const shortcuts = Keymap.useShortcuts()
  11. Keymap.createLayer(() => ({
  12. commands: [
  13. { id: "session.page.up", run() {} },
  14. { id: "session.page.down", run() {} },
  15. ],
  16. }))
  17. read = () => ({
  18. up: shortcuts.get("session.page.up") ?? "",
  19. down: shortcuts.get("session.page.down") ?? "",
  20. })
  21. return <box />
  22. }
  23. const app = await testRender(() => (
  24. <ConfigProvider
  25. config={createTuiResolvedConfig({
  26. keybinds: {
  27. messages_page_up: "pgup",
  28. messages_page_down: "pgdown",
  29. },
  30. })}
  31. >
  32. <Keymap.Provider>
  33. <Harness />
  34. </Keymap.Provider>
  35. </ConfigProvider>
  36. ))
  37. try {
  38. expect(read()).toEqual({ up: "pgup", down: "pgdn" })
  39. } finally {
  40. app.renderer.destroy()
  41. }
  42. })
  43. test("formats navigation keys as arrows", async () => {
  44. let read = () => ({}) as Record<string, string>
  45. const commands = ["session.parent", "session.child.first"]
  46. function Harness() {
  47. const shortcuts = Keymap.useShortcuts()
  48. Keymap.createLayer(() => ({
  49. commands: commands.map((id) => ({ id, run() {} })),
  50. }))
  51. read = () => Object.fromEntries(commands.map((id) => [id, shortcuts.get(id) ?? ""]))
  52. return <box />
  53. }
  54. const app = await testRender(() => (
  55. <ConfigProvider config={createTuiResolvedConfig()}>
  56. <Keymap.Provider>
  57. <Harness />
  58. </Keymap.Provider>
  59. </ConfigProvider>
  60. ))
  61. try {
  62. expect(read()).toEqual({
  63. "session.parent": "↑",
  64. "session.child.first": "↓",
  65. })
  66. } finally {
  67. app.renderer.destroy()
  68. }
  69. })
  70. test("returns every formatted command shortcut", async () => {
  71. let read = () => [] as readonly string[]
  72. function Harness() {
  73. const shortcuts = Keymap.useShortcuts()
  74. Keymap.createLayer(() => ({
  75. commands: [{ id: "demo.command", bind: "x,y", run() {} }],
  76. }))
  77. read = () => shortcuts.list("demo.command")
  78. return <box />
  79. }
  80. const app = await testRender(() => (
  81. <ConfigProvider config={createTuiResolvedConfig()}>
  82. <Keymap.Provider>
  83. <Harness />
  84. </Keymap.Provider>
  85. </ConfigProvider>
  86. ))
  87. try {
  88. expect(read()).toEqual(["x", "y"])
  89. } finally {
  90. app.renderer.destroy()
  91. }
  92. })
  93. test("global commands stay reachable when the mode changes", async () => {
  94. const calls: string[] = []
  95. let exercise = () => {}
  96. function Harness() {
  97. const keymap = Keymap.use()
  98. Keymap.createLayer(() => ({
  99. mode: "global",
  100. commands: [{ id: "session.list", run: () => void calls.push("global") }],
  101. }))
  102. Keymap.createLayer(() => ({
  103. commands: [{ id: "model.list", run: () => void calls.push("base") }],
  104. }))
  105. exercise = () => {
  106. keymap.dispatch("session.list")
  107. keymap.dispatch("model.list")
  108. const pop = keymap.mode.push("question")
  109. keymap.dispatch("session.list")
  110. keymap.dispatch("model.list")
  111. pop()
  112. }
  113. return <box />
  114. }
  115. const app = await testRender(() => (
  116. <ConfigProvider config={createTuiResolvedConfig()}>
  117. <Keymap.Provider>
  118. <Harness />
  119. </Keymap.Provider>
  120. </ConfigProvider>
  121. ))
  122. try {
  123. exercise()
  124. expect(calls).toEqual(["global", "base", "global"])
  125. } finally {
  126. app.renderer.destroy()
  127. }
  128. })