hypertwist/website/scripts/runtime-readiness-cli.test.mjs
2026-06-22 06:46:02 +00:00

162 lines
5.5 KiB
JavaScript

import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { spawn, spawnSync } from 'node:child_process'
import http from 'node:http'
import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest'
const currentFile = fileURLToPath(import.meta.url)
const websiteRoot = path.resolve(path.dirname(currentFile), '..')
const frontendProductionEnv = path.join(websiteRoot, '.env.production.example')
const serverProductionEnv = path.join(websiteRoot, 'server', '.env.production.example')
const runtimeReadinessScript = path.join(websiteRoot, 'scripts', 'check-runtime-readiness.mjs')
function runCli(args, options = {}) {
return new Promise((resolve, reject) => {
const child = spawn(process.execPath, args, {
cwd: websiteRoot,
stdio: ['ignore', 'pipe', 'pipe'],
...options,
})
let stdout = ''
let stderr = ''
child.stdout.on('data', (chunk) => {
stdout += chunk
})
child.stderr.on('data', (chunk) => {
stderr += chunk
})
child.on('error', reject)
child.on('close', (status) => {
resolve({
status,
stdout,
stderr,
})
})
})
}
describe('check-runtime-readiness CLI', () => {
it('fails the real production example env files until placeholder launch values are replaced', () => {
const result = spawnSync(
process.execPath,
[
runtimeReadinessScript,
'--frontend-env',
frontendProductionEnv,
'--server-env',
serverProductionEnv,
'--skip-live-health',
'--json',
],
{
cwd: websiteRoot,
encoding: 'utf8',
},
)
expect(result.status).toBe(1)
expect(result.stderr).toBe('')
const report = JSON.parse(result.stdout)
expect(report.ok).toBe(false)
expect(report.failures).toContain('VITE_WINDOWS_DOWNLOAD_URL still contains a placeholder value.')
expect(report.failures).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR still contains a placeholder value.')
expect(report.failures).toContain('VITE_MPL_SOURCE_URL still contains a placeholder value.')
expect(report.failures).toContain('PADDLE_WEBHOOK_SECRET still contains a placeholder value.')
expect(report.failures).toContain('PADDLE_PRODUCT_PLAN_MAP still contains a placeholder value.')
expect(report.failures).toContain('PADDLE_PRICE_PLAN_MAP still contains a placeholder value.')
})
it('fails a live deployment probe when the public origin still serves the placeholder page instead of JSON routes', async () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hypertwist-runtime-readiness-'))
const frontendEnv = path.join(tempDir, 'frontend.env')
const serverEnv = path.join(tempDir, 'server.env')
fs.writeFileSync(frontendEnv, `
VITE_SUPERTOKENS_API_DOMAIN=https://hypertwist.app
VITE_SUPERTOKENS_WEBSITE_DOMAIN=https://hypertwist.app
VITE_AUTH_API_BASE_URL=https://hypertwist.app
VITE_WINDOWS_DOWNLOAD_URL=https://downloads.hypertwist.app/windows.exe
VITE_PADDLE_CHECKOUT_URL_OPERATOR=https://buy.paddle.com/operator
VITE_PADDLE_CHECKOUT_URL_STUDIO=https://buy.paddle.com/studio
VITE_MPL_SOURCE_URL=https://hypertwist.app/open-source/source
VITE_OPEN_SOURCE_REPO_URL=https://git.scriptoriumai.io/scriptoriumadmin/hypertwist
`)
fs.writeFileSync(serverEnv, `
API_DOMAIN=https://hypertwist.app
WEBSITE_DOMAIN=https://hypertwist.app
SUPERTOKENS_CORE_URI=https://auth-core.internal
COOKIE_SECURE=true
SERVE_STATIC_WEBSITE=true
PADDLE_WEBHOOK_SECRET=secret
PADDLE_PRICE_PLAN_MAP={"pri_operator":"operator"}
`)
const placeholderHtml = `<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>HyperTwist</title>
</head>
<body>
<main>
<h1>HyperTwist</h1>
<p>Deployment target is live on the new VPS. Application rollout is pending.</p>
</main>
</body>
</html>`
const server = http.createServer((req, res) => {
res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' })
res.end(placeholderHtml)
})
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve))
const address = server.address()
if (!address || typeof address === 'string') {
throw new Error('Expected an IPv4 test listener address.')
}
const healthUrl = `http://127.0.0.1:${address.port}`
try {
const result = await runCli(
[
runtimeReadinessScript,
'--frontend-env',
frontendEnv,
'--server-env',
serverEnv,
'--health-url',
healthUrl,
'--json',
],
)
expect(result.status).toBe(1)
expect(result.stderr).toBe('')
const report = JSON.parse(result.stdout)
expect(report.ok).toBe(false)
expect(report.failures.some((item) => item.includes('Live auth health check failed: Live auth health endpoint returned HTML instead of JSON.'))).toBe(true)
expect(report.failures.some((item) => item.includes('placeholder rollout page'))).toBe(true)
expect(report.failures.some((item) => item.includes('Live release manifest check failed: Live release manifest endpoint returned HTML instead of JSON.'))).toBe(true)
expect(report.failures.some((item) => item.includes('Live website root still serves the placeholder rollout page'))).toBe(true)
} finally {
await new Promise((resolve, reject) => {
server.close((error) => {
if (error) {
reject(error)
return
}
resolve()
})
})
fs.rmSync(tempDir, { recursive: true, force: true })
}
})
})