@longsightgroup/qti3-core 0.9.1 → 0.9.3

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 (244) hide show
  1. package/README.md +59 -3
  2. package/dist/adaptive-turn-materializer.d.ts +14 -0
  3. package/dist/adaptive-turn-materializer.d.ts.map +1 -0
  4. package/dist/adaptive-turn-materializer.js +56 -0
  5. package/dist/adaptive-turn-materializer.js.map +1 -0
  6. package/dist/adaptive-turn.d.ts +23 -0
  7. package/dist/adaptive-turn.d.ts.map +1 -0
  8. package/dist/adaptive-turn.js +60 -0
  9. package/dist/adaptive-turn.js.map +1 -0
  10. package/dist/assert-never.d.ts +3 -0
  11. package/dist/assert-never.d.ts.map +1 -0
  12. package/dist/assert-never.js +5 -0
  13. package/dist/assert-never.js.map +1 -0
  14. package/dist/attempt-state-constants.d.ts +6 -0
  15. package/dist/attempt-state-constants.d.ts.map +1 -0
  16. package/dist/attempt-state-constants.js +6 -0
  17. package/dist/attempt-state-constants.js.map +1 -0
  18. package/dist/attempt-state.d.ts +5 -0
  19. package/dist/attempt-state.d.ts.map +1 -0
  20. package/dist/attempt-state.js +190 -0
  21. package/dist/attempt-state.js.map +1 -0
  22. package/dist/catalog.js +1 -1
  23. package/dist/catalog.js.map +1 -1
  24. package/dist/content-text.d.ts.map +1 -1
  25. package/dist/content-text.js +3 -0
  26. package/dist/content-text.js.map +1 -1
  27. package/dist/custom-operators.d.ts +13 -0
  28. package/dist/custom-operators.d.ts.map +1 -0
  29. package/dist/custom-operators.js +2 -0
  30. package/dist/custom-operators.js.map +1 -0
  31. package/dist/delivery-redaction.d.ts +50 -0
  32. package/dist/delivery-redaction.d.ts.map +1 -0
  33. package/dist/delivery-redaction.js +176 -0
  34. package/dist/delivery-redaction.js.map +1 -0
  35. package/dist/delivery-security.d.ts +3 -18
  36. package/dist/delivery-security.d.ts.map +1 -1
  37. package/dist/delivery-security.js +35 -189
  38. package/dist/delivery-security.js.map +1 -1
  39. package/dist/index.d.ts +4 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +3 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/parser-custom-interactions.js +1 -1
  44. package/dist/parser-custom-interactions.js.map +1 -1
  45. package/dist/parser-declarations.d.ts.map +1 -1
  46. package/dist/parser-declarations.js +4 -4
  47. package/dist/parser-declarations.js.map +1 -1
  48. package/dist/parser-item-metadata.d.ts.map +1 -1
  49. package/dist/parser-item-metadata.js +8 -7
  50. package/dist/parser-item-metadata.js.map +1 -1
  51. package/dist/parser-processing.js +2 -2
  52. package/dist/parser-processing.js.map +1 -1
  53. package/dist/parser-values.d.ts +5 -1
  54. package/dist/parser-values.d.ts.map +1 -1
  55. package/dist/parser-values.js +33 -0
  56. package/dist/parser-values.js.map +1 -1
  57. package/dist/processing-evaluator-boolean.d.ts +8 -0
  58. package/dist/processing-evaluator-boolean.d.ts.map +1 -0
  59. package/dist/processing-evaluator-boolean.js +47 -0
  60. package/dist/processing-evaluator-boolean.js.map +1 -0
  61. package/dist/processing-evaluator-collection.d.ts +12 -0
  62. package/dist/processing-evaluator-collection.d.ts.map +1 -0
  63. package/dist/processing-evaluator-collection.js +35 -0
  64. package/dist/processing-evaluator-collection.js.map +1 -0
  65. package/dist/processing-evaluator-comparison.d.ts +8 -0
  66. package/dist/processing-evaluator-comparison.d.ts.map +1 -0
  67. package/dist/processing-evaluator-comparison.js +88 -0
  68. package/dist/processing-evaluator-comparison.js.map +1 -0
  69. package/dist/processing-evaluator-custom.d.ts +8 -0
  70. package/dist/processing-evaluator-custom.d.ts.map +1 -0
  71. package/dist/processing-evaluator-custom.js +14 -0
  72. package/dist/processing-evaluator-custom.js.map +1 -0
  73. package/dist/processing-evaluator-geometry.d.ts +8 -0
  74. package/dist/processing-evaluator-geometry.d.ts.map +1 -0
  75. package/dist/processing-evaluator-geometry.js +21 -0
  76. package/dist/processing-evaluator-geometry.js.map +1 -0
  77. package/dist/processing-evaluator-numeric.d.ts +8 -0
  78. package/dist/processing-evaluator-numeric.d.ts.map +1 -0
  79. package/dist/processing-evaluator-numeric.js +112 -0
  80. package/dist/processing-evaluator-numeric.js.map +1 -0
  81. package/dist/processing-evaluator-string.d.ts +8 -0
  82. package/dist/processing-evaluator-string.d.ts.map +1 -0
  83. package/dist/processing-evaluator-string.js +33 -0
  84. package/dist/processing-evaluator-string.js.map +1 -0
  85. package/dist/processing-evaluator-variable.d.ts +8 -0
  86. package/dist/processing-evaluator-variable.d.ts.map +1 -0
  87. package/dist/processing-evaluator-variable.js +39 -0
  88. package/dist/processing-evaluator-variable.js.map +1 -0
  89. package/dist/processing-evaluator.d.ts +22 -0
  90. package/dist/processing-evaluator.d.ts.map +1 -0
  91. package/dist/processing-evaluator.js +137 -0
  92. package/dist/processing-evaluator.js.map +1 -0
  93. package/dist/processing-expression-children.d.ts +3 -0
  94. package/dist/processing-expression-children.d.ts.map +1 -0
  95. package/dist/processing-expression-children.js +68 -0
  96. package/dist/processing-expression-children.js.map +1 -0
  97. package/dist/processing-mapping.d.ts +13 -0
  98. package/dist/processing-mapping.d.ts.map +1 -0
  99. package/dist/processing-mapping.js +120 -0
  100. package/dist/processing-mapping.js.map +1 -0
  101. package/dist/processing-operators.d.ts +11 -0
  102. package/dist/processing-operators.d.ts.map +1 -0
  103. package/dist/processing-operators.js +178 -0
  104. package/dist/processing-operators.js.map +1 -0
  105. package/dist/processing-random.d.ts +2 -0
  106. package/dist/processing-random.d.ts.map +1 -0
  107. package/dist/processing-random.js +16 -0
  108. package/dist/processing-random.js.map +1 -0
  109. package/dist/processing-state.d.ts +8 -0
  110. package/dist/processing-state.d.ts.map +1 -0
  111. package/dist/processing-state.js +44 -0
  112. package/dist/processing-state.js.map +1 -0
  113. package/dist/processing-templates.d.ts +3 -0
  114. package/dist/processing-templates.d.ts.map +1 -0
  115. package/dist/processing-templates.js +12 -0
  116. package/dist/processing-templates.js.map +1 -0
  117. package/dist/processing-values.d.ts +15 -0
  118. package/dist/processing-values.d.ts.map +1 -0
  119. package/dist/processing-values.js +150 -0
  120. package/dist/processing-values.js.map +1 -0
  121. package/dist/processing-variables.d.ts +7 -0
  122. package/dist/processing-variables.d.ts.map +1 -0
  123. package/dist/processing-variables.js +40 -0
  124. package/dist/processing-variables.js.map +1 -0
  125. package/dist/serializer-processing-expressions.d.ts.map +1 -1
  126. package/dist/serializer-processing-expressions.js +2 -8
  127. package/dist/serializer-processing-expressions.js.map +1 -1
  128. package/dist/serializer-processing-xml.js +2 -2
  129. package/dist/serializer-processing-xml.js.map +1 -1
  130. package/dist/serializer-processing.d.ts.map +1 -1
  131. package/dist/serializer-processing.js +3 -0
  132. package/dist/serializer-processing.js.map +1 -1
  133. package/dist/server-scoring.d.ts +4 -14
  134. package/dist/server-scoring.d.ts.map +1 -1
  135. package/dist/server-scoring.js +19 -157
  136. package/dist/server-scoring.js.map +1 -1
  137. package/dist/session.d.ts +5 -14
  138. package/dist/session.d.ts.map +1 -1
  139. package/dist/session.js +76 -1158
  140. package/dist/session.js.map +1 -1
  141. package/dist/shared-vocabulary-coverage-policy.js +1 -1
  142. package/dist/shared-vocabulary-coverage-policy.js.map +1 -1
  143. package/dist/shared-vocabulary-generated-families.js +1 -1
  144. package/dist/shared-vocabulary-generated-families.js.map +1 -1
  145. package/dist/shared-vocabulary-support.js +3 -3
  146. package/dist/shared-vocabulary-support.js.map +1 -1
  147. package/dist/shared-vocabulary.d.ts.map +1 -1
  148. package/dist/shared-vocabulary.js +4 -3
  149. package/dist/shared-vocabulary.js.map +1 -1
  150. package/dist/support-evidence.d.ts +22 -0
  151. package/dist/support-evidence.d.ts.map +1 -0
  152. package/dist/support-evidence.js +93 -0
  153. package/dist/support-evidence.js.map +1 -0
  154. package/dist/support.d.ts.map +1 -1
  155. package/dist/support.js +38 -47
  156. package/dist/support.js.map +1 -1
  157. package/dist/trusted-item-session.d.ts +49 -0
  158. package/dist/trusted-item-session.d.ts.map +1 -0
  159. package/dist/trusted-item-session.js +261 -0
  160. package/dist/trusted-item-session.js.map +1 -0
  161. package/dist/tts.d.ts.map +1 -1
  162. package/dist/tts.js +16 -2
  163. package/dist/tts.js.map +1 -1
  164. package/dist/validation-geometry.d.ts +8 -0
  165. package/dist/validation-geometry.d.ts.map +1 -0
  166. package/dist/validation-geometry.js +187 -0
  167. package/dist/validation-geometry.js.map +1 -0
  168. package/dist/validation-interactions.d.ts +3 -0
  169. package/dist/validation-interactions.d.ts.map +1 -0
  170. package/dist/validation-interactions.js +644 -0
  171. package/dist/validation-interactions.js.map +1 -0
  172. package/dist/validation-primitives.d.ts +11 -0
  173. package/dist/validation-primitives.d.ts.map +1 -0
  174. package/dist/validation-primitives.js +48 -0
  175. package/dist/validation-primitives.js.map +1 -0
  176. package/dist/validation-processing.d.ts +4 -0
  177. package/dist/validation-processing.d.ts.map +1 -0
  178. package/dist/validation-processing.js +569 -0
  179. package/dist/validation-processing.js.map +1 -0
  180. package/dist/validation-shared-vocabulary-layout.d.ts +10 -0
  181. package/dist/validation-shared-vocabulary-layout.d.ts.map +1 -0
  182. package/dist/validation-shared-vocabulary-layout.js +102 -0
  183. package/dist/validation-shared-vocabulary-layout.js.map +1 -0
  184. package/dist/validation.d.ts.map +1 -1
  185. package/dist/validation.js +27 -1641
  186. package/dist/validation.js.map +1 -1
  187. package/dist/xml.js +1 -1
  188. package/dist/xml.js.map +1 -1
  189. package/package.json +4 -2
  190. package/src/adaptive-turn-materializer.ts +85 -0
  191. package/src/adaptive-turn.ts +109 -0
  192. package/src/assert-never.ts +4 -0
  193. package/src/attempt-state-constants.ts +5 -0
  194. package/src/attempt-state.ts +245 -0
  195. package/src/catalog.ts +1 -1
  196. package/src/content-text.ts +3 -0
  197. package/src/custom-operators.ts +12 -0
  198. package/src/delivery-redaction.ts +268 -0
  199. package/src/delivery-security.ts +59 -245
  200. package/src/index.ts +9 -0
  201. package/src/parser-custom-interactions.ts +1 -1
  202. package/src/parser-declarations.ts +4 -3
  203. package/src/parser-item-metadata.ts +8 -7
  204. package/src/parser-processing.ts +2 -2
  205. package/src/parser-values.ts +36 -0
  206. package/src/processing-evaluator-boolean.ts +48 -0
  207. package/src/processing-evaluator-collection.ts +50 -0
  208. package/src/processing-evaluator-comparison.ts +106 -0
  209. package/src/processing-evaluator-custom.ts +20 -0
  210. package/src/processing-evaluator-geometry.ts +26 -0
  211. package/src/processing-evaluator-numeric.ts +155 -0
  212. package/src/processing-evaluator-string.ts +60 -0
  213. package/src/processing-evaluator-variable.ts +81 -0
  214. package/src/processing-evaluator.ts +173 -0
  215. package/src/processing-expression-children.ts +69 -0
  216. package/src/processing-mapping.ts +153 -0
  217. package/src/processing-operators.ts +184 -0
  218. package/src/processing-random.ts +16 -0
  219. package/src/processing-state.ts +69 -0
  220. package/src/processing-templates.ts +12 -0
  221. package/src/processing-values.ts +162 -0
  222. package/src/processing-variables.ts +83 -0
  223. package/src/serializer-processing-expressions.ts +2 -12
  224. package/src/serializer-processing-xml.ts +2 -2
  225. package/src/serializer-processing.ts +3 -0
  226. package/src/server-scoring.ts +30 -226
  227. package/src/session.ts +128 -2006
  228. package/src/shared-vocabulary-coverage-policy.ts +1 -1
  229. package/src/shared-vocabulary-generated-families.ts +1 -1
  230. package/src/shared-vocabulary-support.ts +3 -3
  231. package/src/shared-vocabulary.ts +3 -2
  232. package/src/support-evidence.ts +107 -0
  233. package/src/support.ts +68 -54
  234. package/src/trusted-item-session.ts +429 -0
  235. package/src/tts.ts +29 -15
  236. package/src/validation-geometry.ts +204 -0
  237. package/src/validation-interactions.ts +831 -0
  238. package/src/validation-primitives.ts +63 -0
  239. package/src/validation-processing.ts +785 -0
  240. package/src/validation-shared-vocabulary-layout.ts +117 -0
  241. package/src/validation.ts +44 -2077
  242. package/src/xml.ts +1 -1
  243. package/src/interaction-test-fixtures.ts +0 -44
  244. package/src/serializer-processing.fixtures.ts +0 -469
@@ -48,7 +48,7 @@ export function findSharedVocabularyCoverageViolations(input: {
48
48
  supportByClass.set(entry.className, existing);
49
49
  }
50
50
 
51
- const gatedSupportClasses = [...supportByClass.keys()].sort();
51
+ const gatedSupportClasses = [...supportByClass.keys()].toSorted();
52
52
  if (gatedSupportClasses.length === 0) {
53
53
  violations.push({ message: "expected at least one enforced shared vocabulary class" });
54
54
  }
@@ -122,7 +122,7 @@ function escapeRegExp(value: string): string {
122
122
 
123
123
  function alternationPattern(values: readonly string[]): string {
124
124
  return [...values]
125
- .sort((left, right) => right.length - left.length)
125
+ .toSorted((left, right) => right.length - left.length)
126
126
  .map(escapeRegExp)
127
127
  .join("|");
128
128
  }
@@ -52,7 +52,7 @@ const graphicBrowserTests = [
52
52
  "tests/browser/player-graphic.spec.ts",
53
53
  "tests/browser/player-graphic-gap-match.spec.ts",
54
54
  ];
55
- const mediaBrowserTests = ["tests/browser/player.spec.ts", ...sharedVocabularyMatrixTests];
55
+ const mediaBrowserTests = ["tests/browser/player-media.spec.ts", ...sharedVocabularyMatrixTests];
56
56
  const mediaPlayerFixture =
57
57
  "packages/fixtures/packages/sv-matrix/items/media-controls-and-pause.xml";
58
58
  const interactionInputWidthFixtures = [
@@ -204,14 +204,14 @@ function registryAttributeSupportProfile(fieldId: string): {
204
204
  fixtures: [mediaPlayerFixture],
205
205
  tests: mediaBrowserTests,
206
206
  notes:
207
- "Reflects authored pause-delay values on rendered media assets. Pause timer behavior is covered in tests/browser/player.spec.ts.",
207
+ "Reflects authored pause-delay values on rendered media assets. Pause timer behavior is covered in tests/browser/player-media.spec.ts.",
208
208
  };
209
209
  case "media-player-pause-duration":
210
210
  return {
211
211
  fixtures: [mediaPlayerFixture],
212
212
  tests: mediaBrowserTests,
213
213
  notes:
214
- "Reflects authored pause-duration values on rendered media assets. Pause timer behavior is covered in tests/browser/player.spec.ts.",
214
+ "Reflects authored pause-duration values on rendered media assets. Pause timer behavior is covered in tests/browser/player-media.spec.ts.",
215
215
  };
216
216
  default:
217
217
  return {
@@ -73,9 +73,10 @@ export function firstMatchingSharedVocabularyClass<T extends string>(
73
73
  classNames: string[],
74
74
  tokens: readonly T[],
75
75
  ): T | undefined {
76
- const tokenSet = new Set<string>(tokens);
77
76
  for (const className of classNames) {
78
- if (tokenSet.has(className)) return className as T;
77
+ for (const token of tokens) {
78
+ if (token === className) return token;
79
+ }
79
80
  }
80
81
  return undefined;
81
82
  }
@@ -0,0 +1,107 @@
1
+ import type { QtiInteractionType } from "./types.js";
2
+
3
+ const coreProcessingTest = "packages/core/src/core.test.ts";
4
+
5
+ export const browserProcessingTests = ["tests/browser/player-processing.spec.ts"];
6
+ export const browserFeedbackTests = ["tests/browser/player-feedback.spec.ts"];
7
+ export const browserAdaptiveTests = ["tests/browser/player-adaptive.spec.ts"];
8
+ export const browserBodyContentTests = ["tests/browser/player-body-content.spec.ts"];
9
+ export const browserHarnessTests = ["tests/browser/player-harness.spec.ts"];
10
+ export const browserMathmlTests = ["tests/browser/player-mathml.spec.ts"];
11
+ export const browserKeyboardA11yTests = ["tests/browser/player-keyboard-a11y.spec.ts"];
12
+ export const browserLifecycleTests = ["tests/browser/player-lifecycle.spec.ts"];
13
+
14
+ const templateProcessingBrowserEvidence = [
15
+ ...browserProcessingTests,
16
+ ...browserBodyContentTests,
17
+ ...browserMathmlTests,
18
+ ];
19
+ const responseProcessingBrowserEvidence = [
20
+ ...browserProcessingTests,
21
+ ...browserFeedbackTests,
22
+ ...browserAdaptiveTests,
23
+ ];
24
+ const randomIntegerBrowserEvidence = browserProcessingTests;
25
+
26
+ /** Browser evidence bundles keyed by parent processing constructs only. */
27
+ export const processingBrowserEvidence = {
28
+ "qti-template-processing": templateProcessingBrowserEvidence,
29
+ "qti-response-processing": responseProcessingBrowserEvidence,
30
+ "qti-random-integer": randomIntegerBrowserEvidence,
31
+ } as const satisfies Record<string, readonly string[]>;
32
+
33
+ export type ProcessingBrowserEvidenceName = keyof typeof processingBrowserEvidence;
34
+
35
+ export const interactionExtraFixtures: Partial<Record<QtiInteractionType, readonly string[]>> = {
36
+ extendedText: [
37
+ "packages/fixtures/packages/sv-matrix/items/extended-text-pattern-mask.xml",
38
+ "packages/fixtures/packages/sv-matrix/items/extended-text-xhtml.xml",
39
+ ],
40
+ textEntry: ["packages/fixtures/packages/sv-matrix/items/text-entry-pattern-mask-inline.xml"],
41
+ };
42
+
43
+ export function browserTestsFor(interactionType: QtiInteractionType): string[] {
44
+ const base = [
45
+ "packages/fixtures/src/fixtures.test.ts",
46
+ "packages/conformance/src/conformance.test.ts",
47
+ "packages/a11y/src/a11y.test.ts",
48
+ "tests/browser/player-interaction-sweep.spec.ts",
49
+ ];
50
+ const extras: Partial<Record<QtiInteractionType, string[]>> = {
51
+ associate: browserKeyboardA11yTests,
52
+ choice: ["tests/browser/player-choice.spec.ts", "tests/browser/player-dom-behavior.spec.ts"],
53
+ drawing: ["tests/browser/player-graphic.spec.ts"],
54
+ endAttempt: ["tests/browser/player-dom-behavior.spec.ts", ...browserKeyboardA11yTests],
55
+ extendedText: [
56
+ "tests/browser/player-dom-behavior.spec.ts",
57
+ "tests/browser/player-extended-text-xhtml.spec.ts",
58
+ ],
59
+ gapMatch: ["tests/browser/player-gap-match.spec.ts"],
60
+ graphicAssociate: ["tests/browser/player-graphic.spec.ts"],
61
+ graphicGapMatch: [
62
+ "tests/browser/player-graphic-gap-match.spec.ts",
63
+ "tests/browser/player-graphic.spec.ts",
64
+ ],
65
+ graphicOrder: ["tests/browser/player-graphic.spec.ts"],
66
+ hotspot: ["tests/browser/player-graphic.spec.ts"],
67
+ hottext: ["tests/browser/player-hottext.spec.ts", "tests/browser/player-dom-behavior.spec.ts"],
68
+ inlineChoice: ["tests/browser/player-inline-choice.spec.ts"],
69
+ match: ["tests/browser/player-match.spec.ts", "tests/browser/player-dom-behavior.spec.ts"],
70
+ media: ["tests/browser/player-media.spec.ts"],
71
+ order: [...browserKeyboardA11yTests, ...browserLifecycleTests],
72
+ portableCustom: ["tests/browser/player-portable-custom.spec.ts"],
73
+ positionObject: ["tests/browser/player-graphic.spec.ts", ...browserKeyboardA11yTests],
74
+ selectPoint: ["tests/browser/player-graphic.spec.ts"],
75
+ slider: browserKeyboardA11yTests,
76
+ textEntry: ["tests/browser/player-dom-behavior.spec.ts"],
77
+ upload: ["tests/browser/player-dom-behavior.spec.ts"],
78
+ };
79
+ return [...base, ...(extras[interactionType] ?? [])];
80
+ }
81
+
82
+ export function interactionSupportFixtures(interactionType: QtiInteractionType): string[] {
83
+ return [
84
+ `packages/fixtures/xml/${interactionType}-reference.xml`,
85
+ ...(interactionExtraFixtures[interactionType] ?? []),
86
+ ];
87
+ }
88
+
89
+ export function interactionSupportTests(interactionType: QtiInteractionType): string[] {
90
+ if (interactionType === "extendedText" || interactionType === "textEntry") {
91
+ return [...browserTestsFor(interactionType), "packages/core/src/pattern-mask.test.ts"];
92
+ }
93
+ return browserTestsFor(interactionType);
94
+ }
95
+
96
+ function isProcessingBrowserEvidenceName(
97
+ qtiName: string,
98
+ ): qtiName is ProcessingBrowserEvidenceName {
99
+ return Object.hasOwn(processingBrowserEvidence, qtiName);
100
+ }
101
+
102
+ export function processingSupportTests(qtiName: string): string[] {
103
+ if (!isProcessingBrowserEvidenceName(qtiName)) {
104
+ return [coreProcessingTest];
105
+ }
106
+ return [coreProcessingTest, ...processingBrowserEvidence[qtiName]];
107
+ }
package/src/support.ts CHANGED
@@ -8,6 +8,13 @@ import type {
8
8
  QtiProcessingElementSupport,
9
9
  QtiSourceLocation,
10
10
  } from "./types.js";
11
+ import {
12
+ browserFeedbackTests,
13
+ browserHarnessTests,
14
+ interactionSupportFixtures,
15
+ interactionSupportTests,
16
+ processingBrowserEvidence,
17
+ } from "./support-evidence.js";
11
18
 
12
19
  export const interactionSupport: QtiInteractionElementSupport[] = [
13
20
  entry("qti-associate-interaction", "associate"),
@@ -51,23 +58,36 @@ export const deprecatedInteractionSupport: QtiInteractionElementSupport[] = [
51
58
  ];
52
59
 
53
60
  export const processingSupport: QtiProcessingElementSupport[] = [
54
- processingEntry("qti-template-processing", "packages/core/src/core.test.ts", [
55
- "packages/fixtures/xml/template-processing-reference.xml",
56
- "packages/fixtures/xml/template-content-reference.xml",
57
- ]),
58
- processingEntry("qti-response-processing", "packages/core/src/core.test.ts", [
59
- "packages/fixtures/xml/mapping-processing-reference.xml",
60
- "packages/fixtures/xml/generic-match-processing-reference.xml",
61
- "packages/fixtures/xml/advanced-processing-reference.xml",
62
- "packages/fixtures/xml/adaptive-feedback-reference.xml",
63
- ]),
61
+ processingEntry(
62
+ "qti-template-processing",
63
+ "packages/core/src/core.test.ts",
64
+ [
65
+ "packages/fixtures/xml/template-processing-reference.xml",
66
+ "packages/fixtures/xml/random-integer-template-reference.xml",
67
+ "packages/fixtures/xml/template-content-reference.xml",
68
+ ],
69
+ [...processingBrowserEvidence["qti-template-processing"]],
70
+ ),
71
+ processingEntry(
72
+ "qti-response-processing",
73
+ "packages/core/src/core.test.ts",
74
+ [
75
+ "packages/fixtures/xml/mapping-processing-reference.xml",
76
+ "packages/fixtures/xml/generic-match-processing-reference.xml",
77
+ "packages/fixtures/xml/advanced-processing-reference.xml",
78
+ "packages/fixtures/xml/adaptive-feedback-reference.xml",
79
+ ],
80
+ [...processingBrowserEvidence["qti-response-processing"]],
81
+ ),
64
82
  processingEntry("qti-set-template-value", "packages/core/src/core.test.ts", [
65
83
  "packages/fixtures/xml/template-processing-reference.xml",
84
+ "packages/fixtures/xml/random-integer-template-reference.xml",
66
85
  "packages/fixtures/xml/template-content-reference.xml",
67
86
  ]),
68
87
  processingEntry("qti-set-default-value", "packages/core/src/core.test.ts"),
69
88
  processingEntry("qti-set-correct-response", "packages/core/src/core.test.ts", [
70
89
  "packages/fixtures/xml/template-processing-reference.xml",
90
+ "packages/fixtures/xml/random-integer-template-reference.xml",
71
91
  ]),
72
92
  processingEntry("qti-template-condition", "packages/core/src/core.test.ts"),
73
93
  processingEntry("qti-template-if", "packages/core/src/core.test.ts"),
@@ -119,11 +139,17 @@ export const processingSupport: QtiProcessingElementSupport[] = [
119
139
  processingEntry("qti-variable", "packages/core/src/core.test.ts", [
120
140
  "packages/fixtures/xml/generic-match-processing-reference.xml",
121
141
  "packages/fixtures/xml/template-processing-reference.xml",
142
+ "packages/fixtures/xml/random-integer-template-reference.xml",
122
143
  "packages/fixtures/xml/template-content-reference.xml",
123
144
  "packages/fixtures/xml/advanced-processing-reference.xml",
124
145
  "packages/fixtures/xml/adaptive-feedback-reference.xml",
125
146
  ]),
126
- processingEntry("qti-random-integer", "packages/core/src/core.test.ts"),
147
+ processingEntry(
148
+ "qti-random-integer",
149
+ "packages/core/src/core.test.ts",
150
+ ["packages/fixtures/xml/random-integer-template-reference.xml"],
151
+ [...processingBrowserEvidence["qti-random-integer"]],
152
+ ),
127
153
  processingEntry("qti-random-float", "packages/core/src/core.test.ts"),
128
154
  processingEntry("qti-random", "packages/core/src/core.test.ts"),
129
155
  processingEntry("qti-multiple", "packages/core/src/core.test.ts", [
@@ -139,8 +165,11 @@ export const processingSupport: QtiProcessingElementSupport[] = [
139
165
  ]),
140
166
  processingEntry("qti-sum", "packages/core/src/core.test.ts", [
141
167
  "packages/fixtures/xml/template-processing-reference.xml",
168
+ "packages/fixtures/xml/random-integer-template-reference.xml",
169
+ ]),
170
+ processingEntry("qti-product", "packages/core/src/core.test.ts", [
171
+ "packages/fixtures/xml/random-integer-template-reference.xml",
142
172
  ]),
143
- processingEntry("qti-product", "packages/core/src/core.test.ts"),
144
173
  processingEntry("qti-min", "packages/core/src/core.test.ts"),
145
174
  processingEntry("qti-max", "packages/core/src/core.test.ts"),
146
175
  processingEntry("qti-subtract", "packages/core/src/core.test.ts"),
@@ -205,24 +234,34 @@ export const itemMetadataSupport: QtiItemMetadataElementSupport[] = [
205
234
  fixtures: [
206
235
  "packages/fixtures/packages/basic-item-player/valid-item-only/items/tolerance-extra-features.xml",
207
236
  ],
208
- tests: ["packages/core/src/core.test.ts", "packages/core/src/parser-item-metadata.test.ts"],
237
+ tests: [
238
+ "packages/core/src/core.test.ts",
239
+ "packages/core/src/parser-item-metadata.test.ts",
240
+ ...browserHarnessTests,
241
+ ],
209
242
  notes:
210
- "Parsed by parser-item-metadata.ts and validated by validateCatalogInfo. Duplicate containers emit item.child.duplicate.",
243
+ "Parsed by parser-item-metadata.ts and validated by validateCatalogInfo. Duplicate containers emit item.child.duplicate. Manual harness debugger coverage is in player-harness.spec.ts.",
211
244
  },
212
245
  {
213
246
  qtiName: "qti-stylesheet",
214
247
  category: "itemMetadata",
215
- support: "parsed",
248
+ support: "rendered",
216
249
  specReference: "QTI 3.0.1 ASI",
217
250
  parse: true,
218
251
  validate: true,
219
- render: false,
252
+ render: true,
220
253
  process: false,
221
254
  fixtures: [
222
255
  "packages/fixtures/packages/basic-item-player/valid-item-only/items/tolerance-extra-features.xml",
223
256
  ],
224
- tests: ["packages/core/src/core.test.ts", "packages/core/src/parser-item-metadata.test.ts"],
225
- notes: "Parsed by parser-item-metadata.ts and validated by validateStylesheets.",
257
+ tests: [
258
+ "packages/core/src/core.test.ts",
259
+ "packages/core/src/parser-item-metadata.test.ts",
260
+ "tests/browser/player-package.spec.ts",
261
+ ...browserHarnessTests,
262
+ ],
263
+ notes:
264
+ "Parsed by parser-item-metadata.ts, validated by validateStylesheets, and delivered by the player only when a host resolveStylesheet hook returns a safe resolved stylesheet URL.",
226
265
  },
227
266
  {
228
267
  qtiName: "qti-modal-feedback",
@@ -234,9 +273,13 @@ export const itemMetadataSupport: QtiItemMetadataElementSupport[] = [
234
273
  render: false,
235
274
  process: false,
236
275
  fixtures: ["packages/fixtures/src/index.ts"],
237
- tests: ["packages/core/src/core.test.ts", "packages/core/src/parser-item-metadata.test.ts"],
276
+ tests: [
277
+ "packages/core/src/core.test.ts",
278
+ "packages/core/src/parser-item-metadata.test.ts",
279
+ ...browserFeedbackTests,
280
+ ],
238
281
  notes:
239
- "Parsed by parser-item-metadata.ts and validated by validateModalFeedback. Player rendering remains out of scope for this metadata slice.",
282
+ "Parsed by parser-item-metadata.ts and validated by validateModalFeedback. Player renders outcome-gated modal feedback in player-feedback.spec.ts.",
240
283
  },
241
284
  {
242
285
  qtiName: "qti-companion-materials-info",
@@ -253,6 +296,7 @@ export const itemMetadataSupport: QtiItemMetadataElementSupport[] = [
253
296
  tests: [
254
297
  "packages/core/src/parser-companion-materials.test.ts",
255
298
  "packages/core/src/parser-item-metadata.test.ts",
299
+ ...browserHarnessTests,
256
300
  ],
257
301
  notes:
258
302
  "Parses qti-physical-material text and qti-digital-material file references. Digital materials require non-empty qti-file-href text and may include label, mime-type, and qti-resource-icon metadata. Hosts read resolved materials through createCompanionMaterialsResolution() or player.getCompanionMaterialsResolution().",
@@ -359,33 +403,14 @@ function entry(qtiName: string, interactionType: QtiInteractionType): QtiInterac
359
403
  validate: true,
360
404
  render: true,
361
405
  process: true,
362
- fixtures: [`packages/fixtures/xml/${interactionType}-reference.xml`],
363
- tests: [
364
- "packages/fixtures/src/fixtures.test.ts",
365
- "packages/conformance/src/conformance.test.ts",
366
- "packages/a11y/src/a11y.test.ts",
367
- "tests/browser/player.spec.ts",
368
- ],
406
+ fixtures: interactionSupportFixtures(interactionType),
407
+ tests: interactionSupportTests(interactionType),
369
408
  };
370
409
  }
371
410
 
372
411
  function extendedTextInteractionEntry(): QtiInteractionElementSupport {
373
412
  return {
374
413
  ...entry("qti-extended-text-interaction", "extendedText"),
375
- fixtures: [
376
- "packages/fixtures/xml/extendedText-reference.xml",
377
- "packages/fixtures/packages/sv-matrix/items/extended-text-pattern-mask.xml",
378
- "packages/fixtures/packages/sv-matrix/items/extended-text-xhtml.xml",
379
- ],
380
- tests: [
381
- "packages/fixtures/src/fixtures.test.ts",
382
- "packages/conformance/src/conformance.test.ts",
383
- "packages/a11y/src/a11y.test.ts",
384
- "packages/core/src/pattern-mask.test.ts",
385
- "tests/browser/player.spec.ts",
386
- "tests/browser/player-dom-behavior.spec.ts",
387
- "tests/browser/player-extended-text-xhtml.spec.ts",
388
- ],
389
414
  notes: "Supports plain and format=xhtml extended text.",
390
415
  };
391
416
  }
@@ -393,18 +418,6 @@ function extendedTextInteractionEntry(): QtiInteractionElementSupport {
393
418
  function textEntryInteractionEntry(): QtiInteractionElementSupport {
394
419
  return {
395
420
  ...entry("qti-text-entry-interaction", "textEntry"),
396
- fixtures: [
397
- "packages/fixtures/xml/textEntry-reference.xml",
398
- "packages/fixtures/packages/sv-matrix/items/text-entry-pattern-mask-inline.xml",
399
- ],
400
- tests: [
401
- "packages/fixtures/src/fixtures.test.ts",
402
- "packages/conformance/src/conformance.test.ts",
403
- "packages/a11y/src/a11y.test.ts",
404
- "packages/core/src/pattern-mask.test.ts",
405
- "tests/browser/player.spec.ts",
406
- "tests/browser/player-dom-behavior.spec.ts",
407
- ],
408
421
  notes: "Supports placeholder-text and pattern-mask on text-entry controls.",
409
422
  };
410
423
  }
@@ -421,6 +434,7 @@ function processingEntry(
421
434
  qtiName: string,
422
435
  test: string,
423
436
  fixtures: string[] = [],
437
+ extraTests: string[] = [],
424
438
  ): QtiProcessingElementSupport {
425
439
  return {
426
440
  qtiName,
@@ -432,6 +446,6 @@ function processingEntry(
432
446
  render: false,
433
447
  process: true,
434
448
  fixtures,
435
- tests: [test],
449
+ tests: [test, ...extraTests],
436
450
  };
437
451
  }