adapt-schemas 1.0.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.
package/test.js ADDED
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Test script for the Adapt Schema Library
3
+ */
4
+ import Schemas from './index.js'
5
+ import path from 'path'
6
+ import { fileURLToPath } from 'url'
7
+ import fs from 'fs/promises'
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
10
+ const hasSpecifiedPath = Boolean(process.argv[2])
11
+
12
+ async function setupTestSchemas() {
13
+ if (hasSpecifiedPath) return
14
+ // Create test schema directory
15
+ const testSchemaDir = path.join(__dirname, 'test-schemas')
16
+ await fs.mkdir(testSchemaDir, { recursive: true })
17
+
18
+ // Create a course schema with _globals
19
+ const courseSchema = {
20
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
21
+ "$anchor": "course",
22
+ "$merge": {
23
+ "source": { "$ref": "base" },
24
+ "with": {
25
+ "properties": {
26
+ "title": {
27
+ "type": "string",
28
+ "description": "Course title",
29
+ "default": "Untitled Course"
30
+ },
31
+ "description": {
32
+ "type": "string",
33
+ "description": "Course description",
34
+ "default": ""
35
+ },
36
+ "_globals": {
37
+ "type": "object",
38
+ "description": "Global settings",
39
+ "properties": {
40
+ "_accessibility": {
41
+ "type": "object",
42
+ "properties": {
43
+ "_isEnabled": {
44
+ "type": "boolean",
45
+ "default": true
46
+ },
47
+ "skipNavigationText": {
48
+ "type": "string",
49
+ "default": "Skip navigation"
50
+ }
51
+ },
52
+ "required": [
53
+ "skipNavigationText"
54
+ ]
55
+ },
56
+ "_extensions": {
57
+ "type": "object",
58
+ "properties": {
59
+ "_trickle": {
60
+ "type": "object",
61
+ "properties": {
62
+ "incompleteContent": {
63
+ "type": "string",
64
+ "default": "There is incomplete content above"
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ },
73
+ "required": ["title"]
74
+ }
75
+ }
76
+ }
77
+
78
+ // Create a content schema
79
+ const contentSchema = {
80
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
81
+ "$anchor": "content",
82
+ "$merge": {
83
+ "source": { "$ref": "base" },
84
+ "with": {
85
+ "properties": {
86
+ "_type": {
87
+ "type": "string",
88
+ "description": "Content type"
89
+ },
90
+ "body": {
91
+ "type": "string",
92
+ "description": "Content body",
93
+ "default": ""
94
+ },
95
+ "_isOptional": {
96
+ "type": "boolean",
97
+ "default": false
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ // Create a component schema that extends content
105
+ const componentSchema = {
106
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
107
+ "$anchor": "component",
108
+ "$merge": {
109
+ "source": { "$ref": "content" },
110
+ "with": {
111
+ "properties": {
112
+ "_component": {
113
+ "type": "string",
114
+ "description": "Component type"
115
+ }
116
+ },
117
+ "required": ["_component"]
118
+ }
119
+ }
120
+ }
121
+
122
+ // Create a patch schema that extends course
123
+ const coursePatchSchema = {
124
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
125
+ "$anchor": "course-extension",
126
+ "$patch": {
127
+ "source": { "$ref": "course" },
128
+ "with": {
129
+ "properties": {
130
+ "_globals": {
131
+ "type": "object",
132
+ "properties": {
133
+ "_myPlugin": {
134
+ "type": "object",
135
+ "properties": {
136
+ "buttonLabel": {
137
+ "type": "string",
138
+ "default": "Click me"
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ await fs.writeFile(
150
+ path.join(testSchemaDir, 'course.schema.json'),
151
+ JSON.stringify(courseSchema, null, 2)
152
+ )
153
+ await fs.writeFile(
154
+ path.join(testSchemaDir, 'content.schema.json'),
155
+ JSON.stringify(contentSchema, null, 2)
156
+ )
157
+ await fs.writeFile(
158
+ path.join(testSchemaDir, 'component.schema.json'),
159
+ JSON.stringify(componentSchema, null, 2)
160
+ )
161
+ await fs.writeFile(
162
+ path.join(testSchemaDir, 'course-extension.schema.json'),
163
+ JSON.stringify(coursePatchSchema, null, 2)
164
+ )
165
+
166
+ return testSchemaDir
167
+ }
168
+
169
+ async function runTests() {
170
+ console.log('=== Adapt Schema Library Tests ===\n')
171
+
172
+ const testSchemaDir = hasSpecifiedPath
173
+ ? path.join(__dirname, process.argv[2])
174
+ : await setupTestSchemas()
175
+
176
+ try {
177
+ // Test 1: Initialize library
178
+ console.log('Test 1: Initialize library')
179
+ const library = new Schemas({
180
+ enableCache: true,
181
+ directoryReplacements: {
182
+ '$ROOT': process.cwd()
183
+ }
184
+ })
185
+ await library.init()
186
+ console.log(' ✓ Library initialized\n')
187
+
188
+ // Test 2: Load schemas with glob
189
+ console.log('Test 2: Load schemas with glob patterns')
190
+ await library.loadSchemas('**/*.schema.json', {
191
+ cwd: testSchemaDir,
192
+ ignore: ['**/excluded/**']
193
+ })
194
+ const schemaNames = library.getSchemaNames()
195
+ console.log(` ✓ Loaded schemas: ${schemaNames.join(', ')}\n`)
196
+
197
+ // Test 3: Get schema
198
+ console.log('Test 3: Get built schema')
199
+ const courseBuilt = await library.getBuiltSchema('course')
200
+ console.log(` ✓ Course schema has properties: ${Object.keys(courseBuilt.properties).join(', ')}\n`)
201
+
202
+ // Test 4: Get defaults
203
+ console.log('Test 4: Get schema defaults')
204
+ const courseDefaults = await library.getSchemaDefaults('course')
205
+ console.log(` ✓ Course defaults:`, JSON.stringify(courseDefaults, null, 4).split('\n').map(l => ' ' + l).join('\n'), '\n')
206
+
207
+ // Test 5: Get _globals defaults
208
+ console.log('Test 5: Get _globals defaults')
209
+ const globalsDefaults = await library.getGlobalsDefaults('course')
210
+ console.log(` ✓ _globals defaults:`, JSON.stringify(globalsDefaults, null, 4).split('\n').map(l => ' ' + l).join('\n'), '\n')
211
+
212
+ // Test 6: Validate data
213
+ console.log('Test 6: Validate data')
214
+ const validData = await library.validate('course', {
215
+ title: 'My Course'
216
+ })
217
+ console.log(` ✓ Validated data has title: "${validData.title}"`)
218
+ console.log(` ✓ Default description applied: "${validData.description}"\n`)
219
+
220
+ // Test 7: Validate with error (missing required field without defaults)
221
+ console.log('Test 7: Validation error handling')
222
+ try {
223
+ await library.validate('course', {
224
+ // Missing required title - disable defaults to trigger required error
225
+ _globals: { _accessibility: {} }
226
+ }, { useDefaults: false, ignoreRequired: false })
227
+ console.log(' ✗ Should have thrown validation error\n')
228
+ } catch (e) {
229
+ console.log(` ✓ Caught validation error: ${e.code}`)
230
+ console.log(` ✓ Error message: ${e.message}\n`)
231
+ }
232
+
233
+ // Test 7b: Validate with type error
234
+ console.log('Test 7b: Type validation error')
235
+ try {
236
+ await library.validate('course', {
237
+ title: 12345 // Should be string, not number
238
+ })
239
+ console.log(' ✗ Should have thrown validation error\n')
240
+ } catch (e) {
241
+ console.log(` ✓ Caught type validation error: ${e.code}\n`)
242
+ }
243
+
244
+ // Test 8: Schema inheritance
245
+ console.log('Test 8: Schema inheritance')
246
+ const componentBuilt = await library.getBuiltSchema('component')
247
+ const hasInheritedBody = componentBuilt.properties.body !== undefined
248
+ const hasOwnComponent = componentBuilt.properties._component !== undefined
249
+ console.log(` ✓ Component has inherited 'body' property: ${hasInheritedBody}`)
250
+ console.log(` ✓ Component has own '_component' property: ${hasOwnComponent}\n`)
251
+
252
+ // Test 9: Schema info
253
+ console.log('Test 9: Schema info')
254
+ const info = library.getSchemaInfo()
255
+ console.log(' ✓ Schema info:')
256
+ Object.entries(info).forEach(([name, details]) => {
257
+ console.log(` - ${name}: extensions=[${details.extensions.join(', ')}], isPatch=${details.isPatch}`)
258
+ })
259
+ console.log('')
260
+
261
+ // Test 10: Events
262
+ console.log('Test 10: Event handling')
263
+ library.on('schemaRegistered', (name) => {
264
+ console.log(` ✓ Event received: schemaRegistered (${name})`)
265
+ })
266
+
267
+ // Create another test schema to trigger the event
268
+ const newSchemaPath = path.join(testSchemaDir, 'test-event.schema.json')
269
+ await fs.writeFile(newSchemaPath, JSON.stringify({
270
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
271
+ "$anchor": "test-event",
272
+ "$merge": {
273
+ "source": { "$ref": "base" },
274
+ "with": { "properties": { "test": { "type": "string" } } }
275
+ }
276
+ }))
277
+ await library.registerSchema(newSchemaPath)
278
+ console.log('')
279
+
280
+ console.log('=== All tests passed! ===')
281
+
282
+ } finally {
283
+ if (hasSpecifiedPath) return
284
+ // Cleanup
285
+ await fs.rm(testSchemaDir, { recursive: true, force: true })
286
+ }
287
+ }
288
+
289
+ runTests().catch(console.error)