adapt-authoring-adaptframework 2.3.2 → 2.3.4

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.
@@ -70,11 +70,14 @@ class AdaptFrameworkModule extends AbstractModule {
70
70
  */
71
71
  this.contentMigrations = []
72
72
 
73
- const content = await this.app.waitForModule('content')
74
- content.accessCheckHook.tap(this.checkContentAccess.bind(this))
73
+ this.app.waitForModule('content').then(content => {
74
+ content.accessCheckHook.tap(this.checkContentAccess.bind(this))
75
+ })
75
76
 
76
77
  await this.installFramework()
77
78
 
79
+ process.env.BROWSERSLIST_IGNORE_OLD_DATA = '1'
80
+
78
81
  if (this.app.args['update-framework'] === true) {
79
82
  await this.updateFramework()
80
83
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adapt-authoring-adaptframework",
3
- "version": "2.3.2",
3
+ "version": "2.3.4",
4
4
  "description": "Adapt framework integration for the Adapt authoring tool",
5
5
  "homepage": "https://github.com/adapt-security/adapt-authoring-adaptframework",
6
6
  "license": "GPL-3.0",
@@ -11,7 +11,6 @@
11
11
  "test": "node --test --test-force-exit --experimental-test-module-mocks 'tests/**/*.spec.js'"
12
12
  },
13
13
  "dependencies": {
14
- "adapt-authoring-browserslist": "^1.3.4",
15
14
  "adapt-authoring-content": "^2.0.0",
16
15
  "adapt-authoring-contentplugin": "^1.0.3",
17
16
  "adapt-authoring-core": "^2.0.0",
@@ -9,6 +9,34 @@ import AdaptFrameworkBuild from '../lib/AdaptFrameworkBuild.js'
9
9
 
10
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
11
11
 
12
+ // ── Helpers ──────────────────────────────────────────────────────────
13
+
14
+ function createBuild (overrides = {}) {
15
+ return new AdaptFrameworkBuild({
16
+ action: 'preview', courseId: 'c1', userId: 'u1', ...overrides
17
+ })
18
+ }
19
+
20
+ function createEmptyCourseData () {
21
+ return {
22
+ course: { dir: '/tmp', fileName: 'course.json', data: undefined },
23
+ config: { dir: '/tmp', fileName: 'config.json', data: undefined },
24
+ contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
25
+ article: { dir: '/tmp', fileName: 'articles.json', data: [] },
26
+ block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
27
+ component: { dir: '/tmp', fileName: 'components.json', data: [] }
28
+ }
29
+ }
30
+
31
+ function createTransformBuild (overrides = {}) {
32
+ const build = createBuild(overrides)
33
+ build.idMap = overrides.idMap || {}
34
+ build.assetData = overrides.assetData || { idMap: {} }
35
+ build.enabledPlugins = overrides.enabledPlugins || []
36
+ build.courseData = overrides.courseData || { course: { dir: '/tmp', data: {} } }
37
+ return build
38
+ }
39
+
12
40
  /**
13
41
  * transformContentItems is async and calls App.instance.waitForModule('tags')
14
42
  * at the end. We extract the synchronous logic here to test it in isolation.
@@ -44,7 +72,7 @@ function transformContentItemsSync (build, items) {
44
72
  describe('AdaptFrameworkBuild', () => {
45
73
  describe('constructor', () => {
46
74
  it('should set action and related boolean flags for preview', () => {
47
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
75
+ const build = createBuild()
48
76
  assert.equal(build.action, 'preview')
49
77
  assert.equal(build.isPreview, true)
50
78
  assert.equal(build.isPublish, false)
@@ -52,64 +80,64 @@ describe('AdaptFrameworkBuild', () => {
52
80
  })
53
81
 
54
82
  it('should set action and related boolean flags for publish', () => {
55
- const build = new AdaptFrameworkBuild({ action: 'publish', courseId: 'c1', userId: 'u1' })
83
+ const build = createBuild({ action: 'publish' })
56
84
  assert.equal(build.isPreview, false)
57
85
  assert.equal(build.isPublish, true)
58
86
  assert.equal(build.isExport, false)
59
87
  })
60
88
 
61
89
  it('should set action and related boolean flags for export', () => {
62
- const build = new AdaptFrameworkBuild({ action: 'export', courseId: 'c1', userId: 'u1' })
90
+ const build = createBuild({ action: 'export' })
63
91
  assert.equal(build.isPreview, false)
64
92
  assert.equal(build.isPublish, false)
65
93
  assert.equal(build.isExport, true)
66
94
  })
67
95
 
68
96
  it('should default compress to false for preview', () => {
69
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
97
+ const build = createBuild()
70
98
  assert.equal(build.compress, false)
71
99
  })
72
100
 
73
101
  it('should default compress to true for publish', () => {
74
- const build = new AdaptFrameworkBuild({ action: 'publish', courseId: 'c1', userId: 'u1' })
102
+ const build = createBuild({ action: 'publish' })
75
103
  assert.equal(build.compress, true)
76
104
  })
77
105
 
78
106
  it('should default compress to true for export', () => {
79
- const build = new AdaptFrameworkBuild({ action: 'export', courseId: 'c1', userId: 'u1' })
107
+ const build = createBuild({ action: 'export' })
80
108
  assert.equal(build.compress, true)
81
109
  })
82
110
 
83
111
  it('should allow overriding compress', () => {
84
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1', compress: true })
112
+ const build = createBuild({ compress: true })
85
113
  assert.equal(build.compress, true)
86
114
  })
87
115
 
88
116
  it('should set courseId and userId', () => {
89
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'course123', userId: 'user456' })
117
+ const build = createBuild({ courseId: 'course123', userId: 'user456' })
90
118
  assert.equal(build.courseId, 'course123')
91
119
  assert.equal(build.userId, 'user456')
92
120
  })
93
121
 
94
122
  it('should set expiresAt when provided', () => {
95
123
  const expires = '2025-01-01T00:00:00.000Z'
96
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1', expiresAt: expires })
124
+ const build = createBuild({ expiresAt: expires })
97
125
  assert.equal(build.expiresAt, expires)
98
126
  })
99
127
 
100
128
  it('should initialise courseData as empty object', () => {
101
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
129
+ const build = createBuild()
102
130
  assert.deepEqual(build.courseData, {})
103
131
  })
104
132
 
105
133
  it('should initialise enabledPlugins and disabledPlugins as empty arrays', () => {
106
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
134
+ const build = createBuild()
107
135
  assert.deepEqual(build.enabledPlugins, [])
108
136
  assert.deepEqual(build.disabledPlugins, [])
109
137
  })
110
138
 
111
139
  it('should set collectionName to "adaptbuilds"', () => {
112
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
140
+ const build = createBuild()
113
141
  assert.equal(build.collectionName, 'adaptbuilds')
114
142
  })
115
143
  })
@@ -136,7 +164,7 @@ describe('AdaptFrameworkBuild', () => {
136
164
 
137
165
  describe('#createIdMap()', () => {
138
166
  it('should create a mapping of _id to _friendlyId', () => {
139
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
167
+ const build = createBuild()
140
168
  const items = [
141
169
  { _id: 'abc', _friendlyId: 'friendly-abc' },
142
170
  { _id: 'def', _friendlyId: 'friendly-def' }
@@ -149,7 +177,7 @@ describe('AdaptFrameworkBuild', () => {
149
177
  })
150
178
 
151
179
  it('should handle items without _friendlyId', () => {
152
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
180
+ const build = createBuild()
153
181
  const items = [{ _id: 'abc' }]
154
182
  build.createIdMap(items)
155
183
  assert.equal(build.idMap.abc, undefined)
@@ -158,15 +186,8 @@ describe('AdaptFrameworkBuild', () => {
158
186
 
159
187
  describe('#sortContentItems()', () => {
160
188
  it('should sort content into correct types', () => {
161
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
162
- build.courseData = {
163
- course: { dir: '/tmp', fileName: 'course.json', data: undefined },
164
- config: { dir: '/tmp', fileName: 'config.json', data: undefined },
165
- contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
166
- article: { dir: '/tmp', fileName: 'articles.json', data: [] },
167
- block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
168
- component: { dir: '/tmp', fileName: 'components.json', data: [] }
169
- }
189
+ const build = createBuild()
190
+ build.courseData = createEmptyCourseData()
170
191
  const items = [
171
192
  { _id: 'course1', _type: 'course' },
172
193
  { _id: 'config1', _type: 'config' },
@@ -186,15 +207,8 @@ describe('AdaptFrameworkBuild', () => {
186
207
  })
187
208
 
188
209
  it('should sort siblings by _sortOrder', () => {
189
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
190
- build.courseData = {
191
- course: { dir: '/tmp', fileName: 'course.json', data: undefined },
192
- config: { dir: '/tmp', fileName: 'config.json', data: undefined },
193
- contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
194
- article: { dir: '/tmp', fileName: 'articles.json', data: [] },
195
- block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
196
- component: { dir: '/tmp', fileName: 'components.json', data: [] }
197
- }
210
+ const build = createBuild()
211
+ build.courseData = createEmptyCourseData()
198
212
  const items = [
199
213
  { _id: 'course1', _type: 'course' },
200
214
  { _id: 'page2', _type: 'page', _parentId: 'course1', _sortOrder: 2 },
@@ -209,15 +223,8 @@ describe('AdaptFrameworkBuild', () => {
209
223
  })
210
224
 
211
225
  it('should categorise "menu" type as contentObject', () => {
212
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
213
- build.courseData = {
214
- course: { dir: '/tmp', fileName: 'course.json', data: undefined },
215
- config: { dir: '/tmp', fileName: 'config.json', data: undefined },
216
- contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
217
- article: { dir: '/tmp', fileName: 'articles.json', data: [] },
218
- block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
219
- component: { dir: '/tmp', fileName: 'components.json', data: [] }
220
- }
226
+ const build = createBuild()
227
+ build.courseData = createEmptyCourseData()
221
228
  const items = [
222
229
  { _id: 'course1', _type: 'course' },
223
230
  { _id: 'menu1', _type: 'menu', _parentId: 'course1', _sortOrder: 1 }
@@ -229,15 +236,8 @@ describe('AdaptFrameworkBuild', () => {
229
236
  })
230
237
 
231
238
  it('should sort deeply nested content in global order', () => {
232
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
233
- build.courseData = {
234
- course: { dir: '/tmp', fileName: 'course.json', data: undefined },
235
- config: { dir: '/tmp', fileName: 'config.json', data: undefined },
236
- contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
237
- article: { dir: '/tmp', fileName: 'articles.json', data: [] },
238
- block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
239
- component: { dir: '/tmp', fileName: 'components.json', data: [] }
240
- }
239
+ const build = createBuild()
240
+ build.courseData = createEmptyCourseData()
241
241
  const items = [
242
242
  { _id: 'course1', _type: 'course' },
243
243
  { _id: 'page1', _type: 'page', _parentId: 'course1', _sortOrder: 1 },
@@ -257,101 +257,69 @@ describe('AdaptFrameworkBuild', () => {
257
257
 
258
258
  describe('#transformContentItems()', () => {
259
259
  it('should replace _courseId and _parentId with friendlyIds from idMap', () => {
260
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
261
- build.idMap = { course1: 'co-friendly', page1: 'page-friendly' }
262
- build.assetData = { idMap: {} }
263
- build.enabledPlugins = []
264
- build.courseData = { course: { dir: '/tmp', data: {} } }
265
-
266
- const items = [
267
- { _courseId: 'course1', _parentId: 'page1' }
268
- ]
260
+ const build = createTransformBuild({
261
+ idMap: { course1: 'co-friendly', page1: 'page-friendly' }
262
+ })
263
+ const items = [{ _courseId: 'course1', _parentId: 'page1' }]
269
264
  transformContentItemsSync(build, items)
270
265
  assert.equal(items[0]._courseId, 'co-friendly')
271
266
  assert.equal(items[0]._parentId, 'page-friendly')
272
267
  })
273
268
 
274
269
  it('should replace _id with _friendlyId when present', () => {
275
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
276
- build.idMap = {}
277
- build.assetData = { idMap: {} }
278
- build.enabledPlugins = []
279
- build.courseData = { course: { dir: '/tmp', data: {} } }
280
-
270
+ const build = createTransformBuild()
281
271
  const items = [{ _id: 'abc', _friendlyId: 'my-friendly' }]
282
272
  transformContentItemsSync(build, items)
283
273
  assert.equal(items[0]._id, 'my-friendly')
284
274
  })
285
275
 
286
276
  it('should not replace _id when _friendlyId is absent', () => {
287
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
288
- build.idMap = {}
289
- build.assetData = { idMap: {} }
290
- build.enabledPlugins = []
291
- build.courseData = { course: { dir: '/tmp', data: {} } }
292
-
277
+ const build = createTransformBuild()
293
278
  const items = [{ _id: 'abc' }]
294
279
  transformContentItemsSync(build, items)
295
280
  assert.equal(items[0]._id, 'abc')
296
281
  })
297
282
 
298
283
  it('should replace asset _ids with relative paths', () => {
299
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
300
- build.idMap = {}
284
+ const build = createTransformBuild({
285
+ assetData: { idMap: { asset123: '/build/course/assets/image.png' } }
286
+ })
301
287
  build.courseDir = '/build/course'
302
- build.assetData = { idMap: { asset123: '/build/course/assets/image.png' } }
303
- build.enabledPlugins = []
304
- build.courseData = { course: { dir: '/tmp', data: {} } }
305
-
306
288
  const items = [{ graphic: 'asset123' }]
307
289
  transformContentItemsSync(build, items)
308
290
  assert.equal(items[0].graphic, 'course/assets/image.png')
309
291
  })
310
292
 
311
293
  it('should resolve _component to targetAttribute', () => {
312
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
313
- build.idMap = {}
314
- build.assetData = { idMap: {} }
315
- build.enabledPlugins = [
316
- { name: 'adapt-contrib-text', targetAttribute: '_text', type: 'component' }
317
- ]
318
- build.courseData = { course: { dir: '/tmp', data: {} } }
319
-
294
+ const build = createTransformBuild({
295
+ enabledPlugins: [
296
+ { name: 'adapt-contrib-text', targetAttribute: '_text', type: 'component' }
297
+ ]
298
+ })
320
299
  const items = [{ _component: 'adapt-contrib-text' }]
321
300
  transformContentItemsSync(build, items)
322
301
  assert.equal(items[0]._component, 'text')
323
302
  })
324
303
 
325
304
  it('should keep _component as-is when plugin not found', () => {
326
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
327
- build.idMap = {}
328
- build.assetData = { idMap: {} }
329
- build.enabledPlugins = []
330
- build.courseData = { course: { dir: '/tmp', data: {} } }
331
-
305
+ const build = createTransformBuild()
332
306
  const items = [{ _component: 'unknown-plugin' }]
333
307
  transformContentItemsSync(build, items)
334
308
  assert.equal(items[0]._component, 'unknown-plugin')
335
309
  })
336
310
 
337
311
  it('should move globals into nested _extensions object', () => {
338
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
339
- build.idMap = {}
340
- build.assetData = { idMap: {} }
341
- build.enabledPlugins = [
342
- { name: 'adapt-contrib-trickle', targetAttribute: '_trickle', type: 'extension' }
343
- ]
344
- build.courseData = {
345
- course: {
346
- dir: '/tmp',
347
- data: {
348
- _globals: {
349
- _trickle: { label: 'Trickle' }
350
- }
312
+ const build = createTransformBuild({
313
+ enabledPlugins: [
314
+ { name: 'adapt-contrib-trickle', targetAttribute: '_trickle', type: 'extension' }
315
+ ],
316
+ courseData: {
317
+ course: {
318
+ dir: '/tmp',
319
+ data: { _globals: { _trickle: { label: 'Trickle' } } }
351
320
  }
352
321
  }
353
- }
354
-
322
+ })
355
323
  transformContentItemsSync(build, [])
356
324
  const globals = build.courseData.course.data._globals
357
325
  assert.equal(globals._extensions._trickle.label, 'Trickle')
@@ -359,35 +327,24 @@ describe('AdaptFrameworkBuild', () => {
359
327
  })
360
328
 
361
329
  it('should use _components key for component type globals', () => {
362
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
363
- build.idMap = {}
364
- build.assetData = { idMap: {} }
365
- build.enabledPlugins = [
366
- { name: 'adapt-contrib-text', targetAttribute: '_text', type: 'component' }
367
- ]
368
- build.courseData = {
369
- course: {
370
- dir: '/tmp',
371
- data: {
372
- _globals: {
373
- _text: { ariaRegion: 'Text' }
374
- }
330
+ const build = createTransformBuild({
331
+ enabledPlugins: [
332
+ { name: 'adapt-contrib-text', targetAttribute: '_text', type: 'component' }
333
+ ],
334
+ courseData: {
335
+ course: {
336
+ dir: '/tmp',
337
+ data: { _globals: { _text: { ariaRegion: 'Text' } } }
375
338
  }
376
339
  }
377
- }
378
-
340
+ })
379
341
  transformContentItemsSync(build, [])
380
342
  const globals = build.courseData.course.data._globals
381
343
  assert.equal(globals._components._text.ariaRegion, 'Text')
382
344
  })
383
345
 
384
346
  it('should keep _courseId as-is when not in idMap', () => {
385
- const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
386
- build.idMap = {}
387
- build.assetData = { idMap: {} }
388
- build.enabledPlugins = []
389
- build.courseData = { course: { dir: '/tmp', data: {} } }
390
-
347
+ const build = createTransformBuild()
391
348
  const items = [{ _courseId: 'unmapped' }]
392
349
  transformContentItemsSync(build, items)
393
350
  assert.equal(items[0]._courseId, 'unmapped')
@@ -396,7 +353,7 @@ describe('AdaptFrameworkBuild', () => {
396
353
 
397
354
  describe('#writeContentJson() asset mapping', () => {
398
355
  it('should map asset data to export format for export builds', () => {
399
- const build = new AdaptFrameworkBuild({ action: 'export', courseId: 'c1', userId: 'u1' })
356
+ const build = createBuild({ action: 'export' })
400
357
  build.assetData = {
401
358
  data: [
402
359
  { title: 'Logo', description: 'A logo', path: 'assets/logo.png', tags: ['branding'], _id: '123', url: '' },
@@ -418,7 +375,7 @@ describe('AdaptFrameworkBuild', () => {
418
375
  })
419
376
 
420
377
  it('should not include assets for export when assetData is empty', () => {
421
- const build = new AdaptFrameworkBuild({ action: 'export', courseId: 'c1', userId: 'u1' })
378
+ const build = createBuild({ action: 'export' })
422
379
  build.assetData = { data: [] }
423
380
  build.courseData = {
424
381
  course: { dir: '/tmp', fileName: 'course.json', data: {} }
@@ -431,7 +388,7 @@ describe('AdaptFrameworkBuild', () => {
431
388
  })
432
389
 
433
390
  it('should include asset data entry for non-empty export', () => {
434
- const build = new AdaptFrameworkBuild({ action: 'export', courseId: 'c1', userId: 'u1' })
391
+ const build = createBuild({ action: 'export' })
435
392
  build.assetData = { data: [{ title: 'img', path: 'a.png' }] }
436
393
  build.courseData = {
437
394
  course: { dir: '/tmp', fileName: 'course.json', data: {} }