Skip to content

Commit d781acf

Browse files
committed
add windows
1 parent ec8e839 commit d781acf

File tree

3 files changed

+79
-80
lines changed

3 files changed

+79
-80
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ on:
1010

1111
jobs:
1212
test:
13-
runs-on: ubuntu-latest
13+
runs-on: ${{ matrix.os }}
14+
strategy:
15+
matrix:
16+
os: [ubuntu-latest, windows-latest]
1417
steps:
1518
- name: Checkout code
1619
uses: actions/checkout@v4

src/_internal/nextjs-runtime-manager.ts

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ async function findNextJsServers(): Promise<NextJsServerInfo[]> {
3434
for (const proc of nodeProcesses) {
3535
const command = proc.cmd || ""
3636

37-
// Enhanced detection patterns for Next.js servers
3837
const isNextJsProcess =
3938
command.includes("next dev") ||
4039
command.includes("next-server") ||
@@ -45,32 +44,18 @@ async function findNextJsServers(): Promise<NextJsServerInfo[]> {
4544
const portMatch =
4645
command.match(/--port[=\s]+(\d+)/) ||
4746
command.match(/-p[=\s]+(\d+)/) ||
47+
command.match(/--port\s+["'](\d+)["']/) ||
48+
command.match(/["']--port["']\s+["']?(\d+)["']?/) ||
49+
command.match(/["'](\d+)["']\s*$/) ||
4850
command.match(/:(\d+)/)
4951

50-
let port = 3000
51-
5252
if (portMatch) {
53-
port = parseInt(portMatch[1], 10)
54-
} else {
55-
const commonPorts = [3000, 3001, 3002, 3003]
56-
for (const testPort of commonPorts) {
57-
try {
58-
const portProcs = await find("port", testPort)
59-
const matchingProc = portProcs.find((p) => p.pid === proc.pid)
60-
if (matchingProc) {
61-
port = testPort
62-
break
63-
}
64-
} catch {
65-
// Port not in use or error checking, continue
66-
}
53+
const port = parseInt(portMatch[1], 10)
54+
if (!seenPorts.has(port)) {
55+
seenPorts.add(port)
56+
servers.push({ port, pid: proc.pid, command })
6757
}
6858
}
69-
70-
if (!seenPorts.has(port)) {
71-
seenPorts.add(port)
72-
servers.push({ port, pid: proc.pid, command })
73-
}
7459
}
7560
}
7661

test/unit/nextjs-runtime-discovery.test.ts

Lines changed: 68 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,116 @@
1-
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
2-
import { spawn, ChildProcess } from 'child_process'
3-
import { join } from 'path'
4-
import { mkdirSync, cpSync, rmSync, existsSync } from 'fs'
5-
import { tmpdir } from 'os'
6-
import { discoverNextJsServer, getAllAvailableServers } from '../../src/_internal/nextjs-runtime-manager'
7-
8-
const FIXTURE_SOURCE = join(__dirname, '../fixtures/nextjs16-minimal')
1+
import { describe, it, expect, beforeAll, afterAll } from "vitest"
2+
import { spawn, ChildProcess } from "child_process"
3+
import { join } from "path"
4+
import { mkdirSync, cpSync, rmSync, existsSync } from "fs"
5+
import { tmpdir } from "os"
6+
import {
7+
discoverNextJsServer,
8+
getAllAvailableServers,
9+
} from "../../src/_internal/nextjs-runtime-manager"
10+
11+
const FIXTURE_SOURCE = join(__dirname, "../fixtures/nextjs16-minimal")
912
const TEST_PORT = 3456
1013
const SERVER_STARTUP_TIMEOUT = 180000
1114
const TEST_TIMEOUT = 240000
1215

13-
describe('nextjs-runtime-discovery', () => {
16+
describe("nextjs-runtime-discovery", () => {
1417
let nextProcess: ChildProcess | null = null
1518
let serverReady = false
1619
let tempDir: string
1720

1821
beforeAll(async () => {
1922
tempDir = join(tmpdir(), `nextjs-test-${Date.now()}`)
20-
console.log('[Test] Creating temp directory:', tempDir)
23+
console.log("[Test] Creating temp directory:", tempDir)
2124
mkdirSync(tempDir, { recursive: true })
2225

23-
console.log('[Test] Copying fixture to temp directory...')
26+
console.log("[Test] Copying fixture to temp directory...")
2427
cpSync(FIXTURE_SOURCE, tempDir, { recursive: true })
2528

26-
console.log('[Test] Installing dependencies in temp directory...')
29+
console.log("[Test] Installing dependencies in temp directory...")
2730
await new Promise<void>((resolve, reject) => {
28-
const installProcess = spawn('pnpm', ['install', '--no-frozen-lockfile'], {
31+
const installProcess = spawn("pnpm", ["install", "--no-frozen-lockfile"], {
2932
cwd: tempDir,
30-
stdio: ['ignore', 'pipe', 'pipe'],
33+
stdio: ["ignore", "pipe", "pipe"],
34+
shell: true,
3135
})
3236

33-
let installOutput = ''
37+
let installOutput = ""
3438

3539
if (installProcess.stdout) {
36-
installProcess.stdout.on('data', (data: Buffer) => {
40+
installProcess.stdout.on("data", (data: Buffer) => {
3741
installOutput += data.toString()
38-
console.log('[Install]', data.toString().trim())
42+
console.log("[Install]", data.toString().trim())
3943
})
4044
}
4145

4246
if (installProcess.stderr) {
43-
installProcess.stderr.on('data', (data: Buffer) => {
47+
installProcess.stderr.on("data", (data: Buffer) => {
4448
installOutput += data.toString()
45-
console.log('[Install stderr]', data.toString().trim())
49+
console.log("[Install stderr]", data.toString().trim())
4650
})
4751
}
4852

49-
installProcess.on('exit', (code: number | null) => {
53+
installProcess.on("exit", (code: number | null) => {
5054
if (code === 0) {
51-
console.log('[Test] Dependencies installed successfully')
55+
console.log("[Test] Dependencies installed successfully")
5256
resolve()
5357
} else {
5458
reject(new Error(`pnpm install failed with code ${code}\n${installOutput}`))
5559
}
5660
})
5761

58-
installProcess.on('error', (error: Error) => {
62+
installProcess.on("error", (error: Error) => {
5963
reject(new Error(`Failed to run pnpm install: ${error.message}`))
6064
})
6165
})
6266

63-
console.log('[Test] Starting Next.js dev server...')
64-
console.log('[Test] Temp directory:', tempDir)
67+
console.log("[Test] Starting Next.js dev server...")
68+
console.log("[Test] Temp directory:", tempDir)
6569

6670
await new Promise<void>((resolve, reject) => {
6771
const timeoutId = setTimeout(() => {
6872
reject(new Error(`Server failed to start within ${SERVER_STARTUP_TIMEOUT}ms`))
6973
}, SERVER_STARTUP_TIMEOUT)
7074

71-
nextProcess = spawn('pnpm', ['dev', '--port', String(TEST_PORT)], {
75+
nextProcess = spawn("pnpm", ["dev", "--port", String(TEST_PORT)], {
7276
cwd: tempDir,
73-
env: { ...process.env, NODE_ENV: 'development' },
74-
stdio: ['ignore', 'pipe', 'pipe'],
77+
env: { ...process.env, NODE_ENV: "development" },
78+
stdio: ["ignore", "pipe", "pipe"],
79+
shell: true,
7580
})
7681

77-
let stdoutData = ''
78-
let stderrData = ''
82+
let stdoutData = ""
83+
let stderrData = ""
7984

8085
if (nextProcess.stdout) {
81-
nextProcess.stdout.on('data', (data: Buffer) => {
86+
nextProcess.stdout.on("data", (data: Buffer) => {
8287
const output = data.toString()
8388
stdoutData += output
84-
console.log('[Next.js stdout]', output.trim())
89+
console.log("[Next.js stdout]", output.trim())
8590

86-
if (output.includes('Local:') || output.includes('localhost:')) {
91+
if (output.includes("Local:") || output.includes("localhost:")) {
8792
clearTimeout(timeoutId)
8893
serverReady = true
89-
console.log('[Test] Server is ready!')
94+
console.log("[Test] Server is ready!")
9095
setTimeout(resolve, 2000)
9196
}
9297
})
9398
}
9499

95100
if (nextProcess.stderr) {
96-
nextProcess.stderr.on('data', (data: Buffer) => {
101+
nextProcess.stderr.on("data", (data: Buffer) => {
97102
const output = data.toString()
98103
stderrData += output
99-
console.log('[Next.js stderr]', output.trim())
104+
console.log("[Next.js stderr]", output.trim())
100105
})
101106
}
102107

103-
nextProcess.on('error', (error: Error) => {
108+
nextProcess.on("error", (error: Error) => {
104109
clearTimeout(timeoutId)
105110
reject(new Error(`Failed to start Next.js server: ${error.message}`))
106111
})
107112

108-
nextProcess.on('exit', (code: number | null) => {
113+
nextProcess.on("exit", (code: number | null) => {
109114
if (!serverReady) {
110115
clearTimeout(timeoutId)
111116
reject(
@@ -120,8 +125,8 @@ describe('nextjs-runtime-discovery', () => {
120125

121126
afterAll(async () => {
122127
if (nextProcess) {
123-
console.log('[Test] Stopping Next.js dev server...')
124-
nextProcess.kill('SIGTERM')
128+
console.log("[Test] Stopping Next.js dev server...")
129+
nextProcess.kill("SIGTERM")
125130

126131
await new Promise<void>((resolve) => {
127132
if (!nextProcess) {
@@ -131,38 +136,41 @@ describe('nextjs-runtime-discovery', () => {
131136

132137
const killTimeout = setTimeout(() => {
133138
if (nextProcess && !nextProcess.killed) {
134-
console.log('[Test] Force killing Next.js server...')
135-
nextProcess.kill('SIGKILL')
139+
console.log("[Test] Force killing Next.js server...")
140+
nextProcess.kill("SIGKILL")
136141
}
137142
resolve()
138143
}, 5000)
139144

140-
nextProcess.on('exit', () => {
145+
nextProcess.on("exit", () => {
141146
clearTimeout(killTimeout)
142-
console.log('[Test] Next.js server stopped')
147+
console.log("[Test] Next.js server stopped")
143148
resolve()
144149
})
145150
})
146151
}
147152

148153
if (tempDir && existsSync(tempDir)) {
149-
console.log('[Test] Cleaning up temp directory:', tempDir)
154+
console.log("[Test] Cleaning up temp directory:", tempDir)
150155
try {
151156
rmSync(tempDir, { recursive: true, force: true })
152-
console.log('[Test] Temp directory cleaned up')
157+
console.log("[Test] Temp directory cleaned up")
153158
} catch (error) {
154-
console.error('[Test] Failed to clean up temp directory:', error)
159+
console.error("[Test] Failed to clean up temp directory:", error)
155160
}
156161
}
157162
})
158163

159164
it(
160-
'should discover the running Next.js 16 dev server when only one is running',
165+
"should discover the running Next.js 16 dev server when only one is running",
161166
async () => {
162-
console.log('[Test] Attempting to discover Next.js server...')
167+
console.log("[Test] Attempting to discover Next.js server...")
163168

164169
const allServers = await getAllAvailableServers(false)
165-
console.log('[Test] All discovered servers:', allServers.map(s => ({ port: s.port, pid: s.pid })))
170+
console.log(
171+
"[Test] All discovered servers:",
172+
allServers.map((s) => ({ port: s.port, pid: s.pid }))
173+
)
166174

167175
const server = await discoverNextJsServer()
168176

@@ -171,36 +179,39 @@ describe('nextjs-runtime-discovery', () => {
171179
expect(server?.port).toBe(TEST_PORT)
172180
expect(server?.pid).toBeGreaterThan(0)
173181
expect(server?.command).toBeTruthy()
174-
expect(server?.command).toContain('next')
182+
expect(server?.command).toContain("next")
175183

176-
console.log('[Test] Successfully discovered server:', {
184+
console.log("[Test] Successfully discovered server:", {
177185
port: server?.port,
178186
pid: server?.pid,
179187
command: server?.command?.substring(0, 100),
180188
})
181189
} else {
182-
console.log('[Test] Multiple servers detected, this is expected to return null')
190+
console.log("[Test] Multiple servers detected, this is expected to return null")
183191
expect(server).toBeNull()
184192
}
185193
},
186194
TEST_TIMEOUT
187195
)
188196

189197
it(
190-
'should return null when multiple servers are running',
198+
"should return null when multiple servers are running",
191199
async () => {
192-
console.log('[Test] Testing behavior with multiple servers...')
200+
console.log("[Test] Testing behavior with multiple servers...")
193201

194202
const allServers = await getAllAvailableServers(false)
195-
console.log('[Test] All discovered servers:', allServers.map(s => ({ port: s.port, pid: s.pid })))
203+
console.log(
204+
"[Test] All discovered servers:",
205+
allServers.map((s) => ({ port: s.port, pid: s.pid }))
206+
)
196207

197208
const server = await discoverNextJsServer()
198209

199210
if (allServers.length > 1) {
200211
expect(server).toBeNull()
201-
console.log('[Test] Correctly returned null for multiple servers')
212+
console.log("[Test] Correctly returned null for multiple servers")
202213
} else {
203-
console.log('[Test] Only one server running, skipping this test case')
214+
console.log("[Test] Only one server running, skipping this test case")
204215
expect(allServers.length).toBeLessThanOrEqual(1)
205216
}
206217
},

0 commit comments

Comments
 (0)