-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathauth.abilities.integration.tests.js
More file actions
179 lines (161 loc) · 6.95 KB
/
Copy pathauth.abilities.integration.tests.js
File metadata and controls
179 lines (161 loc) · 6.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/**
* Module dependencies.
*/
import request from 'supertest';
import path from 'path';
import { beforeAll, afterAll, describe, test, expect } from '@jest/globals';
import { bootstrap } from '../../../lib/app.js';
import mongooseService from '../../../lib/services/mongoose.js';
import config from '../../../config/index.js';
/**
* Abilities integration tests.
*
* These tests verify that signin and token refresh responses
* include a serialized `abilities` array compatible with
* CASL's createMongoAbility() on the client side.
*/
describe('Auth abilities integration tests:', () => {
let UserService;
let agent;
let adminAgent;
let user;
let adminUser;
const originalOrgEnabled = config.organizations.enabled;
const userCredentials = {
email: 'abilities-user@test.com',
password: 'W@os.jsI$Aw3$0m3',
};
const adminCredentials = {
email: 'abilities-admin@test.com',
password: 'W@os.jsI$Aw3$0m3',
};
beforeAll(async () => {
// Disable organizations so signup auto-creates a silent org with membership
config.organizations.enabled = false;
const init = await bootstrap();
UserService = (await import(path.resolve('./modules/users/services/users.service.js'))).default;
agent = request.agent(init.app);
adminAgent = request.agent(init.app);
// clean up stale users from previous runs on shared databases
for (const email of [userCredentials.email, adminCredentials.email]) {
try {
const existing = await UserService.getBrut({ email });
if (existing) await UserService.remove(existing);
} catch (_) { /* cleanup – ignore errors */ }
}
// Create a regular user
const userRes = await agent
.post('/api/auth/signup')
.send({
firstName: 'Abilities',
lastName: 'User',
email: userCredentials.email,
password: userCredentials.password,
provider: 'local',
})
.expect(200);
user = userRes.body.user;
// Create an admin user (signup then promote via service — roles are stripped from signup)
const adminRes = await adminAgent
.post('/api/auth/signup')
.send({
firstName: 'Abilities',
lastName: 'Admin',
email: adminCredentials.email,
password: adminCredentials.password,
provider: 'local',
})
.expect(200);
adminUser = adminRes.body.user;
const adminBrut = await UserService.getBrut({ id: adminUser.id });
await UserService.update(adminBrut, { roles: ['user', 'admin'] }, 'admin');
});
// -------------------------------------------------------
// Signin response includes abilities
// -------------------------------------------------------
describe('Signin response', () => {
test('should include abilities array for a regular user', async () => {
const result = await agent.post('/api/auth/signin').send(userCredentials).expect(200);
expect(result.body.abilities).toBeDefined();
expect(Array.isArray(result.body.abilities)).toBe(true);
expect(result.body.abilities.length).toBeGreaterThan(0);
});
test('should include abilities array for an admin user', async () => {
const result = await adminAgent.post('/api/auth/signin').send(adminCredentials).expect(200);
expect(result.body.abilities).toBeDefined();
expect(Array.isArray(result.body.abilities)).toBe(true);
expect(result.body.abilities.length).toBeGreaterThan(0);
});
test('abilities format should have action and subject fields', async () => {
const result = await agent.post('/api/auth/signin').send(userCredentials).expect(200);
for (const rule of result.body.abilities) {
expect(rule).toHaveProperty('action');
expect(rule).toHaveProperty('subject');
expect(typeof rule.action).toBe('string');
expect(typeof rule.subject).toBe('string');
}
});
test('regular user abilities should contain task rules with conditions', async () => {
const result = await agent.post('/api/auth/signin').send(userCredentials).expect(200);
const taskUpdateRule = result.body.abilities.find(
(r) => r.action === 'update' && r.subject === 'Task',
);
expect(taskUpdateRule).toBeDefined();
expect(taskUpdateRule.conditions).toBeDefined();
expect(taskUpdateRule.conditions.user).toBe(String(user._id));
});
test('admin abilities should contain manage/all rule', async () => {
const result = await adminAgent.post('/api/auth/signin').send(adminCredentials).expect(200);
const manageAll = result.body.abilities.find(
(r) => r.action === 'manage' && r.subject === 'all',
);
expect(manageAll).toBeDefined();
});
});
// -------------------------------------------------------
// Token refresh response includes abilities
// -------------------------------------------------------
describe('Token refresh response', () => {
test('should include abilities array for a regular user', async () => {
// Ensure session is active
await agent.post('/api/auth/signin').send(userCredentials).expect(200);
const result = await agent.get('/api/auth/token').expect(200);
expect(result.body.abilities).toBeDefined();
expect(Array.isArray(result.body.abilities)).toBe(true);
expect(result.body.abilities.length).toBeGreaterThan(0);
});
test('should include abilities array for an admin user', async () => {
await adminAgent.post('/api/auth/signin').send(adminCredentials).expect(200);
const result = await adminAgent.get('/api/auth/token').expect(200);
expect(result.body.abilities).toBeDefined();
expect(Array.isArray(result.body.abilities)).toBe(true);
});
test('abilities format should have action and subject fields', async () => {
await agent.post('/api/auth/signin').send(userCredentials).expect(200);
const result = await agent.get('/api/auth/token').expect(200);
for (const rule of result.body.abilities) {
expect(rule).toHaveProperty('action');
expect(rule).toHaveProperty('subject');
expect(typeof rule.action).toBe('string');
expect(typeof rule.subject).toBe('string');
}
});
test('admin token refresh should contain manage/all rule', async () => {
await adminAgent.post('/api/auth/signin').send(adminCredentials).expect(200);
const result = await adminAgent.get('/api/auth/token').expect(200);
const manageAll = result.body.abilities.find(
(r) => r.action === 'manage' && r.subject === 'all',
);
expect(manageAll).toBeDefined();
});
});
// -------------------------------------------------------
// Cleanup
// -------------------------------------------------------
afterAll(async () => {
config.organizations.enabled = originalOrgEnabled;
try { await UserService.remove(user); } catch (_) { /* cleanup */ }
try { await UserService.remove(adminUser); } catch (_) { /* cleanup */ }
try { await mongooseService.disconnect(); } catch (_) { /* cleanup */ }
});
});