From e4ab08cd886c8b7f37a519123e1e295a585f0d1f Mon Sep 17 00:00:00 2001 From: xRangerDE Date: Mon, 16 Feb 2026 13:30:55 +0100 Subject: [PATCH] Add template-guide E2E test and release validation gate (v4.0.7) --- docs/src/pages/development.mdx | 6 + typescript-version/package-lock.json | 4 +- typescript-version/package.json | 6 +- .../scripts/smoke-test-template-guide.js | 146 ++++++++++++++++++ typescript-version/src/index.html | 4 +- typescript-version/src/main.ts | 2 +- 6 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 typescript-version/scripts/smoke-test-template-guide.js diff --git a/docs/src/pages/development.mdx b/docs/src/pages/development.mdx index 49d8a63..a5aad48 100644 --- a/docs/src/pages/development.mdx +++ b/docs/src/pages/development.mdx @@ -45,9 +45,15 @@ npm start # Quick UI smoke test npm run test:e2e +# Template guide + live preview checks +npm run test:e2e:guide + # Full end-to-end validation pass npm run test:e2e:full +# Release validation suite (build + smoke + guide + full) +npm run test:e2e:release + # Build Windows installer npm run dist:win ``` diff --git a/typescript-version/package-lock.json b/typescript-version/package-lock.json index cec5f88..7563854 100644 --- a/typescript-version/package-lock.json +++ b/typescript-version/package-lock.json @@ -1,12 +1,12 @@ { "name": "twitch-vod-manager", - "version": "4.0.6", + "version": "4.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twitch-vod-manager", - "version": "4.0.6", + "version": "4.0.7", "license": "MIT", "dependencies": { "axios": "^1.6.0", diff --git a/typescript-version/package.json b/typescript-version/package.json index be59de4..ef9bfd1 100644 --- a/typescript-version/package.json +++ b/typescript-version/package.json @@ -1,6 +1,6 @@ { "name": "twitch-vod-manager", - "version": "4.0.6", + "version": "4.0.7", "description": "Twitch VOD Manager - Download Twitch VODs easily", "main": "dist/main.js", "author": "xRangerDE", @@ -9,10 +9,12 @@ "build": "tsc", "start": "npm run build && electron .", "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", "pack": "npm run build && electron-builder --dir", "dist": "npm run build && electron-builder", - "dist:win": "npm run build && electron-builder --win" + "dist:win": "npm run test:e2e:release && electron-builder --win" }, "dependencies": { "axios": "^1.6.0", diff --git a/typescript-version/scripts/smoke-test-template-guide.js b/typescript-version/scripts/smoke-test-template-guide.js new file mode 100644 index 0000000..716a71b --- /dev/null +++ b/typescript-version/scripts/smoke-test-template-guide.js @@ -0,0 +1,146 @@ +const { _electron: electron } = require('playwright'); + +async function run() { + const electronPath = require('electron'); + const app = await electron.launch({ + executablePath: electronPath, + args: ['.'], + cwd: process.cwd() + }); + + const win = await app.firstWindow(); + const issues = []; + const failures = []; + + win.on('pageerror', (err) => { + issues.push(`pageerror: ${String(err)}`); + }); + + win.on('console', (msg) => { + if (msg.type() === 'error') { + issues.push(`console.error: ${msg.text()}`); + } + }); + + const fail = (message) => failures.push(message); + + let settingsPreview = ''; + let variableRows = 0; + let clipPreviewBefore = ''; + let clipPreviewAfter = ''; + + try { + await win.waitForTimeout(2500); + + await win.evaluate(() => { + window.showTab('settings'); + }); + await win.waitForTimeout(200); + + await win.click('#settingsTemplateGuideBtn'); + await win.waitForTimeout(180); + + const guideVisibleFromSettings = await win.evaluate(() => { + return document.getElementById('templateGuideModal')?.classList.contains('show') || false; + }); + + if (!guideVisibleFromSettings) { + fail('Template guide did not open from settings'); + } + + await win.fill('#templateGuideInput', '{title}_{part_padded}_{date_custom="yyyy-MM-dd"}.mp4'); + await win.waitForTimeout(160); + + settingsPreview = await win.locator('#templateGuideOutput').innerText(); + if (!settingsPreview.includes('.mp4')) { + fail('Settings template preview missing .mp4 output'); + } + if (settingsPreview.includes('{title}') || settingsPreview.includes('{part_padded}') || settingsPreview.includes('{date_custom=')) { + fail('Settings template preview did not replace placeholders'); + } + + variableRows = await win.locator('#templateGuideBody tr').count(); + if (variableRows < 12) { + fail(`Template variable table too short (${variableRows})`); + } + + await win.click('#templateGuideUseParts'); + await win.waitForTimeout(150); + const partsContext = await win.locator('#templateGuideContext').innerText(); + if (!/part|teil/i.test(partsContext)) { + fail('Template guide parts context text missing'); + } + + await win.click('#templateGuideCloseBtn'); + await win.waitForTimeout(100); + + await win.evaluate(async () => { + window.showTab('vods'); + await window.selectStreamer('xrohat'); + }); + await win.waitForTimeout(3200); + + const clipButtons = win.locator('.vod-card .vod-btn.secondary'); + const clipCount = await clipButtons.count(); + if (clipCount < 1) { + fail('No clip buttons found in VOD list'); + } else { + await clipButtons.first().click(); + await win.waitForTimeout(260); + + await win.locator('input[name="filenameFormat"][value="template"]').check(); + await win.waitForTimeout(140); + + await win.click('#clipTemplateGuideBtn'); + await win.waitForTimeout(140); + + const clipContext = await win.locator('#templateGuideContext').innerText(); + if (!/clip/i.test(clipContext)) { + fail('Template guide clip context text missing'); + } + + await win.fill('#templateGuideInput', '{trim_start}_{part}.mp4'); + await win.waitForTimeout(120); + clipPreviewBefore = await win.locator('#templateGuideOutput').innerText(); + + await win.fill('#clipStartTime', '00:00:10'); + await win.evaluate(() => { + window.updateFromInput('start'); + }); + await win.waitForTimeout(240); + + clipPreviewAfter = await win.locator('#templateGuideOutput').innerText(); + if (clipPreviewAfter === clipPreviewBefore) { + fail('Clip template guide preview did not react to clip start time changes'); + } + + await win.click('#templateGuideCloseBtn'); + await win.evaluate(() => { + window.closeClipDialog(); + }); + } + } finally { + await app.close(); + } + + const summary = { + failures, + issues, + checks: { + settingsPreview, + variableRows, + clipPreviewBefore, + clipPreviewAfter + } + }; + + console.log(JSON.stringify(summary, null, 2)); + + const hasFailure = failures.length > 0 || issues.length > 0; + process.exit(hasFailure ? 1 : 0); +} + +run().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/typescript-version/src/index.html b/typescript-version/src/index.html index e4b4e61..ad1a32f 100644 --- a/typescript-version/src/index.html +++ b/typescript-version/src/index.html @@ -428,7 +428,7 @@

Updates

-

Version: v4.0.6

+

Version: v4.0.7

@@ -460,7 +460,7 @@
Nicht verbunden - v4.0.6 + v4.0.7 diff --git a/typescript-version/src/main.ts b/typescript-version/src/main.ts index e94af7b..ff31263 100644 --- a/typescript-version/src/main.ts +++ b/typescript-version/src/main.ts @@ -8,7 +8,7 @@ import { autoUpdater } from 'electron-updater'; // ========================================== // CONFIG & CONSTANTS // ========================================== -const APP_VERSION = '4.0.6'; +const APP_VERSION = '4.0.7'; const UPDATE_CHECK_URL = 'http://24-music.de/version.json'; // Paths