Skip to content

Commit 1ea0b49

Browse files
committed
test(admin): cover the deleted source organization and truncated credential counts
`getSourceOrganization` was mocked inline in the module factory, so the reload branch that reports a recorded-but-deleted source organization could not be exercised at all. Hoist it like the other mocks and pin that third tri-state. Every credential fixture also reported zero dropped rows, so the applied and reloaded truncation records would not have caught a regression to the hardcoded zeros they replaced.
1 parent dcd24d1 commit 1ea0b49

1 file changed

Lines changed: 92 additions & 9 deletions

File tree

apps/sim/lib/workspaces/admin-move.test.ts

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ const {
4747
countPendingSeatInvitations,
4848
resolveSeatCapacity,
4949
collectWorkspaceCredentialSummary,
50+
getSourceOrganization,
5051
} = vi.hoisted(() => ({
5152
resolveMoveEntitlements: vi.fn(() =>
5253
Promise.resolve({
@@ -75,8 +76,17 @@ const {
7576
countPendingSeatInvitations: vi.fn(() => Promise.resolve(0)),
7677
resolveSeatCapacity: vi.fn(() => Promise.resolve(10)),
7778
collectWorkspaceCredentialSummary: vi.fn(),
79+
getSourceOrganization: vi.fn(),
7880
}))
7981

82+
const SOURCE_ORGANIZATION = {
83+
id: 'org-source',
84+
name: 'Source',
85+
ownerId: 'source-owner',
86+
ownerName: 'Source Owner',
87+
ownerEmail: 'source-owner@example.com',
88+
}
89+
8090
const EMPTY_CREDENTIALS = {
8191
items: [] as Array<{
8292
id: string
@@ -101,6 +111,13 @@ const POPULATED_CREDENTIALS = {
101111
byokKeyCount: 2,
102112
}
103113

114+
/** A workspace whose secrets exceed the response bounds, so rows were dropped. */
115+
const TRUNCATED_CREDENTIALS = {
116+
...POPULATED_CREDENTIALS,
117+
truncatedCredentials: 3,
118+
truncatedEnvironmentVariableKeys: 7,
119+
}
120+
104121
vi.mock('@sim/audit', () => ({
105122
AuditAction: {
106123
WORKSPACE_UPDATED: 'workspace.updated',
@@ -157,15 +174,7 @@ vi.mock('@/lib/workspaces/admin-move-source-impact', () => ({
157174
findRetainedCollaboratorCaps: vi.fn(() => Promise.resolve([])),
158175
findUnpublishableCustomBlocks,
159176
findSourceOrgCustomBlocksForWorkspace,
160-
getSourceOrganization: vi.fn(() =>
161-
Promise.resolve({
162-
id: 'org-source',
163-
name: 'Source',
164-
ownerId: 'source-owner',
165-
ownerName: 'Source Owner',
166-
ownerEmail: 'source-owner@example.com',
167-
})
168-
),
177+
getSourceOrganization,
169178
resolveMoveEntitlements,
170179
willBrandingChange: vi.fn(() => Promise.resolve(false)),
171180
}))
@@ -269,6 +278,7 @@ beforeEach(() => {
269278
capabilitiesLost: [],
270279
})
271280
collectWorkspaceCredentialSummary.mockResolvedValue(EMPTY_CREDENTIALS)
281+
getSourceOrganization.mockResolvedValue(SOURCE_ORGANIZATION)
272282
changeWorkspaceStoragePayerInTx.mockResolvedValue({
273283
billableBytes: 128,
274284
newPayer: { type: 'organization', id: destination.id },
@@ -898,6 +908,33 @@ describe('moveWorkspaceToOrganization retries', () => {
898908
expect(view.credentials).toEqual(POPULATED_CREDENTIALS)
899909
})
900910

911+
/**
912+
* A recorded id whose organization has since been deleted is the third state:
913+
* the payload answered, but the answer can no longer be resolved to a name.
914+
*/
915+
it('distinguishes a deleted source organization from an unrecorded one', async () => {
916+
getSourceOrganization.mockResolvedValueOnce(null)
917+
queueMoveOperationSelects({
918+
actor: { id: null, name: 'Admin Panel', email: 'admin@sim.ai' },
919+
previousBillingOwnerId: personalWorkspace.billedAccountUserId,
920+
newBillingOwnerId: destination.ownerId,
921+
organizationAssignedAt: '2026-08-20T00:00:00.000Z',
922+
sourceOrganizationId: 'org-source',
923+
})
924+
925+
const view = await getWorkspaceMoveOperation(
926+
movedWorkspace.id,
927+
destination.id,
928+
movedWorkspace.ownerId,
929+
'operation-1'
930+
)
931+
932+
expect(view.sourceOrganization).toBeNull()
933+
expect(view.notices).toEqual([
934+
'The organization this workspace came from has since been deleted, so it can no longer be named.',
935+
])
936+
})
937+
901938
it('reports the workspace credentials in the applied summary', async () => {
902939
queueMoveSelects(organizationWorkspace)
903940
collectWorkspaceCredentialSummary.mockResolvedValueOnce(POPULATED_CREDENTIALS)
@@ -916,6 +953,52 @@ describe('moveWorkspaceToOrganization retries', () => {
916953
expect.anything()
917954
)
918955
expect(summary.credentials).toEqual(POPULATED_CREDENTIALS)
956+
/** Nothing was dropped, so the review is complete and says nothing about truncation. */
957+
expect(summary.sourceOrganizationImpact.truncated).toBeNull()
958+
})
959+
960+
/**
961+
* The applied path used to hardcode these two counters to zero, which would
962+
* present a truncated credential list as a complete one.
963+
*/
964+
it('carries dropped credential counts into the applied truncation record', async () => {
965+
queueMoveSelects(organizationWorkspace)
966+
collectWorkspaceCredentialSummary.mockResolvedValueOnce(TRUNCATED_CREDENTIALS)
967+
968+
const summary = await moveWorkspaceToOrganization({
969+
workspaceId: organizationWorkspace.id,
970+
destinationOrganizationId: destination.id,
971+
adminEmail: 'admin@sim.ai',
972+
durableOperationId: 'operation-1',
973+
})
974+
975+
expect(summary.sourceOrganizationImpact.truncated).toMatchObject({
976+
credentials: 3,
977+
environmentVariableKeys: 7,
978+
})
979+
})
980+
981+
it('carries dropped credential counts into a reloaded truncation record', async () => {
982+
collectWorkspaceCredentialSummary.mockResolvedValueOnce(TRUNCATED_CREDENTIALS)
983+
queueMoveOperationSelects({
984+
actor: { id: null, name: 'Admin Panel', email: 'admin@sim.ai' },
985+
previousBillingOwnerId: personalWorkspace.billedAccountUserId,
986+
newBillingOwnerId: destination.ownerId,
987+
organizationAssignedAt: '2026-08-20T00:00:00.000Z',
988+
sourceOrganizationId: 'org-source',
989+
})
990+
991+
const view = await getWorkspaceMoveOperation(
992+
movedWorkspace.id,
993+
destination.id,
994+
movedWorkspace.ownerId,
995+
'operation-1'
996+
)
997+
998+
expect(view.sourceOrganizationImpact.truncated).toMatchObject({
999+
credentials: 3,
1000+
environmentVariableKeys: 7,
1001+
})
9191002
})
9201003

9211004
it('reports the workspace credentials on a retry of a completed move', async () => {

0 commit comments

Comments
 (0)