mocks.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
  2. // SPDX-License-Identifier: Apache-2.0
  3. // SPDX-License-Identifier: MIT
  4. /**
  5. * Intercepts all IPC requests with the given mock handler.
  6. *
  7. * This function can be used when testing tauri frontend applications or when running the frontend in a Node.js context during static site generation.
  8. *
  9. * # Examples
  10. *
  11. * Testing setup using vitest:
  12. * ```js
  13. * import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
  14. * import { invoke } from "@tauri-apps/api/tauri"
  15. *
  16. * afterEach(() => {
  17. * clearMocks()
  18. * })
  19. *
  20. * test("mocked command", () => {
  21. * mockIPC((cmd, args) => {
  22. * switch (cmd) {
  23. * case "add":
  24. * return (args.a as number) + (args.b as number);
  25. * default:
  26. * break;
  27. * }
  28. * });
  29. *
  30. * expect(invoke('add', { a: 12, b: 15 })).resolves.toBe(27);
  31. * })
  32. * ```
  33. *
  34. * The callback function can also return a Promise:
  35. * ```js
  36. * import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
  37. * import { invoke } from "@tauri-apps/api/tauri"
  38. *
  39. * afterEach(() => {
  40. * clearMocks()
  41. * })
  42. *
  43. * test("mocked command", () => {
  44. * mockIPC((cmd, args) => {
  45. * if(cmd === "get_data") {
  46. * return fetch("https://example.com/data.json")
  47. * .then((response) => response.json())
  48. * }
  49. * });
  50. *
  51. * expect(invoke('get_data')).resolves.toBe({ foo: 'bar' });
  52. * })
  53. * ```
  54. *
  55. * @since 1.0.0
  56. */
  57. function mockIPC(cb) {
  58. // eslint-disable-next-line @typescript-eslint/no-misused-promises
  59. window.__TAURI_IPC__ = async ({ cmd, callback, error, ...args }) => {
  60. try {
  61. // @ts-expect-error The function key is dynamic and therefore not typed
  62. // eslint-disable-next-line @typescript-eslint/no-unsafe-call
  63. window[`_${callback}`](await cb(cmd, args));
  64. }
  65. catch (err) {
  66. // @ts-expect-error The function key is dynamic and therefore not typed
  67. // eslint-disable-next-line @typescript-eslint/no-unsafe-call
  68. window[`_${error}`](err);
  69. }
  70. };
  71. }
  72. /**
  73. * Mocks one or many window labels.
  74. * In non-tauri context it is required to call this function *before* using the `@tauri-apps/api/window` module.
  75. *
  76. * This function only mocks the *presence* of windows,
  77. * window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
  78. *
  79. * # Examples
  80. *
  81. * ```js
  82. * import { mockWindows } from "@tauri-apps/api/mocks";
  83. * import { getCurrent } from "@tauri-apps/api/window";
  84. *
  85. * mockWindows("main", "second", "third");
  86. *
  87. * const win = getCurrent();
  88. *
  89. * win.label // "main"
  90. * ```
  91. *
  92. * ```js
  93. * import { mockWindows } from "@tauri-apps/api/mocks";
  94. *
  95. * mockWindows("main", "second", "third");
  96. *
  97. * mockIPC((cmd, args) => {
  98. * if (cmd === "tauri") {
  99. * if (
  100. * args?.__tauriModule === "Window" &&
  101. * args?.message?.cmd === "manage" &&
  102. * args?.message?.data?.cmd?.type === "close"
  103. * ) {
  104. * console.log('closing window!');
  105. * }
  106. * }
  107. * });
  108. *
  109. * const { getCurrent } = await import("@tauri-apps/api/window");
  110. *
  111. * const win = getCurrent();
  112. * await win.close(); // this will cause the mocked IPC handler to log to the console.
  113. * ```
  114. *
  115. * @param current Label of window this JavaScript context is running in.
  116. * @param additionalWindows Label of additional windows the app has.
  117. *
  118. * @since 1.0.0
  119. */
  120. function mockWindows(current, ...additionalWindows) {
  121. window.__TAURI_METADATA__ = {
  122. __windows: [current, ...additionalWindows].map((label) => ({ label })),
  123. __currentWindow: { label: current }
  124. };
  125. }
  126. /**
  127. * Mock `convertFileSrc` function
  128. *
  129. *
  130. * @example
  131. * ```js
  132. * import { mockConvertFileSrc } from "@tauri-apps/api/mocks";
  133. * import { convertFileSrc } from "@tauri-apps/api/tauri";
  134. *
  135. * mockConvertFileSrc("windows")
  136. *
  137. * const url = convertFileSrc("C:\\Users\\user\\file.txt")
  138. * ```
  139. *
  140. * @param osName The operating system to mock, can be one of linux, macos, or windows
  141. * @param windowsProtocolScheme The scheme to use on Windows, can be either `http` or `https` and defaults to `https`
  142. *
  143. * @since 1.6.0
  144. */
  145. function mockConvertFileSrc(osName, windowsProtocolScheme = 'https') {
  146. var _a;
  147. window.__TAURI__ = (_a = window.__TAURI__) !== null && _a !== void 0 ? _a : {};
  148. window.__TAURI__.convertFileSrc = function (filePath, protocol = 'asset') {
  149. const path = encodeURIComponent(filePath);
  150. return osName === 'windows'
  151. ? `${windowsProtocolScheme}://${protocol}.localhost/${path}`
  152. : `${protocol}://localhost/${path}`;
  153. };
  154. }
  155. /**
  156. * Clears mocked functions/data injected by the other functions in this module.
  157. * When using a test runner that doesn't provide a fresh window object for each test, calling this function will reset tauri specific properties.
  158. *
  159. * # Example
  160. *
  161. * ```js
  162. * import { mockWindows, clearMocks } from "@tauri-apps/api/mocks"
  163. *
  164. * afterEach(() => {
  165. * clearMocks()
  166. * })
  167. *
  168. * test("mocked windows", () => {
  169. * mockWindows("main", "second", "third");
  170. *
  171. * expect(window).toHaveProperty("__TAURI_METADATA__")
  172. * })
  173. *
  174. * test("no mocked windows", () => {
  175. * expect(window).not.toHaveProperty("__TAURI_METADATA__")
  176. * })
  177. * ```
  178. *
  179. * @since 1.0.0
  180. */
  181. function clearMocks() {
  182. var _a;
  183. // @ts-expect-error "The operand of a 'delete' operator must be optional' does not matter in this case
  184. if ((_a = window.__TAURI__) === null || _a === void 0 ? void 0 : _a.convertFileSrc)
  185. delete window.__TAURI__.convertFileSrc;
  186. // @ts-expect-error "The operand of a 'delete' operator must be optional' does not matter in this case
  187. if (window.__TAURI_IPC__)
  188. delete window.__TAURI_IPC__;
  189. // @ts-expect-error "The operand of a 'delete' operator must be optional' does not matter in this case
  190. if (window.__TAURI_METADATA__)
  191. delete window.__TAURI_METADATA__;
  192. }
  193. export { clearMocks, mockConvertFileSrc, mockIPC, mockWindows };