@nextsparkjs/theme-default 0.1.0-beta.22 → 0.1.0-beta.25
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/LICENSE +21 -0
- package/package.json +3 -3
- package/tests/jest/__mocks__/@nextsparkjs/core/components/ui/badge.js +16 -0
- package/tests/jest/__mocks__/@nextsparkjs/core/lib/db.js +11 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/permissions-registry.ts +155 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/theme-registry.ts +68 -0
- package/tests/jest/__mocks__/jose.js +22 -0
- package/tests/jest/__mocks__/next/image.js +15 -0
- package/tests/jest/__mocks__/next-server.js +56 -0
- package/tests/jest/jest.config.cjs +138 -0
- package/tests/jest/langchain/streaming.test.ts +6 -3
- package/tests/jest/services/tasks.service.test.ts +707 -0
- package/tests/jest/setup.ts +170 -0
- package/tests/jest/tsconfig.jest.json +6 -0
- package/tests/jest/config/role-config.test.ts +0 -529
- package/tests/jest/jest.config.ts +0 -81
- package/tests/jest/user-roles/role-helpers.test.ts +0 -432
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jest Setup for Default Theme
|
|
3
|
+
*
|
|
4
|
+
* This file provides complete Jest setup for npm mode.
|
|
5
|
+
* It includes all necessary polyfills and mocks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import '@testing-library/jest-dom'
|
|
9
|
+
import { TextEncoder, TextDecoder } from 'util'
|
|
10
|
+
|
|
11
|
+
// Polyfill TextEncoder/TextDecoder for jsdom
|
|
12
|
+
global.TextEncoder = TextEncoder
|
|
13
|
+
global.TextDecoder = TextDecoder as typeof global.TextDecoder
|
|
14
|
+
|
|
15
|
+
// Polyfill Web APIs for Next.js server components testing
|
|
16
|
+
class MockHeaders {
|
|
17
|
+
private _headers: Map<string, string> = new Map()
|
|
18
|
+
|
|
19
|
+
constructor(init?: HeadersInit) {
|
|
20
|
+
if (init) {
|
|
21
|
+
if (init instanceof MockHeaders) {
|
|
22
|
+
init._headers.forEach((value, key) => this._headers.set(key, value))
|
|
23
|
+
} else if (Array.isArray(init)) {
|
|
24
|
+
init.forEach(([key, value]) => this._headers.set(key.toLowerCase(), value))
|
|
25
|
+
} else {
|
|
26
|
+
Object.entries(init).forEach(([key, value]) => this._headers.set(key.toLowerCase(), value))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get(name: string) { return this._headers.get(name.toLowerCase()) || null }
|
|
32
|
+
set(name: string, value: string) { this._headers.set(name.toLowerCase(), value) }
|
|
33
|
+
has(name: string) { return this._headers.has(name.toLowerCase()) }
|
|
34
|
+
delete(name: string) { this._headers.delete(name.toLowerCase()) }
|
|
35
|
+
forEach(cb: (value: string, key: string) => void) { this._headers.forEach(cb) }
|
|
36
|
+
entries() { return this._headers.entries() }
|
|
37
|
+
keys() { return this._headers.keys() }
|
|
38
|
+
values() { return this._headers.values() }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
class MockRequest {
|
|
42
|
+
url: string
|
|
43
|
+
method: string
|
|
44
|
+
headers: MockHeaders
|
|
45
|
+
private _body: any
|
|
46
|
+
|
|
47
|
+
constructor(input: string | URL, init?: RequestInit) {
|
|
48
|
+
this.url = typeof input === 'string' ? input : input.toString()
|
|
49
|
+
this.method = init?.method || 'GET'
|
|
50
|
+
this.headers = new MockHeaders(init?.headers as HeadersInit)
|
|
51
|
+
this._body = init?.body
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async json() {
|
|
55
|
+
if (!this._body) return {}
|
|
56
|
+
return typeof this._body === 'string' ? JSON.parse(this._body) : this._body
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async text() {
|
|
60
|
+
return this._body?.toString() || ''
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
clone() {
|
|
64
|
+
return new MockRequest(this.url, {
|
|
65
|
+
method: this.method,
|
|
66
|
+
headers: Object.fromEntries(this.headers.entries()),
|
|
67
|
+
body: this._body,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
class MockResponse {
|
|
73
|
+
body: any
|
|
74
|
+
status: number
|
|
75
|
+
statusText: string
|
|
76
|
+
headers: MockHeaders
|
|
77
|
+
ok: boolean
|
|
78
|
+
|
|
79
|
+
constructor(body?: any, init?: ResponseInit) {
|
|
80
|
+
this.body = body
|
|
81
|
+
this.status = init?.status || 200
|
|
82
|
+
this.statusText = init?.statusText || 'OK'
|
|
83
|
+
this.headers = new MockHeaders(init?.headers as HeadersInit)
|
|
84
|
+
this.ok = this.status >= 200 && this.status < 300
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async json() {
|
|
88
|
+
if (!this.body) return {}
|
|
89
|
+
return typeof this.body === 'string' ? JSON.parse(this.body) : this.body
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async text() {
|
|
93
|
+
return this.body?.toString() || ''
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
clone() {
|
|
97
|
+
return new MockResponse(this.body, {
|
|
98
|
+
status: this.status,
|
|
99
|
+
statusText: this.statusText,
|
|
100
|
+
headers: Object.fromEntries(this.headers.entries()),
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static json(data: any, init?: ResponseInit) {
|
|
105
|
+
return new MockResponse(JSON.stringify(data), {
|
|
106
|
+
...init,
|
|
107
|
+
headers: { 'Content-Type': 'application/json', ...(init?.headers || {}) as object },
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Assign to global scope
|
|
113
|
+
global.Headers = MockHeaders as any
|
|
114
|
+
global.Request = MockRequest as any
|
|
115
|
+
global.Response = MockResponse as any
|
|
116
|
+
|
|
117
|
+
// Mock fetch
|
|
118
|
+
global.fetch = jest.fn().mockResolvedValue(new MockResponse('{}', { status: 200 }))
|
|
119
|
+
|
|
120
|
+
// Mock Web Crypto API
|
|
121
|
+
const crypto = require('crypto')
|
|
122
|
+
Object.defineProperty(global, 'crypto', {
|
|
123
|
+
value: {
|
|
124
|
+
getRandomValues: (arr: Uint8Array) => crypto.randomFillSync(arr),
|
|
125
|
+
randomUUID: () => crypto.randomUUID(),
|
|
126
|
+
subtle: {
|
|
127
|
+
digest: async (algorithm: string, data: BufferSource) => {
|
|
128
|
+
const hash = crypto.createHash(algorithm.toLowerCase().replace('-', ''))
|
|
129
|
+
hash.update(Buffer.from(data as ArrayBuffer))
|
|
130
|
+
return hash.digest().buffer
|
|
131
|
+
},
|
|
132
|
+
encrypt: jest.fn(),
|
|
133
|
+
decrypt: jest.fn(),
|
|
134
|
+
sign: jest.fn(),
|
|
135
|
+
verify: jest.fn(),
|
|
136
|
+
generateKey: jest.fn(),
|
|
137
|
+
importKey: jest.fn(),
|
|
138
|
+
exportKey: jest.fn(),
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
// Mock matchMedia for component tests with media queries
|
|
144
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
145
|
+
writable: true,
|
|
146
|
+
value: jest.fn().mockImplementation((query) => ({
|
|
147
|
+
matches: false,
|
|
148
|
+
media: query,
|
|
149
|
+
onchange: null,
|
|
150
|
+
addListener: jest.fn(),
|
|
151
|
+
removeListener: jest.fn(),
|
|
152
|
+
addEventListener: jest.fn(),
|
|
153
|
+
removeEventListener: jest.fn(),
|
|
154
|
+
dispatchEvent: jest.fn(),
|
|
155
|
+
})),
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// Mock ResizeObserver
|
|
159
|
+
global.ResizeObserver = jest.fn().mockImplementation(() => ({
|
|
160
|
+
observe: jest.fn(),
|
|
161
|
+
unobserve: jest.fn(),
|
|
162
|
+
disconnect: jest.fn(),
|
|
163
|
+
}))
|
|
164
|
+
|
|
165
|
+
// Mock IntersectionObserver
|
|
166
|
+
global.IntersectionObserver = jest.fn().mockImplementation(() => ({
|
|
167
|
+
observe: jest.fn(),
|
|
168
|
+
unobserve: jest.fn(),
|
|
169
|
+
disconnect: jest.fn(),
|
|
170
|
+
}))
|
|
@@ -1,529 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit Tests - Role Configuration (app.config.ts)
|
|
3
|
-
*
|
|
4
|
-
* Tests role configuration for Developer Area feature:
|
|
5
|
-
* - Developer role in availableRoles array
|
|
6
|
-
* - Developer hierarchy value (100, highest)
|
|
7
|
-
* - Developer displayName translation key
|
|
8
|
-
* - Developer description
|
|
9
|
-
* - Configuration completeness
|
|
10
|
-
*
|
|
11
|
-
* Focus on developer role configuration validation.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { DEFAULT_APP_CONFIG } from '@nextsparkjs/core/lib/config/app.config'
|
|
15
|
-
|
|
16
|
-
describe('Role Configuration - Developer Role', () => {
|
|
17
|
-
describe('availableRoles Array', () => {
|
|
18
|
-
it('should include developer role', () => {
|
|
19
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
20
|
-
|
|
21
|
-
expect(roles).toContain('developer')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('should include superadmin role', () => {
|
|
25
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
26
|
-
|
|
27
|
-
expect(roles).toContain('superadmin')
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
it('should include member role', () => {
|
|
31
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
32
|
-
|
|
33
|
-
expect(roles).toContain('member')
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('should have exactly 3 roles', () => {
|
|
37
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
38
|
-
|
|
39
|
-
expect(roles.length).toBe(3)
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('should have roles in correct order', () => {
|
|
43
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
44
|
-
|
|
45
|
-
expect(roles).toEqual(['member', 'superadmin', 'developer'])
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
it('should have all roles as strings', () => {
|
|
49
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
50
|
-
|
|
51
|
-
roles.forEach(role => {
|
|
52
|
-
expect(typeof role).toBe('string')
|
|
53
|
-
})
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('should have all roles in lowercase', () => {
|
|
57
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
58
|
-
|
|
59
|
-
roles.forEach(role => {
|
|
60
|
-
expect(role).toBe(role.toLowerCase())
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('should not have duplicate roles', () => {
|
|
65
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
66
|
-
const uniqueRoles = new Set(roles)
|
|
67
|
-
|
|
68
|
-
expect(uniqueRoles.size).toBe(roles.length)
|
|
69
|
-
})
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
describe('Role Hierarchy', () => {
|
|
73
|
-
it('should have developer at level 100', () => {
|
|
74
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
75
|
-
|
|
76
|
-
expect(hierarchy.developer).toBe(100)
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('should have superadmin at level 99', () => {
|
|
80
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
81
|
-
|
|
82
|
-
expect(hierarchy.superadmin).toBe(99)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('should have member at level 1', () => {
|
|
86
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
87
|
-
|
|
88
|
-
expect(hierarchy.member).toBe(1)
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
it('should have developer as highest hierarchy', () => {
|
|
92
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
93
|
-
|
|
94
|
-
expect(hierarchy.developer).toBeGreaterThan(hierarchy.superadmin)
|
|
95
|
-
expect(hierarchy.developer).toBeGreaterThan(hierarchy.member)
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
it('should have superadmin higher than member', () => {
|
|
99
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
100
|
-
|
|
101
|
-
expect(hierarchy.superadmin).toBeGreaterThan(hierarchy.member)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('should have all hierarchy values as numbers', () => {
|
|
105
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
106
|
-
|
|
107
|
-
expect(typeof hierarchy.developer).toBe('number')
|
|
108
|
-
expect(typeof hierarchy.superadmin).toBe('number')
|
|
109
|
-
expect(typeof hierarchy.member).toBe('number')
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('should have all hierarchy values as positive integers', () => {
|
|
113
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
114
|
-
|
|
115
|
-
expect(hierarchy.developer).toBeGreaterThan(0)
|
|
116
|
-
expect(hierarchy.superadmin).toBeGreaterThan(0)
|
|
117
|
-
expect(hierarchy.member).toBeGreaterThan(0)
|
|
118
|
-
|
|
119
|
-
expect(Number.isInteger(hierarchy.developer)).toBe(true)
|
|
120
|
-
expect(Number.isInteger(hierarchy.superadmin)).toBe(true)
|
|
121
|
-
expect(Number.isInteger(hierarchy.member)).toBe(true)
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('should have correct hierarchy gap between developer and superadmin', () => {
|
|
125
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
126
|
-
|
|
127
|
-
// Developer (100) should be 1 level above superadmin (99)
|
|
128
|
-
expect(hierarchy.developer - hierarchy.superadmin).toBe(1)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
it('should have large gap between superadmin and member', () => {
|
|
132
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
133
|
-
|
|
134
|
-
// Large gap indicates future extensibility
|
|
135
|
-
expect(hierarchy.superadmin - hierarchy.member).toBeGreaterThan(50)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
it('should have hierarchy keys matching availableRoles', () => {
|
|
139
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
140
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
141
|
-
|
|
142
|
-
roles.forEach(role => {
|
|
143
|
-
expect(hierarchy[role as keyof typeof hierarchy]).toBeDefined()
|
|
144
|
-
expect(typeof hierarchy[role as keyof typeof hierarchy]).toBe('number')
|
|
145
|
-
})
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
describe('Display Names (Translation Keys)', () => {
|
|
150
|
-
it('should have translation key for developer role', () => {
|
|
151
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
152
|
-
|
|
153
|
-
expect(displayNames.developer).toBe('common.userRoles.developer')
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('should have translation key for superadmin role', () => {
|
|
157
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
158
|
-
|
|
159
|
-
expect(displayNames.superadmin).toBe('common.userRoles.superadmin')
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should have translation key for member role', () => {
|
|
163
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
164
|
-
|
|
165
|
-
expect(displayNames.member).toBe('common.userRoles.member')
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
it('should have translation keys in correct format', () => {
|
|
169
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
170
|
-
|
|
171
|
-
Object.values(displayNames).forEach(key => {
|
|
172
|
-
expect(key).toMatch(/^common\.userRoles\.\w+$/)
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('should have translation keys for all available roles', () => {
|
|
177
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
178
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
179
|
-
|
|
180
|
-
roles.forEach(role => {
|
|
181
|
-
expect(displayNames[role as keyof typeof displayNames]).toBeDefined()
|
|
182
|
-
expect(displayNames[role as keyof typeof displayNames]).toContain('common.userRoles.')
|
|
183
|
-
})
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
it('should use common namespace for all role names', () => {
|
|
187
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
188
|
-
|
|
189
|
-
Object.values(displayNames).forEach(key => {
|
|
190
|
-
expect(key).toMatch(/^common\./)
|
|
191
|
-
})
|
|
192
|
-
})
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
describe('Role Descriptions', () => {
|
|
196
|
-
it('should have description for developer role', () => {
|
|
197
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
198
|
-
|
|
199
|
-
expect(descriptions.developer).toBe('Ultimate access (platform developers only)')
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
it('should have description for superadmin role', () => {
|
|
203
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
204
|
-
|
|
205
|
-
expect(descriptions.superadmin).toBe('Full system access (product owners only)')
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
it('should have description for member role', () => {
|
|
209
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
210
|
-
|
|
211
|
-
expect(descriptions.member).toBe('Regular user with team-based permissions')
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
it('should have descriptions as non-empty strings', () => {
|
|
215
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
216
|
-
|
|
217
|
-
Object.values(descriptions).forEach(description => {
|
|
218
|
-
expect(typeof description).toBe('string')
|
|
219
|
-
expect(description.length).toBeGreaterThan(0)
|
|
220
|
-
})
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
it('should have descriptions for all available roles', () => {
|
|
224
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
225
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
226
|
-
|
|
227
|
-
roles.forEach(role => {
|
|
228
|
-
expect(descriptions[role as keyof typeof descriptions]).toBeDefined()
|
|
229
|
-
expect(descriptions[role as keyof typeof descriptions].length).toBeGreaterThan(0)
|
|
230
|
-
})
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
it('should have developer description indicating highest access', () => {
|
|
234
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
235
|
-
|
|
236
|
-
expect(descriptions.developer.toLowerCase()).toContain('ultimate')
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
it('should have developer description indicating platform developer usage', () => {
|
|
240
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
241
|
-
|
|
242
|
-
expect(descriptions.developer.toLowerCase()).toContain('developer')
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
it('should have superadmin description indicating product owner usage', () => {
|
|
246
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
247
|
-
|
|
248
|
-
expect(descriptions.superadmin.toLowerCase()).toContain('owner')
|
|
249
|
-
})
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
describe('Default Role', () => {
|
|
253
|
-
it('should have member as default role', () => {
|
|
254
|
-
const defaultRole = DEFAULT_APP_CONFIG.userRoles.defaultRole
|
|
255
|
-
|
|
256
|
-
expect(defaultRole).toBe('member')
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
it('should have default role in availableRoles', () => {
|
|
260
|
-
const defaultRole = DEFAULT_APP_CONFIG.userRoles.defaultRole
|
|
261
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
262
|
-
|
|
263
|
-
expect(roles).toContain(defaultRole)
|
|
264
|
-
})
|
|
265
|
-
|
|
266
|
-
it('should not have developer as default role', () => {
|
|
267
|
-
const defaultRole = DEFAULT_APP_CONFIG.userRoles.defaultRole
|
|
268
|
-
|
|
269
|
-
expect(defaultRole).not.toBe('developer')
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
it('should not have superadmin as default role', () => {
|
|
273
|
-
const defaultRole = DEFAULT_APP_CONFIG.userRoles.defaultRole
|
|
274
|
-
|
|
275
|
-
expect(defaultRole).not.toBe('superadmin')
|
|
276
|
-
})
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
describe('Configuration Completeness', () => {
|
|
280
|
-
it('should have all roles in hierarchy map', () => {
|
|
281
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
282
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
283
|
-
|
|
284
|
-
roles.forEach(role => {
|
|
285
|
-
expect(hierarchy[role as keyof typeof hierarchy]).toBeDefined()
|
|
286
|
-
})
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
it('should have all roles in displayNames map', () => {
|
|
290
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
291
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
292
|
-
|
|
293
|
-
roles.forEach(role => {
|
|
294
|
-
expect(displayNames[role as keyof typeof displayNames]).toBeDefined()
|
|
295
|
-
})
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
it('should have all roles in descriptions map', () => {
|
|
299
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
300
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
301
|
-
|
|
302
|
-
roles.forEach(role => {
|
|
303
|
-
expect(descriptions[role as keyof typeof descriptions]).toBeDefined()
|
|
304
|
-
})
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
it('should have no extra keys in hierarchy map', () => {
|
|
308
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
309
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
310
|
-
|
|
311
|
-
const hierarchyKeys = Object.keys(hierarchy)
|
|
312
|
-
|
|
313
|
-
expect(hierarchyKeys.length).toBe(roles.length)
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
it('should have no extra keys in displayNames map', () => {
|
|
317
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
318
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
319
|
-
|
|
320
|
-
const displayNameKeys = Object.keys(displayNames)
|
|
321
|
-
|
|
322
|
-
expect(displayNameKeys.length).toBe(roles.length)
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
it('should have no extra keys in descriptions map', () => {
|
|
326
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
327
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
328
|
-
|
|
329
|
-
const descriptionKeys = Object.keys(descriptions)
|
|
330
|
-
|
|
331
|
-
expect(descriptionKeys.length).toBe(roles.length)
|
|
332
|
-
})
|
|
333
|
-
})
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
describe('Role Configuration - Backwards Compatibility', () => {
|
|
337
|
-
describe('Existing Roles Preserved', () => {
|
|
338
|
-
it('should still have member role (Phase 1)', () => {
|
|
339
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
340
|
-
|
|
341
|
-
expect(roles).toContain('member')
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
it('should still have superadmin role (Phase 2)', () => {
|
|
345
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
346
|
-
|
|
347
|
-
expect(roles).toContain('superadmin')
|
|
348
|
-
})
|
|
349
|
-
|
|
350
|
-
it('should preserve member hierarchy value', () => {
|
|
351
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
352
|
-
|
|
353
|
-
expect(hierarchy.member).toBe(1)
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
it('should preserve superadmin hierarchy value', () => {
|
|
357
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
358
|
-
|
|
359
|
-
expect(hierarchy.superadmin).toBe(99)
|
|
360
|
-
})
|
|
361
|
-
|
|
362
|
-
it('should preserve default role as member', () => {
|
|
363
|
-
const defaultRole = DEFAULT_APP_CONFIG.userRoles.defaultRole
|
|
364
|
-
|
|
365
|
-
expect(defaultRole).toBe('member')
|
|
366
|
-
})
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
describe('New Role Addition (Phase 3)', () => {
|
|
370
|
-
it('should add developer role without breaking existing config', () => {
|
|
371
|
-
const config = DEFAULT_APP_CONFIG.userRoles
|
|
372
|
-
|
|
373
|
-
// All Phase 1-2 features still work
|
|
374
|
-
expect(config.defaultRole).toBe('member')
|
|
375
|
-
expect(config.availableRoles).toContain('member')
|
|
376
|
-
expect(config.availableRoles).toContain('superadmin')
|
|
377
|
-
|
|
378
|
-
// Phase 3 addition
|
|
379
|
-
expect(config.availableRoles).toContain('developer')
|
|
380
|
-
})
|
|
381
|
-
|
|
382
|
-
it('should have developer hierarchy higher than existing roles', () => {
|
|
383
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
384
|
-
|
|
385
|
-
expect(hierarchy.developer).toBeGreaterThan(hierarchy.superadmin)
|
|
386
|
-
expect(hierarchy.developer).toBeGreaterThan(hierarchy.member)
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
it('should not affect superadmin hierarchy relative to member', () => {
|
|
390
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
391
|
-
|
|
392
|
-
expect(hierarchy.superadmin).toBeGreaterThan(hierarchy.member)
|
|
393
|
-
})
|
|
394
|
-
})
|
|
395
|
-
})
|
|
396
|
-
|
|
397
|
-
describe('Role Configuration - Edge Cases', () => {
|
|
398
|
-
describe('Type Safety', () => {
|
|
399
|
-
it('should have userRoles as an object', () => {
|
|
400
|
-
expect(typeof DEFAULT_APP_CONFIG.userRoles).toBe('object')
|
|
401
|
-
expect(DEFAULT_APP_CONFIG.userRoles).not.toBeNull()
|
|
402
|
-
})
|
|
403
|
-
|
|
404
|
-
it('should have availableRoles as readonly array', () => {
|
|
405
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
406
|
-
|
|
407
|
-
expect(Array.isArray(roles)).toBe(true)
|
|
408
|
-
})
|
|
409
|
-
|
|
410
|
-
it('should have hierarchy as object with string keys', () => {
|
|
411
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
412
|
-
|
|
413
|
-
expect(typeof hierarchy).toBe('object')
|
|
414
|
-
Object.keys(hierarchy).forEach(key => {
|
|
415
|
-
expect(typeof key).toBe('string')
|
|
416
|
-
})
|
|
417
|
-
})
|
|
418
|
-
})
|
|
419
|
-
|
|
420
|
-
describe('Invalid Data Protection', () => {
|
|
421
|
-
it('should not have empty string roles', () => {
|
|
422
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
423
|
-
|
|
424
|
-
roles.forEach(role => {
|
|
425
|
-
expect(role.length).toBeGreaterThan(0)
|
|
426
|
-
})
|
|
427
|
-
})
|
|
428
|
-
|
|
429
|
-
it('should not have negative hierarchy values', () => {
|
|
430
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
431
|
-
|
|
432
|
-
Object.values(hierarchy).forEach(value => {
|
|
433
|
-
expect(value).toBeGreaterThan(0)
|
|
434
|
-
})
|
|
435
|
-
})
|
|
436
|
-
|
|
437
|
-
it('should not have hierarchy values as floats', () => {
|
|
438
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
439
|
-
|
|
440
|
-
Object.values(hierarchy).forEach(value => {
|
|
441
|
-
expect(Number.isInteger(value)).toBe(true)
|
|
442
|
-
})
|
|
443
|
-
})
|
|
444
|
-
|
|
445
|
-
it('should not have empty translation keys', () => {
|
|
446
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
447
|
-
|
|
448
|
-
Object.values(displayNames).forEach(key => {
|
|
449
|
-
expect(key.length).toBeGreaterThan(0)
|
|
450
|
-
})
|
|
451
|
-
})
|
|
452
|
-
|
|
453
|
-
it('should not have empty descriptions', () => {
|
|
454
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
455
|
-
|
|
456
|
-
Object.values(descriptions).forEach(description => {
|
|
457
|
-
expect(description.length).toBeGreaterThan(0)
|
|
458
|
-
})
|
|
459
|
-
})
|
|
460
|
-
})
|
|
461
|
-
})
|
|
462
|
-
|
|
463
|
-
describe('Real-World Configuration Usage', () => {
|
|
464
|
-
describe('Guard Implementation Support', () => {
|
|
465
|
-
it('should support DeveloperGuard role check', () => {
|
|
466
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
467
|
-
|
|
468
|
-
// DeveloperGuard checks if role === 'developer'
|
|
469
|
-
expect(roles).toContain('developer')
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
it('should support SuperAdminGuard dual role check', () => {
|
|
473
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
474
|
-
|
|
475
|
-
// SuperAdminGuard allows both superadmin and developer
|
|
476
|
-
expect(roles).toContain('superadmin')
|
|
477
|
-
expect(roles).toContain('developer')
|
|
478
|
-
})
|
|
479
|
-
|
|
480
|
-
it('should support middleware role validation', () => {
|
|
481
|
-
const hierarchy = DEFAULT_APP_CONFIG.userRoles.hierarchy
|
|
482
|
-
|
|
483
|
-
// Middleware compares hierarchy levels
|
|
484
|
-
expect(hierarchy.developer).toBeDefined()
|
|
485
|
-
expect(hierarchy.superadmin).toBeDefined()
|
|
486
|
-
expect(hierarchy.member).toBeDefined()
|
|
487
|
-
})
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
describe('UI Display Support', () => {
|
|
491
|
-
it('should provide translation keys for role selection dropdown', () => {
|
|
492
|
-
const displayNames = DEFAULT_APP_CONFIG.userRoles.displayNames
|
|
493
|
-
|
|
494
|
-
const roles = ['developer', 'superadmin', 'member'] as const
|
|
495
|
-
|
|
496
|
-
roles.forEach(role => {
|
|
497
|
-
expect(displayNames[role]).toMatch(/^common\.userRoles\.\w+$/)
|
|
498
|
-
})
|
|
499
|
-
})
|
|
500
|
-
|
|
501
|
-
it('should provide descriptions for role info tooltips', () => {
|
|
502
|
-
const descriptions = DEFAULT_APP_CONFIG.userRoles.descriptions
|
|
503
|
-
|
|
504
|
-
const roles = ['developer', 'superadmin', 'member'] as const
|
|
505
|
-
|
|
506
|
-
roles.forEach(role => {
|
|
507
|
-
expect(descriptions[role].length).toBeGreaterThan(10) // Meaningful description
|
|
508
|
-
})
|
|
509
|
-
})
|
|
510
|
-
})
|
|
511
|
-
|
|
512
|
-
describe('Database Schema Support', () => {
|
|
513
|
-
it('should have role values compatible with database enum', () => {
|
|
514
|
-
const roles = DEFAULT_APP_CONFIG.userRoles.availableRoles
|
|
515
|
-
|
|
516
|
-
// Database enum values should be lowercase strings
|
|
517
|
-
roles.forEach(role => {
|
|
518
|
-
expect(role).toMatch(/^[a-z]+$/)
|
|
519
|
-
})
|
|
520
|
-
})
|
|
521
|
-
|
|
522
|
-
it('should have default role for user creation', () => {
|
|
523
|
-
const defaultRole = DEFAULT_APP_CONFIG.userRoles.defaultRole
|
|
524
|
-
|
|
525
|
-
expect(defaultRole).toBe('member')
|
|
526
|
-
expect(DEFAULT_APP_CONFIG.userRoles.availableRoles).toContain(defaultRole)
|
|
527
|
-
})
|
|
528
|
-
})
|
|
529
|
-
})
|