From f61af0beb134b872e64ec891b450e497aaaf703d Mon Sep 17 00:00:00 2001 From: Sarthak Agrawal Date: Mon, 5 Oct 2026 06:03:27 +0530 Subject: [PATCH] fix(rolepatch): run production smoke from spaced paths --- __tests__/production-smoke.test.ts | 113 +++++++++++++++++++++++++++++ scripts/production-smoke.mjs | 4 +- 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/__tests__/production-smoke.test.ts b/__tests__/production-smoke.test.ts index 0a6c131..0004e4a 100644 --- a/__tests__/production-smoke.test.ts +++ b/__tests__/production-smoke.test.ts @@ -1,3 +1,9 @@ +import { spawn } from 'node:child_process'; +import { copyFile, mkdtemp, rm } from 'node:fs/promises'; +import { createServer } from 'node:http'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + import { describe, expect, it, vi } from 'vitest'; import { @@ -122,4 +128,111 @@ describe('production smoke harness', () => { errors: ['connection refused'], }); }); + + it('runs the CLI from a path containing spaces and exits nonzero when a public check fails', async () => { + const requestedPaths: string[] = []; + const server = createServer((request, response) => { + const path = new URL(request.url ?? '/', 'http://127.0.0.1').pathname; + requestedPaths.push(path); + + if (path === '/api/proof/truehire-preview') { + response.writeHead(400, { 'content-type': 'application/json' }); + response.end(JSON.stringify({ ok: false, error: 'Invalid preview URL.' })); + return; + } + + if (path === '/jobs') { + response.writeHead(503, { 'content-type': 'text/html' }); + response.end('

Temporarily unavailable

'); + return; + } + + response.writeHead(200, { 'content-type': 'text/html' }); + response.end( + { + '/': '

RolePatch

', + '/pricing': '

Tokens

', + '/proof': '

TrueHire proof project

Candidate proof profile

', + '/settings': '

Operational readiness

Chrome extension

', + }[path] ?? '

Unexpected route

' + ); + }); + + await new Promise((resolve, reject) => { + server.once('error', reject); + server.listen(0, '127.0.0.1', resolve); + }); + + const address = server.address(); + if (!address || typeof address === 'string') throw new Error('Expected an ephemeral TCP port'); + + const tempDirectory = await mkdtemp(join(process.cwd(), '.rolepatch smoke cli ')); + try { + const sourcePath = join( + dirname(fileURLToPath(import.meta.url)), + '../scripts/production-smoke.mjs' + ); + const spacedScriptPath = join(tempDirectory, 'production-smoke.mjs'); + await copyFile(sourcePath, spacedScriptPath); + + const { code, stdout, stderr } = await new Promise<{ + code: number | null; + stdout: string; + stderr: string; + }>((resolve, reject) => { + const child = spawn( + process.execPath, + [spacedScriptPath, '--base-url', `http://127.0.0.1:${address.port}`], + { + env: { PATH: process.env.PATH ?? '', NODE_ENV: 'test' }, + stdio: ['ignore', 'pipe', 'pipe'], + } + ); + let childStdout = ''; + let childStderr = ''; + child.stdout.setEncoding('utf8').on('data', (chunk: string) => { + childStdout += chunk; + }); + child.stderr.setEncoding('utf8').on('data', (chunk: string) => { + childStderr += chunk; + }); + child.once('error', reject); + child.once('close', (exitCode) => + resolve({ code: exitCode, stdout: childStdout, stderr: childStderr }) + ); + }); + + expect(spacedScriptPath).toContain(' '); + expect(stdout).toContain('RolePatch production smoke: 5/6 passed'); + expect(code).toBe(1); + expect(stderr).toBe(''); + expect( + stdout + .split(/\r?\n/) + .filter((line) => /^(PASS|FAIL) /.test(line)) + .map((line) => line.replace(/^(PASS|FAIL) /, '').replace(/ \d+ \d+ms.*$/, '')) + ).toEqual([ + 'landing', + 'jobs browser', + 'pricing', + 'proof project', + 'truehire proof preview guard', + 'settings readiness', + ]); + expect(stdout).toContain('FAIL jobs browser 503'); + expect(requestedPaths).toEqual([ + '/', + '/jobs', + '/pricing', + '/proof', + '/api/proof/truehire-preview', + '/settings', + ]); + } finally { + await new Promise((resolve, reject) => + server.close((error) => (error ? reject(error) : resolve())) + ); + await rm(tempDirectory, { recursive: true, force: true }); + } + }); }); diff --git a/scripts/production-smoke.mjs b/scripts/production-smoke.mjs index 71e519e..9d73aa0 100644 --- a/scripts/production-smoke.mjs +++ b/scripts/production-smoke.mjs @@ -1,5 +1,7 @@ #!/usr/bin/env node +import { pathToFileURL } from 'node:url'; + const DEFAULT_BASE_URL = 'https://rolepatch.com'; const DEFAULT_TIMEOUT_MS = 10_000; @@ -208,7 +210,7 @@ async function main() { if (summary.failed > 0) process.exitCode = 1; } -if (import.meta.url === `file://${process.argv[1]}`) { +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { main().catch((err) => { console.error(err instanceof Error ? err.message : String(err)); process.exitCode = 1;