adapt-authoring-core 2.5.0 → 3.0.1

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,187 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import Logger from '../lib/Logger.js'
4
+
5
+ describe('Logger', () => {
6
+ describe('constructor', () => {
7
+ it('should create with defaults', () => {
8
+ const logger = new Logger()
9
+ assert.ok(logger.config)
10
+ assert.ok(logger.logHook)
11
+ assert.equal(logger.config.mute, false)
12
+ })
13
+
14
+ it('should mute when levels is empty', () => {
15
+ const logger = new Logger({ levels: [] })
16
+ assert.equal(logger.config.mute, true)
17
+ })
18
+
19
+ it('should not mute when levels are provided', () => {
20
+ const logger = new Logger({ levels: ['error'] })
21
+ assert.equal(logger.config.mute, false)
22
+ })
23
+
24
+ it('should configure levels from options', () => {
25
+ const logger = new Logger({ levels: ['error', 'warn'] })
26
+ assert.equal(logger.config.levels.error.enable, true)
27
+ assert.equal(logger.config.levels.debug.enable, false)
28
+ })
29
+ })
30
+
31
+ describe('.isLevelEnabled()', () => {
32
+ it('should return true when level is in config', () => {
33
+ assert.equal(Logger.isLevelEnabled(['error', 'warn'], 'error'), true)
34
+ })
35
+
36
+ it('should return false when level is not in config', () => {
37
+ assert.equal(Logger.isLevelEnabled(['error'], 'debug'), false)
38
+ })
39
+
40
+ it('should return false when level is negated', () => {
41
+ assert.equal(Logger.isLevelEnabled(['error', '!error'], 'error'), false)
42
+ })
43
+ })
44
+
45
+ describe('.getModuleOverrides()', () => {
46
+ it('should return matching overrides', () => {
47
+ const config = ['error', 'debug.mymod', '!debug.other']
48
+ assert.deepEqual(Logger.getModuleOverrides(config, 'debug'), ['debug.mymod', '!debug.other'])
49
+ })
50
+
51
+ it('should return empty array when no overrides', () => {
52
+ assert.deepEqual(Logger.getModuleOverrides(['error'], 'debug'), [])
53
+ })
54
+
55
+ it('should not include line-level (3-segment) entries', () => {
56
+ const config = ['debug.mymod', 'debug.mymod.LOAD', '!debug.other.SAVE']
57
+ assert.deepEqual(Logger.getModuleOverrides(config, 'debug'), ['debug.mymod'])
58
+ })
59
+
60
+ it('should not include id-wide entries', () => {
61
+ const config = ['debug.mymod', 'mymod', '!other']
62
+ assert.deepEqual(Logger.getModuleOverrides(config, 'debug'), ['debug.mymod'])
63
+ })
64
+ })
65
+
66
+ describe('.getLineOverrides()', () => {
67
+ it('should return only 3-segment entries for the level', () => {
68
+ const config = ['debug', 'debug.mymod', 'debug.mymod.LOAD', '!debug.other.SAVE', 'verbose.foo.BAR']
69
+ assert.deepEqual(Logger.getLineOverrides(config, 'debug'), ['debug.mymod.LOAD', '!debug.other.SAVE'])
70
+ })
71
+
72
+ it('should return empty array when no line overrides', () => {
73
+ assert.deepEqual(Logger.getLineOverrides(['debug', 'debug.mymod'], 'debug'), [])
74
+ })
75
+ })
76
+
77
+ describe('.getIdOverrides()', () => {
78
+ it('should return entries whose first segment is not a known level', () => {
79
+ const config = ['debug', 'debug.mymod', 'mymod', '!other', 'datacache']
80
+ assert.deepEqual(Logger.getIdOverrides(config), ['mymod', '!other', 'datacache'])
81
+ })
82
+
83
+ it('should not include bare level entries', () => {
84
+ assert.deepEqual(Logger.getIdOverrides(['debug', '!verbose']), [])
85
+ })
86
+
87
+ it('should not include level-prefixed entries', () => {
88
+ assert.deepEqual(Logger.getIdOverrides(['debug.mymod', '!verbose.foo.BAR']), [])
89
+ })
90
+ })
91
+
92
+ describe('.isLoggingEnabled()', () => {
93
+ it('should return true when level is enabled', () => {
94
+ const levels = { error: { enable: true, moduleOverrides: [] } }
95
+ assert.equal(Logger.isLoggingEnabled(levels, 'error', 'test'), true)
96
+ })
97
+
98
+ it('should return false when level is disabled', () => {
99
+ const levels = { error: { enable: false, moduleOverrides: [] } }
100
+ assert.equal(Logger.isLoggingEnabled(levels, 'error', 'test'), false)
101
+ })
102
+
103
+ it('should allow module-specific override', () => {
104
+ const levels = { debug: { enable: false, moduleOverrides: ['debug.mymod'] } }
105
+ assert.equal(Logger.isLoggingEnabled(levels, 'debug', 'mymod'), true)
106
+ })
107
+
108
+ it('should allow module-specific disable override', () => {
109
+ const levels = { debug: { enable: true, moduleOverrides: ['!debug.mymod'] } }
110
+ assert.equal(Logger.isLoggingEnabled(levels, 'debug', 'mymod'), false)
111
+ })
112
+
113
+ it('should mute a specific line via line-level override', () => {
114
+ const levels = { verbose: { enable: true, moduleOverrides: [], lineOverrides: ['!verbose.server.REQUEST_DURATION'] } }
115
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'server', 'REQUEST_DURATION'), false)
116
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'server', 'ADD_ROUTE'), true)
117
+ })
118
+
119
+ it('should enable a specific line when level is otherwise disabled', () => {
120
+ const levels = { verbose: { enable: false, moduleOverrides: [], lineOverrides: ['verbose.server.ADD_ROUTE'] } }
121
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'server', 'ADD_ROUTE'), true)
122
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'server', 'OTHER'), false)
123
+ })
124
+
125
+ it('should let line-level mute beat per-level module enable', () => {
126
+ const levels = { verbose: { enable: true, moduleOverrides: ['verbose.server'], lineOverrides: ['!verbose.server.REQUEST_DURATION'] } }
127
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'server', 'REQUEST_DURATION'), false)
128
+ })
129
+
130
+ it('should mute via id-wide override at any level', () => {
131
+ const levels = { verbose: { enable: true, moduleOverrides: [], lineOverrides: [] } }
132
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'datacache', undefined, ['!datacache']), false)
133
+ })
134
+
135
+ it('should let per-level module enable beat id-wide mute', () => {
136
+ const levels = { verbose: { enable: false, moduleOverrides: ['verbose.datacache'], lineOverrides: [] } }
137
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'datacache', undefined, ['!datacache']), true)
138
+ })
139
+
140
+ it('should let id-wide enable beat global level mute', () => {
141
+ const levels = { verbose: { enable: false, moduleOverrides: [], lineOverrides: [] } }
142
+ assert.equal(Logger.isLoggingEnabled(levels, 'verbose', 'datacache', undefined, ['datacache']), true)
143
+ })
144
+ })
145
+
146
+ describe('#log()', () => {
147
+ it('should not throw when muted via empty levels', () => {
148
+ const logger = new Logger({ levels: [] })
149
+ assert.doesNotThrow(() => logger.log('error', 'test', 'message'))
150
+ })
151
+
152
+ it('should mute a specific line via config', () => {
153
+ const calls = []
154
+ const origInfo = console.info
155
+ console.info = (...args) => calls.push(args)
156
+ try {
157
+ const logger = new Logger({ levels: ['info', '!info.server.REQUEST_DURATION'], showTimestamp: false })
158
+ logger.log('info', 'server', 'REQUEST_DURATION', 'GET', '/foo')
159
+ logger.log('info', 'server', 'ADD_ROUTE', 'GET', '/foo')
160
+ assert.equal(calls.length, 1)
161
+ assert.match(calls[0].join(' '), /ADD_ROUTE/)
162
+ } finally {
163
+ console.info = origInfo
164
+ }
165
+ })
166
+
167
+ it('should mute an id at every level via config', () => {
168
+ const calls = []
169
+ const origInfo = console.info
170
+ const origWarn = console.warn
171
+ console.info = (...args) => calls.push(['info', args])
172
+ console.warn = (...args) => calls.push(['warn', args])
173
+ try {
174
+ const logger = new Logger({ levels: ['info', 'warn', '!datacache'], showTimestamp: false })
175
+ logger.log('info', 'datacache', 'hit')
176
+ logger.log('warn', 'datacache', 'miss')
177
+ logger.log('info', 'server', 'ok')
178
+ assert.equal(calls.length, 1)
179
+ assert.equal(calls[0][0], 'info')
180
+ assert.match(calls[0][1].join(' '), /server/)
181
+ } finally {
182
+ console.info = origInfo
183
+ console.warn = origWarn
184
+ }
185
+ })
186
+ })
187
+ })
@@ -7,16 +7,10 @@ describe('getArgs()', () => {
7
7
  it('should return an object with parsed arguments', () => {
8
8
  const args = getArgs()
9
9
  assert.equal(typeof args, 'object')
10
- assert.ok(Array.isArray(args.params))
11
10
  })
12
11
 
13
- it('should include the underscore array from minimist', () => {
12
+ it('should include params as an array', () => {
14
13
  const args = getArgs()
15
- assert.ok(Array.isArray(args._))
16
- })
17
-
18
- it('should derive params by slicing first two entries from _', () => {
19
- const args = getArgs()
20
- assert.deepEqual(args.params, args._.slice(2))
14
+ assert.ok(Array.isArray(args.params))
21
15
  })
22
16
  })
package/tests/App.spec.js DELETED
@@ -1,160 +0,0 @@
1
- import { describe, it, before, after } from 'node:test'
2
- import assert from 'node:assert/strict'
3
- import fs from 'fs-extra'
4
- import path from 'path'
5
- import { fileURLToPath } from 'url'
6
- import App from '../lib/App.js'
7
-
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
9
-
10
- describe('App', () => {
11
- let testRootDir
12
- let originalRootDir
13
-
14
- before(async () => {
15
- testRootDir = path.join(__dirname, 'data', 'app-test')
16
- await fs.ensureDir(testRootDir)
17
- await fs.writeJson(path.join(testRootDir, 'package.json'), {
18
- name: 'test-app',
19
- version: '1.0.0'
20
- })
21
- await fs.writeJson(path.join(testRootDir, 'adapt-authoring.json'), {
22
- essentialApis: []
23
- })
24
- originalRootDir = process.env.ROOT_DIR
25
- process.env.ROOT_DIR = testRootDir
26
- })
27
-
28
- after(async () => {
29
- if (originalRootDir !== undefined) {
30
- process.env.ROOT_DIR = originalRootDir
31
- } else {
32
- delete process.env.ROOT_DIR
33
- }
34
- await fs.remove(testRootDir)
35
- })
36
-
37
- describe('.instance', () => {
38
- it('should return an App instance', () => {
39
- const app = App.instance
40
- assert.ok(app instanceof App)
41
- })
42
-
43
- it('should return the same instance on subsequent calls (singleton)', () => {
44
- const app1 = App.instance
45
- const app2 = App.instance
46
- assert.equal(app1, app2)
47
- })
48
- })
49
-
50
- describe('constructor', () => {
51
- it('should set name to adapt-authoring-core', () => {
52
- const app = App.instance
53
- assert.equal(app.name, 'adapt-authoring-core')
54
- })
55
-
56
- it('should set rootDir from ROOT_DIR env var', () => {
57
- const app = App.instance
58
- assert.equal(app.rootDir, testRootDir)
59
- })
60
-
61
- it('should initialize git info', () => {
62
- const app = App.instance
63
- assert.equal(typeof app.git, 'object')
64
- })
65
- })
66
-
67
- describe('#dependencies', () => {
68
- it('should return the dependency configs from dependencyloader', () => {
69
- const app = App.instance
70
- assert.equal(typeof app.dependencies, 'object')
71
- assert.equal(app.dependencies, app.dependencyloader.configs)
72
- })
73
- })
74
-
75
- describe('#getGitInfo()', () => {
76
- it('should return an object', () => {
77
- const app = App.instance
78
- const info = app.getGitInfo()
79
- assert.equal(typeof info, 'object')
80
- })
81
-
82
- it('should return empty object when .git directory does not exist', () => {
83
- const app = App.instance
84
- const origRootDir = app.rootDir
85
- app.rootDir = '/nonexistent/path'
86
- const info = app.getGitInfo()
87
- app.rootDir = origRootDir
88
- assert.deepEqual(info, {})
89
- })
90
-
91
- it('should return object with branch and commit when .git exists', async () => {
92
- const gitDir = path.join(testRootDir, '.git')
93
- const refsDir = path.join(gitDir, 'refs', 'heads')
94
- await fs.ensureDir(refsDir)
95
- await fs.writeFile(path.join(gitDir, 'HEAD'), 'ref: refs/heads/main\n')
96
- await fs.writeFile(path.join(refsDir, 'main'), 'abc123def456\n')
97
-
98
- const app = App.instance
99
- const origRootDir = app.rootDir
100
- app.rootDir = testRootDir
101
- const info = app.getGitInfo()
102
- app.rootDir = origRootDir
103
-
104
- assert.equal(info.branch, 'main')
105
- assert.equal(info.commit, 'abc123def456')
106
-
107
- await fs.remove(gitDir)
108
- })
109
- })
110
-
111
- describe('#waitForModule()', () => {
112
- it('should delegate to dependencyloader.waitForModule', async () => {
113
- const app = App.instance
114
- let calledWith
115
- const origWaitForModule = app.dependencyloader.waitForModule.bind(app.dependencyloader)
116
- app.dependencyloader.waitForModule = async (name) => {
117
- calledWith = name
118
- return { name }
119
- }
120
- const result = await app.waitForModule('test-mod')
121
- app.dependencyloader.waitForModule = origWaitForModule
122
-
123
- assert.equal(calledWith, 'test-mod')
124
- assert.deepEqual(result, { name: 'test-mod' })
125
- })
126
-
127
- it('should return array when multiple module names are passed', async () => {
128
- const app = App.instance
129
- const origWaitForModule = app.dependencyloader.waitForModule.bind(app.dependencyloader)
130
- app.dependencyloader.waitForModule = async (name) => ({ name })
131
- const result = await app.waitForModule('mod-a', 'mod-b')
132
- app.dependencyloader.waitForModule = origWaitForModule
133
-
134
- assert.ok(Array.isArray(result))
135
- assert.equal(result.length, 2)
136
- assert.deepEqual(result[0], { name: 'mod-a' })
137
- assert.deepEqual(result[1], { name: 'mod-b' })
138
- })
139
-
140
- it('should return single result (not array) for single module', async () => {
141
- const app = App.instance
142
- const origWaitForModule = app.dependencyloader.waitForModule.bind(app.dependencyloader)
143
- app.dependencyloader.waitForModule = async (name) => ({ name })
144
- const result = await app.waitForModule('single-mod')
145
- app.dependencyloader.waitForModule = origWaitForModule
146
-
147
- assert.ok(!Array.isArray(result))
148
- assert.deepEqual(result, { name: 'single-mod' })
149
- })
150
- })
151
-
152
- describe('#setReady()', () => {
153
- it('should set _isStarting to false', async () => {
154
- const app = App.instance
155
- app._isStarting = true
156
- await app.setReady()
157
- assert.equal(app._isStarting, false)
158
- })
159
- })
160
- })