forked from wangziqi/gongxue-base
feat: establish production SaaS foundation
This commit is contained in:
139
scripts/taro-components-h5-runtime-patch-test.js
Normal file
139
scripts/taro-components-h5-runtime-patch-test.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import {
|
||||
enforceTaroH5RuntimePatches,
|
||||
replaceExactlyOnce,
|
||||
taroButtonLoadingPatch,
|
||||
taroH5RuntimePatchDefinition,
|
||||
taroInputWatcherPatch,
|
||||
} from './taro-components-h5-runtime-patch.js';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
|
||||
function writeJson(filePath, value) {
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
||||
}
|
||||
|
||||
function installedPristineSource(patch) {
|
||||
const target = path.join(repoRoot, 'node_modules', '@tarojs', 'components', patch.targetRelativePath);
|
||||
const installed = fs.readFileSync(target, 'utf8');
|
||||
const pristine = installed.includes(patch.after) ? installed.replace(patch.after, patch.before) : installed;
|
||||
return pristine;
|
||||
}
|
||||
|
||||
const pristineSources = new Map([
|
||||
[taroInputWatcherPatch.id, installedPristineSource(taroInputWatcherPatch)],
|
||||
[taroButtonLoadingPatch.id, installedPristineSource(taroButtonLoadingPatch)],
|
||||
]);
|
||||
|
||||
function createFixture(options = {}) {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'tiku-taro-h5-runtime-patch-'));
|
||||
const taroManifest = {
|
||||
name: '@tiku-saas/taro',
|
||||
version: '0.1.0',
|
||||
scripts: { postinstall: taroH5RuntimePatchDefinition.postinstallCommand },
|
||||
devDependencies: {
|
||||
'@tarojs/components': options.declaredVersion || taroH5RuntimePatchDefinition.packageVersion,
|
||||
},
|
||||
};
|
||||
writeJson(path.join(root, 'apps', 'taro', 'package.json'), taroManifest);
|
||||
writeJson(path.join(root, 'package-lock.json'), {
|
||||
lockfileVersion: 3,
|
||||
packages: {
|
||||
'apps/taro': {
|
||||
hasInstallScript: true,
|
||||
devDependencies: {
|
||||
'@tarojs/components': options.lockWorkspaceVersion || taroH5RuntimePatchDefinition.packageVersion,
|
||||
},
|
||||
},
|
||||
'node_modules/@tarojs/components': {
|
||||
version: options.lockVersion || taroH5RuntimePatchDefinition.packageVersion,
|
||||
integrity: options.integrity || taroH5RuntimePatchDefinition.lockIntegrity,
|
||||
},
|
||||
},
|
||||
});
|
||||
writeJson(path.join(root, 'node_modules', '@tarojs', 'components', 'package.json'), {
|
||||
name: '@tarojs/components',
|
||||
version: options.installedVersion || taroH5RuntimePatchDefinition.packageVersion,
|
||||
});
|
||||
|
||||
const targets = new Map();
|
||||
for (const patch of taroH5RuntimePatchDefinition.patches) {
|
||||
const target = path.join(root, 'node_modules', '@tarojs', 'components', patch.targetRelativePath);
|
||||
targets.set(patch.id, target);
|
||||
if (options.missingTarget !== patch.id) {
|
||||
fs.mkdirSync(path.dirname(target), { recursive: true });
|
||||
fs.writeFileSync(
|
||||
target,
|
||||
options.sources?.[patch.id] ?? pristineSources.get(patch.id),
|
||||
'utf8',
|
||||
);
|
||||
}
|
||||
}
|
||||
return { root, targets };
|
||||
}
|
||||
|
||||
function targetContents(fixture) {
|
||||
return Object.fromEntries([...fixture.targets].map(([id, target]) => [
|
||||
id,
|
||||
fs.existsSync(target) ? fs.readFileSync(target, 'utf8') : null,
|
||||
]));
|
||||
}
|
||||
|
||||
const workingState = enforceTaroH5RuntimePatches({ root: repoRoot, mode: 'check' });
|
||||
assert.equal(workingState.status, 'pass');
|
||||
assert.equal(workingState.patches.inputWatcher.installedSha256, taroInputWatcherPatch.patchedSha256);
|
||||
assert.equal(workingState.patches.buttonLoading.installedSha256, taroButtonLoadingPatch.patchedSha256);
|
||||
|
||||
const applied = createFixture();
|
||||
try {
|
||||
const first = enforceTaroH5RuntimePatches({ root: applied.root, mode: 'apply' });
|
||||
assert.equal(first.patches.inputWatcher.state, 'patched-now');
|
||||
assert.equal(first.patches.buttonLoading.state, 'patched-now');
|
||||
const second = enforceTaroH5RuntimePatches({ root: applied.root, mode: 'apply' });
|
||||
assert.equal(second.patches.inputWatcher.state, 'patched');
|
||||
assert.equal(second.patches.buttonLoading.state, 'patched');
|
||||
assert.equal(enforceTaroH5RuntimePatches({ root: applied.root, mode: 'check' }).status, 'pass');
|
||||
} finally {
|
||||
fs.rmSync(applied.root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
const pristineCheck = createFixture();
|
||||
try {
|
||||
const before = targetContents(pristineCheck);
|
||||
assert.throws(
|
||||
() => enforceTaroH5RuntimePatches({ root: pristineCheck.root, mode: 'check' }),
|
||||
/patch is not applied/,
|
||||
);
|
||||
assert.deepEqual(targetContents(pristineCheck), before, '--check must never modify a pristine install');
|
||||
} finally {
|
||||
fs.rmSync(pristineCheck.root, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
for (const [name, options, pattern] of [
|
||||
['declared version', { declaredVersion: '4.2.1' }, /must pin/],
|
||||
['lock integrity', { integrity: 'sha512-unreviewed' }, /unexpected.*integrity/],
|
||||
['installed version', { installedVersion: '4.2.1-beta.2' }, /does not match/],
|
||||
['missing Input target', { missingTarget: taroInputWatcherPatch.id }, /target is missing/],
|
||||
['missing Button target', { missingTarget: taroButtonLoadingPatch.id }, /target is missing/],
|
||||
['unknown Input content', { sources: { [taroInputWatcherPatch.id]: `${pristineSources.get(taroInputWatcherPatch.id)}\n// tampered\n` } }, /unreviewed.*hash/],
|
||||
['unknown Button content', { sources: { [taroButtonLoadingPatch.id]: `${pristineSources.get(taroButtonLoadingPatch.id)}\n// tampered\n` } }, /unreviewed.*hash/],
|
||||
]) {
|
||||
const fixture = createFixture(options);
|
||||
try {
|
||||
const before = targetContents(fixture);
|
||||
assert.throws(() => enforceTaroH5RuntimePatches({ root: fixture.root, mode: 'apply' }), pattern, name);
|
||||
assert.deepEqual(targetContents(fixture), before, `${name} failure must not modify either target`);
|
||||
} finally {
|
||||
fs.rmSync(fixture.root, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
assert.throws(() => replaceExactlyOnce('safe', 'unsafe', 'guarded'), /found 0/);
|
||||
assert.throws(() => replaceExactlyOnce('unsafe unsafe', 'unsafe', 'guarded'), /found 2/);
|
||||
assert.equal(replaceExactlyOnce('before unsafe after', 'unsafe', 'guarded'), 'before guarded after');
|
||||
|
||||
console.log('[PASS] Taro H5 runtime patch contract');
|
||||
Reference in New Issue
Block a user