keycloak-api-manager 3.1.0 → 3.2.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.
- package/.mocharc.json +7 -0
- package/Handlers/authenticationManagementHandler.js +1 -1
- package/Handlers/clientScopesHandler.js +5 -5
- package/Handlers/clientsHandler.js +1 -1
- package/Handlers/componentsHandler.js +2 -2
- package/Handlers/groupsHandler.js +2 -2
- package/Handlers/identityProvidersHandler.js +3 -3
- package/README.md +115 -16
- package/docker-compose.yml +27 -0
- package/index.js +1 -1
- package/index.mjs +21 -0
- package/package.json +14 -2
- package/test/authenticationManagement.test.js +329 -0
- package/test/clientScopes.test.js +256 -0
- package/test/clients.test.js +284 -0
- package/test/components.test.js +122 -0
- package/test/config.js +137 -0
- package/test/docker-helpers.js +111 -0
- package/test/groups.test.js +284 -0
- package/test/identityProviders.test.js +197 -0
- package/test/mocha.env.js +55 -0
- package/test/realms.test.js +349 -0
- package/test/roles.test.js +215 -0
- package/test/users.test.js +405 -0
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -93
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
const { expect } = require('chai');
|
|
2
|
+
const { getAdminClient } = require('./config');
|
|
3
|
+
|
|
4
|
+
describe('Groups Handler', function () {
|
|
5
|
+
this.timeout(15000);
|
|
6
|
+
let client;
|
|
7
|
+
let testGroupId;
|
|
8
|
+
let testSubGroupId;
|
|
9
|
+
let testRoleId;
|
|
10
|
+
let testUserId;
|
|
11
|
+
|
|
12
|
+
before(async function () {
|
|
13
|
+
client = getAdminClient();
|
|
14
|
+
|
|
15
|
+
// Create test role for role mappings
|
|
16
|
+
const role = await client.roles.create(
|
|
17
|
+
{ realm: 'test-realm' },
|
|
18
|
+
{ name: `groups-test-role-${Date.now()}` }
|
|
19
|
+
);
|
|
20
|
+
testRoleId = role.id;
|
|
21
|
+
|
|
22
|
+
// Create test user for group membership
|
|
23
|
+
const user = await client.users.create(
|
|
24
|
+
{ realm: 'test-realm' },
|
|
25
|
+
{
|
|
26
|
+
username: `groups-test-user-${Date.now()}`,
|
|
27
|
+
enabled: true,
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
testUserId = user.id;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// ==================== GROUP CRUD ====================
|
|
34
|
+
describe('CRUD Operations', function () {
|
|
35
|
+
describe('create', function () {
|
|
36
|
+
it('should create a group with valid representation', async function () {
|
|
37
|
+
const groupRep = {
|
|
38
|
+
name: `test-group-${Date.now()}`,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const result = await client.groups.create(
|
|
42
|
+
{ realm: 'test-realm' },
|
|
43
|
+
groupRep
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(result).to.have.property('id');
|
|
47
|
+
testGroupId = result.id;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should fail creating duplicate group name', async function () {
|
|
51
|
+
const groupName = `unique-group-${Date.now()}`;
|
|
52
|
+
|
|
53
|
+
await client.groups.create(
|
|
54
|
+
{ realm: 'test-realm' },
|
|
55
|
+
{ name: groupName }
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
await client.groups.create(
|
|
60
|
+
{ realm: 'test-realm' },
|
|
61
|
+
{ name: groupName }
|
|
62
|
+
);
|
|
63
|
+
// Note: Some Keycloak versions allow duplicates at root level
|
|
64
|
+
} catch (err) {
|
|
65
|
+
expect(err).to.exist;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('find', function () {
|
|
71
|
+
it('should list all groups', async function () {
|
|
72
|
+
const groups = await client.groups.find({ realm: 'test-realm' });
|
|
73
|
+
|
|
74
|
+
expect(groups).to.be.an('array');
|
|
75
|
+
expect(groups.length).to.be.greaterThan(0);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should search groups by name', async function () {
|
|
79
|
+
const groups = await client.groups.find({
|
|
80
|
+
realm: 'test-realm',
|
|
81
|
+
search: 'test-group',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
expect(groups).to.be.an('array');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should support pagination', async function () {
|
|
88
|
+
const groups = await client.groups.find({
|
|
89
|
+
realm: 'test-realm',
|
|
90
|
+
first: 0,
|
|
91
|
+
max: 5,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(groups).to.be.an('array');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('findOne', function () {
|
|
99
|
+
it('should find a specific group by id', async function () {
|
|
100
|
+
const group = await client.groups.findOne({
|
|
101
|
+
realm: 'test-realm',
|
|
102
|
+
id: testGroupId,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
expect(group).to.exist;
|
|
106
|
+
expect(group.id).to.equal(testGroupId);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('count', function () {
|
|
111
|
+
it('should count total groups', async function () {
|
|
112
|
+
const count = await client.groups.count({ realm: 'test-realm' });
|
|
113
|
+
|
|
114
|
+
expect(count).to.be.a('number');
|
|
115
|
+
expect(count).to.be.greaterThan(0);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('update', function () {
|
|
120
|
+
it('should update group attributes', async function () {
|
|
121
|
+
const updateRep = {
|
|
122
|
+
name: `updated-group-${Date.now()}`,
|
|
123
|
+
attributes: {
|
|
124
|
+
department: ['Engineering'],
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
await client.groups.update(
|
|
129
|
+
{ realm: 'test-realm', id: testGroupId },
|
|
130
|
+
updateRep
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const updated = await client.groups.findOne({
|
|
134
|
+
realm: 'test-realm',
|
|
135
|
+
id: testGroupId,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
expect(updated.name).to.include('updated-group');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// ==================== SUBGROUPS ====================
|
|
144
|
+
describe('Subgroups', function () {
|
|
145
|
+
describe('listSubGroups', function () {
|
|
146
|
+
it('should list subgroups of a group', async function () {
|
|
147
|
+
const subgroups = await client.groups.listSubGroups({
|
|
148
|
+
realm: 'test-realm',
|
|
149
|
+
id: testGroupId,
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(subgroups).to.be.an('array');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Note: Creating subgroups might require special handling in some Keycloak versions
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// ==================== REALM ROLE MAPPINGS ====================
|
|
160
|
+
describe('Realm Role Mappings', function () {
|
|
161
|
+
describe('addRealmRoleMappings', function () {
|
|
162
|
+
it('should add realm roles to group', async function () {
|
|
163
|
+
await client.groups.addRealmRoleMappings({
|
|
164
|
+
realm: 'test-realm',
|
|
165
|
+
id: testGroupId,
|
|
166
|
+
roles: [
|
|
167
|
+
{
|
|
168
|
+
id: testRoleId,
|
|
169
|
+
name: `groups-test-role-${Date.now()}`,
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Verify role added
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe('listRoleMappings', function () {
|
|
179
|
+
it('should list all role mappings for group', async function () {
|
|
180
|
+
const mappings = await client.groups.listRoleMappings({
|
|
181
|
+
realm: 'test-realm',
|
|
182
|
+
id: testGroupId,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(mappings).to.be.an('object');
|
|
186
|
+
expect(mappings).to.have.property('realmMappings');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe('listRealmRoleMappings', function () {
|
|
191
|
+
it('should list realm role mappings', async function () {
|
|
192
|
+
const mappings = await client.groups.listRealmRoleMappings({
|
|
193
|
+
realm: 'test-realm',
|
|
194
|
+
id: testGroupId,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
expect(mappings).to.be.an('array');
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe('listCompositeRealmRoleMappings', function () {
|
|
202
|
+
it('should list composite realm role mappings', async function () {
|
|
203
|
+
const mappings = await client.groups.listCompositeRealmRoleMappings({
|
|
204
|
+
realm: 'test-realm',
|
|
205
|
+
id: testGroupId,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
expect(mappings).to.be.an('array');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('listAvailableRealmRoleMappings', function () {
|
|
213
|
+
it('should list available realm roles for group', async function () {
|
|
214
|
+
const available = await client.groups.listAvailableRealmRoleMappings({
|
|
215
|
+
realm: 'test-realm',
|
|
216
|
+
id: testGroupId,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
expect(available).to.be.an('array');
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('delRealmRoleMappings', function () {
|
|
224
|
+
it('should remove realm roles from group', async function () {
|
|
225
|
+
const mappings = await client.groups.listRealmRoleMappings({
|
|
226
|
+
realm: 'test-realm',
|
|
227
|
+
id: testGroupId,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
if (mappings.length > 0) {
|
|
231
|
+
await client.groups.delRealmRoleMappings({
|
|
232
|
+
realm: 'test-realm',
|
|
233
|
+
id: testGroupId,
|
|
234
|
+
roles: mappings,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Verify removed
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// ==================== CLIENT ROLE MAPPINGS ====================
|
|
244
|
+
describe('Client Role Mappings', function () {
|
|
245
|
+
describe('listAvailableClientRoleMappings', function () {
|
|
246
|
+
it('should list available client roles for group', async function () {
|
|
247
|
+
// Get a client first
|
|
248
|
+
const clients = await client.clients.find({ realm: 'test-realm' });
|
|
249
|
+
if (clients.length > 0) {
|
|
250
|
+
const available = await client.groups.listAvailableClientRoleMappings({
|
|
251
|
+
realm: 'test-realm',
|
|
252
|
+
id: testGroupId,
|
|
253
|
+
clientUniqueId: clients[0].id,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
expect(available).to.be.an('array');
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// ==================== CLEANUP ====================
|
|
263
|
+
after(async function () {
|
|
264
|
+
try {
|
|
265
|
+
if (testGroupId) {
|
|
266
|
+
await client.groups.del({ realm: 'test-realm', id: testGroupId });
|
|
267
|
+
}
|
|
268
|
+
if (testRoleId) {
|
|
269
|
+
const role = await client.roles.findOneById({
|
|
270
|
+
realm: 'test-realm',
|
|
271
|
+
id: testRoleId,
|
|
272
|
+
});
|
|
273
|
+
if (role) {
|
|
274
|
+
await client.roles.delByName({ realm: 'test-realm', name: role.name });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (testUserId) {
|
|
278
|
+
await client.users.del({ realm: 'test-realm', id: testUserId });
|
|
279
|
+
}
|
|
280
|
+
} catch (err) {
|
|
281
|
+
console.error('Cleanup error:', err.message);
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
});
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
const { expect } = require('chai');
|
|
2
|
+
const { getAdminClient } = require('./config');
|
|
3
|
+
|
|
4
|
+
describe('Identity Providers Handler', function () {
|
|
5
|
+
this.timeout(15000);
|
|
6
|
+
let client;
|
|
7
|
+
let testIdpAlias;
|
|
8
|
+
let testMapperId;
|
|
9
|
+
|
|
10
|
+
before(function () {
|
|
11
|
+
client = getAdminClient();
|
|
12
|
+
testIdpAlias = `test-idp-${Date.now()}`;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// ==================== IDENTITY PROVIDER CRUD ====================
|
|
16
|
+
describe('CRUD Operations', function () {
|
|
17
|
+
describe('create', function () {
|
|
18
|
+
it('should create an identity provider with valid representation', async function () {
|
|
19
|
+
const idpRep = {
|
|
20
|
+
alias: testIdpAlias,
|
|
21
|
+
displayName: 'Test IDP',
|
|
22
|
+
providerId: 'oidc',
|
|
23
|
+
enabled: true,
|
|
24
|
+
config: {
|
|
25
|
+
clientId: 'test-client',
|
|
26
|
+
clientSecret: 'test-secret',
|
|
27
|
+
tokenUrl: 'https://example.com/token',
|
|
28
|
+
authorizationUrl: 'https://example.com/authorize',
|
|
29
|
+
userInfoUrl: 'https://example.com/userinfo',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const result = await client.identityProviders.create(
|
|
34
|
+
{ realm: 'test-realm' },
|
|
35
|
+
idpRep
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(result).to.have.property('alias');
|
|
39
|
+
expect(result.alias).to.equal(testIdpAlias);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('find', function () {
|
|
44
|
+
it('should list all identity providers', async function () {
|
|
45
|
+
const idps = await client.identityProviders.find({ realm: 'test-realm' });
|
|
46
|
+
|
|
47
|
+
expect(idps).to.be.an('array');
|
|
48
|
+
expect(idps.some((idp) => idp.alias === testIdpAlias)).to.be.true;
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('findOne', function () {
|
|
53
|
+
it('should find a specific identity provider by alias', async function () {
|
|
54
|
+
const idp = await client.identityProviders.findOne({
|
|
55
|
+
realm: 'test-realm',
|
|
56
|
+
alias: testIdpAlias,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(idp).to.exist;
|
|
60
|
+
expect(idp.alias).to.equal(testIdpAlias);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('update', function () {
|
|
65
|
+
it('should update identity provider attributes', async function () {
|
|
66
|
+
const updateRep = {
|
|
67
|
+
displayName: 'Updated IDP Name',
|
|
68
|
+
enabled: false,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
await client.identityProviders.update(
|
|
72
|
+
{ realm: 'test-realm', alias: testIdpAlias },
|
|
73
|
+
updateRep
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const updated = await client.identityProviders.findOne({
|
|
77
|
+
realm: 'test-realm',
|
|
78
|
+
alias: testIdpAlias,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(updated.displayName).to.equal('Updated IDP Name');
|
|
82
|
+
expect(updated.enabled).to.be.false;
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// ==================== IDENTITY PROVIDER MAPPERS ====================
|
|
88
|
+
describe('Mappers', function () {
|
|
89
|
+
describe('createMapper', function () {
|
|
90
|
+
it('should create a mapper for identity provider', async function () {
|
|
91
|
+
const mapperRep = {
|
|
92
|
+
name: 'test-mapper',
|
|
93
|
+
identityProviderAlias: testIdpAlias,
|
|
94
|
+
identityProviderMapper: 'oidc-user-attribute-idp-mapper',
|
|
95
|
+
config: {
|
|
96
|
+
'user.attribute': 'email',
|
|
97
|
+
'claim': 'email',
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const result = await client.identityProviders.createMapper(
|
|
102
|
+
{ realm: 'test-realm' },
|
|
103
|
+
mapperRep
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(result).to.exist;
|
|
107
|
+
testMapperId = result.id;
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('findMappers', function () {
|
|
112
|
+
it('should find all mappers for identity provider', async function () {
|
|
113
|
+
const mappers = await client.identityProviders.findMappers({
|
|
114
|
+
realm: 'test-realm',
|
|
115
|
+
alias: testIdpAlias,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(mappers).to.be.an('array');
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('findOneMapper', function () {
|
|
123
|
+
it('should find a specific mapper by id', async function () {
|
|
124
|
+
if (testMapperId) {
|
|
125
|
+
const mapper = await client.identityProviders.findOneMapper({
|
|
126
|
+
realm: 'test-realm',
|
|
127
|
+
alias: testIdpAlias,
|
|
128
|
+
id: testMapperId,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(mapper).to.exist;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('delMapper', function () {
|
|
137
|
+
it('should delete a mapper', async function () {
|
|
138
|
+
if (testMapperId) {
|
|
139
|
+
await client.identityProviders.delMapper({
|
|
140
|
+
realm: 'test-realm',
|
|
141
|
+
alias: testIdpAlias,
|
|
142
|
+
id: testMapperId,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Verify deleted
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// ==================== IDENTITY PROVIDER MANAGEMENT ====================
|
|
152
|
+
describe('Management Operations', function () {
|
|
153
|
+
describe('findFactory', function () {
|
|
154
|
+
it('should retrieve identity provider factory', async function () {
|
|
155
|
+
try {
|
|
156
|
+
const factory = await client.identityProviders.findFactory({
|
|
157
|
+
realm: 'test-realm',
|
|
158
|
+
providerId: 'oidc',
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
expect(factory).to.exist;
|
|
162
|
+
} catch (err) {
|
|
163
|
+
// Factory endpoint might not be available
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('listPermissions', function () {
|
|
169
|
+
it('should list identity provider permissions', async function () {
|
|
170
|
+
try {
|
|
171
|
+
const perms = await client.identityProviders.listPermissions({
|
|
172
|
+
realm: 'test-realm',
|
|
173
|
+
alias: testIdpAlias,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(perms).to.be.an('object');
|
|
177
|
+
} catch (err) {
|
|
178
|
+
// Permissions might not be enabled
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ==================== CLEANUP ====================
|
|
185
|
+
after(async function () {
|
|
186
|
+
try {
|
|
187
|
+
if (testIdpAlias) {
|
|
188
|
+
await client.identityProviders.del({
|
|
189
|
+
realm: 'test-realm',
|
|
190
|
+
alias: testIdpAlias,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
} catch (err) {
|
|
194
|
+
console.error('Cleanup error:', err.message);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mocha Root Setup Hook
|
|
3
|
+
* Orchestrates Docker container lifecycle and Keycloak initialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { startDocker, stopDocker, waitForHealthy } = require('./docker-helpers');
|
|
7
|
+
const { initializeAdminClient, setupTestRealm, cleanupTestRealm } = require('./config');
|
|
8
|
+
|
|
9
|
+
// Root hook plugin for Mocha
|
|
10
|
+
exports.mochaHooks = {
|
|
11
|
+
async beforeAll() {
|
|
12
|
+
this.timeout(120000); // 2 minutes max for setup
|
|
13
|
+
|
|
14
|
+
console.log('\n========== TEST SETUP ==========');
|
|
15
|
+
console.log('Starting Docker containers...');
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
// Start Docker Compose
|
|
19
|
+
await startDocker();
|
|
20
|
+
|
|
21
|
+
// Wait for services to be healthy
|
|
22
|
+
await waitForHealthy();
|
|
23
|
+
|
|
24
|
+
// Initialize Keycloak admin client
|
|
25
|
+
await initializeAdminClient();
|
|
26
|
+
|
|
27
|
+
// Setup test realm
|
|
28
|
+
await setupTestRealm();
|
|
29
|
+
|
|
30
|
+
console.log('✓ Test environment ready\n');
|
|
31
|
+
} catch (err) {
|
|
32
|
+
console.error('✗ Test setup failed:', err.message);
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
async afterAll() {
|
|
38
|
+
this.timeout(60000); // 1 minute max for teardown
|
|
39
|
+
|
|
40
|
+
console.log('\n========== TEST TEARDOWN ==========');
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
// Cleanup Keycloak test realm
|
|
44
|
+
await cleanupTestRealm();
|
|
45
|
+
|
|
46
|
+
// Stop Docker Compose
|
|
47
|
+
await stopDocker();
|
|
48
|
+
|
|
49
|
+
console.log('✓ Test environment cleaned up\n');
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error('✗ Test teardown failed:', err.message);
|
|
52
|
+
// Don't throw during cleanup to allow partial cleanup
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
};
|