|
1 | 1 | import { describe, expect, it } from "vitest"; |
2 | | -import type { Attachment, Coding, Element, Quantity, Reference } from "fhir/r5"; |
| 2 | +import type { |
| 3 | + Attachment, |
| 4 | + Coding, |
| 5 | + Element, |
| 6 | + Quantity, |
| 7 | + QuestionnaireItemAnswerOption, |
| 8 | + Reference, |
| 9 | +} from "fhir/r5"; |
3 | 10 |
|
4 | 11 | import { |
| 12 | + answerify, |
5 | 13 | areValuesEqual, |
6 | 14 | cloneValue, |
7 | 15 | countDecimalPlaces, |
@@ -252,6 +260,143 @@ describe("stringifyValue", () => { |
252 | 260 | }); |
253 | 261 | }); |
254 | 262 |
|
| 263 | +describe("answerify", () => { |
| 264 | + it("flattens nested collections", () => { |
| 265 | + const result = answerify("string", ["Alpha", ["Beta", ["Gamma"]]]); |
| 266 | + expect(result).toEqual([ |
| 267 | + { valueString: "Alpha" }, |
| 268 | + { valueString: "Beta" }, |
| 269 | + { valueString: "Gamma" }, |
| 270 | + ]); |
| 271 | + }); |
| 272 | + |
| 273 | + it("coerces boolean strings", () => { |
| 274 | + const result = answerify("boolean", ["true", "FALSE", "maybe"]); |
| 275 | + expect(result).toEqual([{ valueBoolean: true }, { valueBoolean: false }]); |
| 276 | + }); |
| 277 | + |
| 278 | + it("parses numerics for integer questions", () => { |
| 279 | + const result = answerify("integer", ["5", 7, "oops"]); |
| 280 | + expect(result).toEqual([{ valueInteger: 5 }, { valueInteger: 7 }]); |
| 281 | + }); |
| 282 | + |
| 283 | + it("parses numerics for decimal questions", () => { |
| 284 | + const result = answerify("decimal", ["1.5", 2, "oops"]); |
| 285 | + expect(result).toEqual([{ valueDecimal: 1.5 }, { valueDecimal: 2 }]); |
| 286 | + }); |
| 287 | + |
| 288 | + it("wraps bare coding objects", () => { |
| 289 | + const coding: Coding = { system: "http://loinc.org", code: "718-7" }; |
| 290 | + const [option] = answerify("coding", coding); |
| 291 | + expect(option).toEqual({ valueCoding: coding }); |
| 292 | + expect(option.valueCoding).toBe(coding); |
| 293 | + }); |
| 294 | + |
| 295 | + it("returns structured codings unchanged when provided as answerOption", () => { |
| 296 | + const option: QuestionnaireItemAnswerOption = { |
| 297 | + valueCoding: { system: "http://loinc.org", code: "890-5" }, |
| 298 | + extension: [{ url: "test", valueString: "meta" }], |
| 299 | + }; |
| 300 | + const [result] = answerify("coding", [option]); |
| 301 | + expect(result).not.toBe(option); |
| 302 | + expect(result.valueCoding).toEqual(option.valueCoding); |
| 303 | + expect(result.extension).toBe(option.extension); |
| 304 | + }); |
| 305 | + |
| 306 | + it("clones provided answerOption wrappers", () => { |
| 307 | + const original = { |
| 308 | + valueCoding: { code: "opt", display: "Option" }, |
| 309 | + extension: [{ url: "x", valueString: "meta" }], |
| 310 | + } satisfies QuestionnaireItemAnswerOption; |
| 311 | + |
| 312 | + const [option] = answerify("coding", [original]); |
| 313 | + |
| 314 | + expect(option.valueCoding).toEqual(original.valueCoding); |
| 315 | + expect(option.valueCoding).toBe(original.valueCoding); |
| 316 | + expect(option.extension).toEqual(original.extension); |
| 317 | + expect(option.extension).toBe(original.extension); |
| 318 | + }); |
| 319 | + |
| 320 | + it("filters unsupported values", () => { |
| 321 | + const result = answerify("boolean", [null, undefined, 1, "maybe"]); |
| 322 | + expect(result).toEqual([]); |
| 323 | + }); |
| 324 | + |
| 325 | + it("clones structured quantity answers", () => { |
| 326 | + const quantity = { value: 42, unit: "kg" } satisfies Quantity; |
| 327 | + const result = answerify("quantity", quantity); |
| 328 | + expect(result).toHaveLength(1); |
| 329 | + expect((result[0] as { valueQuantity?: Quantity }).valueQuantity).toBe( |
| 330 | + quantity, |
| 331 | + ); |
| 332 | + }); |
| 333 | + |
| 334 | + it("passes through references", () => { |
| 335 | + const reference = { |
| 336 | + reference: "Patient/1", |
| 337 | + display: "Alice", |
| 338 | + } satisfies Reference; |
| 339 | + const result = answerify("reference", reference); |
| 340 | + expect(result).toHaveLength(1); |
| 341 | + expect((result[0] as { valueReference?: Reference }).valueReference).toBe( |
| 342 | + reference, |
| 343 | + ); |
| 344 | + }); |
| 345 | + |
| 346 | + it("passes through attachments", () => { |
| 347 | + const attachment = { |
| 348 | + url: "https://example.org", |
| 349 | + title: "Scan", |
| 350 | + } satisfies Attachment; |
| 351 | + const result = answerify("attachment", attachment); |
| 352 | + expect(result).toHaveLength(1); |
| 353 | + expect( |
| 354 | + (result[0] as { valueAttachment?: Attachment }).valueAttachment, |
| 355 | + ).toBe(attachment); |
| 356 | + }); |
| 357 | + |
| 358 | + it("accepts string-like types", () => { |
| 359 | + const result = answerify("string", "alpha"); |
| 360 | + expect(result).toEqual([{ valueString: "alpha" }]); |
| 361 | + }); |
| 362 | + |
| 363 | + it("accepts text type", () => { |
| 364 | + const result = answerify("text", "long form"); |
| 365 | + expect(result).toEqual([{ valueString: "long form" }]); |
| 366 | + }); |
| 367 | + |
| 368 | + it("accepts date values", () => { |
| 369 | + const result = answerify("date", ["2025-01-01", "invalid"]); |
| 370 | + expect(result.map((option) => getValue(option, "date"))).toEqual([ |
| 371 | + "2025-01-01", |
| 372 | + "invalid", |
| 373 | + ]); |
| 374 | + }); |
| 375 | + |
| 376 | + it("accepts dateTime values", () => { |
| 377 | + const result = answerify("dateTime", ["2025-01-01T09:30:00Z", 42]); |
| 378 | + expect(result).toEqual([{ valueDateTime: "2025-01-01T09:30:00Z" }]); |
| 379 | + }); |
| 380 | + |
| 381 | + it("accepts time values", () => { |
| 382 | + const result = answerify("time", ["08:15:00", null]); |
| 383 | + expect(result).toEqual([{ valueTime: "08:15:00" }]); |
| 384 | + }); |
| 385 | + |
| 386 | + it("rejects unsupported types", () => { |
| 387 | + const result = answerify("reference", ["string", 42, null]); |
| 388 | + expect(result).toEqual([]); |
| 389 | + }); |
| 390 | + |
| 391 | + it("handles empty source arrays", () => { |
| 392 | + expect(answerify("string", [])).toEqual([]); |
| 393 | + }); |
| 394 | + |
| 395 | + it("ignores undefined root value", () => { |
| 396 | + expect(answerify("string", undefined)).toEqual([]); |
| 397 | + }); |
| 398 | +}); |
| 399 | + |
255 | 400 | describe("areValuesEqual", () => { |
256 | 401 | describe("string", () => { |
257 | 402 | it("returns true for equal strings", () => { |
|
0 commit comments