@fhirust/sdk 0.2.0 → 0.3.1

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 (208) hide show
  1. package/README.md +430 -0
  2. package/dist/bin/cli.d.ts +1 -0
  3. package/dist/bin/cli.d.ts.map +1 -1
  4. package/dist/bin/cli.js +167 -3
  5. package/dist/bin/cli.js.map +1 -1
  6. package/dist/plugin.d.ts +5 -2
  7. package/dist/plugin.d.ts.map +1 -1
  8. package/dist/plugin.js +15 -7
  9. package/dist/plugin.js.map +1 -1
  10. package/dist/r4/allergy-intolerance.d.ts +10 -10
  11. package/dist/r4/allergy-intolerance.d.ts.map +1 -1
  12. package/dist/r4/appointment-response.d.ts +16 -0
  13. package/dist/r4/appointment-response.d.ts.map +1 -0
  14. package/dist/r4/appointment-response.js +2 -0
  15. package/dist/r4/appointment-response.js.map +1 -0
  16. package/dist/r4/appointment.d.ts +37 -0
  17. package/dist/r4/appointment.d.ts.map +1 -0
  18. package/dist/r4/appointment.js +2 -0
  19. package/dist/r4/appointment.js.map +1 -0
  20. package/dist/r4/care-plan.d.ts +59 -0
  21. package/dist/r4/care-plan.d.ts.map +1 -0
  22. package/dist/r4/care-plan.js +2 -0
  23. package/dist/r4/care-plan.js.map +1 -0
  24. package/dist/r4/care-team.d.ts +27 -0
  25. package/dist/r4/care-team.d.ts.map +1 -0
  26. package/dist/r4/care-team.js +2 -0
  27. package/dist/r4/care-team.js.map +1 -0
  28. package/dist/r4/claim-response.d.ts +123 -0
  29. package/dist/r4/claim-response.d.ts.map +1 -0
  30. package/dist/r4/claim-response.js +2 -0
  31. package/dist/r4/claim-response.js.map +1 -0
  32. package/dist/r4/claim.d.ts +146 -0
  33. package/dist/r4/claim.d.ts.map +1 -0
  34. package/dist/r4/claim.js +2 -0
  35. package/dist/r4/claim.js.map +1 -0
  36. package/dist/r4/common.d.ts +82 -0
  37. package/dist/r4/common.d.ts.map +1 -1
  38. package/dist/r4/communication-request.d.ts +36 -0
  39. package/dist/r4/communication-request.d.ts.map +1 -0
  40. package/dist/r4/communication-request.js +2 -0
  41. package/dist/r4/communication-request.js.map +1 -0
  42. package/dist/r4/communication.d.ts +36 -0
  43. package/dist/r4/communication.d.ts.map +1 -0
  44. package/dist/r4/communication.js +2 -0
  45. package/dist/r4/communication.js.map +1 -0
  46. package/dist/r4/composition.d.ts +49 -0
  47. package/dist/r4/composition.d.ts.map +1 -0
  48. package/dist/r4/composition.js +2 -0
  49. package/dist/r4/composition.js.map +1 -0
  50. package/dist/r4/condition.d.ts +7 -7
  51. package/dist/r4/condition.d.ts.map +1 -1
  52. package/dist/r4/coverage.d.ts +39 -0
  53. package/dist/r4/coverage.d.ts.map +1 -0
  54. package/dist/r4/coverage.js +2 -0
  55. package/dist/r4/coverage.js.map +1 -0
  56. package/dist/r4/device-request.d.ts +42 -0
  57. package/dist/r4/device-request.d.ts.map +1 -0
  58. package/dist/r4/device-request.js +2 -0
  59. package/dist/r4/device-request.js.map +1 -0
  60. package/dist/r4/device-use-statement.d.ts +23 -0
  61. package/dist/r4/device-use-statement.d.ts.map +1 -0
  62. package/dist/r4/device-use-statement.js +2 -0
  63. package/dist/r4/device-use-statement.js.map +1 -0
  64. package/dist/r4/device.d.ts +60 -0
  65. package/dist/r4/device.d.ts.map +1 -0
  66. package/dist/r4/device.js +2 -0
  67. package/dist/r4/device.js.map +1 -0
  68. package/dist/r4/diagnostic-report.d.ts +4 -4
  69. package/dist/r4/diagnostic-report.d.ts.map +1 -1
  70. package/dist/r4/document-reference.d.ts +41 -0
  71. package/dist/r4/document-reference.d.ts.map +1 -0
  72. package/dist/r4/document-reference.js +2 -0
  73. package/dist/r4/document-reference.js.map +1 -0
  74. package/dist/r4/encounter.d.ts +7 -7
  75. package/dist/r4/encounter.d.ts.map +1 -1
  76. package/dist/r4/episode-of-care.d.ts +29 -0
  77. package/dist/r4/episode-of-care.d.ts.map +1 -0
  78. package/dist/r4/episode-of-care.js +2 -0
  79. package/dist/r4/episode-of-care.js.map +1 -0
  80. package/dist/r4/flag.d.ts +16 -0
  81. package/dist/r4/flag.d.ts.map +1 -0
  82. package/dist/r4/flag.js +2 -0
  83. package/dist/r4/flag.js.map +1 -0
  84. package/dist/r4/goal.d.ts +37 -0
  85. package/dist/r4/goal.d.ts.map +1 -0
  86. package/dist/r4/goal.js +2 -0
  87. package/dist/r4/goal.js.map +1 -0
  88. package/dist/r4/imaging-study.d.ts +50 -0
  89. package/dist/r4/imaging-study.d.ts.map +1 -0
  90. package/dist/r4/imaging-study.js +2 -0
  91. package/dist/r4/imaging-study.js.map +1 -0
  92. package/dist/r4/immunization.d.ts +61 -0
  93. package/dist/r4/immunization.d.ts.map +1 -0
  94. package/dist/r4/immunization.js +2 -0
  95. package/dist/r4/immunization.js.map +1 -0
  96. package/dist/r4/index.d.ts +47 -11
  97. package/dist/r4/index.d.ts.map +1 -1
  98. package/dist/r4/index.js +47 -1
  99. package/dist/r4/index.js.map +1 -1
  100. package/dist/r4/location.d.ts +36 -0
  101. package/dist/r4/location.d.ts.map +1 -0
  102. package/dist/r4/location.js +2 -0
  103. package/dist/r4/location.js.map +1 -0
  104. package/dist/r4/media.d.ts +31 -0
  105. package/dist/r4/media.d.ts.map +1 -0
  106. package/dist/r4/media.js +2 -0
  107. package/dist/r4/media.js.map +1 -0
  108. package/dist/r4/medication-administration.d.ts +42 -0
  109. package/dist/r4/medication-administration.d.ts.map +1 -0
  110. package/dist/r4/medication-administration.js +2 -0
  111. package/dist/r4/medication-administration.js.map +1 -0
  112. package/dist/r4/medication-dispense.d.ts +44 -0
  113. package/dist/r4/medication-dispense.d.ts.map +1 -0
  114. package/dist/r4/medication-dispense.js +2 -0
  115. package/dist/r4/medication-dispense.js.map +1 -0
  116. package/dist/r4/medication-request.d.ts +21 -16
  117. package/dist/r4/medication-request.d.ts.map +1 -1
  118. package/dist/r4/medication-statement.d.ts +27 -0
  119. package/dist/r4/medication-statement.d.ts.map +1 -0
  120. package/dist/r4/medication-statement.js +2 -0
  121. package/dist/r4/medication-statement.js.map +1 -0
  122. package/dist/r4/medication.d.ts +26 -0
  123. package/dist/r4/medication.d.ts.map +1 -0
  124. package/dist/r4/medication.js +2 -0
  125. package/dist/r4/medication.js.map +1 -0
  126. package/dist/r4/observation.d.ts +21 -17
  127. package/dist/r4/observation.d.ts.map +1 -1
  128. package/dist/r4/organization.d.ts +1 -1
  129. package/dist/r4/organization.d.ts.map +1 -1
  130. package/dist/r4/patient.d.ts +15 -15
  131. package/dist/r4/patient.d.ts.map +1 -1
  132. package/dist/r4/person.d.ts +22 -0
  133. package/dist/r4/person.d.ts.map +1 -0
  134. package/dist/r4/person.js +2 -0
  135. package/dist/r4/person.js.map +1 -0
  136. package/dist/r4/practitioner-role.d.ts +32 -0
  137. package/dist/r4/practitioner-role.d.ts.map +1 -0
  138. package/dist/r4/practitioner-role.js +2 -0
  139. package/dist/r4/practitioner-role.js.map +1 -0
  140. package/dist/r4/practitioner.d.ts +2 -2
  141. package/dist/r4/practitioner.d.ts.map +1 -1
  142. package/dist/r4/procedure.d.ts +14 -7
  143. package/dist/r4/procedure.d.ts.map +1 -1
  144. package/dist/r4/related-person.d.ts +24 -0
  145. package/dist/r4/related-person.d.ts.map +1 -0
  146. package/dist/r4/related-person.js +2 -0
  147. package/dist/r4/related-person.js.map +1 -0
  148. package/dist/r4/risk-assessment.d.ts +36 -0
  149. package/dist/r4/risk-assessment.d.ts.map +1 -0
  150. package/dist/r4/risk-assessment.js +2 -0
  151. package/dist/r4/risk-assessment.js.map +1 -0
  152. package/dist/r4/schedule.d.ts +16 -0
  153. package/dist/r4/schedule.d.ts.map +1 -0
  154. package/dist/r4/schedule.js +2 -0
  155. package/dist/r4/schedule.js.map +1 -0
  156. package/dist/r4/service-request.d.ts +46 -0
  157. package/dist/r4/service-request.d.ts.map +1 -0
  158. package/dist/r4/service-request.js +2 -0
  159. package/dist/r4/service-request.js.map +1 -0
  160. package/dist/r4/slot.d.ts +19 -0
  161. package/dist/r4/slot.d.ts.map +1 -0
  162. package/dist/r4/slot.js +2 -0
  163. package/dist/r4/slot.js.map +1 -0
  164. package/dist/r4/specimen.d.ts +48 -0
  165. package/dist/r4/specimen.d.ts.map +1 -0
  166. package/dist/r4/specimen.js +2 -0
  167. package/dist/r4/specimen.js.map +1 -0
  168. package/dist/r4/task.d.ts +150 -0
  169. package/dist/r4/task.d.ts.map +1 -0
  170. package/dist/r4/task.js +2 -0
  171. package/dist/r4/task.js.map +1 -0
  172. package/dist/testing/__tests__/test-harness.test.d.ts +15 -0
  173. package/dist/testing/__tests__/test-harness.test.d.ts.map +1 -0
  174. package/dist/testing/__tests__/test-harness.test.js +416 -0
  175. package/dist/testing/__tests__/test-harness.test.js.map +1 -0
  176. package/dist/testing/index.d.ts +37 -0
  177. package/dist/testing/index.d.ts.map +1 -0
  178. package/dist/testing/index.js +76 -0
  179. package/dist/testing/index.js.map +1 -0
  180. package/dist/testing/mock-fhir.d.ts +38 -0
  181. package/dist/testing/mock-fhir.d.ts.map +1 -0
  182. package/dist/testing/mock-fhir.js +113 -0
  183. package/dist/testing/mock-fhir.js.map +1 -0
  184. package/dist/testing/mock-http.d.ts +31 -0
  185. package/dist/testing/mock-http.d.ts.map +1 -0
  186. package/dist/testing/mock-http.js +52 -0
  187. package/dist/testing/mock-http.js.map +1 -0
  188. package/dist/testing/mock-utils.d.ts +15 -0
  189. package/dist/testing/mock-utils.d.ts.map +1 -0
  190. package/dist/testing/mock-utils.js +17 -0
  191. package/dist/testing/mock-utils.js.map +1 -0
  192. package/dist/testing/simulator.d.ts +21 -0
  193. package/dist/testing/simulator.d.ts.map +1 -0
  194. package/dist/testing/simulator.js +74 -0
  195. package/dist/testing/simulator.js.map +1 -0
  196. package/dist/testing/types.d.ts +81 -0
  197. package/dist/testing/types.d.ts.map +1 -0
  198. package/dist/testing/types.js +8 -0
  199. package/dist/testing/types.js.map +1 -0
  200. package/dist/types.d.ts +10 -7
  201. package/dist/types.d.ts.map +1 -1
  202. package/dist/types.js +0 -22
  203. package/dist/types.js.map +1 -1
  204. package/package.json +7 -1
  205. package/templates/docker-compose.yml +32 -0
  206. package/templates/gitignore +4 -0
  207. package/wit/plugin.wit +4 -16
  208. package/wit/world.wit +1 -1
@@ -0,0 +1,416 @@
1
+ /**
2
+ * Comprehensive tests for @fhirust/sdk/testing — the plugin test harness.
3
+ *
4
+ * Tests cover:
5
+ * - createTestPlugin factory shape
6
+ * - Hook dispatch (beforeCreate with modifications, rejections, pass-through)
7
+ * - HookContext auto-generation and overrides
8
+ * - Mock FHIR backend (read, search, create, not-found errors)
9
+ * - Mock HTTP backend (configured responses, unmatched URL errors)
10
+ * - Log capture at all levels
11
+ * - Event capture
12
+ * - Exception handling in hooks
13
+ */
14
+ import { describe, it } from "node:test";
15
+ import assert from "node:assert/strict";
16
+ import { createTestPlugin } from "../index.js";
17
+ import { reject } from "../../helpers.js";
18
+ import { FhirClientError } from "../../fhir-client.js";
19
+ import { HttpClientError } from "../../http-client.js";
20
+ // ---------------------------------------------------------------------------
21
+ // 1. createTestPlugin returns all expected properties
22
+ // ---------------------------------------------------------------------------
23
+ describe("createTestPlugin", () => {
24
+ it("returns all expected properties", () => {
25
+ const ctx = createTestPlugin("test-plugin", "1.0.0");
26
+ assert.ok(ctx.plugin, "plugin should be defined");
27
+ assert.ok(ctx.simulate, "simulate should be defined");
28
+ assert.ok(Array.isArray(ctx.logs), "logs should be an array");
29
+ assert.ok(Array.isArray(ctx.events), "events should be an array");
30
+ assert.ok(Array.isArray(ctx.fhirCalls), "fhirCalls should be an array");
31
+ assert.ok(Array.isArray(ctx.httpCalls), "httpCalls should be an array");
32
+ // Verify simulate has the expected methods
33
+ assert.equal(typeof ctx.simulate.beforeCreate, "function");
34
+ assert.equal(typeof ctx.simulate.afterCreate, "function");
35
+ assert.equal(typeof ctx.simulate.beforeRead, "function");
36
+ assert.equal(typeof ctx.simulate.afterRead, "function");
37
+ assert.equal(typeof ctx.simulate.beforeUpdate, "function");
38
+ assert.equal(typeof ctx.simulate.afterUpdate, "function");
39
+ assert.equal(typeof ctx.simulate.beforeDelete, "function");
40
+ assert.equal(typeof ctx.simulate.afterDelete, "function");
41
+ });
42
+ });
43
+ // ---------------------------------------------------------------------------
44
+ // 2. simulate.beforeCreate dispatches to registered hook and returns modified resource
45
+ // ---------------------------------------------------------------------------
46
+ describe("simulate.beforeCreate — modification", () => {
47
+ it("dispatches to registered hook and returns modified resource", () => {
48
+ const { plugin, simulate } = createTestPlugin("tag-plugin", "1.0.0");
49
+ plugin.beforeCreate("Patient", (patient, _ctx) => {
50
+ // Add a meta tag
51
+ const tagged = {
52
+ ...patient,
53
+ meta: {
54
+ tag: [
55
+ ...(patient.meta?.tag ?? []),
56
+ { system: "http://example.com/test", code: "validated" },
57
+ ],
58
+ },
59
+ };
60
+ return tagged;
61
+ });
62
+ const input = {
63
+ resourceType: "Patient",
64
+ id: "123",
65
+ name: [{ family: "Smith" }],
66
+ };
67
+ const result = simulate.beforeCreate("Patient", input);
68
+ assert.equal(result.ok, true);
69
+ if (result.ok) {
70
+ assert.equal(result.resource.resourceType, "Patient");
71
+ assert.equal(result.resource.id, "123");
72
+ assert.ok(result.resource.meta?.tag, "should have meta.tag");
73
+ assert.equal(result.resource.meta.tag.length, 1);
74
+ assert.equal(result.resource.meta.tag[0].code, "validated");
75
+ }
76
+ });
77
+ });
78
+ // ---------------------------------------------------------------------------
79
+ // 3. simulate.beforeCreate returns rejection when hook calls reject()
80
+ // ---------------------------------------------------------------------------
81
+ describe("simulate.beforeCreate — rejection", () => {
82
+ it("returns rejection when hook calls reject()", () => {
83
+ const { plugin, simulate } = createTestPlugin("reject-plugin", "1.0.0");
84
+ plugin.beforeCreate("Patient", (patient, _ctx) => {
85
+ if (!patient.name || patient.name.length === 0) {
86
+ return reject("Patient must have at least one name", "required");
87
+ }
88
+ return patient;
89
+ });
90
+ const input = {
91
+ resourceType: "Patient",
92
+ id: "no-name",
93
+ // no name field
94
+ };
95
+ const result = simulate.beforeCreate("Patient", input);
96
+ assert.equal(result.ok, false);
97
+ if (!result.ok) {
98
+ assert.equal(result.outcome.resourceType, "OperationOutcome");
99
+ assert.equal(result.outcome.issue.length, 1);
100
+ assert.equal(result.outcome.issue[0].code, "required");
101
+ assert.equal(result.outcome.issue[0].severity, "error");
102
+ assert.equal(result.outcome.issue[0].diagnostics, "Patient must have at least one name");
103
+ }
104
+ });
105
+ });
106
+ // ---------------------------------------------------------------------------
107
+ // 4. Pass-through when no handler for the resource type
108
+ // ---------------------------------------------------------------------------
109
+ describe("simulate.beforeCreate — pass-through", () => {
110
+ it("passes through when no handler for the resource type", () => {
111
+ const { plugin, simulate } = createTestPlugin("obs-only-plugin", "1.0.0");
112
+ // Register a hook for Observation only
113
+ plugin.beforeCreate("Observation", (obs, _ctx) => {
114
+ return { ...obs, status: "final" };
115
+ });
116
+ // Simulate beforeCreate for Patient (no handler registered)
117
+ const input = {
118
+ resourceType: "Patient",
119
+ id: "456",
120
+ name: [{ family: "Doe" }],
121
+ };
122
+ const result = simulate.beforeCreate("Patient", input);
123
+ assert.equal(result.ok, true);
124
+ if (result.ok) {
125
+ // Resource should be unchanged (pass-through)
126
+ assert.equal(result.resource.resourceType, "Patient");
127
+ assert.equal(result.resource.id, "456");
128
+ assert.deepEqual(result.resource.name, [{ family: "Doe" }]);
129
+ }
130
+ });
131
+ });
132
+ // ---------------------------------------------------------------------------
133
+ // 5. Auto-generates HookContext with requestId and timestamp
134
+ // ---------------------------------------------------------------------------
135
+ describe("HookContext — auto-generation", () => {
136
+ it("auto-generates requestId, timestamp, and operation", () => {
137
+ const { plugin, simulate } = createTestPlugin("ctx-plugin", "1.0.0");
138
+ let capturedCtx = null;
139
+ plugin.beforeCreate("Patient", (patient, ctx) => {
140
+ capturedCtx = ctx;
141
+ return patient;
142
+ });
143
+ simulate.beforeCreate("Patient", {
144
+ resourceType: "Patient",
145
+ id: "ctx-test",
146
+ });
147
+ assert.ok(capturedCtx, "context should have been captured");
148
+ assert.ok(capturedCtx.requestId, "requestId should be auto-generated");
149
+ assert.equal(typeof capturedCtx.requestId, "string");
150
+ assert.ok(capturedCtx.requestId.length > 0, "requestId should not be empty");
151
+ assert.ok(capturedCtx.timestamp, "timestamp should be auto-generated");
152
+ // Verify it's a valid ISO date string
153
+ const parsed = Date.parse(capturedCtx.timestamp);
154
+ assert.ok(!isNaN(parsed), "timestamp should be a valid date string");
155
+ assert.equal(capturedCtx.operation, "test", "default operation should be 'test'");
156
+ });
157
+ });
158
+ // ---------------------------------------------------------------------------
159
+ // 6. Allows overriding HookContext fields
160
+ // ---------------------------------------------------------------------------
161
+ describe("HookContext — overrides", () => {
162
+ it("allows overriding requestId and userId", () => {
163
+ const { plugin, simulate } = createTestPlugin("ctx-override-plugin", "1.0.0");
164
+ let capturedCtx = null;
165
+ plugin.beforeCreate("Patient", (patient, ctx) => {
166
+ capturedCtx = ctx;
167
+ return patient;
168
+ });
169
+ simulate.beforeCreate("Patient", { resourceType: "Patient", id: "override-test" }, { requestId: "custom-req-id-42", userId: "dr-house" });
170
+ assert.ok(capturedCtx, "context should have been captured");
171
+ assert.equal(capturedCtx.requestId, "custom-req-id-42");
172
+ assert.equal(capturedCtx.userId, "dr-house");
173
+ });
174
+ });
175
+ // ---------------------------------------------------------------------------
176
+ // 7. Mock FHIR read returns pre-loaded data
177
+ // ---------------------------------------------------------------------------
178
+ describe("Mock FHIR — read", () => {
179
+ it("returns pre-loaded data and records fhirCalls", () => {
180
+ const patientData = {
181
+ resourceType: "Patient",
182
+ id: "123",
183
+ name: [{ family: "Smith" }],
184
+ active: true,
185
+ };
186
+ const { plugin, simulate, fhirCalls } = createTestPlugin("fhir-read-plugin", "1.0.0", {
187
+ fhir: { "Patient/123": patientData },
188
+ });
189
+ let readResult = null;
190
+ plugin.beforeCreate("Observation", (obs, _ctx) => {
191
+ // Inside hook, use plugin.fhir.read to fetch the patient
192
+ readResult = plugin.fhir.read("Patient", "123");
193
+ return obs;
194
+ });
195
+ simulate.beforeCreate("Observation", {
196
+ resourceType: "Observation",
197
+ id: "obs-1",
198
+ status: "preliminary",
199
+ });
200
+ // Verify the read returned correct data
201
+ assert.ok(readResult, "read result should be defined");
202
+ assert.equal(readResult.resourceType, "Patient");
203
+ assert.equal(readResult.id, "123");
204
+ assert.equal(readResult.active, true);
205
+ assert.deepEqual(readResult.name, [{ family: "Smith" }]);
206
+ // Verify fhirCalls were recorded
207
+ assert.equal(fhirCalls.length, 1);
208
+ assert.equal(fhirCalls[0].method, "read");
209
+ assert.deepEqual(fhirCalls[0].args[0], "Patient");
210
+ assert.deepEqual(fhirCalls[0].args[1], "123");
211
+ });
212
+ });
213
+ // ---------------------------------------------------------------------------
214
+ // 8. Mock FHIR read throws FhirClientError when not found
215
+ // ---------------------------------------------------------------------------
216
+ describe("Mock FHIR — read not found", () => {
217
+ it("throws FhirClientError when resource does not exist", () => {
218
+ const { plugin, simulate } = createTestPlugin("fhir-404-plugin", "1.0.0");
219
+ let caughtError = null;
220
+ plugin.beforeCreate("Observation", (obs, _ctx) => {
221
+ try {
222
+ plugin.fhir.read("Patient", "999");
223
+ }
224
+ catch (err) {
225
+ caughtError = err;
226
+ }
227
+ return obs;
228
+ });
229
+ simulate.beforeCreate("Observation", {
230
+ resourceType: "Observation",
231
+ id: "obs-2",
232
+ });
233
+ assert.ok(caughtError, "should have caught an error");
234
+ assert.ok(caughtError instanceof FhirClientError, "should be a FhirClientError");
235
+ assert.equal(caughtError.name, "FhirClientError");
236
+ assert.ok(caughtError.outcome.issue[0].diagnostics?.includes("not found"), "diagnostics should mention not found");
237
+ });
238
+ });
239
+ // ---------------------------------------------------------------------------
240
+ // 9. Mock FHIR search returns matching resources
241
+ // ---------------------------------------------------------------------------
242
+ describe("Mock FHIR — search", () => {
243
+ it("returns matching resources filtered by params", () => {
244
+ const { plugin, simulate } = createTestPlugin("fhir-search-plugin", "1.0.0", {
245
+ fhir: {
246
+ "Patient/p1": { resourceType: "Patient", id: "p1", gender: "male" },
247
+ "Patient/p2": { resourceType: "Patient", id: "p2", gender: "female" },
248
+ "Patient/p3": { resourceType: "Patient", id: "p3", gender: "male" },
249
+ },
250
+ });
251
+ let searchBundle = null;
252
+ plugin.beforeCreate("Observation", (obs, _ctx) => {
253
+ searchBundle = plugin.fhir.search("Patient", { gender: "male" });
254
+ return obs;
255
+ });
256
+ simulate.beforeCreate("Observation", {
257
+ resourceType: "Observation",
258
+ id: "obs-3",
259
+ });
260
+ assert.ok(searchBundle, "search bundle should be defined");
261
+ assert.equal(searchBundle.resourceType, "Bundle");
262
+ assert.equal(searchBundle.type, "searchset");
263
+ assert.equal(searchBundle.total, 2, "should match 2 male patients");
264
+ assert.equal(searchBundle.entry.length, 2);
265
+ const ids = searchBundle.entry.map((e) => e.resource.id).sort();
266
+ assert.deepEqual(ids, ["p1", "p3"]);
267
+ });
268
+ });
269
+ // ---------------------------------------------------------------------------
270
+ // 10. Mock FHIR create stores and assigns id
271
+ // ---------------------------------------------------------------------------
272
+ describe("Mock FHIR — create", () => {
273
+ it("stores resource and assigns id when missing", () => {
274
+ const { plugin, simulate, fhirCalls } = createTestPlugin("fhir-create-plugin", "1.0.0");
275
+ let created = null;
276
+ plugin.beforeCreate("Patient", (patient, _ctx) => {
277
+ // Create an Observation from inside the hook
278
+ created = plugin.fhir.create("Observation", {
279
+ resourceType: "Observation",
280
+ status: "preliminary",
281
+ });
282
+ return patient;
283
+ });
284
+ simulate.beforeCreate("Patient", {
285
+ resourceType: "Patient",
286
+ id: "trigger",
287
+ });
288
+ assert.ok(created, "created resource should be defined");
289
+ assert.equal(created.resourceType, "Observation");
290
+ assert.ok(created.id, "should have an auto-assigned id");
291
+ assert.equal(typeof created.id, "string");
292
+ assert.ok(created.id.length > 0, "id should not be empty");
293
+ // Verify the create call was recorded
294
+ const createCalls = fhirCalls.filter((c) => c.method === "create");
295
+ assert.equal(createCalls.length, 1);
296
+ });
297
+ });
298
+ // ---------------------------------------------------------------------------
299
+ // 11. Mock HTTP returns configured response
300
+ // ---------------------------------------------------------------------------
301
+ describe("Mock HTTP — configured response", () => {
302
+ it("returns mock response for configured URL", () => {
303
+ const webhookUrl = "https://example.com/webhook";
304
+ const { plugin, simulate, httpCalls } = createTestPlugin("http-plugin", "1.0.0", {
305
+ http: {
306
+ [webhookUrl]: {
307
+ status: 200,
308
+ headers: { "Content-Type": "application/json" },
309
+ body: JSON.stringify({ received: true }),
310
+ },
311
+ },
312
+ });
313
+ let httpResponse = null;
314
+ plugin.beforeCreate("Patient", (patient, _ctx) => {
315
+ httpResponse = plugin.http.post(webhookUrl, {
316
+ body: { event: "patient-created" },
317
+ });
318
+ return patient;
319
+ });
320
+ simulate.beforeCreate("Patient", {
321
+ resourceType: "Patient",
322
+ id: "http-test",
323
+ });
324
+ assert.ok(httpResponse, "http response should be defined");
325
+ assert.equal(httpResponse.status, 200);
326
+ assert.equal(httpResponse.ok, true);
327
+ assert.deepEqual(httpResponse.json(), { received: true });
328
+ // Verify httpCalls were recorded
329
+ assert.equal(httpCalls.length, 1);
330
+ assert.equal(httpCalls[0].method, "fetch");
331
+ });
332
+ });
333
+ // ---------------------------------------------------------------------------
334
+ // 12. Mock HTTP throws for unmatched URL
335
+ // ---------------------------------------------------------------------------
336
+ describe("Mock HTTP — unmatched URL", () => {
337
+ it("throws HttpClientError with helpful message for unknown URL", () => {
338
+ const { plugin, simulate } = createTestPlugin("http-err-plugin", "1.0.0");
339
+ let caughtError = null;
340
+ plugin.beforeCreate("Patient", (patient, _ctx) => {
341
+ try {
342
+ plugin.http.get("https://unknown.com/api");
343
+ }
344
+ catch (err) {
345
+ caughtError = err;
346
+ }
347
+ return patient;
348
+ });
349
+ simulate.beforeCreate("Patient", {
350
+ resourceType: "Patient",
351
+ id: "http-err-test",
352
+ });
353
+ assert.ok(caughtError, "should have caught an error");
354
+ assert.ok(caughtError instanceof HttpClientError, "should be an HttpClientError");
355
+ assert.equal(caughtError.name, "HttpClientError");
356
+ assert.ok(caughtError.message.includes("https://unknown.com/api"), "error should mention the failed URL");
357
+ });
358
+ });
359
+ // ---------------------------------------------------------------------------
360
+ // 13. Log capture at all levels
361
+ // ---------------------------------------------------------------------------
362
+ describe("Log capture", () => {
363
+ it("captures debug, info, warn, and error messages", () => {
364
+ const { plugin, logs } = createTestPlugin("log-plugin", "1.0.0");
365
+ plugin.log.debug("debug message");
366
+ plugin.log.info("info message");
367
+ plugin.log.warn("warn message");
368
+ plugin.log.error("error message");
369
+ assert.equal(logs.length, 4, "should have captured 4 log entries");
370
+ assert.equal(logs[0].level, "debug");
371
+ assert.equal(logs[0].message, "debug message");
372
+ assert.equal(logs[1].level, "info");
373
+ assert.equal(logs[1].message, "info message");
374
+ assert.equal(logs[2].level, "warn");
375
+ assert.equal(logs[2].message, "warn message");
376
+ assert.equal(logs[3].level, "error");
377
+ assert.equal(logs[3].message, "error message");
378
+ });
379
+ });
380
+ // ---------------------------------------------------------------------------
381
+ // 14. Event capture
382
+ // ---------------------------------------------------------------------------
383
+ describe("Event capture", () => {
384
+ it("captures emitted events with type and payload", () => {
385
+ const { plugin, events } = createTestPlugin("event-plugin", "1.0.0");
386
+ plugin.events.emit("patient.validated", { id: "123" });
387
+ assert.equal(events.length, 1, "should have captured 1 event");
388
+ assert.equal(events[0].type, "patient.validated");
389
+ // EventEmitter JSON.stringify's objects
390
+ assert.equal(events[0].payload, JSON.stringify({ id: "123" }));
391
+ });
392
+ });
393
+ // ---------------------------------------------------------------------------
394
+ // 15. Exception handling — hook throws, returns error outcome
395
+ // ---------------------------------------------------------------------------
396
+ describe("Exception handling", () => {
397
+ it("returns error outcome when hook throws an unexpected error", () => {
398
+ const { plugin, simulate } = createTestPlugin("boom-plugin", "1.0.0");
399
+ plugin.beforeCreate("Patient", (_patient, _ctx) => {
400
+ throw new Error("boom");
401
+ });
402
+ const result = simulate.beforeCreate("Patient", {
403
+ resourceType: "Patient",
404
+ id: "boom-test",
405
+ });
406
+ assert.equal(result.ok, false);
407
+ if (!result.ok) {
408
+ assert.equal(result.outcome.resourceType, "OperationOutcome");
409
+ assert.equal(result.outcome.issue.length, 1);
410
+ assert.equal(result.outcome.issue[0].severity, "error");
411
+ assert.equal(result.outcome.issue[0].code, "exception");
412
+ assert.ok(result.outcome.issue[0].diagnostics?.includes("boom"), "diagnostics should contain the error message 'boom'");
413
+ }
414
+ });
415
+ });
416
+ //# sourceMappingURL=test-harness.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-harness.test.js","sourceRoot":"","sources":["../../../src/testing/__tests__/test-harness.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @fhirust/sdk/testing — Test harness for unit-testing FHIRust plugins.
3
+ *
4
+ * Usage:
5
+ * import { createTestPlugin } from "@fhirust/sdk/testing";
6
+ *
7
+ * const { plugin, simulate, logs, fhirCalls } = createTestPlugin("my-plugin", "1.0.0", {
8
+ * fhir: { "Patient/123": { resourceType: "Patient", id: "123", active: true } },
9
+ * });
10
+ *
11
+ * plugin.beforeCreate<Patient>("Patient", (patient, ctx) => {
12
+ * if (!patient.active) return reject("Patient must be active");
13
+ * return patient;
14
+ * });
15
+ *
16
+ * const result = simulate.beforeCreate("Patient", { resourceType: "Patient", active: false });
17
+ * assert(!result.ok); // rejected
18
+ */
19
+ import type { MockConfig, TestPluginContext } from "./types.js";
20
+ /**
21
+ * Create a fully-wired test plugin with mock backends and a hook simulator.
22
+ *
23
+ * The returned `simulate` object is lazy — the simulator is created on first
24
+ * property access, so hooks can be registered on the plugin after calling
25
+ * `createTestPlugin()` but before calling any `simulate.*` method.
26
+ *
27
+ * @param name - Plugin name (e.g., "my-plugin")
28
+ * @param version - Plugin version (e.g., "1.0.0")
29
+ * @param mocks - Optional pre-seeded data for FHIR and HTTP mocks
30
+ */
31
+ export declare function createTestPlugin(name: string, version: string, mocks?: MockConfig): TestPluginContext;
32
+ export type { EventEntry, HookResult, HookSimulator, LogEntry, MockCall, MockConfig, MockHttpResponse, TestPluginContext, } from "./types.js";
33
+ export { MockFhirBackend } from "./mock-fhir.js";
34
+ export { MockHttpBackend } from "./mock-http.js";
35
+ export { MockUtilsBackend } from "./mock-utils.js";
36
+ export { createSimulator } from "./simulator.js";
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH,OAAO,KAAK,EAAiB,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE/E;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,UAAU,GACjB,iBAAiB,CAwCnB;AAGD,YAAY,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @fhirust/sdk/testing — Test harness for unit-testing FHIRust plugins.
3
+ *
4
+ * Usage:
5
+ * import { createTestPlugin } from "@fhirust/sdk/testing";
6
+ *
7
+ * const { plugin, simulate, logs, fhirCalls } = createTestPlugin("my-plugin", "1.0.0", {
8
+ * fhir: { "Patient/123": { resourceType: "Patient", id: "123", active: true } },
9
+ * });
10
+ *
11
+ * plugin.beforeCreate<Patient>("Patient", (patient, ctx) => {
12
+ * if (!patient.active) return reject("Patient must be active");
13
+ * return patient;
14
+ * });
15
+ *
16
+ * const result = simulate.beforeCreate("Patient", { resourceType: "Patient", active: false });
17
+ * assert(!result.ok); // rejected
18
+ */
19
+ import { FhirPlugin } from "../plugin.js";
20
+ import { MockFhirBackend } from "./mock-fhir.js";
21
+ import { MockHttpBackend } from "./mock-http.js";
22
+ import { MockUtilsBackend } from "./mock-utils.js";
23
+ import { createSimulator } from "./simulator.js";
24
+ /**
25
+ * Create a fully-wired test plugin with mock backends and a hook simulator.
26
+ *
27
+ * The returned `simulate` object is lazy — the simulator is created on first
28
+ * property access, so hooks can be registered on the plugin after calling
29
+ * `createTestPlugin()` but before calling any `simulate.*` method.
30
+ *
31
+ * @param name - Plugin name (e.g., "my-plugin")
32
+ * @param version - Plugin version (e.g., "1.0.0")
33
+ * @param mocks - Optional pre-seeded data for FHIR and HTTP mocks
34
+ */
35
+ export function createTestPlugin(name, version, mocks) {
36
+ const plugin = new FhirPlugin(name, version);
37
+ // Create mock backends
38
+ const fhirBackend = new MockFhirBackend(mocks?.fhir);
39
+ const httpBackend = new MockHttpBackend(mocks?.http);
40
+ const utilsBackend = new MockUtilsBackend();
41
+ // Inject mocks into the plugin's service wrappers.
42
+ // These _bind() calls set the backing implementation before any hook runs.
43
+ // When dispatch() later calls bindIfNeeded(), the try/catch for WASM globals
44
+ // will fail silently (we're in Node.js), setting `bound = true` without
45
+ // overwriting our pre-injected mocks.
46
+ plugin.fhir._bind(fhirBackend);
47
+ plugin.http._bind(httpBackend);
48
+ plugin.log._bind(utilsBackend);
49
+ plugin.events._bind(utilsBackend);
50
+ // Lazy simulator via Proxy: the simulator is created on first property access.
51
+ // This allows the caller to register hooks on `plugin` after createTestPlugin()
52
+ // returns, then call simulate.beforeCreate(...) and have those hooks active.
53
+ let cachedSimulator = null;
54
+ const simulate = new Proxy({}, {
55
+ get(_target, prop, receiver) {
56
+ if (!cachedSimulator) {
57
+ cachedSimulator = createSimulator(plugin);
58
+ }
59
+ return Reflect.get(cachedSimulator, prop, receiver);
60
+ },
61
+ });
62
+ return {
63
+ plugin,
64
+ simulate,
65
+ logs: utilsBackend.logs,
66
+ events: utilsBackend.events,
67
+ fhirCalls: fhirBackend.calls,
68
+ httpCalls: httpBackend.calls,
69
+ };
70
+ }
71
+ // Re-export mock classes for advanced usage (custom mock configurations)
72
+ export { MockFhirBackend } from "./mock-fhir.js";
73
+ export { MockHttpBackend } from "./mock-http.js";
74
+ export { MockUtilsBackend } from "./mock-utils.js";
75
+ export { createSimulator } from "./simulator.js";
76
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGjD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,KAAkB;IAElB,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE7C,uBAAuB;IACvB,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,IAAI,gBAAgB,EAAE,CAAC;IAE5C,mDAAmD;IACnD,2EAA2E;IAC3E,6EAA6E;IAC7E,wEAAwE;IACxE,sCAAsC;IACtC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC/B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC/B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAElC,+EAA+E;IAC/E,gFAAgF;IAChF,6EAA6E;IAC7E,IAAI,eAAe,GAAyB,IAAI,CAAC;IAEjD,MAAM,QAAQ,GAAkB,IAAI,KAAK,CAAC,EAAmB,EAAE;QAC7D,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ;YACzB,IAAI,CAAC,eAAe,EAAE,CAAC;gBACrB,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;YAC5C,CAAC;YACD,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACtD,CAAC;KACF,CAAC,CAAC;IAEH,OAAO;QACL,MAAM;QACN,QAAQ;QACR,IAAI,EAAE,YAAY,CAAC,IAAI;QACvB,MAAM,EAAE,YAAY,CAAC,MAAM;QAC3B,SAAS,EAAE,WAAW,CAAC,KAAK;QAC5B,SAAS,EAAE,WAAW,CAAC,KAAK;KAC7B,CAAC;AACJ,CAAC;AAcD,yEAAyE;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Mock FHIR backend for testing plugins without a real FHIR server.
3
+ *
4
+ * Implements the WitFhir interface with an in-memory resource store.
5
+ * All operations are recorded in the `calls` array for assertion.
6
+ */
7
+ import type { WitFhir } from "../fhir-client.js";
8
+ import type { MockCall } from "./types.js";
9
+ type WitOkString = {
10
+ tag: "ok";
11
+ val: string;
12
+ };
13
+ type WitOkBool = {
14
+ tag: "ok";
15
+ val: boolean;
16
+ };
17
+ type WitErr = {
18
+ tag: "err";
19
+ val: {
20
+ json: string;
21
+ };
22
+ };
23
+ export declare class MockFhirBackend implements WitFhir {
24
+ private readonly store;
25
+ readonly calls: MockCall[];
26
+ /**
27
+ * Create a mock FHIR backend with optional pre-seeded resources.
28
+ * @param initial - Resources keyed by "ResourceType/id" (e.g., "Patient/123")
29
+ */
30
+ constructor(initial?: Record<string, any>);
31
+ read(resourceType: string, id: string): WitOkString | WitErr;
32
+ search(resourceType: string, params: [string, string][]): WitOkString | WitErr;
33
+ create(resourceType: string, resourceJson: string): WitOkString | WitErr;
34
+ update(resourceType: string, id: string, resourceJson: string): WitOkString | WitErr;
35
+ delete(resourceType: string, id: string): WitOkBool | WitErr;
36
+ }
37
+ export {};
38
+ //# sourceMappingURL=mock-fhir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-fhir.d.ts","sourceRoot":"","sources":["../../src/testing/mock-fhir.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,KAAK,WAAW,GAAG;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9C,KAAK,SAAS,GAAG;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AAC7C,KAAK,MAAM,GAAG;IAAE,GAAG,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAcpD,qBAAa,eAAgB,YAAW,OAAO;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAM;IAEhC;;;OAGG;gBACS,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IASzC,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM;IAe5D,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GACzB,WAAW,GAAG,MAAM;IA2CvB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM;IAgBxE,MAAM,CACJ,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,MAAM,EACV,YAAY,EAAE,MAAM,GACnB,WAAW,GAAG,MAAM;IAYvB,MAAM,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM;CAQ7D"}