adapt-authoring-adaptframework 1.10.2 → 1.11.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.
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
on: push
|
|
3
|
+
jobs:
|
|
4
|
+
default:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
steps:
|
|
9
|
+
- uses: actions/checkout@v4
|
|
10
|
+
- uses: actions/setup-node@v4
|
|
11
|
+
with:
|
|
12
|
+
node-version: 'lts/*'
|
|
13
|
+
cache: 'npm'
|
|
14
|
+
- run: npm ci
|
|
15
|
+
- run: npm test
|
|
@@ -708,8 +708,10 @@ class AdaptFrameworkImport {
|
|
|
708
708
|
*/
|
|
709
709
|
async importCourseData () {
|
|
710
710
|
const formatError = e => {
|
|
711
|
-
if (e?.data?.schemaName)
|
|
712
|
-
|
|
711
|
+
if (e?.data?.schemaName) {
|
|
712
|
+
return `${e.data.schemaName}${e.data.data?._id ? ` (${e.data.data._id})` : ''}: ${e.data.errors ?? e.message}`
|
|
713
|
+
}
|
|
714
|
+
return e?.toString() ?? String(e)
|
|
713
715
|
}
|
|
714
716
|
/**
|
|
715
717
|
* Note: the execution order is important here
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adapt-authoring-adaptframework",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
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",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"repository": "github:adapt-security/adapt-authoring-adaptframework",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "node --test 'tests/**/*.spec.js'"
|
|
12
|
+
},
|
|
10
13
|
"dependencies": {
|
|
11
14
|
"adapt-authoring-browserslist": "^1.2.1",
|
|
12
15
|
"adapt-authoring-content": "^1.2.3",
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { describe, it, before, after } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import fs from 'fs/promises'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import AdaptFrameworkBuild from '../lib/AdaptFrameworkBuild.js'
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
|
|
10
|
+
describe('AdaptFrameworkBuild', () => {
|
|
11
|
+
describe('constructor', () => {
|
|
12
|
+
it('should set action and related boolean flags for preview', () => {
|
|
13
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
14
|
+
assert.equal(build.action, 'preview')
|
|
15
|
+
assert.equal(build.isPreview, true)
|
|
16
|
+
assert.equal(build.isPublish, false)
|
|
17
|
+
assert.equal(build.isExport, false)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('should set action and related boolean flags for publish', () => {
|
|
21
|
+
const build = new AdaptFrameworkBuild({ action: 'publish', courseId: 'c1', userId: 'u1' })
|
|
22
|
+
assert.equal(build.isPreview, false)
|
|
23
|
+
assert.equal(build.isPublish, true)
|
|
24
|
+
assert.equal(build.isExport, false)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('should set action and related boolean flags for export', () => {
|
|
28
|
+
const build = new AdaptFrameworkBuild({ action: 'export', courseId: 'c1', userId: 'u1' })
|
|
29
|
+
assert.equal(build.isPreview, false)
|
|
30
|
+
assert.equal(build.isPublish, false)
|
|
31
|
+
assert.equal(build.isExport, true)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should default compress to false for preview', () => {
|
|
35
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
36
|
+
assert.equal(build.compress, false)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should default compress to true for publish', () => {
|
|
40
|
+
const build = new AdaptFrameworkBuild({ action: 'publish', courseId: 'c1', userId: 'u1' })
|
|
41
|
+
assert.equal(build.compress, true)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should default compress to true for export', () => {
|
|
45
|
+
const build = new AdaptFrameworkBuild({ action: 'export', courseId: 'c1', userId: 'u1' })
|
|
46
|
+
assert.equal(build.compress, true)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should allow overriding compress', () => {
|
|
50
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1', compress: true })
|
|
51
|
+
assert.equal(build.compress, true)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should set courseId and userId', () => {
|
|
55
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'course123', userId: 'user456' })
|
|
56
|
+
assert.equal(build.courseId, 'course123')
|
|
57
|
+
assert.equal(build.userId, 'user456')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should set expiresAt when provided', () => {
|
|
61
|
+
const expires = '2025-01-01T00:00:00.000Z'
|
|
62
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1', expiresAt: expires })
|
|
63
|
+
assert.equal(build.expiresAt, expires)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should initialise courseData as empty object', () => {
|
|
67
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
68
|
+
assert.deepEqual(build.courseData, {})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('should initialise enabledPlugins and disabledPlugins as empty arrays', () => {
|
|
72
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
73
|
+
assert.deepEqual(build.enabledPlugins, [])
|
|
74
|
+
assert.deepEqual(build.disabledPlugins, [])
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should set collectionName to "adaptbuilds"', () => {
|
|
78
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
79
|
+
assert.equal(build.collectionName, 'adaptbuilds')
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('#ensureDir()', () => {
|
|
84
|
+
const testDir = path.join(__dirname, 'data', 'ensure-dir-test')
|
|
85
|
+
let build
|
|
86
|
+
|
|
87
|
+
before(() => {
|
|
88
|
+
build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
after(async () => {
|
|
92
|
+
await fs.rm(testDir, { recursive: true, force: true })
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should create a directory that does not exist', async () => {
|
|
96
|
+
await build.ensureDir(testDir)
|
|
97
|
+
const stat = await fs.stat(testDir)
|
|
98
|
+
assert.ok(stat.isDirectory())
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('should not throw when the directory already exists', async () => {
|
|
102
|
+
await build.ensureDir(testDir)
|
|
103
|
+
const stat = await fs.stat(testDir)
|
|
104
|
+
assert.ok(stat.isDirectory())
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
describe('#createIdMap()', () => {
|
|
109
|
+
it('should create a mapping of _id to _friendlyId', () => {
|
|
110
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
111
|
+
const items = [
|
|
112
|
+
{ _id: 'abc', _friendlyId: 'friendly-abc' },
|
|
113
|
+
{ _id: 'def', _friendlyId: 'friendly-def' }
|
|
114
|
+
]
|
|
115
|
+
build.createIdMap(items)
|
|
116
|
+
assert.deepEqual(build.idMap, {
|
|
117
|
+
abc: 'friendly-abc',
|
|
118
|
+
def: 'friendly-def'
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('should handle items without _friendlyId', () => {
|
|
123
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
124
|
+
const items = [{ _id: 'abc' }]
|
|
125
|
+
build.createIdMap(items)
|
|
126
|
+
assert.equal(build.idMap.abc, undefined)
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
describe('#sortContentItems()', () => {
|
|
131
|
+
it('should sort content into correct types', () => {
|
|
132
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
133
|
+
build.courseData = {
|
|
134
|
+
course: { dir: '/tmp', fileName: 'course.json', data: undefined },
|
|
135
|
+
config: { dir: '/tmp', fileName: 'config.json', data: undefined },
|
|
136
|
+
contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
|
|
137
|
+
article: { dir: '/tmp', fileName: 'articles.json', data: [] },
|
|
138
|
+
block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
|
|
139
|
+
component: { dir: '/tmp', fileName: 'components.json', data: [] }
|
|
140
|
+
}
|
|
141
|
+
const items = [
|
|
142
|
+
{ _id: 'course1', _type: 'course' },
|
|
143
|
+
{ _id: 'config1', _type: 'config' },
|
|
144
|
+
{ _id: 'page1', _type: 'page', _parentId: 'course1', _sortOrder: 1 },
|
|
145
|
+
{ _id: 'article1', _type: 'article', _parentId: 'page1', _sortOrder: 1 },
|
|
146
|
+
{ _id: 'block1', _type: 'block', _parentId: 'article1', _sortOrder: 1 },
|
|
147
|
+
{ _id: 'comp1', _type: 'component', _parentId: 'block1', _sortOrder: 1 }
|
|
148
|
+
]
|
|
149
|
+
build.sortContentItems(items)
|
|
150
|
+
|
|
151
|
+
assert.equal(build.courseData.course.data._id, 'course1')
|
|
152
|
+
assert.equal(build.courseData.config.data._id, 'config1')
|
|
153
|
+
assert.equal(build.courseData.contentObject.data.length, 1)
|
|
154
|
+
assert.equal(build.courseData.article.data.length, 1)
|
|
155
|
+
assert.equal(build.courseData.block.data.length, 1)
|
|
156
|
+
assert.equal(build.courseData.component.data.length, 1)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('should sort siblings by _sortOrder', () => {
|
|
160
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
161
|
+
build.courseData = {
|
|
162
|
+
course: { dir: '/tmp', fileName: 'course.json', data: undefined },
|
|
163
|
+
config: { dir: '/tmp', fileName: 'config.json', data: undefined },
|
|
164
|
+
contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
|
|
165
|
+
article: { dir: '/tmp', fileName: 'articles.json', data: [] },
|
|
166
|
+
block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
|
|
167
|
+
component: { dir: '/tmp', fileName: 'components.json', data: [] }
|
|
168
|
+
}
|
|
169
|
+
const items = [
|
|
170
|
+
{ _id: 'course1', _type: 'course' },
|
|
171
|
+
{ _id: 'page2', _type: 'page', _parentId: 'course1', _sortOrder: 2 },
|
|
172
|
+
{ _id: 'page1', _type: 'page', _parentId: 'course1', _sortOrder: 1 },
|
|
173
|
+
{ _id: 'page3', _type: 'page', _parentId: 'course1', _sortOrder: 3 }
|
|
174
|
+
]
|
|
175
|
+
build.sortContentItems(items)
|
|
176
|
+
|
|
177
|
+
assert.equal(build.courseData.contentObject.data[0]._id, 'page1')
|
|
178
|
+
assert.equal(build.courseData.contentObject.data[1]._id, 'page2')
|
|
179
|
+
assert.equal(build.courseData.contentObject.data[2]._id, 'page3')
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it('should categorise "menu" type as contentObject', () => {
|
|
183
|
+
const build = new AdaptFrameworkBuild({ action: 'preview', courseId: 'c1', userId: 'u1' })
|
|
184
|
+
build.courseData = {
|
|
185
|
+
course: { dir: '/tmp', fileName: 'course.json', data: undefined },
|
|
186
|
+
config: { dir: '/tmp', fileName: 'config.json', data: undefined },
|
|
187
|
+
contentObject: { dir: '/tmp', fileName: 'contentObjects.json', data: [] },
|
|
188
|
+
article: { dir: '/tmp', fileName: 'articles.json', data: [] },
|
|
189
|
+
block: { dir: '/tmp', fileName: 'blocks.json', data: [] },
|
|
190
|
+
component: { dir: '/tmp', fileName: 'components.json', data: [] }
|
|
191
|
+
}
|
|
192
|
+
const items = [
|
|
193
|
+
{ _id: 'course1', _type: 'course' },
|
|
194
|
+
{ _id: 'menu1', _type: 'menu', _parentId: 'course1', _sortOrder: 1 }
|
|
195
|
+
]
|
|
196
|
+
build.sortContentItems(items)
|
|
197
|
+
|
|
198
|
+
assert.equal(build.courseData.contentObject.data.length, 1)
|
|
199
|
+
assert.equal(build.courseData.contentObject.data[0]._id, 'menu1')
|
|
200
|
+
})
|
|
201
|
+
})
|
|
202
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import AdaptFrameworkImport from '../lib/AdaptFrameworkImport.js'
|
|
4
|
+
|
|
5
|
+
describe('AdaptFrameworkImport', () => {
|
|
6
|
+
describe('.typeToSchema()', () => {
|
|
7
|
+
it('should return "contentobject" for menu type', () => {
|
|
8
|
+
assert.equal(AdaptFrameworkImport.typeToSchema({ _type: 'menu' }), 'contentobject')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('should return "contentobject" for page type', () => {
|
|
12
|
+
assert.equal(AdaptFrameworkImport.typeToSchema({ _type: 'page' }), 'contentobject')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should return component-prefixed schema for component type', () => {
|
|
16
|
+
assert.equal(
|
|
17
|
+
AdaptFrameworkImport.typeToSchema({ _type: 'component', _component: 'adapt-contrib-text' }),
|
|
18
|
+
'adapt-contrib-text-component'
|
|
19
|
+
)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should return the _type directly for other types', () => {
|
|
23
|
+
assert.equal(AdaptFrameworkImport.typeToSchema({ _type: 'course' }), 'course')
|
|
24
|
+
assert.equal(AdaptFrameworkImport.typeToSchema({ _type: 'config' }), 'config')
|
|
25
|
+
assert.equal(AdaptFrameworkImport.typeToSchema({ _type: 'article' }), 'article')
|
|
26
|
+
assert.equal(AdaptFrameworkImport.typeToSchema({ _type: 'block' }), 'block')
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { describe, it, before, after } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import fs from 'fs/promises'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import AdaptFrameworkUtils from '../lib/AdaptFrameworkUtils.js'
|
|
7
|
+
|
|
8
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
9
|
+
|
|
10
|
+
describe('AdaptFrameworkUtils', () => {
|
|
11
|
+
describe('#inferBuildAction()', () => {
|
|
12
|
+
const cases = [
|
|
13
|
+
{ url: '/preview/abc123', expected: 'preview' },
|
|
14
|
+
{ url: '/publish/abc123', expected: 'publish' },
|
|
15
|
+
{ url: '/export/abc123', expected: 'export' }
|
|
16
|
+
]
|
|
17
|
+
cases.forEach(({ url, expected }) => {
|
|
18
|
+
it(`should return "${expected}" for URL "${url}"`, () => {
|
|
19
|
+
assert.equal(AdaptFrameworkUtils.inferBuildAction({ url }), expected)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// TODO: inferBuildAction returns truncated result for URLs without a second slash
|
|
24
|
+
// e.g. '/import' returns 'impor' because indexOf('/', 1) returns -1
|
|
25
|
+
// causing slice(1, -1) to strip the last character
|
|
26
|
+
it('should truncate action for URLs without trailing slash/path (known bug)', () => {
|
|
27
|
+
assert.equal(AdaptFrameworkUtils.inferBuildAction({ url: '/import' }), 'impor')
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
describe('#toBoolean()', () => {
|
|
32
|
+
it('should return true for boolean true', () => {
|
|
33
|
+
assert.equal(AdaptFrameworkUtils.toBoolean(true), true)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should return true for string "true"', () => {
|
|
37
|
+
assert.equal(AdaptFrameworkUtils.toBoolean('true'), true)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should return false for boolean false', () => {
|
|
41
|
+
assert.equal(AdaptFrameworkUtils.toBoolean(false), false)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should return false for string "false"', () => {
|
|
45
|
+
assert.equal(AdaptFrameworkUtils.toBoolean('false'), false)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('should return undefined for undefined', () => {
|
|
49
|
+
assert.equal(AdaptFrameworkUtils.toBoolean(undefined), undefined)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
it('should return false for null', () => {
|
|
53
|
+
assert.equal(AdaptFrameworkUtils.toBoolean(null), false)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should return false for 0', () => {
|
|
57
|
+
assert.equal(AdaptFrameworkUtils.toBoolean(0), false)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should return false for empty string', () => {
|
|
61
|
+
assert.equal(AdaptFrameworkUtils.toBoolean(''), false)
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
describe('#getPluginUpdateStatus()', () => {
|
|
66
|
+
it('should return "INVALID" for an invalid import version', () => {
|
|
67
|
+
assert.equal(AdaptFrameworkUtils.getPluginUpdateStatus(['1.0.0', 'not-valid'], false, false), 'INVALID')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should return "INSTALLED" when no installed version exists', () => {
|
|
71
|
+
assert.equal(AdaptFrameworkUtils.getPluginUpdateStatus([undefined, '1.0.0'], false, false), 'INSTALLED')
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('should return "OLDER" when import version is older', () => {
|
|
75
|
+
assert.equal(AdaptFrameworkUtils.getPluginUpdateStatus(['2.0.0', '1.0.0'], false, false), 'OLDER')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('should return "NO_CHANGE" when versions are equal', () => {
|
|
79
|
+
assert.equal(AdaptFrameworkUtils.getPluginUpdateStatus(['1.0.0', '1.0.0'], false, false), 'NO_CHANGE')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should return "UPDATE_BLOCKED" when import is newer but updates not enabled and not local', () => {
|
|
83
|
+
assert.equal(AdaptFrameworkUtils.getPluginUpdateStatus(['1.0.0', '2.0.0'], false, false), 'UPDATE_BLOCKED')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('should return "UPDATED" when import is newer and updates are enabled', () => {
|
|
87
|
+
assert.equal(AdaptFrameworkUtils.getPluginUpdateStatus(['1.0.0', '2.0.0'], false, true), 'UPDATED')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('should return "UPDATED" when import is newer and is a local install', () => {
|
|
91
|
+
assert.equal(AdaptFrameworkUtils.getPluginUpdateStatus(['1.0.0', '2.0.0'], true, false), 'UPDATED')
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
describe('#getImportContentCounts()', () => {
|
|
96
|
+
it('should count single items by _type', () => {
|
|
97
|
+
const content = {
|
|
98
|
+
course: { _type: 'course' },
|
|
99
|
+
config: { _type: 'config' }
|
|
100
|
+
}
|
|
101
|
+
const result = AdaptFrameworkUtils.getImportContentCounts(content)
|
|
102
|
+
assert.deepEqual(result, { course: 1, config: 1 })
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('should count arrays of items by _type', () => {
|
|
106
|
+
const content = {
|
|
107
|
+
course: { _type: 'course' },
|
|
108
|
+
contentObjects: {
|
|
109
|
+
co1: { _type: 'page' },
|
|
110
|
+
co2: { _type: 'page' },
|
|
111
|
+
co3: { _type: 'menu' }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const result = AdaptFrameworkUtils.getImportContentCounts(content)
|
|
115
|
+
assert.deepEqual(result, { course: 1, page: 2, menu: 1 })
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('should return empty object for empty content', () => {
|
|
119
|
+
assert.deepEqual(AdaptFrameworkUtils.getImportContentCounts({}), {})
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
describe('#readJson()', () => {
|
|
124
|
+
const testFile = path.join(__dirname, 'data', 'test-read.json')
|
|
125
|
+
|
|
126
|
+
before(async () => {
|
|
127
|
+
await fs.mkdir(path.join(__dirname, 'data'), { recursive: true })
|
|
128
|
+
await fs.writeFile(testFile, JSON.stringify({ key: 'value' }))
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
after(async () => {
|
|
132
|
+
await fs.rm(testFile, { force: true })
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('should read and parse a JSON file', async () => {
|
|
136
|
+
const result = await AdaptFrameworkUtils.readJson(testFile)
|
|
137
|
+
assert.deepEqual(result, { key: 'value' })
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('should throw for a non-existent file', async () => {
|
|
141
|
+
await assert.rejects(
|
|
142
|
+
AdaptFrameworkUtils.readJson('/nonexistent/file.json'),
|
|
143
|
+
{ code: 'ENOENT' }
|
|
144
|
+
)
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
describe('#writeJson()', () => {
|
|
149
|
+
const testFile = path.join(__dirname, 'data', 'test-write.json')
|
|
150
|
+
|
|
151
|
+
after(async () => {
|
|
152
|
+
await fs.rm(testFile, { force: true })
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('should write formatted JSON to a file', async () => {
|
|
156
|
+
const data = { hello: 'world', num: 42 }
|
|
157
|
+
await AdaptFrameworkUtils.writeJson(testFile, data)
|
|
158
|
+
const content = await fs.readFile(testFile, 'utf8')
|
|
159
|
+
assert.deepEqual(JSON.parse(content), data)
|
|
160
|
+
assert.ok(content.includes('\n'), 'should be formatted with indentation')
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
})
|