136 lines
5.2 KiB
JavaScript
136 lines
5.2 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import test from 'node:test'
|
|
import {
|
|
DSH_COMPATIBILITY_PACKAGES,
|
|
DSH_REMOTE_METHODS,
|
|
DSH_STATIC_CLIENT_MODULES,
|
|
DSH_WEB_ROWS,
|
|
verifyDshCompatibility,
|
|
} from '../lib/dsh-compatibility.mjs'
|
|
|
|
const VERSION = '0.1.5-rc.1'
|
|
|
|
async function writeJson(path, value) {
|
|
await writeFile(path, `${JSON.stringify(value)}\n`)
|
|
}
|
|
|
|
async function fixture() {
|
|
const root = await mkdtemp(join(tmpdir(), 'dsh-compatibility-fixture-'))
|
|
await mkdir(join(root, 'lib'), { recursive: true })
|
|
await writeJson(join(root, 'package.json'), {
|
|
name: '@deepseek-ai/dsh',
|
|
version: VERSION,
|
|
type: 'module',
|
|
bin: { dsh: 'lib/bin.js' },
|
|
dependencies: Object.fromEntries(Object.keys(DSH_COMPATIBILITY_PACKAGES).map(name => [name, `^${VERSION}`])),
|
|
})
|
|
const config = Object.entries(DSH_WEB_ROWS)
|
|
.map(([id, name]) => `- id: ${id}\n name: '${name}'`)
|
|
.join('\n')
|
|
await writeFile(join(root, 'lib/bin.js'), `console.log(${JSON.stringify(config)})\n`)
|
|
for (const [name, exports] of Object.entries(DSH_COMPATIBILITY_PACKAGES)) {
|
|
const directory = join(root, 'node_modules', ...name.split('/'))
|
|
await mkdir(join(directory, 'lib'), { recursive: true })
|
|
await writeJson(join(directory, 'package.json'), {
|
|
name,
|
|
version: VERSION,
|
|
exports: Object.fromEntries(exports.map(subpath => [subpath, './lib/index.js'])),
|
|
})
|
|
await writeFile(join(directory, 'lib/index.js'), '')
|
|
}
|
|
await writeFile(
|
|
packageFile(root, '@deepseek-ai/dsh-api-remotes', 'lib/client.js'),
|
|
DSH_REMOTE_METHODS.join('\n'),
|
|
)
|
|
const frontendAssets = packageFile(root, '@deepseek-ai/dsh-web-frontend', 'dist/assets')
|
|
await mkdir(frontendAssets, { recursive: true })
|
|
await writeFile(join(frontendAssets, 'index.js'), `{${DSH_STATIC_CLIENT_MODULES
|
|
.map(name => `${JSON.stringify(name)}:fixture`)
|
|
.join(',')}}\n`)
|
|
return root
|
|
}
|
|
|
|
function packageFile(root, packageName, file) {
|
|
return join(root, 'node_modules', ...packageName.split('/'), file)
|
|
}
|
|
|
|
function removeAfter(t, ...paths) {
|
|
t.after(() => Promise.all(paths.map(path => rm(path, { recursive: true, force: true }))))
|
|
}
|
|
|
|
test('accepts the complete DSH package, Web profile, and Remote contract', async t => {
|
|
const packageRoot = await fixture()
|
|
const home = await mkdtemp(join(tmpdir(), 'dsh-compatibility-home-'))
|
|
removeAfter(t, packageRoot, home)
|
|
assert.deepEqual(await verifyDshCompatibility({ packageRoot, expectedVersion: VERSION, home }), {
|
|
name: '@deepseek-ai/dsh',
|
|
version: VERSION,
|
|
packages: 10,
|
|
remoteMethods: 3,
|
|
webRows: 5,
|
|
})
|
|
})
|
|
|
|
test('rejects a stale installed package in the DSH dependency closure', async t => {
|
|
const packageRoot = await fixture()
|
|
const home = await mkdtemp(join(tmpdir(), 'dsh-compatibility-home-'))
|
|
removeAfter(t, packageRoot, home)
|
|
const manifestPath = packageFile(packageRoot, '@deepseek-ai/dsh-client-connection', 'package.json')
|
|
const manifest = JSON.parse(await readFile(manifestPath, 'utf8'))
|
|
await writeJson(manifestPath, { ...manifest, version: '0.1.2-rc.1' })
|
|
await assert.rejects(
|
|
verifyDshCompatibility({ packageRoot, expectedVersion: VERSION, home }),
|
|
/dsh-client-connection is not installed at DSH version 0\.1\.5-rc\.1/,
|
|
)
|
|
})
|
|
|
|
test('rejects missing Web rows and management Remote methods', async t => {
|
|
const packageRoot = await fixture()
|
|
const home = await mkdtemp(join(tmpdir(), 'dsh-compatibility-home-'))
|
|
removeAfter(t, packageRoot, home)
|
|
await writeFile(join(packageRoot, 'lib/bin.js'), 'console.log("- id: connection\\n name: missing")\n')
|
|
await assert.rejects(
|
|
verifyDshCompatibility({ packageRoot, expectedVersion: VERSION, home }),
|
|
/DSH Web profile does not contain/,
|
|
)
|
|
|
|
await writeFile(
|
|
packageFile(packageRoot, '@deepseek-ai/dsh-api-remotes', 'lib/client.js'),
|
|
DSH_REMOTE_METHODS.slice(1).join('\n'),
|
|
)
|
|
await assert.rejects(
|
|
verifyDshCompatibility({ packageRoot, expectedVersion: VERSION, home }),
|
|
/Remote registry is missing/,
|
|
)
|
|
})
|
|
|
|
test('rejects each missing static module required by a bundled System Plugin', async t => {
|
|
for (const missing of DSH_STATIC_CLIENT_MODULES) {
|
|
await t.test(missing, async t => {
|
|
const packageRoot = await fixture()
|
|
const home = await mkdtemp(join(tmpdir(), 'dsh-compatibility-home-'))
|
|
removeAfter(t, packageRoot, home)
|
|
const present = DSH_STATIC_CLIENT_MODULES.filter(name => name !== missing)
|
|
await writeFile(
|
|
packageFile(packageRoot, '@deepseek-ai/dsh-web-frontend', 'dist/assets/index.js'),
|
|
`{${present.map(name => `${JSON.stringify(name)}:fixture`).join(',')}}\n`,
|
|
)
|
|
await assert.rejects(
|
|
verifyDshCompatibility({ packageRoot, expectedVersion: VERSION, home }),
|
|
new RegExp(`Web static module table is missing ${JSON.stringify(missing).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`),
|
|
)
|
|
})
|
|
}
|
|
})
|
|
|
|
test('requires every static browser module consumed directly by bundled System Plugins', () => {
|
|
assert.deepEqual(DSH_STATIC_CLIENT_MODULES, [
|
|
'@deepseek-ai/dsh-client-ui-primitives',
|
|
'react',
|
|
'react-dom',
|
|
])
|
|
})
|