Skip to content

Commit 46916e9

Browse files
committed
fix(deps): upgrade vitest to ^4.1.0 to patch critical Vitest UI advisory (GHSA-5xrq-8626-4rwp)
- Bump vitest and @vitest/coverage-v8 to ^4.1.0 across all workspaces (only patched release for the critical 'Vitest UI server arbitrary file read/execute' advisory; no 3.x backport exists) - Widen @sim/testing peer range to ^3.0.0 || ^4.0.0 - Migrate constructor mocks to class expressions: vitest 4 uses Reflect.construct for mocks invoked with new, and arrow/function implementations are not constructable (function expressions also get reverted to arrows by biome's useArrowFunction) - Remove deprecated test.poolOptions from apps/sim/vitest.config.ts (options are now top-level in vitest 4)
1 parent e5a46d7 commit 46916e9

35 files changed

Lines changed: 447 additions & 333 deletions

File tree

apps/realtime/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@
4343
"@types/node": "24.2.1",
4444
"socket.io-client": "4.8.1",
4545
"typescript": "^5.7.3",
46-
"vitest": "^3.0.8"
46+
"vitest": "^4.1.0"
4747
}
4848
}

apps/sim/app/api/copilot/checkpoints/revert/route.test.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,23 @@ describe('Copilot Checkpoints Revert API Route', () => {
9494
vi.spyOn(Date, 'now').mockReturnValue(1640995200000)
9595

9696
const originalDate = Date
97-
vi.spyOn(global, 'Date').mockImplementation(((...args: any[]) => {
97+
const buildDate = (args: any[]): Date => {
9898
if (args.length === 0) {
99-
const mockDate = new originalDate('2024-01-01T00:00:00.000Z')
100-
return mockDate
99+
return new originalDate('2024-01-01T00:00:00.000Z')
101100
}
102101
if (args.length === 1) {
103102
return new originalDate(args[0])
104103
}
105104
return new originalDate(args[0], args[1], args[2], args[3], args[4], args[5], args[6])
106-
}) as any)
105+
}
106+
vi.spyOn(global, 'Date').mockImplementation(
107+
class {
108+
constructor(...args: any[]) {
109+
// biome-ignore lint/correctness/noConstructorReturn: vitest 4 constructs mocks via Reflect.construct; returning a real Date overrides the instance so `new Date(...)` yields a genuine Date the route can call .toISOString()/.getTime() on
110+
return buildDate(args)
111+
}
112+
} as any
113+
)
107114
})
108115

109116
afterEach(() => {

apps/sim/lib/copilot/request/lifecycle/start.test.ts

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,31 +65,33 @@ vi.mock('@/lib/copilot/request/session', () => ({
6565
startAbortPoller: vi.fn().mockReturnValue(setInterval(() => {}, 999999)),
6666
isExplicitStopReason: vi.fn().mockReturnValue(false),
6767
SSE_RESPONSE_HEADERS: {},
68-
StreamWriter: vi.fn().mockImplementation(() => ({
69-
attach: vi.fn().mockImplementation((ctrl: ReadableStreamDefaultController) => {
70-
mockPublisherController = ctrl
71-
}),
72-
startKeepalive: vi.fn(),
73-
stopKeepalive: vi.fn(),
74-
flush: vi.fn(),
75-
close: vi.fn().mockImplementation(() => {
76-
try {
77-
mockPublisherController?.close()
78-
} catch {
79-
// already closed
68+
StreamWriter: vi.fn().mockImplementation(
69+
class {
70+
attach = vi.fn().mockImplementation((ctrl: ReadableStreamDefaultController) => {
71+
mockPublisherController = ctrl
72+
})
73+
startKeepalive = vi.fn()
74+
stopKeepalive = vi.fn()
75+
flush = vi.fn()
76+
close = vi.fn().mockImplementation(() => {
77+
try {
78+
mockPublisherController?.close()
79+
} catch {
80+
// already closed
81+
}
82+
})
83+
markDisconnected = vi.fn()
84+
publish = vi.fn().mockImplementation(async (event: Record<string, unknown>) => {
85+
appendEvent(event)
86+
})
87+
get clientDisconnected() {
88+
return false
89+
}
90+
get sawComplete() {
91+
return false
8092
}
81-
}),
82-
markDisconnected: vi.fn(),
83-
publish: vi.fn().mockImplementation(async (event: Record<string, unknown>) => {
84-
appendEvent(event)
85-
}),
86-
get clientDisconnected() {
87-
return false
88-
},
89-
get sawComplete() {
90-
return false
91-
},
92-
})),
93+
}
94+
),
9395
}))
9496
vi.mock('@/lib/copilot/request/session/sse', () => ({
9597
SSE_RESPONSE_HEADERS: {},

apps/sim/lib/core/config/redis.test.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ const { MockRedisConstructor } = vi.hoisted(() => ({
66
}))
77

88
const mockRedisInstance = createMockRedis()
9-
MockRedisConstructor.mockImplementation(() => mockRedisInstance)
9+
MockRedisConstructor.mockImplementation(
10+
class {
11+
constructor() {
12+
Object.assign(this, mockRedisInstance)
13+
}
14+
}
15+
)
1016

1117
vi.mock('@/lib/core/config/env', () => createEnvMock({ REDIS_URL: 'redis://localhost:6379' }))
1218
vi.mock('ioredis', () => ({
@@ -26,7 +32,13 @@ describe('redis config', () => {
2632
vi.clearAllMocks()
2733
vi.useFakeTimers()
2834
resetForTesting()
29-
MockRedisConstructor.mockImplementation(() => mockRedisInstance)
35+
MockRedisConstructor.mockImplementation(
36+
class {
37+
constructor() {
38+
Object.assign(this, mockRedisInstance)
39+
}
40+
}
41+
)
3042
})
3143

3244
afterEach(() => {
@@ -197,10 +209,14 @@ describe('redis config', () => {
197209
describe('retryStrategy', () => {
198210
function captureRetryStrategy(): (times: number) => number {
199211
let capturedConfig: Record<string, unknown> = {}
200-
MockRedisConstructor.mockImplementation((_url: string, config: Record<string, unknown>) => {
201-
capturedConfig = config
202-
return { ping: vi.fn(), on: vi.fn() }
203-
})
212+
MockRedisConstructor.mockImplementation(
213+
class {
214+
constructor(_url: string, config: Record<string, unknown>) {
215+
capturedConfig = config
216+
Object.assign(this, { ping: vi.fn(), on: vi.fn() })
217+
}
218+
}
219+
)
204220

205221
getRedisClient()
206222

apps/sim/lib/core/rate-limiter/storage/factory.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@ vi.mock('@/lib/core/storage', () => ({
1919
}))
2020

2121
vi.mock('@/lib/core/rate-limiter/storage/db-token-bucket', () => ({
22-
DbTokenBucket: vi.fn(() => ({ type: 'db' })),
22+
DbTokenBucket: vi.fn().mockImplementation(
23+
class {
24+
type = 'db'
25+
}
26+
),
2327
}))
2428

2529
vi.mock('@/lib/core/rate-limiter/storage/redis-token-bucket', () => ({
26-
RedisTokenBucket: vi.fn(() => ({ type: 'redis' })),
30+
RedisTokenBucket: vi.fn().mockImplementation(
31+
class {
32+
type = 'redis'
33+
}
34+
),
2735
}))
2836

2937
import { createStorageAdapter, resetStorageAdapter } from '@/lib/core/rate-limiter/storage/factory'

apps/sim/lib/data-drains/destinations/azure_blob.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ const { mockUpload, mockDeleteIfExists, BlobServiceClientCtor, StorageSharedKeyC
1212
return {
1313
mockUpload,
1414
mockDeleteIfExists,
15-
BlobServiceClientCtor: vi.fn(() => ({ getContainerClient: vi.fn(() => containerClient) })),
16-
StorageSharedKeyCredentialCtor: vi.fn(),
15+
BlobServiceClientCtor: vi.fn().mockImplementation(
16+
class {
17+
getContainerClient = vi.fn(() => containerClient)
18+
}
19+
),
20+
StorageSharedKeyCredentialCtor: vi.fn().mockImplementation(class {}),
1721
}
1822
})
1923

apps/sim/lib/data-drains/destinations/bigquery.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ const { mockGetAccessToken, JWTCtor, loggerInstance } = vi.hoisted(() => {
1717
}
1818
return {
1919
mockGetAccessToken,
20-
JWTCtor: vi.fn(() => ({ getAccessToken: mockGetAccessToken })),
20+
JWTCtor: vi.fn().mockImplementation(
21+
class {
22+
getAccessToken = mockGetAccessToken
23+
}
24+
),
2125
loggerInstance,
2226
}
2327
})

apps/sim/lib/data-drains/destinations/gcs.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ const { mockGetAccessToken, JWTCtor } = vi.hoisted(() => {
77
const mockGetAccessToken = vi.fn(async () => ({ token: 'fake-access-token' }))
88
return {
99
mockGetAccessToken,
10-
JWTCtor: vi.fn(() => ({ getAccessToken: mockGetAccessToken })),
10+
JWTCtor: vi.fn().mockImplementation(
11+
class {
12+
getAccessToken = mockGetAccessToken
13+
}
14+
),
1115
}
1216
})
1317

apps/sim/lib/data-drains/destinations/s3.test.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,30 @@ const { mockSend, mockDestroy, S3ClientCtor, PutObjectCommandCtor, DeleteObjectC
1010
return {
1111
mockSend,
1212
mockDestroy,
13-
S3ClientCtor: vi.fn(() => ({ send: mockSend, destroy: mockDestroy })),
14-
PutObjectCommandCtor: vi.fn((args: unknown) => ({ __cmd: 'put', args })),
15-
DeleteObjectCommandCtor: vi.fn((args: unknown) => ({ __cmd: 'delete', args })),
13+
S3ClientCtor: vi.fn().mockImplementation(
14+
class {
15+
send = mockSend
16+
destroy = mockDestroy
17+
}
18+
),
19+
PutObjectCommandCtor: vi.fn().mockImplementation(
20+
class {
21+
__cmd = 'put'
22+
args: unknown
23+
constructor(args: unknown) {
24+
this.args = args
25+
}
26+
}
27+
),
28+
DeleteObjectCommandCtor: vi.fn().mockImplementation(
29+
class {
30+
__cmd = 'delete'
31+
args: unknown
32+
constructor(args: unknown) {
33+
this.args = args
34+
}
35+
}
36+
),
1637
}
1738
})
1839

apps/sim/lib/mcp/client.test.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,33 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
1010
let capturedNotificationHandler: (() => Promise<void>) | null = null
1111

1212
vi.mock('@modelcontextprotocol/sdk/client/index.js', () => ({
13-
Client: vi.fn().mockImplementation(() => ({
14-
connect: vi.fn().mockResolvedValue(undefined),
15-
close: vi.fn().mockResolvedValue(undefined),
16-
getServerVersion: vi.fn().mockReturnValue('2025-06-18'),
17-
getServerCapabilities: vi.fn().mockReturnValue({ tools: { listChanged: true } }),
18-
setNotificationHandler: vi
19-
.fn()
20-
.mockImplementation((_schema: unknown, handler: () => Promise<void>) => {
21-
capturedNotificationHandler = handler
22-
}),
23-
listTools: vi.fn().mockResolvedValue({ tools: [] }),
24-
})),
13+
Client: vi.fn().mockImplementation(
14+
class {
15+
constructor() {
16+
Object.assign(this, {
17+
connect: vi.fn().mockResolvedValue(undefined),
18+
close: vi.fn().mockResolvedValue(undefined),
19+
getServerVersion: vi.fn().mockReturnValue('2025-06-18'),
20+
getServerCapabilities: vi.fn().mockReturnValue({ tools: { listChanged: true } }),
21+
setNotificationHandler: vi
22+
.fn()
23+
.mockImplementation((_schema: unknown, handler: () => Promise<void>) => {
24+
capturedNotificationHandler = handler
25+
}),
26+
listTools: vi.fn().mockResolvedValue({ tools: [] }),
27+
})
28+
}
29+
}
30+
),
2531
}))
2632

2733
vi.mock('@modelcontextprotocol/sdk/client/streamableHttp.js', () => ({
28-
StreamableHTTPClientTransport: vi.fn().mockImplementation(() => ({
29-
onclose: null,
30-
sessionId: 'test-session',
31-
})),
34+
StreamableHTTPClientTransport: vi.fn().mockImplementation(
35+
class {
36+
onclose: null = null
37+
sessionId = 'test-session'
38+
}
39+
),
3240
}))
3341

3442
vi.mock('@modelcontextprotocol/sdk/types.js', () => ({

0 commit comments

Comments
 (0)