mirror of
https://gh-proxy.org/https://github.com/klinsmaya/portal-template-default.git
synced 2026-11-09 01:27:53 +08:00
234 lines
6.8 KiB
JavaScript
234 lines
6.8 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import {
|
|
existsSync,
|
|
mkdirSync,
|
|
mkdtempSync,
|
|
readFileSync,
|
|
rmSync,
|
|
writeFileSync,
|
|
} from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import test from 'node:test';
|
|
import {
|
|
checkCorePeers,
|
|
recordTemplatePlugins,
|
|
templatePlugins,
|
|
} from '../template-plugins.mjs';
|
|
|
|
const mail = '@nocobase/app-plugin-mail';
|
|
const scheduler = '@nocobase/app-plugin-scheduler';
|
|
const json = (file) => JSON.parse(readFileSync(file, 'utf8'));
|
|
const writeJson = (file, value) => writeFileSync(file, JSON.stringify(value));
|
|
|
|
function fixture(t) {
|
|
const root = mkdtempSync(path.join(os.tmpdir(), 'template-plugins-'));
|
|
t.after(() => rmSync(root, { recursive: true, force: true }));
|
|
const app = path.join(root, 'app');
|
|
const diagnostics = path.join(root, 'diagnostics');
|
|
mkdirSync(app);
|
|
const metadata = {
|
|
template: '@nocobase/app-template-default',
|
|
templateVersion: '1.0.0-beta.61',
|
|
};
|
|
const manifest = {
|
|
dependencies: {
|
|
[mail]: '^1.0.0-beta.10',
|
|
[scheduler]: '^1.0.0-beta.16',
|
|
'@nocobase/app-server': '^2.0.0-beta.3',
|
|
},
|
|
devDependencies: {
|
|
'@nocobase/app-client': '^3.0.0-beta.0',
|
|
'@nocobase/app-plugin-template-print': '0.0.2-beta.1',
|
|
},
|
|
};
|
|
writeJson(path.join(app, 'package.json'), manifest);
|
|
writeJson(path.join(app, 'factory-template.json'), metadata);
|
|
writeFileSync(path.join(app, 'pnpm-lock.yaml'), 'original lockfile\n');
|
|
for (const [name, version] of [
|
|
[mail, '1.0.0-beta.10'],
|
|
[scheduler, '1.0.0-beta.16'],
|
|
]) {
|
|
const directory = path.join(app, 'node_modules', name);
|
|
mkdirSync(directory, { recursive: true });
|
|
writeJson(path.join(directory, 'package.json'), {
|
|
name,
|
|
version,
|
|
peerDependencies: { '@nocobase/app-client': '^3.0.0-beta.0' },
|
|
});
|
|
}
|
|
return { app, diagnostics, manifest, metadata };
|
|
}
|
|
|
|
test('the template owns the production plugin set, without mandatory old AI plugins', () => {
|
|
assert.deepEqual(
|
|
templatePlugins({
|
|
dependencies: {
|
|
[mail]: '^1.0.0-beta.10',
|
|
'@nocobase/app-server': '^2.0.0-beta.3',
|
|
},
|
|
devDependencies: { [scheduler]: '^1.0.0-beta.16' },
|
|
}),
|
|
[mail],
|
|
);
|
|
assert.deepEqual(templatePlugins({}), []);
|
|
});
|
|
|
|
test('records actual template dependency versions without changing manifests or lockfiles', (t) => {
|
|
const f = fixture(t);
|
|
const expected = [
|
|
{ packageName: mail, version: '1.0.0-beta.10' },
|
|
{ packageName: scheduler, version: '1.0.0-beta.16' },
|
|
];
|
|
assert.deepEqual(recordTemplatePlugins(f.app, f.diagnostics), expected);
|
|
assert.deepEqual(json(path.join(f.app, 'factory-template.json')), {
|
|
...f.metadata,
|
|
plugins: expected,
|
|
});
|
|
assert.deepEqual(
|
|
json(path.join(f.diagnostics, 'template-plugins/inventory.json')),
|
|
expected,
|
|
);
|
|
assert.deepEqual(json(path.join(f.app, 'package.json')), f.manifest);
|
|
assert.equal(
|
|
readFileSync(path.join(f.app, 'pnpm-lock.yaml'), 'utf8'),
|
|
'original lockfile\n',
|
|
);
|
|
});
|
|
|
|
test('a template without Mail does not acquire a Mail or AI dependency', (t) => {
|
|
const f = fixture(t);
|
|
delete f.manifest.dependencies[mail];
|
|
writeJson(path.join(f.app, 'package.json'), f.manifest);
|
|
assert.deepEqual(recordTemplatePlugins(f.app, f.diagnostics), [
|
|
{ packageName: scheduler, version: '1.0.0-beta.16' },
|
|
]);
|
|
});
|
|
|
|
for (const [name, change] of [
|
|
[
|
|
'a missing package',
|
|
(f) => rmSync(path.join(f.app, 'node_modules', mail), { recursive: true }),
|
|
],
|
|
[
|
|
'a wrong package identity',
|
|
(p) => {
|
|
p.name = 'another';
|
|
},
|
|
],
|
|
[
|
|
'an unknown version',
|
|
(p) => {
|
|
p.version = 'beta';
|
|
},
|
|
],
|
|
[
|
|
'an incompatible core',
|
|
(p) => {
|
|
p.peerDependencies['@nocobase/app-client'] = '^2.0.0-beta.2';
|
|
},
|
|
],
|
|
]) {
|
|
test(`${name} prevents successful inventory publication`, (t) => {
|
|
const f = fixture(t);
|
|
const file = path.join(f.app, 'node_modules', mail, 'package.json');
|
|
if (name === 'a missing package') change(f);
|
|
else {
|
|
const installed = json(file);
|
|
change(installed);
|
|
writeJson(file, installed);
|
|
}
|
|
assert.throws(() => recordTemplatePlugins(f.app, f.diagnostics));
|
|
assert.deepEqual(
|
|
json(path.join(f.app, 'factory-template.json')),
|
|
f.metadata,
|
|
);
|
|
assert.equal(
|
|
existsSync(path.join(f.diagnostics, 'template-plugins/inventory.json')),
|
|
false,
|
|
);
|
|
});
|
|
}
|
|
|
|
test('workflow synchronizes template Skills and checks dependencies without adding plugins or config', () => {
|
|
const workflow = readFileSync(
|
|
new URL('../../workflows/refresh-template.yml', import.meta.url),
|
|
'utf8',
|
|
);
|
|
assert.match(workflow, /--no-install --template=default --template-tag=beta/);
|
|
assert.doesNotMatch(
|
|
workflow,
|
|
/app-template-pro-default|template-plugins\.mjs install|template-mail-config\.mjs/,
|
|
);
|
|
const step = workflow
|
|
.split('- name: Sync Skills and record the template plugin inventory\n')[1]
|
|
.split(/\n {6}- (?=name:|uses:)/)[0];
|
|
assert.match(step, /pnpm --dir "\$APP_ROOT" exec nocobase skills sync/);
|
|
assert.match(step, /template-plugins\.mjs record/);
|
|
assert.doesNotMatch(step, /continue-on-error/);
|
|
assert.ok(
|
|
workflow.indexOf('template-plugins.mjs record') >
|
|
workflow.indexOf('pnpm install --no-frozen-lockfile'),
|
|
);
|
|
assert.ok(
|
|
workflow.indexOf('template-plugins.mjs record') <
|
|
workflow.indexOf(
|
|
'Verify factory, application, clean database, and browser login',
|
|
),
|
|
);
|
|
});
|
|
|
|
test('core peer check compares release lines with the template', () => {
|
|
const app = {
|
|
dependencies: { '@nocobase/app-server': '^2.0.0-beta.0' },
|
|
devDependencies: { '@nocobase/app-client': '^2.0.0-beta.0' },
|
|
};
|
|
const plugin = (peerDependencies) => ({
|
|
name: '@nocobase/app-plugin-mail',
|
|
version: '0.1.0-beta.0',
|
|
peerDependencies,
|
|
});
|
|
checkCorePeers(
|
|
app,
|
|
plugin({
|
|
'@nocobase/app-server': '^2.0.0-beta.0',
|
|
'@nocobase/app-client': '>=2.1.0 <3',
|
|
}),
|
|
);
|
|
checkCorePeers(app, plugin({ react: '^19.0.0' }));
|
|
assert.throws(
|
|
() =>
|
|
checkCorePeers(
|
|
app,
|
|
plugin({
|
|
'@nocobase/app-server': '^1.0.0-beta.22',
|
|
'@nocobase/app-client': '^1.0.0-beta.19',
|
|
}),
|
|
),
|
|
(error) =>
|
|
/app-plugin-mail@0\.1\.0-beta\.0 is built for a different NocoBase core/.test(
|
|
error.message,
|
|
) &&
|
|
/app-server \^1\.0\.0-beta\.22, but the template declares \^2\.0\.0-beta\.0/.test(
|
|
error.message,
|
|
) &&
|
|
/app-client/.test(error.message),
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
checkCorePeers(
|
|
{ dependencies: { '@nocobase/app-server': '^0.11.0' } },
|
|
plugin({ '@nocobase/app-server': '^0.12.0' }),
|
|
),
|
|
/different NocoBase core/,
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
checkCorePeers(
|
|
{ dependencies: {} },
|
|
plugin({ '@nocobase/app-server': '^2.0.0' }),
|
|
),
|
|
/which the template does not declare/,
|
|
);
|
|
});
|