import test from 'node:test' import { runInNewContext } from 'node:vm' import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' const read = path => readFile(new URL(path, import.meta.url), 'utf8') test('H5 image copies only compiled assets and static nginx configuration', async () => { const dockerfile = await read('../deploy/Dockerfile.h5') const copies = dockerfile.split(/\r?\n/).filter(line => line.startsWith('COPY ')) assert.deepEqual(copies, ['COPY deploy/nginx.conf /etc/nginx/conf.d/default.conf', 'COPY unpackage/dist/build/web/ /srv/pda-h5/']) assert.match(dockerfile, /ARG NGINX_BASE_IMAGE=/) assert.match(dockerfile, /FROM \$\{NGINX_BASE_IMAGE\}/) assert.doesNotMatch(dockerfile, /RUN |npm|node_modules|COPY \. /) const ignore = await read('../.dockerignore') assert.ok(ignore.split(/\r?\n/).includes('**')) assert.ok(ignore.includes('!unpackage/dist/build/web/**')) assert.doesNotMatch(ignore, /!\.env|!node_modules|!src/) }) test('static server serves the domain root and returns genuine missing-resource errors', async () => { const nginx = await read('../deploy/nginx.conf') assert.match(nginx, /listen 80;/) assert.ok(nginx.includes('location /')) assert.match(nginx, /root \/srv\/pda-h5;/) assert.match(nginx, /try_files \$uri \$uri\/ =404;/) assert.match(nginx, /Cache-Control "no-store" always/) assert.doesNotMatch(nginx, /pda-domestic|pda-overseas/) assert.match(nginx, /location = \/healthz/) assert.doesNotMatch(nginx, /proxy_pass|gateway-api|try_files[^;]*index\.html/) }) test('TEST H5 deployment has a required image tag and internal-only dual health checks', async () => { const compose = await read('../deploy/docker-compose.h5.test.yml') assert.ok(compose.includes('${IMAGE_TAG:?IMAGE_TAG is required}')) assert.match(compose, /context: \.\./) assert.match(compose, /dockerfile: deploy\/Dockerfile\.h5/) assert.match(compose, /container_name: pda-domestic-h5-test/) assert.match(compose, /aliases:\s*\n\s*- pda-domestic-h5-test/) assert.match(compose, /external: true/) assert.match(compose, /name: firstleg-test-network/) assert.match(compose, /expose:\s*\n\s*- "80"/) assert.ok(compose.includes('http://127.0.0.1/healthz && wget -qO /dev/null http://127.0.0.1/')) assert.doesNotMatch(compose, /\bports:|volumes:|API_UPSTREAM|privileged:|pid: host/) }) test('only H5 production overrides the toolchain asset base', async () => { const source = (await read('../vite.config.js')) .replace(/^import .*$/gm, '') .replace('export default ', '') for (const platform of ['h5', 'app', 'app-plus', 'app-harmony', undefined]) { for (const mode of ['production', 'development']) { const factory = runInNewContext(source, { defineConfig: value => value, loadEnv: () => ({}), uni: () => ({}), process: { env: { UNI_PLATFORM: platform }, cwd: () => '/project' } }) assert.equal(factory({ mode }).base, platform === 'h5' && mode === 'production' ? '/' : undefined, `${platform}:${mode}`) } } }) test('H5 proxy uses the shared gateway prefix and preserves API suffixes', async () => { const source = (await read('../vite.config.js')).replace(/^import .*$/gm, '').replace('export default ', '') const factory = runInNewContext(source, { defineConfig: value => value, loadEnv: () => ({ API_PROXY_TARGET: 'https://gateway.example.com' }), uni: () => ({}), process: { env: { UNI_PLATFORM: 'h5' }, cwd: () => '/project' } }) const proxy = factory({ mode: 'development' }).server.proxy assert.deepEqual(Object.keys(proxy), ['/gateway-api']) assert.equal(proxy['/gateway-api'].target, 'https://gateway.example.com') for (const suffix of ['/auth/login', '/pda/v1/last-leg/photos/1/download?preview=1']) { assert.equal(proxy['/gateway-api'].rewrite(`/gateway-api${suffix}`), `/api${suffix}`) } }) test('gray H5 runs on an isolated network with same-origin Gateway API', async () => { const compose = await read('../deploy/docker-compose.h5.production.yml') const nginx = await read('../deploy/nginx.production.conf.template') const docker = await read('../deploy/Dockerfile.h5.production') assert.match(compose, /name: firstleg-production-network/) assert.match(compose, /127\.0\.0\.1:/) assert.doesNotMatch(compose, /test-network|gateway-overseas/) assert.match(nginx, /location \/gateway-api\//) assert.ok(nginx.includes('proxy_pass ${API_UPSTREAM}/api/;')) assert.match(docker, /COPY deploy\/nginx.production.conf.template \/etc\/nginx\/templates\/default.conf.template/) })