mirror of
https://github.com/stablyai/orca.git
synced 2026-10-02 16:02:15 +00:00
* Reduce repeated PR setup and transcript timing waits; add hosted comparisons * Align parallelism contract with Node-only external rebuild toolchain * Record hosted coverage and launch package, store, and cancellation comparisons * Apply hosted Windows setup savings and remove measured test waits * Keep measured PR package gains and remove completed comparison jobs * Report measured test counts with precise units
208 lines
8.1 KiB
JavaScript
208 lines
8.1 KiB
JavaScript
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { dirname, join, resolve } from 'node:path'
|
|
import { runProcess } from '../../src/shared/child-process/run-process'
|
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
|
|
const scriptPath = resolve('config/scripts/project-renderer-web-client.mjs')
|
|
const temporaryRoots = []
|
|
|
|
function projectFixture(root) {
|
|
return runProcess({
|
|
program: process.execPath,
|
|
args: [scriptPath],
|
|
cwd: root,
|
|
env: { ...process.env, ORCA_BACKGROUND_LAUNCH: '1' },
|
|
timeoutMs: 30000
|
|
})
|
|
}
|
|
|
|
function writeFixtureFile(root, relativePath, contents) {
|
|
const targetPath = join(root, relativePath)
|
|
mkdirSync(dirname(targetPath), { recursive: true })
|
|
writeFileSync(targetPath, contents)
|
|
}
|
|
|
|
function createRendererFixture() {
|
|
const root = mkdtempSync(join(tmpdir(), 'orca-web-projection-'))
|
|
temporaryRoots.push(root)
|
|
const manifest = {
|
|
'web-index.html': {
|
|
file: 'assets/web-entry.js',
|
|
isEntry: true,
|
|
imports: ['_web-shared.js'],
|
|
dynamicImports: ['src/lazy.ts']
|
|
},
|
|
'_web-shared.js': {
|
|
file: 'assets/web-shared.js',
|
|
css: ['assets/web.css'],
|
|
assets: ['assets/logo.png']
|
|
},
|
|
'src/lazy.ts': { file: 'assets/lazy.js' },
|
|
'index.html': { file: 'assets/desktop-entry.js', isEntry: true }
|
|
}
|
|
|
|
writeFixtureFile(root, 'out/renderer/.vite/manifest.json', JSON.stringify(manifest))
|
|
writeFixtureFile(
|
|
root,
|
|
'out/renderer/web-index.html',
|
|
'<script type="module" src="./assets/web-entry.js"></script>'
|
|
)
|
|
writeFixtureFile(
|
|
root,
|
|
'out/renderer/assets/web-entry.js',
|
|
'import "./web-shared.js"; new Worker(new URL("editor.worker-fixture.js", import.meta.url));'
|
|
)
|
|
writeFixtureFile(root, 'out/renderer/assets/web-shared.js', 'export const value = 1;')
|
|
writeFixtureFile(root, 'out/renderer/assets/lazy.js', 'export const lazyValue = true;')
|
|
writeFixtureFile(root, 'out/renderer/assets/web.css', '.root { color: red; }')
|
|
writeFixtureFile(root, 'out/renderer/assets/logo.png', 'fixture-logo')
|
|
writeFixtureFile(
|
|
root,
|
|
'out/renderer/assets/editor.worker-fixture.js',
|
|
'self.onmessage = function (event) { self.postMessage(event.data) }'
|
|
)
|
|
writeFixtureFile(root, 'out/renderer/assets/desktop-entry.js', 'export const desktop = true;')
|
|
writeFixtureFile(root, 'out/web/stale.js', 'stale')
|
|
return root
|
|
}
|
|
|
|
afterEach(() => {
|
|
for (const root of temporaryRoots.splice(0)) {
|
|
rmSync(root, { force: true, recursive: true })
|
|
}
|
|
})
|
|
|
|
describe('renderer web client projection', () => {
|
|
it('keeps the build-only manifest out of packaged apps', () => {
|
|
const builderConfig = readFileSync(resolve('config/electron-builder.config.cjs'), 'utf8')
|
|
|
|
expect(builderConfig).toContain("'!out/renderer/.vite{,/**/*}'")
|
|
})
|
|
|
|
it('copies and minifies only the web dependency closure', async () => {
|
|
const root = createRendererFixture()
|
|
const result = await projectFixture(root)
|
|
|
|
expect(result.code, result.stderr).toBe(0)
|
|
expect(result.stdout).toContain('Projected web client: 7 files')
|
|
expect(existsSync(join(root, 'out/web/web-index.html'))).toBe(true)
|
|
expect(existsSync(join(root, 'out/web/assets/editor.worker-fixture.js'))).toBe(true)
|
|
expect(existsSync(join(root, 'out/web/assets/logo.png'))).toBe(true)
|
|
expect(existsSync(join(root, 'out/web/assets/desktop-entry.js'))).toBe(false)
|
|
expect(existsSync(join(root, 'out/web/stale.js'))).toBe(false)
|
|
expect(readFileSync(join(root, 'out/web/assets/web.css'), 'utf8')).toBe('.root{color:red}\n')
|
|
})
|
|
|
|
it('follows transitive relative references and cycles with the existing substring behavior', async () => {
|
|
const root = createRendererFixture()
|
|
writeFixtureFile(
|
|
root,
|
|
'out/renderer/assets/editor.worker-fixture.js',
|
|
'const referenced = "../workers/one.mjs"; const overlapping = "assets/token.png.backup";'
|
|
)
|
|
writeFixtureFile(root, 'out/renderer/workers/one.mjs', 'const icon = "../icons/link.svg";')
|
|
writeFixtureFile(root, 'out/renderer/icons/link.svg', '<image href="../workers/one.mjs"/>')
|
|
writeFixtureFile(root, 'out/renderer/assets/token.png', 'substring-token')
|
|
writeFixtureFile(root, 'out/renderer/assets/token.png.backup', 'longer-token')
|
|
writeFixtureFile(root, 'out/renderer/workers/unreferenced.mjs', 'export const absent = true;')
|
|
|
|
const result = await projectFixture(root)
|
|
|
|
expect(result.code, result.stderr).toBe(0)
|
|
for (const file of [
|
|
'workers/one.mjs',
|
|
'icons/link.svg',
|
|
'assets/token.png',
|
|
'assets/token.png.backup'
|
|
]) {
|
|
expect(existsSync(join(root, 'out/web', file)), file).toBe(true)
|
|
}
|
|
expect(readFileSync(join(root, 'out/web/assets/token.png'), 'utf8')).toBe('substring-token')
|
|
expect(existsSync(join(root, 'out/web/workers/unreferenced.mjs'))).toBe(false)
|
|
})
|
|
|
|
it('retains all PDFJS viewer asset directories even without textual references', async () => {
|
|
const root = createRendererFixture()
|
|
const assets = ['cmaps/fixture.bcmap', 'standard_fonts/fixture.pfb', 'wasm/fixture.wasm']
|
|
for (const file of assets) {
|
|
writeFixtureFile(root, `out/renderer/${file}`, Buffer.from([0, 255, 42]))
|
|
}
|
|
|
|
const result = await projectFixture(root)
|
|
|
|
expect(result.code, result.stderr).toBe(0)
|
|
for (const file of assets) {
|
|
expect(readFileSync(join(root, 'out/web', file))).toEqual(Buffer.from([0, 255, 42]))
|
|
}
|
|
})
|
|
|
|
it('follows referenced PDFJS text assets without expanding unreferenced viewer modules', async () => {
|
|
const root = createRendererFixture()
|
|
writeFixtureFile(
|
|
root,
|
|
'out/renderer/assets/web-entry.js',
|
|
'const viewer = "../wasm/viewer.mjs";'
|
|
)
|
|
writeFixtureFile(
|
|
root,
|
|
'out/renderer/wasm/viewer.mjs',
|
|
'const image = "../assets/viewer-image.png";'
|
|
)
|
|
writeFixtureFile(
|
|
root,
|
|
'out/renderer/wasm/unused.mjs',
|
|
'const unused = "../assets/unreferenced-image.png";'
|
|
)
|
|
writeFixtureFile(root, 'out/renderer/assets/viewer-image.png', 'viewer-image')
|
|
writeFixtureFile(root, 'out/renderer/assets/unreferenced-image.png', 'unreferenced-image')
|
|
|
|
const result = await projectFixture(root)
|
|
|
|
expect(result.code, result.stderr).toBe(0)
|
|
expect(existsSync(join(root, 'out/web/wasm/viewer.mjs'))).toBe(true)
|
|
expect(existsSync(join(root, 'out/web/wasm/unused.mjs'))).toBe(true)
|
|
expect(readFileSync(join(root, 'out/web/assets/viewer-image.png'), 'utf8')).toBe('viewer-image')
|
|
expect(existsSync(join(root, 'out/web/assets/unreferenced-image.png'))).toBe(false)
|
|
})
|
|
|
|
it.each(['../outside.js', '/absolute.js', 'C:/drive.js', 'assets\\backslash.js'])(
|
|
'rejects invalid manifest output paths: %s',
|
|
async (outputPath) => {
|
|
const root = createRendererFixture()
|
|
const manifestPath = join(root, 'out/renderer/.vite/manifest.json')
|
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
|
|
manifest['web-index.html'].file = outputPath
|
|
writeFileSync(manifestPath, JSON.stringify(manifest))
|
|
|
|
const result = await projectFixture(root)
|
|
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain('Invalid renderer output path:')
|
|
expect(readFileSync(join(root, 'out/web/stale.js'), 'utf8')).toBe('stale')
|
|
}
|
|
)
|
|
|
|
it('fails when the renderer manifest omits the web entry', async () => {
|
|
const root = createRendererFixture()
|
|
writeFixtureFile(root, 'out/renderer/.vite/manifest.json', '{}')
|
|
const result = await projectFixture(root)
|
|
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain('Renderer manifest is missing entry: web-index.html')
|
|
})
|
|
|
|
it('rejects renderer entries that execute another entry root', async () => {
|
|
const root = createRendererFixture()
|
|
const manifestPath = join(root, 'out/renderer/.vite/manifest.json')
|
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
|
|
manifest['web-index.html'].dynamicImports.push('index.html')
|
|
writeFileSync(manifestPath, JSON.stringify(manifest))
|
|
|
|
const result = await projectFixture(root)
|
|
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain('Renderer entry web-index.html executes entry index.html')
|
|
})
|
|
})
|