config-v2.test.tsx 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /** @jsxImportSource @opentui/solid */
  2. import { testRender } from "@opentui/solid"
  3. import { expect, test } from "bun:test"
  4. import { Schema } from "effect"
  5. import { resolve, ConfigProvider, Info, useConfig, type Interface } from "../src/config"
  6. import { settings } from "../src/component/dialog-config"
  7. test("validates mini replay settings", () => {
  8. const decode = Schema.decodeUnknownSync(Info)
  9. expect(decode({ mini: { replay: false, replay_limit: 50 } })).toEqual({
  10. mini: { replay: false, replay_limit: 50 },
  11. })
  12. expect(() => decode({ mini: { replay_limit: 0 } })).toThrow()
  13. expect(() => decode({ mini: { replay_limit: 1.5 } })).toThrow()
  14. })
  15. test("validates the session tabs setting", () => {
  16. const decode = Schema.decodeUnknownSync(Info)
  17. expect(decode({ tabs: { enabled: true, layout: "vertical" } })).toEqual({
  18. tabs: { enabled: true, layout: "vertical" },
  19. })
  20. expect(() => decode({ tabs: { layout: true } })).toThrow()
  21. expect(() => decode({ tabs: { enabled: "on" } })).toThrow()
  22. })
  23. test("resolves nested config and keybind defaults", () => {
  24. const config = resolve(
  25. {
  26. keybinds: { leader: "ctrl+o" },
  27. leader: { timeout: 500 },
  28. scroll: { speed: 2, acceleration: true },
  29. diffs: { view: "split" },
  30. debug: { devtools: true },
  31. },
  32. { terminalSuspend: true },
  33. )
  34. expect(config.leader.timeout).toBe(500)
  35. expect(config.keybinds.get("leader")?.[0]?.key).toBe("ctrl+o")
  36. expect(config.scroll).toEqual({ speed: 2, acceleration: true })
  37. expect(config.diffs).toEqual({ view: "split" })
  38. expect(config.debug).toEqual({ devtools: true })
  39. expect(config.tabs).toEqual({ enabled: true, scope: "cwd", layout: "horizontal" })
  40. })
  41. test("shows resolved tab defaults in settings", () => {
  42. expect(settings.find((setting) => setting.path.join(".") === "tabs.enabled")?.default).toBe(true)
  43. expect(settings.find((setting) => setting.path.join(".") === "tabs.scope")?.default).toBe("cwd")
  44. expect(settings.find((setting) => setting.path.join(".") === "tabs.layout")?.default).toBe("horizontal")
  45. })
  46. test("provides config and its host interface", async () => {
  47. const config = resolve({}, { terminalSuspend: true })
  48. let current = {}
  49. const service: Interface = {
  50. get: async () => current,
  51. update: async (update) => {
  52. const draft: Record<string, any> = { ...current }
  53. update(draft)
  54. current = draft
  55. return draft
  56. },
  57. }
  58. let context: ReturnType<typeof useConfig> | undefined
  59. function Consumer() {
  60. context = useConfig()
  61. return <text>{`${context.data.mouse ? "mouse" : "none"} ${context.data.keybinds.get("leader")?.[0]?.key}`}</text>
  62. }
  63. const app = await testRender(() => (
  64. <ConfigProvider config={config} service={service}>
  65. <Consumer />
  66. </ConfigProvider>
  67. ))
  68. try {
  69. await app.renderOnce()
  70. expect(app.captureCharFrame()).toContain("mouse ctrl+x")
  71. if (!context) throw new Error("Config context was not provided")
  72. await context.update((draft) => {
  73. draft.mouse = false
  74. draft.keybinds = { leader: "ctrl+o" }
  75. })
  76. await app.renderOnce()
  77. expect(app.captureCharFrame()).toContain("none ctrl+o")
  78. } finally {
  79. app.renderer.destroy()
  80. }
  81. })