@@ -143,6 +143,53 @@ describe('MetadataManager — IMetadataService Contract', () => {
143143 } ) ;
144144 } ) ;
145145
146+ // ==========================================
147+ // UI Convenience Methods
148+ // ==========================================
149+
150+ describe ( 'UI convenience methods' , ( ) => {
151+ it ( 'should get a view via getView()' , async ( ) => {
152+ const viewDef = { name : 'account_list' , object : 'account' , type : 'grid' } ;
153+ await manager . register ( 'view' , 'account_list' , viewDef ) ;
154+
155+ const result = await manager . getView ( 'account_list' ) ;
156+ expect ( result ) . toEqual ( viewDef ) ;
157+ } ) ;
158+
159+ it ( 'should list views via listViews()' , async ( ) => {
160+ await manager . register ( 'view' , 'account_list' , { name : 'account_list' , object : 'account' } ) ;
161+ await manager . register ( 'view' , 'contact_list' , { name : 'contact_list' , object : 'contact' } ) ;
162+
163+ const allViews = await manager . listViews ( ) ;
164+ expect ( allViews ) . toHaveLength ( 2 ) ;
165+ } ) ;
166+
167+ it ( 'should filter views by object via listViews(object)' , async ( ) => {
168+ await manager . register ( 'view' , 'account_list' , { name : 'account_list' , object : 'account' } ) ;
169+ await manager . register ( 'view' , 'contact_list' , { name : 'contact_list' , object : 'contact' } ) ;
170+
171+ const accountViews = await manager . listViews ( 'account' ) ;
172+ expect ( accountViews ) . toHaveLength ( 1 ) ;
173+ expect ( ( accountViews [ 0 ] as any ) . name ) . toBe ( 'account_list' ) ;
174+ } ) ;
175+
176+ it ( 'should get a dashboard via getDashboard()' , async ( ) => {
177+ const dashDef = { name : 'sales' , label : 'Sales Overview' } ;
178+ await manager . register ( 'dashboard' , 'sales' , dashDef ) ;
179+
180+ const result = await manager . getDashboard ( 'sales' ) ;
181+ expect ( result ) . toEqual ( dashDef ) ;
182+ } ) ;
183+
184+ it ( 'should list dashboards via listDashboards()' , async ( ) => {
185+ await manager . register ( 'dashboard' , 'sales' , { name : 'sales' } ) ;
186+ await manager . register ( 'dashboard' , 'ops' , { name : 'ops' } ) ;
187+
188+ const dashboards = await manager . listDashboards ( ) ;
189+ expect ( dashboards ) . toHaveLength ( 2 ) ;
190+ } ) ;
191+ } ) ;
192+
146193 // ==========================================
147194 // Package Management
148195 // ==========================================
@@ -328,6 +375,44 @@ describe('MetadataManager — IMetadataService Contract', () => {
328375 const effective = await manager . getEffective ( 'object' , 'account' ) as any ;
329376 expect ( effective . label ) . toBe ( 'Original' ) ;
330377 } ) ;
378+
379+ it ( 'should apply user overlay scoped to specific userId via getEffective context' , async ( ) => {
380+ await manager . register ( 'view' , 'account_list' , {
381+ name : 'account_list' ,
382+ columns : [ 'name' , 'email' , 'status' ]
383+ } ) ;
384+
385+ // Platform overlay
386+ await manager . saveOverlay ( {
387+ id : 'platform-view-1' ,
388+ baseType : 'view' ,
389+ baseName : 'account_list' ,
390+ scope : 'platform' ,
391+ patch : { columns : [ 'name' , 'email' , 'status' , 'created_at' ] } ,
392+ active : true ,
393+ } ) ;
394+
395+ // User-specific overlay
396+ await manager . saveOverlay ( {
397+ id : 'user-view-1' ,
398+ baseType : 'view' ,
399+ baseName : 'account_list' ,
400+ scope : 'user' ,
401+ owner : 'user-456' ,
402+ patch : { columns : [ 'name' , 'status' ] } ,
403+ active : true ,
404+ } ) ;
405+
406+ // Without context — should apply platform but not user overlay (no owner match)
407+ const general = await manager . getEffective ( 'view' , 'account_list' ) as any ;
408+ expect ( general . columns ) . toEqual ( [ 'name' , 'email' , 'status' , 'created_at' ] ) ;
409+
410+ // With userId context — should apply user overlay
411+ const forUser = await manager . getEffective ( 'view' , 'account_list' , {
412+ userId : 'user-456'
413+ } ) as any ;
414+ expect ( forUser . columns ) . toEqual ( [ 'name' , 'status' ] ) ;
415+ } ) ;
331416 } ) ;
332417
333418 // ==========================================
0 commit comments