Files
Multi-Hoster-Upload/tests/updater-version.test.js
T
Sucukdeluxe 9444bf1351 fix(updater): show header action only when update is available
Hide the header update action until a newer release is confirmed.
Register update notifications before renderer initialization so startup cannot miss them.
Refresh the public product screenshot and release metadata for v2.0.7.
2026-08-10 13:11:14 +02:00

144 lines
5.2 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const path = require('node:path');
const fs = require('node:fs');
const os = require('node:os');
const { pathToFileURL } = require('node:url');
const { isNewer, resolveReleaseVersion, prepareUpdate, launchPreparedUpdate } = require('../lib/updater');
const releasePlanUrl = pathToFileURL(path.resolve(__dirname, '../scripts/release-plan.mjs')).href;
test('bridge title resolves product version instead of transport tag', () => {
assert.equal(resolveReleaseVersion({ name: 'Multi-Hoster-Upload v2.0.1', tag_name: 'v3.3.109' }), '2.0.1');
assert.equal(isNewer('2.0.1', '2.0.1'), false);
assert.equal(isNewer('2.0.2', '2.0.1'), true);
});
test('release arguments reject a malformed transport tag', async () => {
const { parseReleaseArgs } = await import(releasePlanUrl);
assert.throws(
() => parseReleaseArgs(['2.0.1', '--transport-tag', '3.3.109', 'Bridge', '--dry-run']),
/--transport-tag must match vX\.Y\.Z/
);
});
test('update preparation writes a verified installer without launching it', async () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mhu-updater-test-'));
const installer = Buffer.alloc(128 * 1024, 0);
installer[0] = 0x4d;
installer[1] = 0x5a;
let reads = 0;
const progress = [];
try {
const prepared = await prepareUpdate(value => progress.push(value), {
checkResult: {
available: true,
assetUrl: 'https://update.invalid/setup.exe',
assetName: 'setup.exe',
assetSize: installer.length,
latestYmlUrl: null
},
tempDir,
fetchImpl: async () => ({
ok: true,
status: 200,
body: {
getReader: () => ({
read: async () => {
reads++;
return reads === 1 ? { done: false, value: installer } : { done: true };
}
})
}
})
});
assert.equal(prepared.installerPath, path.join(tempDir, 'setup.exe'));
assert.deepEqual(fs.readFileSync(prepared.installerPath), installer);
assert.equal(progress.at(-1).stage, 'prepared');
} finally {
fs.rmSync(tempDir, { recursive: true, force: true });
}
});
test('a prepared installer launches at most once', () => {
const calls = [];
const child = { unrefCalls: 0, unref() { this.unrefCalls++; } };
const prepared = { installerPath: 'C:\\Temp\\mhu-setup.exe' };
const spawnImpl = (...args) => {
calls.push(args);
return child;
};
assert.equal(launchPreparedUpdate(prepared, { spawnImpl }), true);
assert.equal(launchPreparedUpdate(prepared, { spawnImpl }), false);
assert.equal(calls.length, 1);
assert.deepEqual(calls[0], [
prepared.installerPath,
['/S', '--updated', '--force-run'],
{ detached: true, stdio: 'ignore' }
]);
assert.equal(child.unrefCalls, 1);
});
test('release plan keeps product artifacts separate from the transport tag', async () => {
const { createReleasePlan, parseReleaseArgs, renderLatestYml } = await import(releasePlanUrl);
const plan = createReleasePlan(parseReleaseArgs(['2.0.7', '--transport-tag', 'v3.3.115', 'Update', 'visibility']));
const latestYml = renderLatestYml(plan, 'abc123', 456, '2026-08-07T12:00:00.000Z');
assert.deepEqual({
version: plan.version,
transportTag: plan.transportTag,
releaseTitle: plan.releaseTitle,
releaseBody: plan.releaseBody,
expectedArtifacts: plan.expectedArtifacts,
latestYml
}, {
version: '2.0.7',
transportTag: 'v3.3.115',
releaseTitle: 'Multi-Hoster-Upload v2.0.7',
releaseBody: 'Update visibility',
expectedArtifacts: [
'Multi-Hoster-Upload Setup 2.0.7.exe',
'Multi-Hoster-Upload 2.0.7.exe',
'Multi-Hoster-Upload Setup 2.0.7.exe.blockmap',
'latest.yml'
],
latestYml: "version: 2.0.7\nfiles:\n - url: Multi-Hoster-Upload Setup 2.0.7.exe\n sha512: abc123\n size: 456\npath: Multi-Hoster-Upload Setup 2.0.7.exe\nsha512: abc123\nreleaseDate: '2026-08-07T12:00:00.000Z'\n"
});
});
test('compatible existing release preserves the recovery id', async () => {
const { createReleasePlan, parseReleaseArgs, resolveExistingReleaseId } = await import(releasePlanUrl);
const plan = createReleasePlan(parseReleaseArgs(['2.0.1', '--transport-tag', 'v3.3.109', 'Bridge notes']));
const release = {
id: 81,
tag_name: 'v3.3.109',
name: 'Multi-Hoster-Upload v2.0.1',
body: 'Bridge notes',
draft: false,
prerelease: false,
assets: []
};
assert.equal(resolveExistingReleaseId(plan, release), 81);
});
test('incompatible existing release title fails closed', async () => {
const { createReleasePlan, parseReleaseArgs, resolveExistingReleaseId } = await import(releasePlanUrl);
const plan = createReleasePlan(parseReleaseArgs(['2.0.1', '--transport-tag', 'v3.3.109', 'Bridge notes']));
const release = {
id: 81,
tag_name: 'v3.3.109',
name: 'Multi-Hoster-Upload v3.3.109',
body: 'Old transport release',
draft: false,
prerelease: false,
assets: []
};
assert.throws(
() => resolveExistingReleaseId(plan, release),
/Refusing recovery for v3\.3\.109: existing release title "Multi-Hoster-Upload v3\.3\.109" does not match "Multi-Hoster-Upload v2\.0\.1"/
);
});