hypertwist/website/scripts/render-same-origin-bundle-lib.test.mjs
2026-06-22 07:53:11 +00:00

185 lines
7.3 KiB
JavaScript

import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { describe, expect, it } from 'vitest'
import {
buildBundleValidationReport,
buildFrontendEnvEntries,
buildServerEnvEntries,
renderSameOriginBundle,
writeSameOriginBundle,
} from './render-same-origin-bundle-lib.mjs'
function createValidManifest() {
return {
deploymentTier: 'launch',
checkoutRoot: '/srv/hypertwist/current',
publicOrigin: 'https://hypertwist.app',
supportEmail: 'hello@hypertwist.app',
publicDocsUrl: 'https://docs.hypertwist.app',
releaseNotesUrl: 'https://notes.hypertwist.app',
correspondingSourceUrl: 'https://hypertwist.app/open-source/source.zip',
openSourceRepoUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
operatorCheckoutUrl: 'https://buy.paddle.com/operator',
studioCheckoutUrl: 'https://buy.paddle.com/studio',
windowsDownloadUrl: 'https://downloads.hypertwist.app/windows.exe',
releaseManifestVersion: '1.0.0',
releaseManifestChannel: 'candidate',
windowsRelease: {
buildId: 'win64-1000',
sha256: 'abc123',
fileSizeBytes: 123456789,
publishedAt: '2026-06-22T00:00:00.000Z',
},
server: {
paddleWebhookSecret: 'secret',
paddleProductPlanMap: {
prod_operator: 'operator',
},
paddlePricePlanMap: {
pri_operator: 'operator',
},
},
}
}
function createPreviewManifest() {
return {
deploymentTier: 'preview',
checkoutRoot: '/srv/hypertwist/current',
publicOrigin: 'https://hypertwist.app',
supportEmail: 'hello@hypertwist.app',
publicDocsUrl: 'https://hypertwist.app/docs',
releaseNotesUrl: 'https://hypertwist.app/changelog',
correspondingSourceUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
openSourceRepoUrl: 'https://git.scriptoriumai.io/scriptoriumadmin/hypertwist',
operatorCheckoutUrl: '',
studioCheckoutUrl: '',
windowsDownloadUrl: '',
releaseManifestVersion: '',
releaseManifestChannel: 'preview',
windowsRelease: {
buildId: '',
sha256: '',
fileSizeBytes: '',
publishedAt: '',
},
server: {
paddleWebhookSecret: '',
paddleProductPlanMap: {},
paddlePricePlanMap: {},
},
}
}
describe('buildFrontendEnvEntries', () => {
it('derives consistent frontend env from the bundle manifest', () => {
const env = buildFrontendEnvEntries(createValidManifest())
expect(env.VITE_AUTH_API_BASE_URL).toBe('https://hypertwist.app')
expect(env.VITE_WINDOWS_DOWNLOAD_URL).toBe('https://downloads.hypertwist.app/windows.exe')
expect(env.VITE_PADDLE_CHECKOUT_URL_OPERATOR).toBe('https://buy.paddle.com/operator')
})
it('uses the manifest public origin when deriving auth env', () => {
const env = buildFrontendEnvEntries({
...createValidManifest(),
publicOrigin: 'https://preview.hypertwist.app',
})
expect(env.VITE_SUPERTOKENS_API_DOMAIN).toBe('https://preview.hypertwist.app')
expect(env.VITE_SUPERTOKENS_WEBSITE_DOMAIN).toBe('https://preview.hypertwist.app')
expect(env.VITE_AUTH_API_BASE_URL).toBe('https://preview.hypertwist.app')
})
})
describe('buildServerEnvEntries', () => {
it('derives consistent server env from the bundle manifest', () => {
const env = buildServerEnvEntries(createValidManifest())
expect(env.PORT).toBe('3011')
expect(env.API_DOMAIN).toBe('https://hypertwist.app')
expect(env.WINDOWS_RELEASE_BUILD_ID).toBe('win64-1000')
expect(env.PADDLE_PRODUCT_PLAN_MAP).toContain('prod_operator')
})
it('derives the public origin from server names when no explicit publicOrigin is set', () => {
const env = buildServerEnvEntries({
...createValidManifest(),
publicOrigin: '',
serverNames: ['preview.hypertwist.app', 'hypertwist.app'],
})
expect(env.API_DOMAIN).toBe('https://preview.hypertwist.app')
expect(env.WEBSITE_DOMAIN).toBe('https://preview.hypertwist.app')
})
})
describe('buildBundleValidationReport', () => {
it('fails when placeholder values are still present in the manifest', () => {
const report = buildBundleValidationReport({
...createValidManifest(),
operatorCheckoutUrl: 'https://buy.paddle.com/replace-me-operator',
})
expect(report.ok).toBe(false)
expect(report.failures).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR still contains a placeholder value.')
})
it('accepts preview-tier bundle manifests with honest missing launch values', () => {
const report = buildBundleValidationReport(createPreviewManifest())
expect(report.ok).toBe(true)
expect(report.failures).toEqual([])
expect(report.warnings).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR is not set; Operator pricing will stay on the support fallback until checkout is configured.')
expect(report.warnings).toContain('VITE_WINDOWS_DOWNLOAD_URL or WINDOWS_DOWNLOAD_URL is not set; Windows download will remain in preview posture until the release lane is configured.')
})
})
describe('renderSameOriginBundle', () => {
it('renders a runtime-ready bundle when required values are present', () => {
const rendered = renderSameOriginBundle(createValidManifest())
expect(rendered.validationReport.ok).toBe(true)
expect(rendered.frontendEnvContent).toContain('VITE_PUBLIC_DEPLOYMENT_TIER=launch')
expect(rendered.serverEnvContent).toContain('PORT=3011')
expect(rendered.frontendEnvContent).toContain('VITE_WINDOWS_DOWNLOAD_URL=https://downloads.hypertwist.app/windows.exe')
expect(rendered.serverEnvContent).toContain('RELEASE_MANIFEST_VERSION=1.0.0')
expect(rendered.systemdContent).toContain('WorkingDirectory=/srv/hypertwist/current/website/server')
expect(rendered.nginxContent).toContain('server_name hypertwist.app www.hypertwist.app;')
expect(rendered.nginxContent).toContain('server 127.0.0.1:3011;')
})
it('renders a preview-tier bundle without checkout, download, or webhook values', () => {
const rendered = renderSameOriginBundle(createPreviewManifest())
expect(rendered.validationReport.ok).toBe(true)
expect(rendered.frontendEnvContent).toContain('VITE_PUBLIC_DEPLOYMENT_TIER=preview')
expect(rendered.frontendEnvContent).toContain('VITE_PADDLE_CHECKOUT_URL_OPERATOR=')
expect(rendered.serverEnvContent).toContain('DEPLOYMENT_TIER=preview')
expect(rendered.serverEnvContent).toContain('PADDLE_WEBHOOK_SECRET=')
})
})
describe('writeSameOriginBundle', () => {
it('writes all bundle outputs to the chosen directory', () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'hypertwist-bundle-render-'))
try {
const written = writeSameOriginBundle({
manifest: createValidManifest(),
outDir: tempDir,
})
expect(fs.readFileSync(written.frontendEnvPath, 'utf8')).toContain('VITE_SUPPORT_EMAIL=hello@hypertwist.app')
expect(fs.readFileSync(written.serverEnvPath, 'utf8')).toContain('PADDLE_WEBHOOK_SECRET=secret')
expect(fs.readFileSync(written.systemdPath, 'utf8')).toContain('EnvironmentFile=/srv/hypertwist/current/website/server/.env')
expect(fs.readFileSync(written.nginxPath, 'utf8')).toContain('proxy_pass http://hypertwist_website_auth_server;')
expect(JSON.parse(fs.readFileSync(written.summaryPath, 'utf8')).validationReport.ok).toBe(true)
} finally {
fs.rmSync(tempDir, { recursive: true, force: true })
}
})
})