From d1fcbfaadb1e58865efa6aca200b1bb2d0955796 Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Sat, 21 Feb 2026 01:24:25 +0100 Subject: [PATCH] Add updater skip-version regression coverage and shared version utils (v4.1.13) --- typescript-version/package-lock.json | 4 +- typescript-version/package.json | 5 +- .../smoke-test-update-version-logic.js | 84 +++++++++++++++++++ typescript-version/src/index.html | 4 +- typescript-version/src/main.ts | 38 +-------- .../src/update-version-utils.ts | 34 ++++++++ 6 files changed, 128 insertions(+), 41 deletions(-) create mode 100644 typescript-version/scripts/smoke-test-update-version-logic.js create mode 100644 typescript-version/src/update-version-utils.ts diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json index 9f97f14..ecd52eb 100644 --- a/typescript-version/package-lock.json +++ b/typescript-version/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "4.1.12", + "version": "4.1.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "4.1.12", + "version": "4.1.13", "license": "MIT", "dependencies": { "axios": "^1.6.0", diff --git a/typescript-version/package.json b/typescript-version/package.json index f705958..0f7846c 100644 --- a/typescript-version/package.json +++ b/typescript-version/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "4.1.12", + "version": "4.1.13", "description": "Twitch VOD Manager - Download Twitch VODs easily", "main": "dist/main.js", "author": "xRangerDE", @@ -8,10 +8,11 @@ "scripts": { "build": "tsc", "start": "npm run build && electron .", + "test:e2e:update-logic": "node scripts/smoke-test-update-version-logic.js", "test:e2e": "npm exec --yes --package=playwright -- node scripts/smoke-test.js", "test:e2e:guide": "npm exec --yes --package=playwright -- node scripts/smoke-test-template-guide.js", "test:e2e:full": "npm exec --yes --package=playwright -- node scripts/smoke-test-full.js", - "test:e2e:release": "npm run build && npm run test:e2e && npm run test:e2e:guide && npm run test:e2e:full", + "test:e2e:release": "npm run build && npm run test:e2e:update-logic && npm run test:e2e && npm run test:e2e:guide && npm run test:e2e:full", "test:e2e:stress": "npm run test:e2e:release && npm run test:e2e:release && npm run test:e2e:release", "pack": "npm run build && electron-builder --dir", "dist": "npm run build && electron-builder", diff --git a/typescript-version/scripts/smoke-test-update-version-logic.js b/typescript-version/scripts/smoke-test-update-version-logic.js new file mode 100644 index 0000000..1848a16 --- /dev/null +++ b/typescript-version/scripts/smoke-test-update-version-logic.js @@ -0,0 +1,84 @@ +const path = require('path'); + +const { + normalizeUpdateVersion, + compareUpdateVersions, + isNewerUpdateVersion +} = require(path.join(process.cwd(), 'dist', 'update-version-utils.js')); + +function run() { + const failures = []; + + const assert = (condition, message) => { + if (!condition) failures.push(message); + }; + + const comparisons = [ + { left: '4.1.18', right: '4.1.10', expected: 1 }, + { left: '4.1.10', right: '4.1.18', expected: -1 }, + { left: 'v4.1.12', right: '4.1.12', expected: 0 }, + { left: '4.1.12', right: '4.1.12.1', expected: -1 }, + { left: '4.2.0', right: '4.1.999', expected: 1 }, + { left: '4.1.12-beta', right: '4.1.12', expected: 0 } + ]; + + const compareResults = comparisons.map((testCase) => { + const actual = compareUpdateVersions(testCase.left, testCase.right); + const pass = actual === testCase.expected; + assert(pass, `compare failed: ${testCase.left} vs ${testCase.right} expected ${testCase.expected}, got ${actual}`); + return { ...testCase, actual, pass }; + }); + + const skipVersionScenarios = [ + { + name: 'old downloaded, newer available', + downloaded: '4.1.11', + latestKnown: '4.1.18', + expectedNeedsNewer: true + }, + { + name: 'already latest downloaded', + downloaded: '4.1.18', + latestKnown: '4.1.18', + expectedNeedsNewer: false + }, + { + name: 'downgrade should not trigger', + downloaded: '4.1.18', + latestKnown: '4.1.11', + expectedNeedsNewer: false + } + ]; + + const scenarioResults = skipVersionScenarios.map((scenario) => { + const needsNewer = isNewerUpdateVersion(scenario.latestKnown, scenario.downloaded); + const pass = needsNewer === scenario.expectedNeedsNewer; + assert(pass, `${scenario.name} expected ${scenario.expectedNeedsNewer}, got ${needsNewer}`); + return { ...scenario, needsNewer, pass }; + }); + + const normalizationChecks = { + fromVPrefix: normalizeUpdateVersion('v4.1.12') === '4.1.12', + trimmed: normalizeUpdateVersion(' 4.1.12 ') === '4.1.12' + }; + + assert(normalizationChecks.fromVPrefix, 'normalize did not remove v prefix'); + assert(normalizationChecks.trimmed, 'normalize did not trim whitespace'); + + const summary = { + checks: { + compareResults, + scenarioResults, + normalizationChecks + }, + failures + }; + + console.log(JSON.stringify(summary, null, 2)); + + if (failures.length) { + process.exitCode = 1; + } +} + +run(); diff --git a/typescript-version/src/index.html b/typescript-version/src/index.html index e1847dd..60e283a 100644 --- a/typescript-version/src/index.html +++ b/typescript-version/src/index.html @@ -457,7 +457,7 @@

Updates

-

Version: v4.1.12

+

Version: v4.1.13

@@ -502,7 +502,7 @@
Nicht verbunden - v4.1.12 + v4.1.13 diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts index e7051bb..91a51d3 100644 --- a/typescript-version/src/main.ts +++ b/typescript-version/src/main.ts @@ -4,11 +4,12 @@ import * as fs from 'fs'; import { spawn, ChildProcess, execSync, exec, spawnSync } from 'child_process'; import axios from 'axios'; import { autoUpdater } from 'electron-updater'; +import { compareUpdateVersions, isNewerUpdateVersion, normalizeUpdateVersion } from './update-version-utils'; // ========================================== // CONFIG & CONSTANTS // ========================================== -const APP_VERSION = '4.1.12'; +const APP_VERSION = '4.1.13'; const UPDATE_CHECK_URL = 'http://24-music.de/version.json'; // Paths @@ -2944,45 +2945,12 @@ function createWindow(): void { // ========================================== // AUTO-UPDATER (electron-updater) // ========================================== -function normalizeUpdateVersion(version: string | null | undefined): string { - return (version || '').trim().replace(/^v/i, ''); -} - -function compareUpdateVersions(left: string | null | undefined, right: string | null | undefined): number { - const a = normalizeUpdateVersion(left); - const b = normalizeUpdateVersion(right); - - if (!a && !b) return 0; - if (!a) return -1; - if (!b) return 1; - - const aParts = a.split('.').map((part) => { - const numeric = Number(part.replace(/[^0-9].*$/, '')); - return Number.isFinite(numeric) ? numeric : 0; - }); - - const bParts = b.split('.').map((part) => { - const numeric = Number(part.replace(/[^0-9].*$/, '')); - return Number.isFinite(numeric) ? numeric : 0; - }); - - const maxLength = Math.max(aParts.length, bParts.length); - for (let i = 0; i < maxLength; i += 1) { - const av = aParts[i] || 0; - const bv = bParts[i] || 0; - if (av > bv) return 1; - if (av < bv) return -1; - } - - return 0; -} - function hasNewerKnownUpdateThanDownloaded(): boolean { if (!latestKnownUpdateVersion || !downloadedUpdateVersion) { return false; } - return compareUpdateVersions(latestKnownUpdateVersion, downloadedUpdateVersion) > 0; + return isNewerUpdateVersion(latestKnownUpdateVersion, downloadedUpdateVersion); } async function requestUpdateCheck(source: UpdateCheckSource, force = false): Promise<{ started: boolean; reason?: string }> { diff --git a/typescript-version/src/update-version-utils.ts b/typescript-version/src/update-version-utils.ts new file mode 100644 index 0000000..885ec35 --- /dev/null +++ b/typescript-version/src/update-version-utils.ts @@ -0,0 +1,34 @@ +export function normalizeUpdateVersion(version: string | null | undefined): string { + return (version || '').trim().replace(/^v/i, ''); +} + +function parseVersionPart(part: string): number { + const numeric = Number(part.replace(/[^0-9].*$/, '')); + return Number.isFinite(numeric) ? numeric : 0; +} + +export function compareUpdateVersions(left: string | null | undefined, right: string | null | undefined): number { + const a = normalizeUpdateVersion(left); + const b = normalizeUpdateVersion(right); + + if (!a && !b) return 0; + if (!a) return -1; + if (!b) return 1; + + const aParts = a.split('.').map(parseVersionPart); + const bParts = b.split('.').map(parseVersionPart); + const maxLength = Math.max(aParts.length, bParts.length); + + for (let i = 0; i < maxLength; i += 1) { + const av = aParts[i] || 0; + const bv = bParts[i] || 0; + if (av > bv) return 1; + if (av < bv) return -1; + } + + return 0; +} + +export function isNewerUpdateVersion(candidate: string | null | undefined, baseline: string | null | undefined): boolean { + return compareUpdateVersions(candidate, baseline) > 0; +}