From 1d97e0500052bcb166853fd276648886e9618a36 Mon Sep 17 00:00:00 2001 From: elpatron Date: Wed, 1 Oct 2025 13:39:12 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Google=20Apps=20Script=20f=C3=BCr=20aut?= =?UTF-8?q?omatische=20Test-Formular-Erstellung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Automatische Generierung eines Google Forms aus der Test-Checkliste - ~180 Checkbox-Items über 14 Sections - Testergebnis-Bereich mit Fehlerberichten und Gesamtbewertung - Kein API-Key erforderlich - läuft direkt im Google Account - Schritt-für-Schritt-Anleitung im Code-Kommentar - Exportierbar nach Google Sheets - Mehrfach verwendbar für verschiedene Test-Runden --- docs/google-apps-script-test-form.js | 422 +++++++++++++++++++++++++++ 1 file changed, 422 insertions(+) create mode 100644 docs/google-apps-script-test-form.js diff --git a/docs/google-apps-script-test-form.js b/docs/google-apps-script-test-form.js new file mode 100644 index 0000000..abb15b4 --- /dev/null +++ b/docs/google-apps-script-test-form.js @@ -0,0 +1,422 @@ +/** + * Google Apps Script zur automatischen Erstellung eines Test-Formulars + * für die Kunden-Statusseite + * + * ANLEITUNG: + * 1. Öffne https://script.google.com/ + * 2. Klicke auf "Neues Projekt" + * 3. Kopiere diesen Code in den Editor + * 4. Klicke auf "Ausführen" (Play-Button) → Funktion "createTestForm" + * 5. Erlaube die benötigten Berechtigungen + * 6. Nach Ausführung wird die URL des erstellten Formulars in den Logs angezeigt + * 7. Öffne die URL oder finde das Formular in Google Drive + */ + +function createTestForm() { + // Erstelle neues Formular + const form = FormApp.create('Test-Checkliste: Kunden-Statusseite'); + + // Formular-Einstellungen + form.setDescription('Blackbox-Tests für das Feature "Token-basierte Buchungsübersicht"\n\nBranch: Statusseite\nDatum: 2025-10-01'); + form.setConfirmationMessage('Vielen Dank! Die Testergebnisse wurden gespeichert.'); + form.setAllowResponseEdits(true); + form.setShowLinkToRespondAgain(false); + + // Sammle E-Mail-Adressen + form.setCollectEmail(true); + + // === VORBEREITUNG === + addSection(form, 'Vorbereitung', 'Stelle sicher, dass die Testumgebung bereit ist'); + addCheckboxes(form, [ + 'Entwicklungsserver läuft (pnpm dev)', + 'E-Mail-Service konfiguriert (RESEND_API_KEY gesetzt)', + 'Admin-Account verfügbar', + 'Testbehandlungen vorhanden', + 'Verfügbare Slots erstellt' + ]); + + // === 1. BUCHUNGSERSTELLUNG & TOKEN-GENERIERUNG === + addSection(form, '1. Buchungserstellung & Token-Generierung', 'Teste die Token-Erstellung bei neuen Buchungen'); + + addParagraph(form, '1.1 Neue Buchung (Status: pending)'); + addCheckboxes(form, [ + 'Buchung über Formular erstellen', + 'Pending-E-Mail erhalten', + 'Status-Link (/booking/{token}) in E-Mail vorhanden', + 'Button "Status ansehen" vorhanden und korrekt verlinkt', + 'Link funktioniert beim Klick' + ]); + + addParagraph(form, '1.2 Token-Validierung'); + addCheckboxes(form, [ + 'Gültiger Token öffnet Statusseite', + 'Ungültiger Token zeigt Fehlermeldung', + 'Abgelaufener Token zeigt entsprechende Meldung', + 'Token ohne Parameter zeigt Fehler' + ]); + + // === 2. STATUSSEITE UI/UX === + addSection(form, '2. Statusseite UI/UX (Allgemein)', 'Teste das generelle Layout und Design'); + + addParagraph(form, '2.1 Layout & Design'); + addCheckboxes(form, [ + 'Logo wird angezeigt', + 'Seite ist responsive (Desktop, Tablet, Mobile)', + 'Alle Texte sind auf Deutsch', + 'Farben entsprechen dem Branding (Pink/Purple)', + '"Zurück zur Startseite" Link funktioniert' + ]); + + addParagraph(form, '2.2 Navigation'); + addCheckboxes(form, [ + 'Link zur Startseite funktioniert', + 'Browser-Zurück-Button funktioniert korrekt', + 'URL ist teilbar (Copy & Paste)' + ]); + + // === 3. STATUS: PENDING === + addSection(form, '3. Status: Pending', 'Teste den Status "Wartet auf Bestätigung"'); + + addParagraph(form, '3.1 Anzeige'); + addCheckboxes(form, [ + 'Status-Badge zeigt "⏳ Wartet auf Bestätigung" (gelb)', + 'Banner mit gelber Hintergrundfarbe', + 'Text erklärt, dass Termin geprüft wird', + 'Datum im Format dd.mm.yyyy', + 'Uhrzeit wird angezeigt', + 'Behandlung wird angezeigt', + 'Dauer in Minuten wird angezeigt', + 'Preis wird angezeigt (wenn > 0)', + 'Kundenname wird angezeigt', + 'E-Mail wird angezeigt', + 'Telefon wird angezeigt', + 'Notizen werden angezeigt (falls vorhanden)' + ]); + + addParagraph(form, '3.2 Stornierung'); + addCheckboxes(form, [ + 'Stornierungsbereich ist NICHT sichtbar', + 'Keine Stornierungsbuttons vorhanden' + ]); + + // === 4. STATUS: CONFIRMED === + addSection(form, '4. Status: Confirmed', 'Teste den Status "Bestätigt"'); + + addParagraph(form, '4.1 Statuswechsel'); + addCheckboxes(form, [ + 'Admin bestätigt Buchung', + 'Confirmed-E-Mail wird versendet', + 'E-Mail enthält "Termin verwalten" Button', + 'Link in E-Mail zeigt auf /booking/{token}', + 'ICS-Datei ist im E-Mail-Anhang', + 'AGB-PDF ist im E-Mail-Anhang' + ]); + + addParagraph(form, '4.2 Anzeige'); + addCheckboxes(form, [ + 'Status-Badge zeigt "✓ Bestätigt" (grün)', + 'Banner mit grüner Hintergrundfarbe', + 'Text bestätigt den Termin', + '"Verbleibende Zeit" wird angezeigt', + 'Stunden bis zum Termin korrekt berechnet' + ]); + + addParagraph(form, '4.3 Stornierung (wenn möglich)'); + addCheckboxes(form, [ + 'Stornierungsbereich ist sichtbar', + 'Hinweistext zur Stornierungsfrist angezeigt', + 'Button "Termin stornieren" vorhanden', + 'Klick zeigt Bestätigungsdialog', + 'Dialog enthält Warnhinweis in rot', + 'Dialog hat "Ja, stornieren" Button', + 'Dialog hat "Abbrechen" Button', + '"Abbrechen" schließt Dialog ohne Aktion', + '"Ja, stornieren" führt Stornierung durch', + 'Nach Stornierung: Erfolgsmeldung angezeigt', + 'Nach Stornierung: Status aktualisiert' + ]); + + addParagraph(form, '4.4 Stornierung (nicht mehr möglich)'); + addCheckboxes(form, [ + 'Termin < 24h: Kein Stornierungsbutton', + 'Gelber Hinweiskasten wird angezeigt', + 'Text erklärt abgelaufene Frist', + 'Kontakthinweis wird angezeigt' + ]); + + // === 5. STATUS: CANCELLED === + addSection(form, '5. Status: Cancelled', 'Teste den Status "Storniert"'); + + addParagraph(form, '5.1 Nach Stornierung'); + addCheckboxes(form, [ + 'Status-Badge zeigt "✕ Storniert" (rot)', + 'Banner mit roter Hintergrundfarbe', + 'Text erklärt Stornierung', + 'Hinweis auf Neubuchung vorhanden', + 'Stornierungsbereich nicht mehr sichtbar' + ]); + + addParagraph(form, '5.2 Cancelled-E-Mail'); + addCheckboxes(form, [ + 'E-Mail wird an Kunden gesendet', + 'E-Mail enthält storniertes Datum', + 'E-Mail enthält Hinweis auf Neubuchung' + ]); + + // === 6. STATUS: COMPLETED === + addSection(form, '6. Status: Completed', 'Teste den Status "Abgeschlossen"'); + addCheckboxes(form, [ + 'Status-Badge zeigt "✓ Abgeschlossen" (grau)', + 'Banner mit grauer Hintergrundfarbe', + 'Dankestext wird angezeigt', + 'Stornierungsbereich nicht sichtbar', + 'Alle Termin-Details bleiben sichtbar' + ]); + + // === 7. E-MAIL-INTEGRATION === + addSection(form, '7. E-Mail-Integration', 'Teste alle E-Mail-Typen'); + + addParagraph(form, '7.1 Pending-Mail'); + addCheckboxes(form, [ + 'Betreff: "Deine Terminanfrage ist eingegangen"', + 'Orangefarbener "Status ansehen" Button', + 'Link funktioniert', + 'Text erklärt folgende Bestätigung', + 'Rechtliche Informationen enthalten' + ]); + + addParagraph(form, '7.2 Confirmed-Mail'); + addCheckboxes(form, [ + 'Betreff: "Dein Termin wurde bestätigt - AGB im Anhang"', + 'Pinker "Termin ansehen & verwalten" Button', + 'Link zeigt auf /booking/{token}', + 'ICS-Datei im Anhang: "Termin_Stargirlnails.ics"', + 'ICS-Datei kann in Kalender importiert werden', + 'AGB-PDF im Anhang: "AGB_Stargirlnails_Kiel.pdf"' + ]); + + addParagraph(form, '7.3 Cancelled-Mail'); + addCheckboxes(form, [ + 'Betreff: "Dein Termin wurde abgesagt"', + 'Text erklärt Stornierung', + 'Hinweis auf Neubuchung', + 'Rechtliche Informationen enthalten' + ]); + + // === 8. ICS-KALENDEREINTRÄGE === + addSection(form, '8. ICS-Kalendereinträge', 'Teste die Kalenderdatei-Funktionalität'); + + addParagraph(form, '8.1 ICS-Datei Inhalt'); + addCheckboxes(form, [ + 'Zeitzone: Europe/Berlin', + 'Startzeit korrekt', + 'Endzeit korrekt (Start + Behandlungsdauer)', + 'Titel: "{Behandlung} - Stargirlnails Kiel"', + 'Location: "Stargirlnails Kiel"', + 'Beschreibung enthalten', + '24h-Erinnerung konfiguriert' + ]); + + addParagraph(form, '8.2 Kalender-Import'); + addCheckboxes(form, [ + 'Import in Kalender-App funktioniert', + 'Termin erscheint mit korrekter Zeit', + 'Erinnerung wird ausgelöst' + ]); + + // === 9. STORNIERUNGSLOGIK === + addSection(form, '9. Stornierungslogik', 'Teste die Stornierungsregeln'); + + addParagraph(form, '9.1 Zeitbasierte Validierung'); + addCheckboxes(form, [ + 'Termin > 24h: Stornierung möglich', + 'Termin < 24h: Stornierung nicht möglich', + 'Termin in Vergangenheit: nicht möglich', + 'Verbleibende Stunden korrekt berechnet' + ]); + + addParagraph(form, '9.2 Statusbasierte Validierung'); + addCheckboxes(form, [ + 'Status "pending": Keine Stornierung', + 'Status "confirmed": Stornierung möglich (wenn Zeit OK)', + 'Status "cancelled": Keine Stornierung', + 'Status "completed": Keine Stornierung' + ]); + + addParagraph(form, '9.3 Stornierungsablauf'); + addCheckboxes(form, [ + 'Bestätigungsdialog erscheint', + 'Loading-Spinner während Stornierung', + 'Erfolgsmeldung nach Stornierung', + 'Fehlermeldung bei Fehler', + 'Token bleibt nach Stornierung gültig', + 'Slot wird wieder freigegeben', + 'Status aktualisiert sich' + ]); + + // === 10. FEHLERBEHANDLUNG === + addSection(form, '10. Fehlerbehandlung', 'Teste das Fehler-Handling'); + + addParagraph(form, '10.1 Ungültige Token'); + addCheckboxes(form, [ + 'Nicht existierender Token: Fehlermeldung', + 'Abgelaufener Token: Fehlermeldung', + 'Leerer Token: Fehlermeldung', + 'Fehlermeldung benutzerfreundlich auf Deutsch' + ]); + + addParagraph(form, '10.2 Netzwerkfehler'); + addCheckboxes(form, [ + 'API nicht erreichbar: Fehlermeldung', + 'Timeout: Fehlermeldung', + 'Fehler während Stornierung: Meldung bleibt sichtbar' + ]); + + // === 11. PERFORMANCE === + addSection(form, '11. Performance & Ladezeiten', 'Teste Performance-Aspekte'); + addCheckboxes(form, [ + 'Statusseite lädt in < 2 Sekunden', + 'Keine sichtbaren Layout-Shifts', + 'Loading-Spinner während Laden', + 'Bilder optimiert geladen', + 'Keine JavaScript-Fehler in Console' + ]); + + // === 12. ACCESSIBILITY & BROWSER === + addSection(form, '12. Accessibility & Browser-Kompatibilität', 'Teste Zugänglichkeit und Browser'); + + addParagraph(form, '12.1 Accessibility'); + addCheckboxes(form, [ + 'Buttons mit Tastatur erreichbar', + 'Fokus-Indikatoren sichtbar', + 'Farbkontraste ausreichend (WCAG AA)', + 'Alt-Texte für Bilder vorhanden' + ]); + + addParagraph(form, '12.2 Browser-Kompatibilität'); + addCheckboxes(form, [ + 'Chrome (aktuell): Funktioniert', + 'Firefox (aktuell): Funktioniert', + 'Edge (aktuell): Funktioniert', + 'Mobile Browser: Funktioniert' + ]); + + addParagraph(form, '12.3 Responsive Design'); + addCheckboxes(form, [ + 'Desktop (>1024px): Layout korrekt', + 'Tablet (768-1024px): Layout korrekt', + 'Mobile (320-767px): Layout korrekt', + 'Touch-Targets ausreichend groß (≥44x44px)' + ]); + + // === 13. SICHERHEIT === + addSection(form, '13. Sicherheit', 'Teste Sicherheitsaspekte'); + + addParagraph(form, '13.1 Token-Sicherheit'); + addCheckboxes(form, [ + 'Token ausreichend lang (UUID)', + 'Token nicht vorhersagbar', + 'Token läuft nach 30 Tagen ab', + 'Abgelaufene Token werden abgelehnt' + ]); + + addParagraph(form, '13.2 Datenschutz'); + addCheckboxes(form, [ + 'Keine sensiblen Daten in URLs (außer Token)', + 'Keine Kundendaten in Browser-Console', + 'E-Mail-Adressen geschützt', + 'Telefonnummern geschützt' + ]); + + // === 14. EDGE CASES === + addSection(form, '14. Edge Cases', 'Teste Sonderfälle und Extremwerte'); + + addParagraph(form, '14.1 Extremwerte'); + addCheckboxes(form, [ + 'Sehr lange Behandlungsnamen korrekt dargestellt', + 'Sehr lange Notizen korrekt dargestellt', + 'Sehr hohe Preise korrekt formatiert', + 'Termin > 30 Tage: Token-Ablauf korrekt' + ]); + + addParagraph(form, '14.2 Sonderfälle'); + addCheckboxes(form, [ + 'Termin heute 23:59: Frist korrekt', + 'Sommerzeit/Winterzeit-Wechsel: Korrekt', + 'Mehrere Buchungen desselben Kunden: Eigene Tokens', + 'Gleichzeitiger Zugriff: Kein Konflikt' + ]); + + // === TESTERGEBNISSE === + addSection(form, 'Testergebnisse & Bewertung', 'Dokumentiere deine Testergebnisse'); + + form.addTextItem() + .setTitle('Getestet von (Name)') + .setRequired(true); + + form.addDateItem() + .setTitle('Test-Datum') + .setRequired(true); + + form.addTextItem() + .setTitle('Browser/Gerät (z.B. "Chrome 120 auf Windows 11")'); + + form.addParagraphTextItem() + .setTitle('Kritische Fehler (Blocker)') + .setHelpText('Beschreibe kritische Fehler, die ein Release verhindern würden'); + + form.addParagraphTextItem() + .setTitle('Mittelschwere Fehler') + .setHelpText('Beschreibe Fehler, die behoben werden sollten'); + + form.addParagraphTextItem() + .setTitle('Kleinere Probleme') + .setHelpText('Beschreibe kleinere Verbesserungsvorschläge'); + + form.addMultipleChoiceItem() + .setTitle('Gesamtbewertung') + .setChoiceValues([ + '✅ Alle Tests bestanden - Release-fähig', + '⚠️ Tests bestanden mit kleineren Problemen', + '❌ Kritische Fehler gefunden - Nachbesserung erforderlich' + ]) + .setRequired(true); + + form.addParagraphTextItem() + .setTitle('Zusätzliche Notizen') + .setHelpText('Weitere Beobachtungen und Anmerkungen'); + + // === FORMULAR ABSCHLUSS === + Logger.log('✅ Formular erfolgreich erstellt!'); + Logger.log('📋 Titel: ' + form.getTitle()); + Logger.log('🔗 URL: ' + form.getPublishedUrl()); + Logger.log('📝 Editor-URL: ' + form.getEditUrl()); + Logger.log(''); + Logger.log('👉 Öffne das Formular in deinem Browser:'); + Logger.log(form.getPublishedUrl()); + + return form; +} + +// === HILFSFUNKTIONEN === + +function addSection(form, title, description) { + form.addPageBreakItem() + .setTitle(title) + .setHelpText(description); +} + +function addParagraph(form, text) { + form.addSectionHeaderItem() + .setTitle(text); +} + +function addCheckboxes(form, items) { + items.forEach(item => { + form.addCheckboxItem() + .setTitle(item) + .setChoiceValues(['✓']) + .showOtherOption(false); + }); +} +