@multiplatform.one/frappe 7.10.0 → 7.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/README.md +59 -1
  2. package/dist/cjs/auth.native.js.map +1 -1
  3. package/dist/cjs/call.native.js.map +1 -1
  4. package/dist/cjs/collection.native.js.map +1 -1
  5. package/dist/cjs/common/types.native.js.map +1 -1
  6. package/dist/cjs/core/http.native.js.map +1 -1
  7. package/dist/cjs/core/types.native.js.map +1 -1
  8. package/dist/cjs/core/wire.native.js.map +1 -1
  9. package/dist/cjs/db.native.js.map +1 -1
  10. package/dist/cjs/devtools/FrappeDevtoolsPanel.native.js.map +1 -1
  11. package/dist/cjs/devtools/index.native.js.map +1 -1
  12. package/dist/cjs/devtools/plugin.native.js.map +1 -1
  13. package/dist/cjs/devtools/theme.native.js.map +1 -1
  14. package/dist/cjs/doctype.cjs +25 -43
  15. package/dist/cjs/doctype.native.js +27 -43
  16. package/dist/cjs/doctype.native.js.map +1 -1
  17. package/dist/cjs/file.native.js.map +1 -1
  18. package/dist/cjs/fixtureDb.native.js.map +1 -1
  19. package/dist/cjs/fixtures.cjs +3 -0
  20. package/dist/cjs/fixtures.native.js +3 -0
  21. package/dist/cjs/fixtures.native.js.map +1 -1
  22. package/dist/cjs/frappeApp.native.js.map +1 -1
  23. package/dist/cjs/frappeReact.cjs +67 -31
  24. package/dist/cjs/frappeReact.native.js +87 -34
  25. package/dist/cjs/frappeReact.native.js.map +1 -1
  26. package/dist/cjs/index.cjs +7 -0
  27. package/dist/cjs/index.native.js +9 -2
  28. package/dist/cjs/index.native.js.map +1 -1
  29. package/dist/cjs/optimistic.native.js.map +1 -1
  30. package/dist/cjs/pacer.native.js.map +1 -1
  31. package/dist/cjs/plugin/index.native.js.map +1 -1
  32. package/dist/cjs/realtime.native.js.map +1 -1
  33. package/dist/cjs/serverLoaders.cjs +74 -0
  34. package/dist/cjs/serverLoaders.native.js +88 -0
  35. package/dist/cjs/serverLoaders.native.js.map +1 -0
  36. package/dist/cjs/sync/backfill.native.js.map +1 -1
  37. package/dist/cjs/sync/filters.native.js.map +1 -1
  38. package/dist/cjs/sync/index.cjs +99 -14
  39. package/dist/cjs/sync/index.native.js +129 -14
  40. package/dist/cjs/sync/index.native.js.map +1 -1
  41. package/dist/cjs/sync/merge.native.js.map +1 -1
  42. package/dist/cjs/sync/mutationEngine.native.js.map +1 -1
  43. package/dist/cjs/sync/mutationJournal.native.js.map +1 -1
  44. package/dist/cjs/sync/normalizedCache.native.js.map +1 -1
  45. package/dist/cjs/sync/persistence.native.js.map +1 -1
  46. package/dist/cjs/sync/realtime.native.js.map +1 -1
  47. package/dist/cjs/sync/rehydration.cjs +4 -0
  48. package/dist/cjs/sync/rehydration.native.js +6 -0
  49. package/dist/cjs/sync/rehydration.native.js.map +1 -1
  50. package/dist/cjs/sync/storage.native.js.map +1 -1
  51. package/dist/cjs/sync/subscriptionManager.native.js.map +1 -1
  52. package/dist/cjs/sync/types.native.js.map +1 -1
  53. package/dist/cjs/sync/virtualPageManager.native.js.map +1 -1
  54. package/dist/cjs/syncOptionsKey.cjs +59 -0
  55. package/dist/cjs/syncOptionsKey.native.js +82 -0
  56. package/dist/cjs/syncOptionsKey.native.js.map +1 -0
  57. package/dist/cjs/useLiveQuery.cjs +2 -20
  58. package/dist/cjs/useLiveQuery.native.js +1 -22
  59. package/dist/cjs/useLiveQuery.native.js.map +1 -1
  60. package/dist/cjs/util.native.js.map +1 -1
  61. package/dist/esm/auth.native.js.map +1 -1
  62. package/dist/esm/call.native.js.map +1 -1
  63. package/dist/esm/collection.native.js.map +1 -1
  64. package/dist/esm/common/types.native.js.map +1 -1
  65. package/dist/esm/core/http.native.js.map +1 -1
  66. package/dist/esm/core/types.native.js.map +1 -1
  67. package/dist/esm/core/wire.native.js.map +1 -1
  68. package/dist/esm/db.native.js.map +1 -1
  69. package/dist/esm/devtools/FrappeDevtoolsPanel.native.js.map +1 -1
  70. package/dist/esm/devtools/index.native.js.map +1 -1
  71. package/dist/esm/devtools/plugin.native.js.map +1 -1
  72. package/dist/esm/devtools/theme.native.js.map +1 -1
  73. package/dist/esm/doctype.mjs +23 -44
  74. package/dist/esm/doctype.mjs.map +1 -1
  75. package/dist/esm/doctype.native.js +25 -44
  76. package/dist/esm/doctype.native.js.map +1 -1
  77. package/dist/esm/file.native.js.map +1 -1
  78. package/dist/esm/fixtureDb.native.js.map +1 -1
  79. package/dist/esm/fixtures.mjs +3 -0
  80. package/dist/esm/fixtures.mjs.map +1 -1
  81. package/dist/esm/fixtures.native.js +3 -0
  82. package/dist/esm/fixtures.native.js.map +1 -1
  83. package/dist/esm/frappeApp.native.js.map +1 -1
  84. package/dist/esm/frappeReact.mjs +68 -33
  85. package/dist/esm/frappeReact.mjs.map +1 -1
  86. package/dist/esm/frappeReact.native.js +87 -35
  87. package/dist/esm/frappeReact.native.js.map +1 -1
  88. package/dist/esm/index.mjs +4 -3
  89. package/dist/esm/index.mjs.map +1 -1
  90. package/dist/esm/index.native.js +4 -3
  91. package/dist/esm/index.native.js.map +1 -1
  92. package/dist/esm/optimistic.native.js.map +1 -1
  93. package/dist/esm/pacer.native.js.map +1 -1
  94. package/dist/esm/plugin/index.native.js.map +1 -1
  95. package/dist/esm/realtime.native.js.map +1 -1
  96. package/dist/esm/serverLoaders.mjs +48 -0
  97. package/dist/esm/serverLoaders.mjs.map +1 -0
  98. package/dist/esm/serverLoaders.native.js +59 -0
  99. package/dist/esm/serverLoaders.native.js.map +1 -0
  100. package/dist/esm/sync/backfill.native.js.map +1 -1
  101. package/dist/esm/sync/filters.native.js.map +1 -1
  102. package/dist/esm/sync/index.mjs +99 -14
  103. package/dist/esm/sync/index.mjs.map +1 -1
  104. package/dist/esm/sync/index.native.js +129 -14
  105. package/dist/esm/sync/index.native.js.map +1 -1
  106. package/dist/esm/sync/merge.native.js.map +1 -1
  107. package/dist/esm/sync/mutationEngine.native.js.map +1 -1
  108. package/dist/esm/sync/mutationJournal.native.js.map +1 -1
  109. package/dist/esm/sync/normalizedCache.native.js.map +1 -1
  110. package/dist/esm/sync/persistence.native.js.map +1 -1
  111. package/dist/esm/sync/realtime.native.js.map +1 -1
  112. package/dist/esm/sync/rehydration.mjs +4 -0
  113. package/dist/esm/sync/rehydration.mjs.map +1 -1
  114. package/dist/esm/sync/rehydration.native.js +6 -0
  115. package/dist/esm/sync/rehydration.native.js.map +1 -1
  116. package/dist/esm/sync/storage.native.js.map +1 -1
  117. package/dist/esm/sync/subscriptionManager.native.js.map +1 -1
  118. package/dist/esm/sync/types.mjs.map +1 -1
  119. package/dist/esm/sync/types.native.js.map +1 -1
  120. package/dist/esm/sync/virtualPageManager.native.js.map +1 -1
  121. package/dist/esm/syncOptionsKey.mjs +34 -0
  122. package/dist/esm/syncOptionsKey.mjs.map +1 -0
  123. package/dist/esm/syncOptionsKey.native.js +54 -0
  124. package/dist/esm/syncOptionsKey.native.js.map +1 -0
  125. package/dist/esm/useLiveQuery.mjs +1 -19
  126. package/dist/esm/useLiveQuery.mjs.map +1 -1
  127. package/dist/esm/useLiveQuery.native.js +1 -22
  128. package/dist/esm/useLiveQuery.native.js.map +1 -1
  129. package/dist/esm/util.native.js.map +1 -1
  130. package/dist/jsx/auth.native.js.map +1 -1
  131. package/dist/jsx/call.native.js.map +1 -1
  132. package/dist/jsx/collection.native.js.map +1 -1
  133. package/dist/jsx/common/types.native.js.map +1 -1
  134. package/dist/jsx/core/http.native.js.map +1 -1
  135. package/dist/jsx/core/types.native.js.map +1 -1
  136. package/dist/jsx/core/wire.native.js.map +1 -1
  137. package/dist/jsx/db.native.js.map +1 -1
  138. package/dist/jsx/devtools/FrappeDevtoolsPanel.native.js.map +1 -1
  139. package/dist/jsx/devtools/index.native.js.map +1 -1
  140. package/dist/jsx/devtools/plugin.native.js.map +1 -1
  141. package/dist/jsx/devtools/theme.native.js.map +1 -1
  142. package/dist/jsx/doctype.mjs +23 -44
  143. package/dist/jsx/doctype.mjs.map +1 -1
  144. package/dist/jsx/doctype.native.js +27 -43
  145. package/dist/jsx/doctype.native.js.map +1 -1
  146. package/dist/jsx/file.native.js.map +1 -1
  147. package/dist/jsx/fixtureDb.native.js.map +1 -1
  148. package/dist/jsx/fixtures.mjs +3 -0
  149. package/dist/jsx/fixtures.mjs.map +1 -1
  150. package/dist/jsx/fixtures.native.js +3 -0
  151. package/dist/jsx/fixtures.native.js.map +1 -1
  152. package/dist/jsx/frappeApp.native.js.map +1 -1
  153. package/dist/jsx/frappeReact.mjs +68 -33
  154. package/dist/jsx/frappeReact.mjs.map +1 -1
  155. package/dist/jsx/frappeReact.native.js +87 -34
  156. package/dist/jsx/frappeReact.native.js.map +1 -1
  157. package/dist/jsx/index.js +4 -3
  158. package/dist/jsx/index.js.map +1 -1
  159. package/dist/jsx/index.mjs +4 -3
  160. package/dist/jsx/index.mjs.map +1 -1
  161. package/dist/jsx/index.native.js +9 -2
  162. package/dist/jsx/index.native.js.map +1 -1
  163. package/dist/jsx/optimistic.native.js.map +1 -1
  164. package/dist/jsx/pacer.native.js.map +1 -1
  165. package/dist/jsx/plugin/index.native.js.map +1 -1
  166. package/dist/jsx/realtime.native.js.map +1 -1
  167. package/dist/jsx/serverLoaders.mjs +48 -0
  168. package/dist/jsx/serverLoaders.mjs.map +1 -0
  169. package/dist/jsx/serverLoaders.native.js +88 -0
  170. package/dist/jsx/serverLoaders.native.js.map +1 -0
  171. package/dist/jsx/sync/backfill.native.js.map +1 -1
  172. package/dist/jsx/sync/filters.native.js.map +1 -1
  173. package/dist/jsx/sync/index.mjs +99 -14
  174. package/dist/jsx/sync/index.mjs.map +1 -1
  175. package/dist/jsx/sync/index.native.js +129 -14
  176. package/dist/jsx/sync/index.native.js.map +1 -1
  177. package/dist/jsx/sync/merge.native.js.map +1 -1
  178. package/dist/jsx/sync/mutationEngine.native.js.map +1 -1
  179. package/dist/jsx/sync/mutationJournal.native.js.map +1 -1
  180. package/dist/jsx/sync/normalizedCache.native.js.map +1 -1
  181. package/dist/jsx/sync/persistence.native.js.map +1 -1
  182. package/dist/jsx/sync/realtime.native.js.map +1 -1
  183. package/dist/jsx/sync/rehydration.mjs +4 -0
  184. package/dist/jsx/sync/rehydration.mjs.map +1 -1
  185. package/dist/jsx/sync/rehydration.native.js +6 -0
  186. package/dist/jsx/sync/rehydration.native.js.map +1 -1
  187. package/dist/jsx/sync/storage.native.js.map +1 -1
  188. package/dist/jsx/sync/subscriptionManager.native.js.map +1 -1
  189. package/dist/jsx/sync/types.mjs.map +1 -1
  190. package/dist/jsx/sync/types.native.js.map +1 -1
  191. package/dist/jsx/sync/virtualPageManager.native.js.map +1 -1
  192. package/dist/jsx/syncOptionsKey.mjs +34 -0
  193. package/dist/jsx/syncOptionsKey.mjs.map +1 -0
  194. package/dist/jsx/syncOptionsKey.native.js +82 -0
  195. package/dist/jsx/syncOptionsKey.native.js.map +1 -0
  196. package/dist/jsx/useLiveQuery.mjs +1 -19
  197. package/dist/jsx/useLiveQuery.mjs.map +1 -1
  198. package/dist/jsx/useLiveQuery.native.js +1 -22
  199. package/dist/jsx/useLiveQuery.native.js.map +1 -1
  200. package/dist/jsx/util.native.js.map +1 -1
  201. package/package.json +12 -12
  202. package/src/doctype.spec.ts +148 -5
  203. package/src/doctype.ts +202 -173
  204. package/src/fixtures.ts +1 -0
  205. package/src/frappeReact.catchUp.spec.tsx +105 -0
  206. package/src/frappeReact.hydration.spec.tsx +164 -0
  207. package/src/frappeReact.spec.ts +56 -0
  208. package/src/frappeReact.ts +93 -43
  209. package/src/index.ts +14 -0
  210. package/src/serverLoaders.ts +77 -0
  211. package/src/sync/catchUp.spec.ts +142 -0
  212. package/src/sync/index.ts +106 -9
  213. package/src/sync/rehydration.ts +5 -0
  214. package/src/sync/syncModule.spec.ts +20 -0
  215. package/src/sync/types.ts +9 -1
  216. package/src/syncOptionsKey.spec.ts +46 -0
  217. package/src/syncOptionsKey.ts +45 -0
  218. package/src/useLiveQuery.hydration.spec.tsx +129 -0
  219. package/src/useLiveQuery.spec.ts +3 -11
  220. package/src/useLiveQuery.ts +3 -57
  221. package/types/doctype.d.ts +117 -33
  222. package/types/doctype.d.ts.map +1 -1
  223. package/types/fixtures.d.ts.map +1 -1
  224. package/types/frappeReact.d.ts +9 -3
  225. package/types/frappeReact.d.ts.map +1 -1
  226. package/types/index.d.ts +6 -5
  227. package/types/index.d.ts.map +1 -1
  228. package/types/serverLoaders.d.ts +40 -0
  229. package/types/serverLoaders.d.ts.map +1 -0
  230. package/types/sync/index.d.ts +15 -1
  231. package/types/sync/index.d.ts.map +1 -1
  232. package/types/sync/rehydration.d.ts +2 -0
  233. package/types/sync/rehydration.d.ts.map +1 -1
  234. package/types/sync/types.d.ts +8 -1
  235. package/types/sync/types.d.ts.map +1 -1
  236. package/types/syncOptionsKey.d.ts +3 -0
  237. package/types/syncOptionsKey.d.ts.map +1 -0
  238. package/types/useLiveQuery.d.ts +3 -13
  239. package/types/useLiveQuery.d.ts.map +1 -1
@@ -2,8 +2,11 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import { act, renderHook, waitFor } from "@testing-library/react";
3
3
  import type { DocTypeField, FrappeFieldType } from "./doctype";
4
4
  import {
5
+ customFieldTypes,
6
+ frappeFieldTypes,
5
7
  parseDependsOn,
6
8
  parseFormLayout,
9
+ stockFieldTypes,
7
10
  useDocTypeMeta,
8
11
  useLinkSearch,
9
12
  useLinkTitle,
@@ -53,6 +56,18 @@ describe("FrappeFieldType", () => {
53
56
  const action = field("make_payment_entry", "Button", { label: "Make Payment Entry" });
54
57
  expect(action.fieldtype).toBe("Button");
55
58
  });
59
+
60
+ it("is the one list of fieldtypes: every stock type plus the registry's custom ones", () => {
61
+ expect(frappeFieldTypes).toEqual([...stockFieldTypes, ...customFieldTypes]);
62
+ expect(new Set(frappeFieldTypes).size).toBe(frappeFieldTypes.length);
63
+ expect(stockFieldTypes).toContain("Fold");
64
+ expect(stockFieldTypes).toHaveLength(43);
65
+ const fold: FrappeFieldType = "Fold";
66
+ const toggle: FrappeFieldType = "Toggle Group";
67
+ expect([fold, toggle].every((t) => frappeFieldTypes.includes(t))).toBe(true);
68
+ // @ts-expect-error a fieldtype outside the union is not a DocTypeField
69
+ field("bogus", "Not A Fieldtype");
70
+ });
56
71
  });
57
72
 
58
73
  // ---------------------------------------------------------------------------
@@ -141,7 +156,7 @@ describe("parseFormLayout", () => {
141
156
  });
142
157
 
143
158
  it("skips hidden fields", () => {
144
- const fields = [field("visible", "Data"), field("secret", "Data", { hidden: true })];
159
+ const fields = [field("visible", "Data"), field("secret", "Data", { hidden: 1 })];
145
160
  const sections = parseFormLayout(fields);
146
161
  expect(sections[0].columns[0].fields).toHaveLength(1);
147
162
  expect(sections[0].columns[0].fields[0].fieldname).toBe("visible");
@@ -150,7 +165,7 @@ describe("parseFormLayout", () => {
150
165
  it("starts a new section on Section Break", () => {
151
166
  const fields = [
152
167
  field("field1", "Data"),
153
- field("sec", "Section Break", { label: "Details", collapsible: true }),
168
+ field("sec", "Section Break", { label: "Details", collapsible: 1 }),
154
169
  field("field2", "Data"),
155
170
  ];
156
171
  const sections = parseFormLayout(fields);
@@ -227,7 +242,7 @@ describe("parseFormLayout", () => {
227
242
 
228
243
  it("drops a leading section whose fields are all hidden", () => {
229
244
  const fields = [
230
- field("secret", "Data", { hidden: true }),
245
+ field("secret", "Data", { hidden: 1 }),
231
246
  field("sec", "Section Break", { label: "Details" }),
232
247
  field("field1", "Data"),
233
248
  ];
@@ -250,7 +265,7 @@ describe("parseFormLayout", () => {
250
265
  });
251
266
 
252
267
  it("keeps one section for a fieldless doctype", () => {
253
- const sections = parseFormLayout([field("secret", "Data", { hidden: true })]);
268
+ const sections = parseFormLayout([field("secret", "Data", { hidden: 1 })]);
254
269
  expect(sections).toHaveLength(1);
255
270
  expect(sections[0].columns[0].fields).toHaveLength(0);
256
271
  });
@@ -295,7 +310,58 @@ describe("useDocTypeMeta", () => {
295
310
  expect(result.current.meta).toBeDefined();
296
311
  expect(result.current.meta!.name).toBe(doctype);
297
312
  expect(result.current.meta!.fields).toHaveLength(2);
298
- expect(result.current.meta!.permissions[0].read).toBe(true);
313
+ expect(result.current.meta!.permissions?.[0]?.read).toBe(1);
314
+ });
315
+
316
+ // FrappeForm read this hook's meta, and the old parse copied seventeen keys
317
+ // and dropped the rest, so permlevel, fetch_from, set_only_once and the
318
+ // *_depends_on chains never reached a form. The meta is the server's own
319
+ // now, keys and 0|1 flags alike.
320
+ it("keeps every key the server sends, on the fields and on the meta", async () => {
321
+ const doctype = `DocLossless${testId}`;
322
+ const config = { baseURL: `https://meta-lossless-${testId}.example.com` };
323
+ const raw = {
324
+ ...rawDocType(doctype),
325
+ is_submittable: 1,
326
+ links: [{ link_doctype: "Payment Entry", link_fieldname: "reference_name", group: null }],
327
+ fields: [
328
+ {
329
+ fieldname: "customer",
330
+ fieldtype: "Link",
331
+ options: "Customer",
332
+ reqd: 1,
333
+ set_only_once: 1,
334
+ permlevel: 1,
335
+ },
336
+ { fieldname: "customer_name", fieldtype: "Data", fetch_from: "customer.customer_name" },
337
+ {
338
+ fieldname: "po_no",
339
+ fieldtype: "Data",
340
+ mandatory_depends_on: "eval:doc.is_export",
341
+ read_only_depends_on: "eval:doc.docstatus==1",
342
+ allow_on_submit: 1,
343
+ },
344
+ { fieldname: "more", fieldtype: "Section Break", collapsible_depends_on: "po_no" },
345
+ ],
346
+ };
347
+ mockGetFn.mockResolvedValueOnce({ payload: { docs: [raw] } });
348
+
349
+ const { result } = renderHook(() => useDocTypeMeta(config, doctype));
350
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
351
+
352
+ const meta = result.current.meta!;
353
+ expect(meta.is_submittable).toBe(1);
354
+ expect(meta.links?.[0]?.link_doctype).toBe("Payment Entry");
355
+ const byName = Object.fromEntries(meta.fields.map((f) => [f.fieldname, f]));
356
+ expect(byName.customer).toMatchObject({ reqd: 1, set_only_once: 1, permlevel: 1 });
357
+ expect(byName.customer_name.fetch_from).toBe("customer.customer_name");
358
+ expect(byName.po_no).toMatchObject({
359
+ mandatory_depends_on: "eval:doc.is_export",
360
+ read_only_depends_on: "eval:doc.docstatus==1",
361
+ allow_on_submit: 1,
362
+ });
363
+ expect(byName.more.collapsible_depends_on).toBe("po_no");
364
+ expect(meta.fields[0]).not.toBe(raw.fields[0]);
299
365
  });
300
366
 
301
367
  // The REST route reads the DocType *document* — System-Manager-only, so
@@ -391,6 +457,83 @@ describe("useDocTypeMeta", () => {
391
457
  expect(result.current.error!.message).toBe("Not found");
392
458
  });
393
459
 
460
+ // MPO-322: getdoctype and the DocType document are closed to Guest, so a
461
+ // signed-out visitor's meta read was a certain 403 in the browser log.
462
+ describe("signed out", () => {
463
+ const signedOut = { useToken: true, type: "Bearer", token: async () => "" };
464
+
465
+ afterEach(() => {
466
+ document.cookie = "user_id=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
467
+ });
468
+
469
+ it("never asks for meta when the token source resolves empty", async () => {
470
+ const doctype = `DocGuest${testId}`;
471
+ const config = { baseURL: `https://meta-guest-${testId}.example.com`, auth: signedOut };
472
+
473
+ const { result } = renderHook(() => useDocTypeMeta(config, doctype));
474
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
475
+
476
+ expect(mockGetFn).not.toHaveBeenCalled();
477
+ expect(result.current.meta).toBeUndefined();
478
+ expect(result.current.error).toMatchObject({ status: 403 });
479
+ });
480
+
481
+ it("still reads fixture meta", async () => {
482
+ const doctype = `DocGuestFix${testId}`;
483
+ const fixtures = {
484
+ getDoc: vi.fn(async () => rawDocType(doctype)),
485
+ } as unknown as NonNullable<Parameters<typeof useDocTypeMeta>[0]>["fixtures"];
486
+ const config = {
487
+ baseURL: `https://meta-guest-fix-${testId}.example.com`,
488
+ auth: signedOut,
489
+ fixtures,
490
+ };
491
+
492
+ const { result } = renderHook(() => useDocTypeMeta(config, doctype));
493
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
494
+
495
+ expect(result.current.meta!.name).toBe(doctype);
496
+ expect(mockGetFn).not.toHaveBeenCalled();
497
+ });
498
+
499
+ it("asks when a token resolves", async () => {
500
+ const doctype = `DocSignedIn${testId}`;
501
+ const config = {
502
+ baseURL: `https://meta-signed-in-${testId}.example.com`,
503
+ auth: { ...signedOut, token: async () => "jwt" },
504
+ };
505
+ mockGetFn.mockResolvedValueOnce({ payload: { docs: [rawDocType(doctype)] } });
506
+
507
+ const { result } = renderHook(() => useDocTypeMeta(config, doctype));
508
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
509
+
510
+ expect(result.current.meta!.name).toBe(doctype);
511
+ });
512
+
513
+ it("asks when a Frappe desk session names a user", async () => {
514
+ document.cookie = "user_id=desk%40example.com; path=/";
515
+ const doctype = `DocDesk${testId}`;
516
+ const config = { baseURL: `https://meta-desk-${testId}.example.com`, auth: signedOut };
517
+ mockGetFn.mockResolvedValueOnce({ payload: { docs: [rawDocType(doctype)] } });
518
+
519
+ const { result } = renderHook(() => useDocTypeMeta(config, doctype));
520
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
521
+
522
+ expect(result.current.meta!.name).toBe(doctype);
523
+ });
524
+
525
+ it("asks on a cookie connection, which names no token source", async () => {
526
+ const doctype = `DocCookie${testId}`;
527
+ const config = { baseURL: `https://meta-cookie-${testId}.example.com` };
528
+ mockGetFn.mockRejectedValueOnce(Object.assign(new Error("Not permitted"), { status: 403 }));
529
+
530
+ const { result } = renderHook(() => useDocTypeMeta(config, doctype));
531
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
532
+
533
+ expect(mockGetFn).toHaveBeenCalledTimes(1);
534
+ });
535
+ });
536
+
394
537
  it("returns undefined meta and isLoading=false when config is undefined", () => {
395
538
  const { result } = renderHook(() => useDocTypeMeta(undefined, "AnyDoc"));
396
539