11/**
22 * @vitest -environment node
33 */
4+ import { db } from '@sim/db'
45import { member , user } from '@sim/db/schema'
56import { authMockFns , createMockRequest , queueTableRows , resetDbChainMock } from '@sim/testing'
67import { beforeEach , describe , expect , it , vi } from 'vitest'
@@ -52,6 +53,7 @@ vi.mock('@/ee/access-control/utils/permission-check', () => ({
5253vi . mock ( '@/lib/invitations/core' , ( ) => ( {
5354 getInvitationById : mockGetInvitationById ,
5455 resolveInvitationAdmissionOrganizationId : mockResolveInvitationAdmissionOrganizationId ,
56+ requireInvitationResendAuthority : vi . fn ( ) ,
5557} ) )
5658vi . mock ( '@/lib/invitations/send' , ( ) => ( {
5759 sendInvitationEmail : mockSendInvitationEmail ,
@@ -70,13 +72,15 @@ vi.mock('@/lib/workspaces/permissions/utils', () => ({
7072} ) )
7173vi . mock ( '@/lib/workspaces/policy' , ( ) => ( {
7274 getWorkspaceInvitePolicy : mockGetWorkspaceInvitePolicy ,
75+ WORKSPACE_MODE : { ORGANIZATION : 'organization' } ,
7376} ) )
7477
7578vi . mock ( '@/lib/permission-groups/resolve.server' , ( ) => ( {
7679 getUserPermissionConfigForOrganization : vi . fn ( ) . mockResolvedValue ( null ) ,
7780} ) )
7881
7982import { OrchestrationError } from '@/lib/core/orchestration/types'
83+ import { lockInvitationResendPolicy } from '@/lib/invitations/resend-policy'
8084import type { PreparedInvitationResend } from '@/lib/invitations/send'
8185import { POST } from '@/app/api/invitations/[id]/resend/route'
8286
@@ -141,10 +145,21 @@ describe('POST /api/invitations/[id]/resend', () => {
141145 mockGetWorkspaceWithOwner . mockResolvedValue ( {
142146 id : 'workspace-1' ,
143147 organizationId : 'organization-1' ,
148+ workspaceMode : 'organization' ,
149+ billedAccountUserId : 'owner' ,
150+ ownerId : 'owner' ,
144151 } )
145152 mockGetWorkspaceInvitePolicy . mockResolvedValue ( { allowed : true } )
146153 mockValidateInvitationsAllowed . mockResolvedValue ( undefined )
147- mockPrepareInvitationResend . mockResolvedValue ( preparedResend )
154+ mockPrepareInvitationResend . mockImplementation ( async ( params ) => {
155+ await lockInvitationResendPolicy (
156+ db ,
157+ await mockGetInvitationById ( params . invitationId ) ,
158+ params . actorUserId ,
159+ params . expectedOrganizationId
160+ )
161+ return preparedResend
162+ } )
148163 mockSendInvitationEmail . mockResolvedValue ( { success : true } )
149164 mockRevertInvitationResend . mockResolvedValue ( true )
150165 } )
@@ -153,9 +168,13 @@ describe('POST /api/invitations/[id]/resend', () => {
153168 const response = await callResend ( )
154169
155170 expect ( response . status ) . toBe ( 200 )
156- expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith ( 'user-1' , {
157- workspaceId : 'workspace-1' ,
158- } )
171+ expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith (
172+ 'user-1' ,
173+ {
174+ workspaceId : 'workspace-1' ,
175+ } ,
176+ db
177+ )
159178 expect ( mockSendInvitationEmail ) . toHaveBeenCalled ( )
160179 expect ( mockPrepareInvitationResend . mock . invocationCallOrder [ 0 ] ) . toBeLessThan (
161180 mockSendInvitationEmail . mock . invocationCallOrder [ 0 ]
@@ -210,12 +229,20 @@ describe('POST /api/invitations/[id]/resend', () => {
210229 const response = await callResend ( )
211230
212231 expect ( response . status ) . toBe ( 200 )
213- expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith ( 'user-1' , {
214- organizationId : 'organization-1' ,
215- } )
216- expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith ( 'user-1' , {
217- workspaceId : 'workspace-1' ,
218- } )
232+ expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith (
233+ 'user-1' ,
234+ {
235+ organizationId : 'organization-1' ,
236+ } ,
237+ db
238+ )
239+ expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith (
240+ 'user-1' ,
241+ {
242+ workspaceId : 'workspace-1' ,
243+ } ,
244+ db
245+ )
219246 } )
220247
221248 it ( 'refuses an organization invitation the organization default group withholds, even when its granted workspace allows' , async ( ) => {
@@ -245,13 +272,24 @@ describe('POST /api/invitations/[id]/resend', () => {
245272 const response = await callResend ( )
246273
247274 expect ( response . status ) . toBe ( 200 )
248- expect ( mockResolveInvitationAdmissionOrganizationId ) . toHaveBeenCalledWith ( workspaceInvitation )
249- expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith ( 'user-1' , {
250- organizationId : 'organization-1' ,
251- } )
252- expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith ( 'user-1' , {
253- workspaceId : 'workspace-1' ,
254- } )
275+ expect ( mockResolveInvitationAdmissionOrganizationId ) . toHaveBeenCalledWith (
276+ workspaceInvitation ,
277+ db
278+ )
279+ expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith (
280+ 'user-1' ,
281+ {
282+ organizationId : 'organization-1' ,
283+ } ,
284+ db
285+ )
286+ expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith (
287+ 'user-1' ,
288+ {
289+ workspaceId : 'workspace-1' ,
290+ } ,
291+ db
292+ )
255293 } )
256294
257295 it ( 'refuses a workspace invitation whose admitting organization withholds invitations' , async ( ) => {
@@ -281,9 +319,13 @@ describe('POST /api/invitations/[id]/resend', () => {
281319
282320 expect ( response . status ) . toBe ( 200 )
283321 expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledTimes ( 1 )
284- expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith ( 'user-1' , {
285- workspaceId : 'workspace-1' ,
286- } )
322+ expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith (
323+ 'user-1' ,
324+ {
325+ workspaceId : 'workspace-1' ,
326+ } ,
327+ db
328+ )
287329 } )
288330
289331 it ( 'resolves the organization default group for an invitation with no grants' , async ( ) => {
@@ -298,9 +340,13 @@ describe('POST /api/invitations/[id]/resend', () => {
298340 const response = await callResend ( )
299341
300342 expect ( response . status ) . toBe ( 200 )
301- expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith ( 'user-1' , {
302- organizationId : 'organization-1' ,
303- } )
343+ expect ( mockValidateInvitationsAllowed ) . toHaveBeenCalledWith (
344+ 'user-1' ,
345+ {
346+ organizationId : 'organization-1' ,
347+ } ,
348+ db
349+ )
304350 } )
305351 it . each ( [ 'pending' , 'expired' ] ) (
306352 'rejects an expired %s invitation consistently' ,
0 commit comments