Skip to content

Commit ee9ae35

Browse files
committed
fix(test-utils): Use spotlight from repo root and fix port detection
- Find monorepo root by looking for package.json with workspaces - Use spotlight binary from root's node_modules/.bin/ - Fix regex to match 'Spotlight listening on PORT' format - Resolve immediately when listening message detected Tested locally - startSpotlight correctly detects port and starts.
1 parent fa8debc commit ee9ae35

File tree

1 file changed

+51
-11
lines changed

1 file changed

+51
-11
lines changed

dev-packages/test-utils/src/spotlight.ts

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,37 @@ import type { Envelope, EnvelopeItem, Event, SerializedSession } from '@sentry/c
22
import { parseEnvelope } from '@sentry/core';
33
import type { ChildProcess } from 'child_process';
44
import { spawn } from 'child_process';
5+
import * as fs from 'fs';
6+
import * as path from 'path';
57
import * as readline from 'readline';
68

9+
/**
10+
* Find the monorepo root by looking for a package.json with workspaces.
11+
* This works regardless of whether we're running from source or built output.
12+
*/
13+
function findRepoRoot(startDir: string): string {
14+
let dir = startDir;
15+
while (dir !== path.dirname(dir)) {
16+
const pkgPath = path.join(dir, 'package.json');
17+
if (fs.existsSync(pkgPath)) {
18+
try {
19+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
20+
if (pkg.workspaces) {
21+
return dir;
22+
}
23+
} catch {
24+
// Continue searching
25+
}
26+
}
27+
dir = path.dirname(dir);
28+
}
29+
throw new Error('Could not find monorepo root');
30+
}
31+
32+
// Find spotlight binary in repo root's node_modules
33+
const REPO_ROOT = findRepoRoot(__dirname);
34+
const SPOTLIGHT_BIN = path.join(REPO_ROOT, 'node_modules', '.bin', 'spotlight');
35+
736
interface SpotlightOptions {
837
/** Port for the Spotlight sidecar. Use 0 for dynamic port assignment. */
938
port?: number;
@@ -48,9 +77,8 @@ export async function startSpotlight(options: SpotlightOptions = {}): Promise<Sp
4877
const { port = 0, cwd = process.cwd(), debug = false } = options;
4978

5079
return new Promise((resolve, reject) => {
51-
// Use npx to run Spotlight - works regardless of package manager
52-
// and will use the installed version or download if needed
53-
const args = ['--yes', '@spotlightjs/spotlight', 'run', '-f', 'json'];
80+
// Run Spotlight directly from repo root's node_modules
81+
const args = ['run', '-f', 'json'];
5482

5583
if (port !== 0) {
5684
args.push('-p', String(port));
@@ -60,7 +88,7 @@ export async function startSpotlight(options: SpotlightOptions = {}): Promise<Sp
6088
args.push('-d');
6189
}
6290

63-
const spotlightProcess = spawn('npx', args, {
91+
const spotlightProcess = spawn(SPOTLIGHT_BIN, args, {
6492
cwd,
6593
stdio: ['ignore', 'pipe', 'pipe'],
6694
});
@@ -81,21 +109,33 @@ export async function startSpotlight(options: SpotlightOptions = {}): Promise<Sp
81109
console.log('[spotlight stderr]', line);
82110
}
83111

84-
// Look for port in various formats
85-
const portMatch = line.match(/localhost:(\d+)/i) || line.match(/port[:\s]+(\d+)/i);
112+
// Look for port in various formats:
113+
// - "Spotlight listening on 39143"
114+
// - "http://localhost:8969"
115+
// - "port: 8969"
116+
const portMatch =
117+
line.match(/listening on (\d+)/i) ||
118+
line.match(/localhost:(\d+)/i) ||
119+
line.match(/port[:\s]+(\d+)/i);
120+
86121
if (portMatch?.[1] && !resolvedPort) {
87122
resolvedPort = parseInt(portMatch[1], 10);
88-
}
89-
90-
// Also check for "Sidecar running" or similar ready messages
91-
if ((line.includes('listening') || line.includes('running') || line.includes('started')) && resolvedPort) {
92-
if (!resolved) {
123+
// Resolve immediately when we have the port from a "listening" message
124+
if (!resolved && line.includes('listening')) {
93125
resolved = true;
94126
const instance = createSpotlightInstance(spotlightProcess, resolvedPort, debug);
95127
currentSpotlightInstance = instance;
96128
resolve(instance);
97129
}
98130
}
131+
132+
// Fallback: check for other ready messages if we have a port
133+
if (!resolved && resolvedPort && (line.includes('running') || line.includes('started'))) {
134+
resolved = true;
135+
const instance = createSpotlightInstance(spotlightProcess, resolvedPort, debug);
136+
currentSpotlightInstance = instance;
137+
resolve(instance);
138+
}
99139
});
100140

101141
// Parse stdout for JSON events

0 commit comments

Comments
 (0)