@@ -7,12 +7,26 @@ import { authMockFns } from '@sim/testing'
77import { renderToStaticMarkup } from 'react-dom/server'
88import { beforeEach , describe , expect , it , vi } from 'vitest'
99
10- const { mockGetOrganizationSurfaceContext, mockWorkspaceChrome, mockPrefetchUserProfile } =
11- vi . hoisted ( ( ) => ( {
12- mockGetOrganizationSurfaceContext : vi . fn ( ) ,
13- mockWorkspaceChrome : vi . fn ( ( { children } : { children : ReactNode } ) => children ) ,
14- mockPrefetchUserProfile : vi . fn ( async ( ) => undefined ) ,
15- } ) )
10+ const {
11+ mockGetOrganizationSurfaceContext,
12+ mockWorkspaceChrome,
13+ mockPrefetchUserProfile,
14+ mockUseSession,
15+ } = vi . hoisted ( ( ) => ( {
16+ mockGetOrganizationSurfaceContext : vi . fn ( ) ,
17+ mockWorkspaceChrome : vi . fn ( ( { children } : { children : ReactNode } ) => children ) ,
18+ mockPrefetchUserProfile : vi . fn ( async ( ) => undefined ) ,
19+ mockUseSession : vi . fn ( ) ,
20+ } ) )
21+
22+ vi . mock ( '@/lib/auth/auth-client' , ( ) => ( { useSession : mockUseSession } ) )
23+ vi . mock ( '@/hooks/queries/admin-users' , ( ) => ( {
24+ useStopImpersonating : ( ) => ( { mutate : vi . fn ( ) , isPending : false } ) ,
25+ } ) )
26+ vi . mock ( '@/stores' , ( ) => ( { clearUserData : vi . fn ( ) } ) )
27+ vi . mock ( '@/lib/auth/stale-session-recovery' , ( ) => ( {
28+ recoverFromStaleSession : vi . fn ( ) ,
29+ } ) )
1630
1731vi . mock ( '@tanstack/react-query' , ( ) => ( {
1832 HydrationBoundary : ( { children } : { children : ReactNode } ) => children ,
@@ -67,6 +81,7 @@ describe('OrganizationLayout', () => {
6781 beforeEach ( ( ) => {
6882 vi . clearAllMocks ( )
6983 mockGetSession . mockResolvedValue ( { user : { id : 'viewer-1' } } )
84+ mockUseSession . mockReturnValue ( { data : { user : { id : 'viewer-1' } } , isPending : false } )
7085 } )
7186
7287 it ( 'returns signed-out visitors to the organization entry after sign-in' , async ( ) => {
@@ -93,12 +108,58 @@ describe('OrganizationLayout', () => {
93108 expect ( mockGetOrganizationSurfaceContext ) . toHaveBeenCalledWith ( 'org-1' , 'viewer-1' )
94109 expect ( mockPrefetchUserProfile ) . toHaveBeenCalledWith ( { } , 'viewer-1' )
95110 expect ( html ) . toContain ( 'Organization child' )
111+ expect ( html ) . not . toContain ( 'Stop impersonating' )
96112 expect ( mockWorkspaceChrome ) . toHaveBeenCalledWith (
97113 expect . objectContaining ( { initialSidebarCollapsed : true } ) ,
98114 undefined
99115 )
100116 } )
101117
118+ it ( 'shows the shared impersonation banner above organization content' , async ( ) => {
119+ const session = {
120+ user : { id : 'viewer-1' , name : 'QA Member' , email : 'member@example.com' } ,
121+ session : { impersonatedBy : 'platform-admin' } ,
122+ }
123+ mockGetSession . mockResolvedValue ( session )
124+ mockUseSession . mockReturnValue ( { data : session , isPending : false } )
125+ mockGetOrganizationSurfaceContext . mockResolvedValue ( SURFACE_CONTEXT )
126+
127+ const html = renderToStaticMarkup (
128+ await OrganizationLayout ( {
129+ children : < div > Organization child</ div > ,
130+ params : Promise . resolve ( { organizationId : 'org-1' } ) ,
131+ } )
132+ )
133+
134+ expect ( mockGetOrganizationSurfaceContext ) . toHaveBeenCalledWith ( 'org-1' , 'viewer-1' )
135+ expect ( html ) . toContain ( 'Impersonating QA Member (member@example.com)' )
136+ expect ( html ) . toContain ( 'Stop impersonating' )
137+ expect ( html . indexOf ( 'Stop impersonating' ) ) . toBeLessThan ( html . indexOf ( 'Organization child' ) )
138+ } )
139+
140+ it ( 'does not use the impersonating admin to enter an organization outside the rollout' , async ( ) => {
141+ mockGetSession . mockResolvedValue ( {
142+ user : { id : 'customer-member' } ,
143+ session : { impersonatedBy : 'platform-admin' } ,
144+ } )
145+ mockGetOrganizationSurfaceContext . mockResolvedValue ( {
146+ ...SURFACE_CONTEXT ,
147+ searchAccess : { memberScoped : false , sourceMirrored : false } ,
148+ } )
149+
150+ await expect (
151+ OrganizationLayout ( {
152+ children : < div > Organization child</ div > ,
153+ params : Promise . resolve ( { organizationId : 'customer-org' } ) ,
154+ } )
155+ ) . rejects . toThrow ( 'redirect:/workspace?redirect=settings' )
156+ expect ( mockGetOrganizationSurfaceContext ) . toHaveBeenCalledWith (
157+ 'customer-org' ,
158+ 'customer-member'
159+ )
160+ expect ( mockWorkspaceChrome ) . not . toHaveBeenCalled ( )
161+ } )
162+
102163 it ( 'renders an explicit denial for a non-member without the surface' , async ( ) => {
103164 mockGetOrganizationSurfaceContext . mockResolvedValue ( null )
104165
0 commit comments