From c0efd56c9c3ac5c33df5e98f6f28da0812c8e52e Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 11 Mar 2026 16:37:08 +0100 Subject: [PATCH] feat(clickTtPlayerRegistrationService): add debug HTML file generation for error diagnostics - Introduced a new function to generate a timestamped HTML file containing the page content during error handling, improving diagnostics for failed registration attempts. - Enhanced error reporting to include the path to the generated HTML file, providing better context for troubleshooting issues in the registration flow. --- .../clickTtPlayerRegistrationService.js | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/backend/services/clickTtPlayerRegistrationService.js b/backend/services/clickTtPlayerRegistrationService.js index 0cf2bb56..c0e8e712 100644 --- a/backend/services/clickTtPlayerRegistrationService.js +++ b/backend/services/clickTtPlayerRegistrationService.js @@ -1,4 +1,5 @@ import { chromium } from 'playwright'; +import { writeFile } from 'fs/promises'; import Member from '../models/Member.js'; import Club from '../models/Club.js'; import ClickTtAccount from '../models/ClickTtAccount.js'; @@ -35,6 +36,11 @@ function escapeRegExp(value) { return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } +function buildDebugHtmlPath() { + const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); + return `/tmp/clicktt-debug-${timestamp}.html`; +} + class ClickTtPlayerRegistrationService { async submitExistingPlayerApplication({ userToken, userId, clubId, memberId }) { await checkAccess(userToken, clubId); @@ -135,10 +141,17 @@ class ClickTtPlayerRegistrationService { } catch (error) { let diagnostics = {}; try { + const html = await page?.content?.(); + const htmlPath = html ? buildDebugHtmlPath() : null; + if (html && htmlPath) { + await writeFile(htmlPath, html, 'utf8'); + } + diagnostics = { url: page?.url?.() || null, text: sanitizePageText(await page?.locator?.('body')?.innerText?.()), - traceTail: trace.slice(-25) + traceTail: trace.slice(-25), + htmlPath }; } catch (_err) { diagnostics = {}; @@ -146,13 +159,15 @@ class ClickTtPlayerRegistrationService { this._trace(trace, 'error', { message: error?.message || String(error), - url: diagnostics.url || null + url: diagnostics.url || null, + htmlPath: diagnostics.htmlPath || null }); const message = error instanceof HttpError ? error.message : `Click-TT-Automatisierung fehlgeschlagen: ${error.message || error}`; - const wrappedError = new HttpError(`${message}${diagnostics.url ? ` (Seite: ${diagnostics.url})` : ''}${diagnostics.text ? ` - ${diagnostics.text}` : ''}`, error.statusCode || error.status || 500); + const wrappedError = new HttpError(`${message}${diagnostics.url ? ` (Seite: ${diagnostics.url})` : ''}${diagnostics.htmlPath ? ` (HTML: ${diagnostics.htmlPath})` : ''}${diagnostics.text ? ` - ${diagnostics.text}` : ''}`, error.statusCode || error.status || 500); wrappedError.trace = diagnostics.traceTail || []; + wrappedError.htmlPath = diagnostics.htmlPath || null; throw wrappedError; } finally { if (context) {