Skip to content

Commit a74d40f

Browse files
samuvrenovate[bot]
andauthored
chore(deps): bump to vitest 4 and adjust tests after the upgrade (#1198)
* chore(deps): update vitest monorepo to v4 * test: adjust test for vitest 4 * chore: format * tests: use find --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
1 parent 5233a45 commit a74d40f

File tree

14 files changed

+393
-321
lines changed

14 files changed

+393
-321
lines changed

__mocks__/fs.cjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Mock for node:fs using memfs
2+
// See: https://vitest.dev/guide/mocking/file-system.html
3+
4+
const { fs } = require('memfs')
5+
module.exports = fs

__mocks__/fs/promises.cjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Mock for node:fs/promises using memfs
2+
// See: https://vitest.dev/guide/mocking/file-system.html
3+
4+
const { fs } = require('memfs')
5+
module.exports = fs.promises

main/src/tests/auto-update.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ vi.mock('electron-store', () => {
104104
}
105105

106106
return {
107-
default: vi.fn().mockImplementation(() => mockStoreInstance),
107+
default: vi.fn(function ElectronStore() {
108+
return mockStoreInstance
109+
}),
108110
}
109111
})
110112

main/src/tests/graceful-exit.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ vi.mock('electron-store', () => {
4848
).__mockStoreInstance = mockStoreInstance
4949

5050
return {
51-
default: vi.fn().mockImplementation(() => mockStoreInstance),
51+
default: vi.fn(function ElectronStore() {
52+
return mockStoreInstance
53+
}),
5254
}
5355
})
5456

main/src/tests/toolhive-manager.test.ts

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,48 @@
11
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
2+
import { EventEmitter } from 'node:events'
3+
import { vol } from 'memfs'
24
import { spawn } from 'node:child_process'
3-
import { existsSync } from 'node:fs'
45
import net from 'node:net'
56
import { app } from 'electron'
6-
import { EventEmitter } from 'node:events'
77
import {
88
startToolhive,
99
getToolhivePort,
1010
getToolhiveMcpPort,
1111
isToolhiveRunning,
1212
stopToolhive,
1313
restartToolhive,
14+
binPath,
1415
} from '../toolhive-manager'
1516
import { updateTrayStatus } from '../system-tray'
1617
import log from '../logger'
1718
import * as Sentry from '@sentry/electron/main'
1819
import { getQuittingState } from '../app-state'
1920

20-
// Mock dependencies
21-
vi.mock('node:child_process')
21+
vi.mock('node:child_process', async (importOriginal) => {
22+
const actual = await importOriginal<typeof import('node:child_process')>()
23+
const mockSpawnFn = vi.fn()
24+
return {
25+
...actual,
26+
spawn: mockSpawnFn,
27+
default: {
28+
...actual,
29+
spawn: mockSpawnFn,
30+
},
31+
}
32+
})
2233
vi.mock('node:fs')
23-
vi.mock('node:net')
34+
vi.mock('node:net', async (importOriginal) => {
35+
const actual = await importOriginal<typeof import('node:net')>()
36+
const mockCreateServerFn = vi.fn()
37+
return {
38+
...actual,
39+
createServer: mockCreateServerFn,
40+
default: {
41+
...actual,
42+
createServer: mockCreateServerFn,
43+
},
44+
}
45+
})
2446
vi.mock('electron', () => ({
2547
app: {
2648
isPackaged: false,
@@ -53,12 +75,14 @@ vi.mock('electron-store', () => {
5375
}
5476

5577
return {
56-
default: vi.fn().mockImplementation(() => mockStoreInstance),
78+
default: vi.fn(function ElectronStore() {
79+
return mockStoreInstance
80+
}),
5781
}
5882
})
5983

84+
// Get mocked functions
6085
const mockSpawn = vi.mocked(spawn)
61-
const mockExistsSync = vi.mocked(existsSync)
6286
const mockNet = vi.mocked(net)
6387
const mockApp = vi.mocked(app)
6488
const mockUpdateTrayStatus = vi.mocked(updateTrayStatus)
@@ -112,26 +136,35 @@ describe('toolhive-manager', () => {
112136
vi.clearAllMocks()
113137
vi.useFakeTimers()
114138

139+
// Reset the in-memory file system
140+
vol.reset()
141+
142+
// Setup the file system state - make binary exist by default
143+
vol.fromJSON({
144+
[binPath]: '', // Mock the binary file exists
145+
})
146+
115147
// Reset module state
116148
stopToolhive()
117149

118150
// Setup mocks
119151
mockProcess = new MockProcess()
120152

121-
mockSpawn.mockReturnValue(
122-
mockProcess as unknown as ReturnType<typeof spawn>
123-
)
124-
mockExistsSync.mockReturnValue(true)
153+
mockSpawn.mockImplementation(function spawn() {
154+
return mockProcess as unknown as ReturnType<
155+
typeof import('node:child_process').spawn
156+
>
157+
})
125158
Object.defineProperty(mockApp, 'isPackaged', {
126159
value: false,
127160
configurable: true,
128161
})
129162
vi.mocked(mockApp.getPath).mockReturnValue('/test/userData')
130163

131164
// Mock net.createServer to return a new MockServer instance each time
132-
mockNet.createServer.mockImplementation(
133-
() => new MockServer() as unknown as net.Server
134-
)
165+
mockNet.createServer.mockImplementation(function createServer() {
166+
return new MockServer() as unknown as net.Server
167+
})
135168

136169
// Mock logger methods
137170
mockLog.info = vi.fn()
@@ -147,7 +180,8 @@ describe('toolhive-manager', () => {
147180

148181
describe('startToolhive', () => {
149182
it('returns early if binary does not exist', async () => {
150-
mockExistsSync.mockReturnValue(false)
183+
// Remove the binary file from the in-memory file system
184+
vol.reset()
151185

152186
await startToolhive()
153187

@@ -382,28 +416,30 @@ describe('toolhive-manager', () => {
382416
describe('port finding with fallback', () => {
383417
it('falls back to random port when preferred range is unavailable', async () => {
384418
// Mock all ports in range to be unavailable, then allow random port
385-
mockNet.createServer.mockImplementation(() => {
419+
mockNet.createServer.mockImplementation(function createServer() {
386420
const server = new MockServer() as unknown as net.Server
387421
const originalListen = server.listen.bind(server)
388422

389-
server.listen = vi
390-
.fn()
391-
.mockImplementation((port: number, callback?: () => void) => {
392-
if (port >= 50000 && port <= 50100) {
393-
// Simulate all ports in range being unavailable
394-
setTimeout(() => {
395-
server.emit('error', { code: 'EADDRINUSE' })
396-
}, 5)
397-
} else if (port === 0) {
398-
// Allow OS assignment (fallback)
399-
setTimeout(() => {
400-
originalListen(port, callback)
401-
}, 5)
402-
} else {
403-
// Any other specific port
423+
server.listen = vi.fn(function listen(
424+
port: number,
425+
callback?: () => void
426+
) {
427+
if (port >= 50000 && port <= 50100) {
428+
// Simulate all ports in range being unavailable
429+
setTimeout(() => {
430+
server.emit('error', { code: 'EADDRINUSE' })
431+
}, 5)
432+
} else if (port === 0) {
433+
// Allow OS assignment (fallback)
434+
setTimeout(() => {
404435
originalListen(port, callback)
405-
}
406-
})
436+
}, 5)
437+
} else {
438+
// Any other specific port
439+
originalListen(port, callback)
440+
}
441+
return server
442+
}) as unknown as typeof server.listen
407443

408444
return server
409445
})
@@ -566,10 +602,12 @@ describe('toolhive-manager', () => {
566602

567603
it('handles kill errors and attempts force kill as fallback', () => {
568604
const killSpy = vi.spyOn(mockProcess, 'kill')
569-
killSpy.mockImplementationOnce(() => {
605+
killSpy.mockImplementationOnce(function killImpl() {
570606
throw new Error('Kill failed')
571607
})
572-
killSpy.mockImplementationOnce(() => true)
608+
killSpy.mockImplementationOnce(function killImpl() {
609+
return true
610+
})
573611

574612
stopToolhive()
575613

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"@types/regexp.escape": "^2.0.0",
6262
"@types/unzipper": "^0.10.11",
6363
"@vitejs/plugin-react-swc": "^4.0.0",
64-
"@vitest/coverage-istanbul": "^3.1.4",
64+
"@vitest/coverage-istanbul": "^4.0.0",
6565
"ajv": "^8.17.1",
6666
"autoprefixer": "^10.4.21",
6767
"dotenv": "^17.0.0",
@@ -76,6 +76,7 @@
7676
"json-schema-faker": "^0.5.9",
7777
"knip": "^5.58.1",
7878
"lint-staged": "^16.0.0",
79+
"memfs": "^4.50.0",
7980
"msw": "^2.8.4",
8081
"prettier": "3.6.2",
8182
"prettier-plugin-classnames": "^0.8.0",
@@ -87,7 +88,7 @@
8788
"typescript-eslint": "^8.30.1",
8889
"unzipper": "^0.12.3",
8990
"vite": "^7.0.0",
90-
"vitest": "^3.1.4",
91+
"vitest": "^4.0.0",
9192
"vitest-fail-on-console": "^0.10.0"
9293
},
9394
"dependencies": {

parallel-requests.sh

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
3+
# Colors for output
4+
GREEN='\033[0;32m'
5+
YELLOW='\033[1;33m'
6+
BLUE='\033[0;34m'
7+
RED='\033[0;31m'
8+
NC='\033[0m' # No Color
9+
10+
echo "================================"
11+
echo " Starting API Requests"
12+
echo "================================"
13+
echo ""
14+
15+
# Function to run curl and track its status
16+
run_request() {
17+
local name=$1
18+
local url=$2
19+
local method=$3
20+
local data=$4
21+
22+
echo -e "${YELLOW}⏳ [$method]${NC} $name - ${BLUE}PENDING${NC}"
23+
24+
if [ "$method" == "POST" ]; then
25+
response=$(curl -s -w "\n%{http_code}" "$url" --data-raw "$data" 2>&1)
26+
else
27+
response=$(curl -s -w "\n%{http_code}" "$url" 2>&1)
28+
fi
29+
30+
http_code=$(echo "$response" | tail -n1)
31+
body=$(echo "$response" | head -n-1)
32+
33+
if [ "$http_code" == "200" ] || [ "$http_code" == "201" ]; then
34+
echo -e "${GREEN}✓ [$method]${NC} $name - ${GREEN}COMPLETED${NC} (HTTP $http_code)"
35+
else
36+
echo -e "${RED}✗ [$method]${NC} $name - ${RED}FAILED${NC} (HTTP $http_code)"
37+
fi
38+
39+
# Optionally print response body (truncated)
40+
# echo "$body" | head -c 200
41+
}
42+
43+
# Launch POST request in background
44+
run_request "Create Workload" \
45+
"http://localhost:50018/api/v1beta/workloads" \
46+
"POST" \
47+
'{"name":"everything-2","image":"docker.io/mcp/everything:latest","transport":"stdio","env_vars":{},"secrets":[],"cmd_arguments":[],"network_isolation":false,"volumes":[],"group":"default"}' &
48+
pid1=$!
49+
50+
# Launch GET requests in background
51+
run_request "Health Check" \
52+
"http://localhost:50018/health" \
53+
"GET" \
54+
"" &
55+
pid2=$!
56+
57+
run_request "List Workloads" \
58+
"http://localhost:50018/api/v1beta/workloads?all=true&group=default" \
59+
"GET" \
60+
"" &
61+
pid3=$!
62+
63+
# Wait for all background jobs to complete
64+
wait $pid1 $pid2 $pid3
65+
66+
echo ""
67+
echo "================================"
68+
echo " All Requests Completed"
69+
echo "================================"
70+

0 commit comments

Comments
 (0)