Tests & Konfiguration
CodeMole wählt die passenden Checks pro Repo automatisch — und du kannst alles per .codemole.yml überschreiben. Hier steht, welche Checks es gibt, was sie tun und wie du sie steuerst.
01Wie Tests gewählt werden
Für jeden PR löst CodeMole die Checks in drei Stufen auf — die erste, die greift, gewinnt:
1. .codemole.yml im Repo? → exakt das nutzen (versioniert, pro Branch/PR)
2. sonst: Repo-Analyse → Profil automatisch erkennen
3. immer, für alle → secret-scan + conflict-markers + sensitive-files + ai-review
Im Report-Kopf steht transparent, was gewählt wurde:
## 🧪 CodeMole — automations.yaml
Profil: ha-config · automatisch erkannt · ⚙ überschreibbar
02Auto-Erkennung
Ohne .codemole.yml bestimmt CodeMole das Profil über Marker-Dateien im Repo — deterministisch, kein Raten:
| Marker im Repo | Profil |
|---|---|
configuration.yaml / automations.yaml | ha-config |
manifest.json + custom_components/ | ha-component |
blocks/ + package.json (EDS) | aem-eds |
| nichts davon | generic |
profile: in der .codemole.yml — dann entfällt die Erkennung.03Profile
Ein Profil ist nur ein benanntes Bündel Checks. universell läuft zusätzlich immer mit.
| Profil | Checks |
|---|---|
ha-config | yamllintha-validateincludessecret-refsduplicate-idsautomation-safetyentity-existsdiff-size |
ha-component | python-syntaxruffmanifesthacstranslationsjson-validdiff-size |
aem-eds | file-guardpr-vollständigkeitjs-lintcss-lintplaceholder-keysunit-testsvisual-testsmerge-freshnessstatic-scans |
generic | diff-size |
| universell | secret-scanconflict-markerssensitive-filesai-review |
aem-eds ist besonders: das Profil läuft über einen spezialisierten Node-Runner — die 9 Checks oben sind dessen fester Umfang, zusätzlich steuerbar über testing-rules.json im Repo. disable/ignore aus der .codemole.yml gelten trotzdem. Dazu optional (alle Profile): page-audit lighthouse — siehe Katalog.04Check-Katalog
Jeder Check ist ein eigenständiger Baustein. Kurzüberblick unten — die ausführliche Check-Referenz erklärt jeden Check mit Beispiel-Finding und Fix (die Check-Namen in PR-Reports verlinken direkt dorthin):
entity-exists, automation-safety, yamllint) und ai-review posten ihre Funde zeilengenau als Inline-Kommentare am Diff; im Report steht dann nur ein Kurz-Zähler. Checks ohne feste Zeile erscheinen als Zusammenfassung im Report. Auf jeden Inline-Kommentar kannst du antworten — der Bot erklärt oder räumt ein und schließt den Thread (siehe Mit dem Bot reden).🔍 ai-review
Ein LLM (aktuell Claude) liest den Diff gegen deine echten Projekt-Konventionen und findet Logik-Bugs, die kein Linter sieht. Postet zeilengenaue Inline-Kommentare.
from: 'on' ergänzen."🛡️ secret-scan
Sucht Klartext-Secrets im Diff (Passwörter, API-Keys, Tokens). Schlägt fehl, sobald etwas durchrutscht.
const.py."📏 yamllint
yamllint nur auf den geänderten Zeilen, mit HA-tauglichen Regeln — keine tausenden Vorbestand-Warnungen.
✅ ha-validate
Validiert die HA-Konfiguration mit einem aktuellen HA-Core (2026.x) — Zwei-Pass: Base und Branch werden geprüft, gemeldet werden nur neue Fehler (Umgebungs-Bestandsfehler wie „Unknown device" zählen nicht), inkl. konkreter Fehlerzeilen im Report.
🔗 includes
Prüft Änderungen an !include-Strukturen auf gebrochene Referenzen.
⏰ automation-safety
HA-Automations-Fallen in geänderten Zeilen: State-Trigger mit to: ohne from: (feuert beim HA-Neustart, unavailable→on) und device_id: statt entity_id:.
to: ohne from: — feuert beim HA-Neustart."🆔 entity-exists opt-in
Prüft referenzierte entity_ids in neuen Zeilen live gegen die HA-Instanz — fängt Tippfehler, die häufigste Fehlerklasse. Aktivierung: ha_url + verschlüsselter ha_token in der .codemole.yml (Secrets-Tool).
binary_sensor.flur_obenn existiert nicht in der HA-Instanz."🔐 secret-refs / ♊ duplicate-ids
Gebrochene !secret-Referenzen gegen secrets.yaml; doppelte Automation-id/alias (überschreiben sich sonst still).
!secret wifi_pw2 nicht definiert." / „id doppelt vergeben."🐍 python-syntax / ruff
Kompilier-Check + Ruff-Lint auf geänderten Python-Dateien — Style + häufige Fehler.
requests.get im async-Loop."🧾 json-valid / 🪢 conflict-markers / 🗂️ sensitive-files
Geänderte JSON-Dateien müssen parsen; übrig gebliebene Git-Konflikt-Marker; Warnung bei sensiblen Dateien im PR (.env, Keys, .storage …).
automations.yaml:88."📦 manifest / hacs
Prüft manifest.json-Pflichtfelder und hacs.json fürs HACS-Listing.
manifest.json: version fehlt."🌐 translations
Stellt sicher, dass die Pflicht-Sprache en.json existiert.
en.json fehlt — keine Pflicht-Sprache."🧹 js-lint / css-lint aem-eds
ESLint + Stylelint auf den geänderten Dateien (EDS-Regelwerk).
.js-Endung."🧩 static-scans aem-eds
Framework-Imports (React/Vue/jQuery), outline:none (WCAG), JS-Bundle-Zuwachs und Token-Compliance (hardcodierte Hex/rgba-Farben statt var(--…) in neuen CSS-Zeilen).
teaser.css: color: #e30613."🛟 file-guard / merge-freshness / pr-vollständigkeit aem-eds
Gelöschte/geleerte Dateien, Branch-Rückstand zur Base, Pflicht-Abschnitte in der PR-Beschreibung.
wcms-2777-tokens (bitte rebasen)."📊 diff-size
Meldet Umfang des Diffs (Zeilen/Dateien) — Orientierung für Reviewer, warnt bei XXL-PRs.
🖼️ visual-tests aem-eds
Visuelle Regression pro Block gegen committete Baselines (Playwright) — Anlegen: siehe unten.
button→teaser-xl)."🔎 page-audit opt-in
Rendert konfigurierte Seiten auf Base- und Branch-Preview und prüft mit axe-core (WCAG 2.1 A/AA + Best Practice: Kontrast, Semantik, Landmarks, Labels) — gemeldet werden nur neue Findings. Timing (DCL/Load/KB) informativ. Aktivierung: page-audit: in der .codemole.yml.
button-name (critical): 3 Element(e) — Buttons must have discernible text."⚡ lighthouse on-demand
Voller Lighthouse-Score-Vergleich (Performance/A11y/Best-Practices/SEO + LCP/CLS) Base↔Branch. Langsam (Minuten) — läuft nicht bei jedem Push, sondern nur, wenn du das Label lighthouse an den PR hängst.
05Konfiguration: .codemole.yml
Leg die Datei ins Repo-Root (oder unter .github/). Sie ist optional — ohne sie greift die Auto-Erkennung. Vollständiges Beispiel mit allen Möglichkeiten:
# Sprache der Bot-Ausgaben erzwingen (sonst automatisch aus PR-Titel/-Text erkannt)
lang: en # de | en
# Profil erzwingen (überschreibt die Auto-Erkennung)
profile: ha-config # ha-config | ha-component | aem-eds | generic
# ODER Checks explizit wählen (statt profile):
# checks: [yamllint, secret-scan, ai-review]
disable: [diff-size] # einzelne Checks ausschalten
ignore: # Pfade global ausnehmen (glob)
- "**/*.generated.yaml"
- "vendor/**"
# Per-Check-Optionen:
yamllint:
changed-lines-only: true
ai-review:
focus: "native HA-Trigger statt Jinja, entity_id statt device_id"
severity: major # nur major-Findings posten (major | minor)
# page-audit aktivieren (Frontend-Repos mit Branch-Previews; {branch} wird ersetzt):
page-audit:
base_url: "https://{branch}--mein-site--meine-org.aem.page"
pages: ["/de/de/", "/de/de/products/"] # max. 5 Seiten; gilt auch für Lighthouse (Label)
.codemole.yml geprüft. Kein zentrales Setting, kein Drift.🔐 Secrets sicher hinterlegen (z. B. HA-Token für entity-exists)
Manche Checks brauchen ein Secret — z. B. prüft entity-exists Entity-IDs live gegen deine Home-Assistant-Instanz und braucht dafür einen Long-Lived Access Token (HA: Profil → Sicherheit → Token erstellen). Secrets gehören nie im Klartext ins Repo. Deshalb: hier im Browser verschlüsseln (nichts verlässt deinen Browser — WebCrypto gegen den CodeMole-Public-Key) und den Blob in die .codemole.yml legen. Nur der CodeMole-Server kann ihn entschlüsseln.
entity-exists:
ha_url: "http://homeassistant.local:8123"
ha_token: "enc:v1:<hier den Blob aus dem Tool>"
enc:v1:-Blob zu sehen (in deiner .codemole.yml im Repo) und kann ihn nur entschlüsseln, weil er den passenden privaten Schlüssel hält.Lieber lokal per Skript? (maximale Sicherheit, kein Browser)
Wer ganz sichergehen will, verschlüsselt offline auf dem eigenen Rechner — nur openssl + der eingebettete öffentliche Schlüssel, kein Netzwerk:
# Skript laden (Klartext — vorher reinschauen!) und ausführen:
curl -O https://web.skycryer.com/codemole/encrypt-secret.sh
bash encrypt-secret.sh # fragt das Secret versteckt ab, gibt enc:v1:… aus
Das Skript ist bewusst kurz und lesbar: es ruft nur openssl pkeyutl -encrypt mit dem öffentlichen Schlüssel auf und macht keinen einzigen Netzwerk-Aufruf — du kannst es vor dem Ausführen komplett prüfen. Ergebnis 1:1 wie beim Browser-Tool. Skript ansehen →
06Überschreiben & Ausschalten
.codemole.yml + die Config des jeweiligen Tools). Du musst uns nie bitten, den CodeMole-Code für dein Projekt anzupassen.Ein Check meldet Unsinn? — so löst du's selbst
- Findings auf generierten/Vendor-Dateien (Build-Bundles, Fonts, Fixtures) → das steht in der Ignore deines Tools (
.stylelintignore,.eslintignore). CodeMole respektiert die und überstimmt sie nie — nichts zu tun. - Eine Lint-Regel ist dir zu streng (z. B.
at-rule-empty-line-before) → schalt sie in deiner Tool-Config ab (.stylelintrc,.eslintrc). CodeMole nutzt deine Config, nicht seine eigene. - Der Check ist hier grundsätzlich irrelevant →
disable: [check-name]. - Nur bestimmte Pfade nerven →
ignore: ["pfad/**"]. - Einmalige Ausnahme (aem-eds) →
testing-rules.jsonim Repo.
Profil erzwingen
Erkennung daneben? profile: setzen — dann zählt nur das.
Einzelne Checks aus
disable: [diff-size, visual] entfernt Checks aus dem aufgelösten Satz (Profil bleibt sonst gleich).
Pfade ignorieren
ignore: mit Glob-Mustern — generierte Dateien, Vendor-Code, Fixtures. Findings auf diesen Pfaden werden unterdrückt.
Sprache festlegen
Standardmäßig erkennt CodeMole die Sprache automatisch (deutscher PR → deutsche Ausgaben, englischer PR → englische). Mit lang: de bzw. lang: en in der .codemole.yml erzwingst du eine feste Sprache für alle Bot-Ausgaben (Report, Findings, Antworten) — sinnvoll bei sehr kurzen oder gemischtsprachigen PR-Texten.
Wie die Auto-Erkennung funktioniert: Ausgewertet werden PR-Titel + Beschreibung (nicht der Code-Diff — Code ist immer englisch). Eine schnelle, dependency-freie Heuristik vergibt Punkte:
de_score = deutsche Stopwörter (der/die/und/nicht/für…) + Umlaute/ß × 3
en_score = englische Stopwörter (the/and/with/for/this…)
→ "en" wenn en_score > de_score, sonst "de"
Umlaute/ß zählen dreifach, weil ein einziges „ä/ö/ü/ß" ein sehr starkes Deutsch-Signal ist. Bei Gleichstand, leerem Text oder Fehler gilt de (Fail-safe). Die Heuristik ist bewusst simpel — für kurze oder gemischte Texte lieber lang: setzen.
Komplett pausieren
checks: [] (leer) schaltet alles bis auf nichts ab — oder häng das Repo einfach aus der App-Installation aus.
.codemole.yml oder Auto) gegriffen hat — so siehst du sofort, ob deine Config angekommen ist.07Neues Repo anbinden
Für ein Repo in der eigenen Organisation ist das Onboarding ein Klick — kein Workflow, kein Webhook, kein Token:
1. App installieren → Repo anhaken → fertig, läuft beim nächsten PR
2. optional: .codemole.yml ins Repo → Profil/Checks feinsteuern (Sektion 05)
Das Profil wird automatisch erkannt (Sektion 02). Ohne passende Marker läuft generic (diff-size + universelle Checks + KI-Review) — schon das ist brauchbar.
Wann doch Hand anlegen nötig ist
| Situation | Was zu tun ist |
|---|---|
| Repo in fremder Organisation | App auf „Any account" stellen + Org in die Handler-Whitelist (ALLOWED_OWNERS) |
| Neuer Repo-Typ braucht eigene Checks | Profil in resolve-profile.py + Check-Module ergänzen (sonst: generic) |
entity-exists aktivieren | ha_url + verschlüsselter ha_token in der .codemole.yml (Secrets-Tool) — kein Server-Zugriff nötig |
page-audit/lighthouse gewünscht | nur page-audit:-Block in der .codemole.yml (Sektion 05) |
08Mit dem Bot reden
CodeMole ist kein Einweg-Reporter — er reagiert auf dich, direkt im PR:
| Du machst… | CodeMole… |
|---|---|
| Antwortest auf ein Inline-Finding im Diff | antwortet im selben Thread — verteidigt den Hinweis mit Begründung oder räumt ihn ein |
| Dein Einwand ist berechtigt | zieht den Hinweis zurück und resolved die Conversation automatisch ✔ |
Schreibst einen PR-Kommentar mit @the-codemole + Frage | beantwortet die Frage mit Kontext (PR-Beschreibung, Diff, bisheriger Verlauf) |
Hängst das Label lighthouse an den PR | fährt den vollen Lighthouse-Vergleich und postet die Score-Tabelle |
| Pushst neue Commits | aktualisiert Report & Findings (bestehende Kommentare werden geupdatet, keine Flut) |
@the-codemole) reagiert der Bot bewusst nicht — er grätscht nicht in Unterhaltungen.⚡ Lighthouse richtig einsetzen (Best Practice)
Lighthouse ist der schwere Lauf (~1–2 min pro Seite, Zwei-Pass, max. 2 Seiten) und läuft deshalb nie automatisch — nur wenn du das Label lighthouse setzt. Er läuft komplett auf unserer eigenen Infrastruktur (kein Google/PageSpeed — keine API-Limits).
Wann das Label setzen?
→ einmal, wenn der PR performance-relevant ist:
CSS-/JS-Umbau, Bild-Handling, neue Blöcke, Lazy-Loading, Fonts
Empfohlener Ablauf
1. PR fertig entwickeln (normale Checks laufen bei jedem Push mit)
2. vor dem Review/Merge: Label lighthouse setzen → Score-Tabelle abwarten
3. Verschlechterung? fixen & pushen — dann Label entfernen + neu setzen für den Re-Run
Gut zu wissen
· neue Pushes triggern Lighthouse NICHT erneut (bewusst — nur das Label zählt)
· der Ergebnis-Kommentar wird aktualisiert, nicht dupliziert
· Scores schwanken CDN-bedingt um ±2–3 Punkte — erst ab größeren Deltas reagieren
09Visual Tests einrichten
Visual-Regression heißt: CodeMole macht einen Screenshot eines Blocks und vergleicht ihn pixelgenau gegen ein gespeichertes Baseline-Bild. Weicht etwas ab, gibt's ein Finding. Technisch ist das Playwright (@playwright/test) — im JUMO-Repo bereits eingerichtet. Du legst nur pro Block eine kleine Test-Datei + ein Referenzbild an. Schritt für Schritt (auch wenn du das noch nie gemacht hast):
1 · Spec anlegen — zwei Layouts (beide gleichwertig)
CodeMole unterstützt zwei Spec-Layouts gleichberechtigt — nimm das, was im Repo schon zum jeweiligen Block passt. In beiden landen die Baselines daneben in <name>.spec.js-snapshots/.
A · Styleguide / nested — tests/visual-styleguide/<block>/
Ordner = Block-Name, Spec heißt ex-N.spec.js. Ein Einzeiler über einen Helper, kein Boilerplate — der Helper rendert die Block-Demo aus dem Pattern-Styleguide (/patterns/styleguide/#demo/<block>/<index>/…) und screenshottet sie:
// tests/visual-styleguide/contact-overlay-role/ex-0.spec.js
import { patternScreenshot } from '../_helpers/pattern-screenshot.js';
// (Block-Id, Beispiel-Index im Styleguide, Snapshot-Name)
patternScreenshot('contact-overlay-role', 0, 'ex-0');
Mehrere Varianten eines Blocks → ex-0, ex-1, … (ein Aufruf bzw. File pro Beispiel-Index).
B · Component-Page / flach — tests/visual/<block>.spec.js
Dateiname = Block-Name, voller Playwright-Spec: öffnet die echte Demo-Seite und screenshottet den Block-Wrapper. Die URL ist projektspezifisch (bei JUMO die Component-Library):
import { test, expect } from '@playwright/test';
import { getBaseUrl } from './helpers/test-setup.js';
// projektspezifische Demo-Seite; ?wcmmode=disabled blendet die AEM-Author-UI aus
const TEST_URL = `${getBaseUrl()}/de/de/components/base/teaser-xl/columns-blockquote`;
test.beforeEach(async ({ page }) => {
await page.goto(`${TEST_URL}?wcmmode=disabled`);
await page.waitForLoadState('networkidle'); // (+ Cookie-Banner wegklicken)
});
test('blockquote should match reference', async ({ page }) => {
const block = page.locator('.blockquote-wrapper').first();
await expect(block).toHaveScreenshot('blockquote.png', { maxDiffPixels: 500 });
});
2 · Baseline-Bild erzeugen (einmalig pro Spec)
Beim ersten Mal gibt es noch kein Vergleichsbild — einmal erzeugen und mitcommitten (npm-Scripts liegen schon im Repo, gilt für beide Layouts):
# Vergleich laufen: npm run test:visual
# Baselines schreiben/updaten: npm run test:visual:update
git add tests/**/*-snapshots/ # erzeugte .png-Baselines mit committen
Ohne committete Baseline kann CodeMole nichts vergleichen.
3 · Was CodeMole dann automatisch macht
- PR ändert Dateien eines Blocks → CodeMole findet dessen Spec (nested: Ordnername = Block · flach: Dateiname = Block) und führt ihn gegen die Preview-Hosts (
BASE_URL_DEV/BASE_URL_BRANCH) aus. - Screenshot weicht von der Baseline ab → Finding mit Diff-Bild. Passt alles → grün.
- Atoms (
button,text,image,link) triggern viablock-deps.jsonautomatisch die Specs aller Organisms, die sie einbetten. - Kein Spec für einen geänderten Block? → CodeMole warnt: „Kein Visual-Spec für: <block>". Dann einen anlegen (Layout A oder B).
tests/visual-styleguide/<block>/ex-0.spec.js (Einzeiler via patternScreenshot) oder tests/visual/<block>.spec.js (voller Spec) → npm run test:visual:update → die *-snapshots/-PNGs mitcommitten. Den Rest macht CodeMole.