plugin-add.test.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { expect, spyOn, test } from "bun:test"
  2. import fs from "fs/promises"
  3. import path from "path"
  4. import { pathToFileURL } from "url"
  5. import { tmpdir } from "../../fixture/fixture"
  6. import { createTuiPluginApi } from "../../fixture/tui-plugin"
  7. import { TuiConfig } from "../../../src/cli/cmd/tui/config/tui"
  8. const { TuiPluginRuntime } = await import("../../../src/cli/cmd/tui/plugin/runtime")
  9. test("adds tui plugin at runtime from spec", async () => {
  10. await using tmp = await tmpdir({
  11. init: async (dir) => {
  12. const file = path.join(dir, "add-plugin.ts")
  13. const spec = pathToFileURL(file).href
  14. const marker = path.join(dir, "add.txt")
  15. await Bun.write(
  16. file,
  17. `export default {
  18. id: "demo.add",
  19. tui: async () => {
  20. await Bun.write(${JSON.stringify(marker)}, "called")
  21. },
  22. }
  23. `,
  24. )
  25. return { spec, marker }
  26. },
  27. })
  28. process.env.KILO_PLUGIN_META_FILE = path.join(tmp.path, "plugin-meta.json")
  29. const config: TuiConfig.Info = {
  30. plugin: [],
  31. plugin_origins: undefined,
  32. }
  33. const wait = spyOn(TuiConfig, "waitForDependencies").mockResolvedValue()
  34. const cwd = spyOn(process, "cwd").mockImplementation(() => tmp.path)
  35. try {
  36. await TuiPluginRuntime.init({
  37. api: createTuiPluginApi(),
  38. config,
  39. })
  40. await expect(TuiPluginRuntime.addPlugin(tmp.extra.spec)).resolves.toBe(true)
  41. await expect(fs.readFile(tmp.extra.marker, "utf8")).resolves.toBe("called")
  42. expect(TuiPluginRuntime.list().find((item) => item.id === "demo.add")).toEqual({
  43. id: "demo.add",
  44. source: "file",
  45. spec: tmp.extra.spec,
  46. target: tmp.extra.spec,
  47. enabled: true,
  48. active: true,
  49. })
  50. } finally {
  51. await TuiPluginRuntime.dispose()
  52. cwd.mockRestore()
  53. wait.mockRestore()
  54. delete process.env.KILO_PLUGIN_META_FILE
  55. }
  56. })
  57. test("retries runtime add for file plugins after dependency wait", async () => {
  58. await using tmp = await tmpdir({
  59. init: async (dir) => {
  60. const mod = path.join(dir, "retry-plugin")
  61. const spec = pathToFileURL(mod).href
  62. const marker = path.join(dir, "retry-add.txt")
  63. await fs.mkdir(mod, { recursive: true })
  64. return { mod, spec, marker }
  65. },
  66. })
  67. process.env.KILO_PLUGIN_META_FILE = path.join(tmp.path, "plugin-meta.json")
  68. const config: TuiConfig.Info = {
  69. plugin: [],
  70. plugin_origins: undefined,
  71. }
  72. const wait = spyOn(TuiConfig, "waitForDependencies").mockImplementation(async () => {
  73. await Bun.write(
  74. path.join(tmp.extra.mod, "index.ts"),
  75. `export default {
  76. id: "demo.add.retry",
  77. tui: async () => {
  78. await Bun.write(${JSON.stringify(tmp.extra.marker)}, "called")
  79. },
  80. }
  81. `,
  82. )
  83. })
  84. const cwd = spyOn(process, "cwd").mockImplementation(() => tmp.path)
  85. try {
  86. await TuiPluginRuntime.init({
  87. api: createTuiPluginApi(),
  88. config,
  89. })
  90. await expect(TuiPluginRuntime.addPlugin(tmp.extra.spec)).resolves.toBe(true)
  91. await expect(fs.readFile(tmp.extra.marker, "utf8")).resolves.toBe("called")
  92. expect(wait).toHaveBeenCalledTimes(1)
  93. expect(TuiPluginRuntime.list().find((item) => item.id === "demo.add.retry")?.active).toBe(true)
  94. } finally {
  95. await TuiPluginRuntime.dispose()
  96. cwd.mockRestore()
  97. wait.mockRestore()
  98. delete process.env.KILO_PLUGIN_META_FILE
  99. }
  100. })