1+ /**
2+ * ACL: GET One Resource - Permission and Field-Level Security
3+ *
4+ * This test suite verifies ACL enforcement for fetching individual resources by ID.
5+ * It tests three permission levels with different capabilities:
6+ *
7+ * 1. Admin Role: Full access without conditions
8+ * - Can read any resource by ID with all fields
9+ * - Can include all relationships
10+ *
11+ * 2. Moderator Role: Full access with field restrictions
12+ * - Can read any resource by ID
13+ * - Cannot read sensitive fields (salary, role in nested relations)
14+ * - Field filtering applied automatically by ACL
15+ *
16+ * 3. User Role: Conditional row-level access with field restrictions
17+ * - Can read own profile with phone number visible
18+ * - Can read public profiles with phone number hidden
19+ * - CANNOT read private profiles (returns 404 Not Found)
20+ * - Cannot read sensitive fields (salary, role, isPublic, createdAt, updatedAt)
21+ * - Row-level filtering prevents access to forbidden resources
22+ */
23+
124import {
225 ContextTestAcl ,
326 UserProfileAcl ,
@@ -10,7 +33,7 @@ import { AxiosError } from 'axios';
1033import { creatSdk } from '../utils/run-application' ;
1134import { AbilityBuilder , CheckFieldAndInclude } from '../utils/acl/acl' ;
1235
13- describe ( 'ACL getOne: ' , ( ) => {
36+ describe ( 'ACL: GET One Resource (Single Resource Fetching) ' , ( ) => {
1437 let contextTestAcl = new ContextTestAcl ( ) ;
1538 let usersAcl : UsersAcl [ ] ;
1639 contextTestAcl . aclRules = { rules : [ ] } ;
@@ -34,7 +57,7 @@ describe('ACL getOne:', () => {
3457 await jsonSdk . jonApiSdkService . deleteOne ( contextTestAcl ) ;
3558 } ) ;
3659
37- describe ( 'Without conditional: admin ' , ( ) => {
60+ describe ( 'Admin Role: Full Access Without Restrictions ' , ( ) => {
3861 beforeEach ( async ( ) => {
3962 const adminUser = usersAcl . find ( ( user ) => user . login === 'admin' ) ;
4063 if ( ! adminUser ) throw new Error ( 'Daphne user not found' ) ;
@@ -46,18 +69,18 @@ describe('ACL getOne:', () => {
4669 await jsonSdk . jonApiSdkService . patchOne ( contextTestAcl ) ;
4770 } ) ;
4871
49- it ( 'get one profile ' , async ( ) => {
72+ it ( 'should fetch any user by ID with all fields (no ACL restrictions) ' , async ( ) => {
5073 await jsonSdk . jonApiSdkService . getOne ( UsersAcl , usersAcl [ 0 ] . id ) ;
5174 } ) ;
5275
53- it ( 'get one users with profile' , async ( ) => {
76+ it ( 'should fetch any user by ID with included profile with all fields ' , async ( ) => {
5477 await jsonSdk . jonApiSdkService . getOne ( UsersAcl , usersAcl [ 0 ] . id , {
5578 include : [ 'profile' ] ,
5679 } ) ;
5780 } ) ;
5881 } ) ;
5982
60- describe ( 'Without conditional but with fields: moderator ' , ( ) => {
83+ describe ( 'Moderator Role: Full Access with Field-Level Restrictions ' , ( ) => {
6184 beforeEach ( async ( ) => {
6285 const moderatorUser = usersAcl . find ( ( user ) => user . login === 'moderator' ) ;
6386 if ( ! moderatorUser ) throw new Error ( 'Sheila user not found' ) ;
@@ -69,7 +92,7 @@ describe('ACL getOne:', () => {
6992 await jsonSdk . jonApiSdkService . patchOne ( contextTestAcl ) ;
7093 } ) ;
7194
72- it ( 'get one profile' , async ( ) => {
95+ it ( 'should fetch any profile by ID but exclude sensitive fields (role, salary) ' , async ( ) => {
7396 const item = await jsonSdk . jonApiSdkService . getOne (
7497 UserProfileAcl ,
7598 usersAcl [ 0 ] . id
@@ -85,7 +108,7 @@ describe('ACL getOne:', () => {
85108 expect ( item . updatedAt ) . toBeDefined ( ) ;
86109 } ) ;
87110
88- it ( 'get one users with profile' , async ( ) => {
111+ it ( 'should fetch any user by ID with profile but exclude salary from nested profile' , async ( ) => {
89112 const item = await jsonSdk . jonApiSdkService . getOne (
90113 UsersAcl ,
91114 usersAcl [ 0 ] . id ,
@@ -99,7 +122,7 @@ describe('ACL getOne:', () => {
99122 } ) ;
100123 } ) ;
101124
102- describe ( 'With conditional: user ' , ( ) => {
125+ describe ( 'User Role: Conditional Row-Level Access with Field Restrictions ' , ( ) => {
103126 let bobUser : UsersAcl ;
104127 beforeEach ( async ( ) => {
105128 const posibleBobUser = usersAcl . find ( ( user ) => user . login === 'bob' ) ;
@@ -112,7 +135,7 @@ describe('ACL getOne:', () => {
112135 await jsonSdk . jonApiSdkService . patchOne ( contextTestAcl ) ;
113136 } ) ;
114137
115- it ( 'should be able to get owner profile ' , async ( ) => {
138+ it ( 'should fetch own profile with phone visible and sensitive fields excluded ' , async ( ) => {
116139 const item = await jsonSdk . jonApiSdkService . getOne (
117140 UserProfileAcl ,
118141 bobUser . profile . id
@@ -129,7 +152,7 @@ describe('ACL getOne:', () => {
129152 expect ( item . bio ) . toBeDefined ( ) ;
130153 } ) ;
131154
132- it ( 'should be able to get public profile ' , async ( ) => {
155+ it ( 'should fetch public profile with phone hidden and sensitive fields excluded ' , async ( ) => {
133156 const item = await jsonSdk . jonApiSdkService . getOne (
134157 UserProfileAcl ,
135158 publicUser . profile . id
@@ -145,7 +168,7 @@ describe('ACL getOne:', () => {
145168 expect ( item . avatar ) . toBeDefined ( ) ;
146169 expect ( item . bio ) . toBeDefined ( ) ;
147170 } ) ;
148- it ( 'should be not found to get not public profile' , async ( ) => {
171+ it ( 'should return 404 Not Found when attempting to fetch private profile of another user ' , async ( ) => {
149172 try {
150173 await jsonSdk . jonApiSdkService . getOne (
151174 UserProfileAcl ,
0 commit comments