API-Referenz (kuratiert)
Die meistgenutzten Exports von @meintest/cc-testframework, plus die Self-Healing-Writeback- und Custom-Step-Ergänzungen. Für die vollständige Export-Liste siehe die TypeScript-Deklarationen im Paket unter pm/node_modules/@meintest/cc-testframework/dist/*.d.ts.
← Zurück zur Übersicht · 🇬🇧 English · ← Konzepte · Self-Healing →
Konventionen
- Alle async-Funktionen geben
Promise<void>zurück, sofern nicht anders vermerkt. - Alle UI-suchenden Funktionen nehmen ein view-name + view-type Präfix, um den Lookup zu skopen (z.B.
'Login', 'dialog'sucht Elemente in einem Dialog mit Titel “Login”). - Alle TestStep-Level-Helfer loggen ihre Aktion in den Test-Step-Report — du musst kein manuelles Logging hinzufügen.
1. Action
Low-Level-Aktions-Primitives: Clicks, Fills, Hovers, Scrolls, Navigation.
import { Action } from '@meintest/cc-testframework';
await Action.click(locator, 'Submit-Button');
await Action.fill(locator, 'jane@example.com', 'Email-Feld');
await Action.hover(locator, 'Menü-Item');
await Action.scroll(page, 500);
Wann direkt nutzen: in Step_*.ts-Dateien, nachdem ein Control den Locator aufgelöst hat. Nicht aus TestCases aufrufen — dort TestSteps verwenden.
2. Check
Assertion-Primitives für Labels, URLs, Element-Existenz, Dialog-Zustände.
import { Check } from '@meintest/cc-testframework';
await Check.label_ByXpath_IsEqual(page, './/h1', 'Welcome');
await Check.label_ByXpath_Contains(page, './/p', 'Erfolgreich angelegt');
await Check.urlContains(page, '/dashboard');
await Check.elementExists(page, '#user-menu');
Jeder Check wirft einen aussagekräftigen Error bei Nichtübereinstimmung (Playwright-Standard-expect()-Semantik, mit framework-freundlichen Fehlermeldungen).
3. Step
Block-Strukturen und Step-Level-Orchestrierung.
import { Step } from '@meintest/cc-testframework';
Step.setCurrentTestCaseName('TC_UserCreation');
await Step.numberedStepBlock('Login', async () => {
// Inhalt wird zu nummerierten Kind-Steps im Test-Report
});
await Step.logParam('username', 'jane@example.com');
numberedStepBlock ist der verbindliche Gruppierungs-Mechanismus — jeder TestCase wickelt seine Arbeit in numberedStepBlocks ein, damit der Test-Report eine lesbare Struktur zeigt.
4. baseConfig
Ein PlaywrightTestConfig-Objekt, das du in die playwright.config.ts deines Projekts spreadest. Enthält Framework-Defaults, die sich zwischen Projekten nicht ändern.
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
import { baseConfig } from '@meintest/cc-testframework';
export default defineConfig({
...baseConfig,
timeout: 300000,
testDir: './3_Cases',
use: {
...baseConfig.use,
baseURL: 'https://<deine-app>',
headless: false,
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
],
});
Was drin ist: fullyParallel, forbidOnly, retries, workers, reportSlowTests, reporter und use.{ignoreHTTPSErrors, acceptDownloads, screenshot, trace, video}. Nicht drin: alles Projekt-spezifische (testDir, baseURL, projects, headless, slowMo, globalSetup).
reporter enthält immer ['html']. Zusätzlich enthält es bedingt SelfHealingWritebackReporter, automatisch angehängt, sobald SELF_HEALING_WRITEBACK oder SELF_HEALING_WRITEBACK_DISCOVERY in der Umgebung auf true gesetzt ist, in dem Moment, in dem diese Datei lädt — siehe Self-Healing Locators — Setup. Ein Projekt, das reporter in seiner eigenen Config überschreibt (statt baseConfig.reporter zu spreaden), muss den Reporter selbst ergänzen, wenn es ihn nutzen will.
5. SearchEngine
Locator-Strategien mit hierarchischem Fallback.
import { SearchEngine } from '@meintest/cc-testframework';
const locator = await SearchEngine.findLocators(page, {
view: { name: 'Login', type: 'dialog' },
element: { tag: 'button', text: 'Sign in' },
});
Die SearchEngine handhabt Edge-Cases: Elemente in iframes, Shadow DOM, Multi-Match-Disambiguation, Retry-on-not-yet-rendered. Aus Control-Dateien heraus nutzen statt page.locator() direkt — du bekommst die Framework-Robustheit gratis.
6. AppReady
Page/Browser-Lifecycle-Helfer.
import { AppReady } from '@meintest/cc-testframework';
await AppReady.waitForPageLoad(page, { timeout: 30000 });
await AppReady.waitForNetworkIdle(page);
Nützlich in TestSteps, die sicherstellen müssen, dass die Anwendung fertig geladen ist, bevor interagiert wird. Reduziert Flakiness von “Click war zu früh”-Szenarien.
7. Filesystem / I_Filesystem
File-I/O-Utilities. Der Filesystem-Export ist intern; der I_Filesystem-Export ist das Public-Interface für TestSteps.
import { I_Filesystem } from '@meintest/cc-testframework';
const content = await I_Filesystem.readFile('./data/users.csv');
await I_Filesystem.writeFile('./output/result.json', JSON.stringify(data));
8. Logger
Strukturiertes Logging, integriert mit dem Test-Report.
import { Logger } from '@meintest/cc-testframework';
Logger.info('Starte Test-Setup');
Logger.warn('Falle auf zweite Selector-Strategie zurück');
Logger.error('Element nach Retries nicht gefunden');
Output erscheint sowohl in der Konsole als auch in den per-Test-Artefakten. Statt console.log für jegliche test-relevante Meldungen verwenden.
9. I_PasswordManager
Passwort-Abruf — nützlich für Tests, die Credentials brauchen, ohne sie hart zu codieren.
import { I_PasswordManager } from '@meintest/cc-testframework';
const password = await I_PasswordManager.TS_GetPassword('TestUser');
Die Implementierung liest aus einem konfigurierten Secret-Store (Env-Vars, Keystore oder verschlüsselte Datei — je nach Setup). Niemals das Ergebnis loggen.
10. I_Utils
Misc-Utilities — Datums-Formatierung, Random-IDs, etc.
import { I_Utils } from '@meintest/cc-testframework';
const timestamp = I_Utils.GetDate('ssms'); // → "20260603143015123"
const dateStr = I_Utils.GetDate('iso'); // → "2026-06-03"
const randomId = I_Utils.GenerateRandomId(8); // → "kP9xQ2bA"
Datums-Formatierung ist besonders nützlich für eindeutige Email-Adressen in Registrierungs-Tests: ${user}${I_Utils.GetDate('ssms')}@mailinator.com.
11. Self-Healing-Exports (Core.xpath, SelfHealingWritebackReporter, withCoordinatedWrite)
Locator-Reparatur-Infrastruktur — siehe Self-Healing Locators für die vollständige Setup-Anleitung, dieser Abschnitt listet nur die Exports selbst.
import { xpath, SelfHealingWritebackReporter, withCoordinatedWrite, getProjectConfig, resolveSelfHealingConfig, PROJECT_CONFIG_FILE_NAME, setTestCaseId, getTestCaseId } from '@meintest/cc-testframework';
import type { WritebackResult, WriteResult, ProjectConfig, SelfHealingResolution } from '@meintest/cc-testframework';
// In einem Control — einen Locator taggen, damit er writeback-fähig wird
Core.xpath`(//*[@ControlType='ControlType.DataItem'])[${rowIndex}]`;
// Am Anfang einer TC_*.spec.ts-Datei — dem TestCase eine stabile, umbenennungssichere ID geben
Core.setTestCaseId('tc_<dein-szenario>');
Core.setTestCaseId(uid: string): void— setzt eine stabile, dateisystem-sichere ID für den aktuellen TestCase, über die dessen Referenz-Asset-Ordner (7_Assets/<uid>/) unabhängig vom Playwright-Test-Titel referenziert wird. Empfohlenes Slug-Format:tc_[a-z0-9-]{4,}. Siehe Self-Healing Locators — Einem TestCase eine stabile ID geben für wann/wo der Aufruf erfolgt und die vollständige Pfadauflösungs- und Migrations-Geschichte.Core.getTestCaseId(): string | null— liest die übersetTestCaseIdgesetzte ID des aktuellen TestCase zurück;null, wenn keine gesetzt wurde.Core.xpath— ein Tagged-Template-Literal. Erzeugt exakt denselben String wie ein äquivalentes rohes Template-Literal; der Tag erlaubt dem Framework zusätzlich, den Locator bis zu seiner Datei:Zeile zurückzuverfolgen für Self-Healing. Rein additiv — ungetaggte Locators funktionieren unverändert weiter.SelfHealingWritebackReporter— eine Playwright-Reporter-Klasse, die du imreporter-Array deinerplaywright.config.tsregistrierst — oder diebaseConfigautomatisch für dich registriert, sobaldSELF_HEALING_WRITEBACK/_DISCOVERYgesetzt ist (siehe Sektion 4). Läuft einmalig am Ende des Test-Laufs und persistiert erfolgreiche Heilungen in ihre jeweiligen Control-Dateien (Opt-in viaSELF_HEALING_WRITEBACK=true, als Umgebungs-Variable oder über die persistierte Config-Datei). Leitet ihre Schreibzugriffe überwithCoordinatedWrite(siehe unten), sodass sie nie mit einem Kollegen kollidiert, der dieselbe Datei bearbeitet — siehe Self-Healing Locators — Multi-User-Koordination. Auch erreichbar über den dedizierten Sub-Pfad-Export@meintest/cc-testframework/reporter/self-healing-writeback(sowohl ein benannter als auch ein Default-Export, beide zur selben Klasse aufgelöst) für ein Projekt mit eigenemreporter[]-Array, das nicht das komplette Paket-Barrel importiert — siehe Self-Healing Locators — Den Reporter manuell registrieren. Der ältere, wildcard-abgeleitete Pfad@meintest/cc-testframework/Reporter/SelfHealingWritebackReporter(großgeschrieben) löst für bestehende Configs weiterhin auf; der kleingeschriebene Sub-Pfad oben ist ab jetzt die kanonische Form.WritebackResult(nur Typ) — die Form eines einzelnen Writeback-Ergebnisses (pro geheiltem Locator: angewendet vs. übersprungen, und warum); exportiert für fortgeschrittenes Tooling, das den Writeback-Schritt programmatisch umschließt oder inspiziert. Die meisten Kunden brauchen nur die JSON-Report-Datei (.self-healing-report.json), nicht diesen Typ direkt.withCoordinatedWrite(files, writeFn)— ein wiederverwendbarer Koordinations-Wrapper: führtwriteFnunter einem Git-basierten Lock aus, sodass gleichzeitige Schreibzugriffe auf dieselben getrackten Dateien (von einem Kollegen, einem anderen CI-Job oder anderem Code, der auf derselben Funktion aufbaut) nie einen Merge-Konflikt erzeugen. In Projekten ohneorigin-Remote degradiert er zu einem Overhead-freien No-op. Die meisten Kunden rufen das nie direkt auf —SelfHealingWritebackReporternutzt es bereits intern —, aber es ist exportiert für Teams, die eigenes Agent-gesteuertes Schreib-Tooling auf dem Framework aufbauen.WriteResult(nur Typ) — die Rückgabe-Form vonwithCoordinatedWrite:status('applied' | 'skipped' | 'partial' | 'error'),mode('local-only' | 'coordinated'), die ListefilesWritten, und — bei einem Skip —lockedFilesmit Owner und Erwerbszeitpunkt jedes blockierenden Locks.getProjectConfig(startDir?)— liest und validiert die projekt-lokale Config-Datei.cc-testframework.local.json(aufwärts gesucht abstartDir, Defaultprocess.cwd()). Liefertnullbei fehlender Datei, ungültigem JSON, nicht unterstützterschemaVersion, oder wenn kein Repo-Root gefunden wurde — wirft nie. Die meisten Kunden nutzen dafür die CLInpx cc-testframework config self-healing <action>(siehe Self-Healing Locators — Setup dauerhaft speichern) statt das direkt aufzurufen.resolveSelfHealingConfig()— merged die Umgebungs-VariablenSELF_HEALING_WRITEBACK/SELF_HEALING_WRITEBACK_DISCOVERY/SELF_HEALING_AGENT_IDENTITYmit demselfHealing-Block der Config-Datei zu einerSelfHealingResolution, nach derselben Priority-Chain (Env-Var vor Config-Datei vor Default), die auch Credential Management (Abschnitt “Priority-Chain für die automatische Auflösung”) befolgt.PROJECT_CONFIG_FILE_NAME— der wörtliche Dateiname.cc-testframework.local.json, exportiert, damit Tooling ihn nicht hardcoden muss.ProjectConfig(nur Typ) — die On-Disk-Form:schemaVersion: 1, optionalselfHealing: { enabled?, discoveryMode?, agentIdentity? }.SelfHealingResolution(nur Typ) — das gemergte Ergebnis:enabled,discoveryMode,agentIdentity: string | null, plus einsource-Objekt, das für jeden der drei Werte benennt, welche Stufe ('env' | 'config' | 'default') ihn geliefert hat.
12. Custom-Step-Exports (discoverCustomSteps, validateCustomStep, runAuthoringAgent, runAuthorCli, runAuthorTestRunner)
Konvention, Discovery, Validierung, automatisierte Implementierung und der Test-Case-getriebene Runtime-Authoring-Loop für Steps ohne bisherige automatisierte Implementierung — siehe Custom Steps für die vollständige Authoring-Anleitung, dieser Abschnitt listet nur die Exports selbst.
import {
discoverCustomSteps, validateCustomStep, runAuthoringAgent, AnthropicElementFinderClient,
runAuthorCli, runAuthorTestRunner, classifyFailure, synthesizeCustomStepFromFailure,
} from '@meintest/cc-testframework';
import type {
CustomSpec, CustomStepDiscovery, ValidationResult,
AuthoringAgentOptions, AuthoringProgressEvent, AuthoringResult,
AppliedStep, SkippedStep, ErrorStep,
IElementFinderClient, ElementFinderResult, GeneratedImplementation,
AuthorCliOptions, AuthorCliResult,
AuthorTestRunnerOptions, AuthorTestResult, AuthorTestProgressEvent, TestRunResult,
FixContext, FixResult, IterationRecord, FixRecord,
FailureClassification, FailureKind,
} from '@meintest/cc-testframework';
const discoveries = await discoverCustomSteps(path.join(process.cwd(), 'tests'));
const result = validateCustomStep(discoveries[0]);
const authoringResult = await runAuthoringAgent({
rootDir: path.join(process.cwd(), 'tests'),
treeDigest: myLiveTreeDigest,
});
const cliResult = await runAuthorCli({ app: 'DemoApp', batchMode: true }); // bootet die App selbst, kein treeDigest nötig
const testResult = await runAuthorTestRunner({ testPath: 'pm/3_Cases/TC_<DeinAblauf>.spec.ts' });
discoverCustomSteps(rootDir)— durchsucht<rootDir>/2_Apps/*/2_Steps/*.tsnachTS_*-Exports mit@custom-JSDoc-Block und liefert pro Step eineCustomStepDiscovery, in Datei-Reihenfolge. Liefert ein leeres Array, wenn2_Appsnicht existiert. Doppelte@step-IDs über Dateien hinweg werden als Warnung geloggt, beide werden trotzdem zurückgegeben.validateCustomStep(discovery)— prüft eine einzelneCustomStepDiscoveryauf gängige Authoring-Fehler und liefert einValidationResultmit getrenntenerrors- (blockierend) undwarnings-Arrays (informativ).CustomSpec(nur Typ) — der geparste@custom-JSDoc-Block:description,intent('check' | 'action'), optionaltarget({ view, section, control, label }), optionalproperty/operator/expected, sowie die erforderlichestepId.CustomStepDiscovery(nur Typ) — ein entdeckter Step:file,stepName,line, das geparstespecsowieisNotImplemented(true, solange der Body noch den “not yet automated”-Platzhalter wirft).ValidationResult(nur Typ) —isValid,warnings: string[],errors: string[].runAuthoringAgent(options)— entdeckt, validiert und implementiert (pro Step, wo das Vertrauen es zulässt) Custom Steps anhand eines übergebenen UI-Baum-Digests. Siehe Custom Steps — Automatisierte Implementierung für das vollständige Setup, die Konfigurations-Env-Vars und die Skip-Reason-Tabelle.AnthropicElementFinderClient— die Standard-IElementFinderClient-Implementierung, die die Anthropic-API aufruft (BYOK viaANTHROPIC_API_KEY, Modell-Override viaAI_VISION_MODELodernpx cc-testframework set-ai-vision-model <model>). Die meisten Kunden konstruieren das nie direkt —runAuthoringAgenttut das intern, sofern du nicht über erweiterte Optionen einen eigenen Client übergibst.AuthoringAgentOptions(nur Typ) —rootDir,treeDigest, optionaldryRun/maxSteps/onProgress/anthropicApiKey.AuthoringProgressEvent(nur Typ) — eine gestreamte Progress-Benachrichtigung:phase('discover' | 'validate' | 'infer' | 'generate' | 'write' | 'done'), optionalstep,message, optionaldetail.AuthoringResult(nur Typ) — der Rückgabewert vonrunAuthoringAgent:schemaVersion: 1,runTimestamp,mode('applied' | 'dry-run'),totalDiscovered,applied: AppliedStep[],skipped: SkippedStep[],errors: ErrorStep[], optionalcommitSha, optionallockedByHumans.AppliedStep/SkippedStep/ErrorStep(nur Typ) — je ein Eintrag inAuthoringResult.applied/.skipped/.errors; siehe Custom Steps (Abschnitt “Warum ein Step übersprungen wird”) für die vollständige Aufzählung vonSkippedStep.reason.IElementFinderClient/ElementFinderResult(nur Typ) — der austauschbare Vision-Client-Contract hinterAnthropicElementFinderClient, für Teams mit eigenem Element-Finding-Backend.GeneratedImplementation(nur Typ) — die Form, die der interne Code-Generator vonrunAuthoringAgenterzeugt, bevor sie in den Body eines Custom Steps geschrieben wird; exportiert für fortgeschrittenes Tooling, das eine generierte Implementierung vor dem Anwenden inspizieren will.runAuthorCli(options)— die Logik hinternpx cc-testframework author, exportiert für Teams, die sie programmatisch aufrufen wollen statt über die Shell. Läuft in einem von zwei sich gegenseitig ausschließenden Modi, je nachdem welche Option gesetzt ist — Runtime (options.testPath, delegiert anrunAuthorTestRunner) oder Batch (options.batchMode: true+options.app, löst die Runtime-Strategie der App auf, startet eine Session, erfasst das UI-Baum-Digest, ruftrunAuthoringAgentauf, persistiert das Ergebnis als JSON und schließt die Session). Siehe Custom Steps — Der Agent als Kommandozeilen-Befehl für den vollständigen CLI-Contract (Optionen, Umgebungs-Variablen, Exit-Codes) beider Modi.AuthorCliOptions(nur Typ) —app(nur erforderlich beibatchMode: true),testPath(erforderlich für Runtime-Modus) /batchMode, optionalmaxIterations/maxAttemptsPerStep(Runtime-Modus), optionaltestsRoot/appsConfig/maxSteps(Batch-Modus), plusdryRun/reportPath/anthropicApiKeygemeinsam für beide.AuthorCliResult(nur Typ) —exitCode(0 | 1 | 2 | 3 | 4;3nur im Batch-Modus,4der Credential-bezogene Fehler aus Sektion 13), optionalresult: AuthoringResult(Batch-Modus) odertestResult: AuthorTestResult(Runtime-Modus) — nie beide, optionalerror(nur beiexitCode: 2gesetzt).runAuthorTestRunner(options)— der Runtime-Authoring-Loop: führtoptions.testPathiterativ als frischen Playwright-Subprozess pro Versuch aus, klassifiziert jeden Fehlschlag (classifyFailure) und ruft, für die drei behebbaren Kategorien, den Authoring-Agenten auf, bis der Test-Case besteht oder ein nicht behebbarer Fehler bzw. ein Circuit-Breaker greift. Persistiert einenAuthorTestResult-JSON-Report und gibt ihn immer zurück (wirft nicht bei einem behebbaren, aber fehlgeschlagenen Lauf). Siehe Custom Steps — Runtime-Modus.AuthorTestRunnerOptions(nur Typ) —testPath(erforderlich), optionalprojectRoot/maxIterations/maxAttemptsPerStep/dryRun/reportPath/anthropicApiKey/onProgress.AuthorTestResult(nur Typ) —schemaVersion: 1,runTimestamp,mode('runtime' | 'runtime-dry-run'),testPath,finalStatus('passed' | 'failed-non-fixable' | 'stuck-in-loop' | 'max-iterations-reached' | 'credential-error'),totalIterations,iterations: IterationRecord[],fixes: FixRecord[],commitShas: string[], optionalcredentialIssues: CredentialIssueRecord[]— gesetzt, wennfinalStatus === 'credential-error'(Credential-bezogene Einträge), und/oder immer dann, wenn die Null-Treffer-Guard während eines sonst normalen Laufs ausgelöst hat (kind: 'playwright-0-tests') — prüfe dieses Array auch nach einem scheinbarenfinalStatus: 'passed'. Siehe Sektion 13.AuthorTestProgressEvent(nur Typ) — ein gestreamtes Loop-Ereignis:phase('test-run' | 'test-pass' | 'test-fail' | 'classify' | 'fix-attempt' | 'fix-applied' | 'fix-failed' | 'stuck' | 'real-fail' | 'done' | 'credential-expired' | 'credential-expiring-soon' | 'credential-missing' | 'credential-invalid' | 'interactive-prompt-required' | 'interactive-prompt-shown' | 'playwright-0-tests'),iteration,message, optionaldetail.TestRunResult(nur Typ) — das Ergebnis eines Playwright-Subprozess-Laufs:passed,exitCode,stdout/stderr, optional geparsterjsonReport, optional aus dessen Attachments extrahiertescreenshotPath/htmlSnapshotPath.FixContext/FixResult(nur Typ) — der Contract zwischen dem Loop und seinem Agent-Dispatch-Schritt: eineFailureClassificationplus Artefakt-Pfade rein, ein Status'applied' | 'skipped' | 'error'(plus optionalcommitSha) raus. Vor allem relevant für Teams, die einen eigenen_agentDispatcher-Test-Double oder eine eigene Dispatch-Strategie liefern.IterationRecord/FixRecord(nur Typ) — das Ergebnis einer einzelnen Loop-Iteration bzw. das kumulierte Ergebnis einer einzelnen Fix-Stelle über den gesamten Lauf — beide innerhalb vonAuthorTestResultpersistiert.classifyFailure(errorText, stackTrace?, testFileContent?)— reine, abhängigkeitsfreie Klassifizierung des Fehlertexts eines Playwright-Fehlschlags in einen von neunFailureKind-Werten (von denen nur dreifixable: truesind). Wird intern von der Standard-Verdrahtung vonrunAuthorTestRunnergenutzt; eigenständig exportiert für Teams, die eigenes Fehler-Triage-Tooling darauf aufbauen. Siehe Custom Steps — Runtime-Modus für die Bedeutung jeder behebbaren Kategorie.FailureClassification(nur Typ) —kind: FailureKind,fixable, optionalfile/line/stepName,originalError.FailureKind(nur Typ) — die neunwertige String-Union:'custom-not-implemented' | 'element-not-found-no-refid' | 'element-not-found-refid-exhausted' | 'timeout-no-refid' | 'assertion-fail' | 'runtime-error' | 'network-fail' | 'app-crash' | 'unknown'.synthesizeCustomStepFromFailure(file, line, failedXPath, failedActionText?)— baut eine synthetischeCustomStepDiscoveryfür einen bereits implementierten Step ohne@custom-Tag, damit dieselbe Authoring-Agent-Maschinerie, die Custom Steps implementiert, auch versuchen kann, einen Fix dafür zu identifizieren. Wird intern für die Klassifizierungenelement-not-found-no-refid/timeout-no-refidgenutzt; eigenständig exportiert für fortgeschrittenes Tooling.
13. Credential-Management-Exports (getCredential, setCredential, resolveCredentialWithPrompt)
Eine plattformübergreifende OS-Credential-Store-Abstraktion (Windows Credential Manager / macOS Keychain / Linux Secret Service) plus die gemeinsame Auflösungs-Logik, die von der Authoring-Agent-CLI genutzt wird — siehe Credential Management für die vollständige Setup-Anleitung (den config-CLI-Subcommand, Projekt-Scoping, Ablauf-Handling), dieser Abschnitt listet nur die Exports selbst.
import {
getCredential, setCredential, deleteCredential, listCredentials,
getCredentialEnvelope, checkCredentialStatus, detectProjectId,
normalizeGitRemoteUrl, KNOWN_CREDENTIAL_TYPES, resolveCredentialWithPrompt,
} from '@meintest/cc-testframework';
import type {
CredentialScope, CredentialTypeSpec, CredentialStore, CredentialEnvelope, CredentialStatus,
CredentialSource, ResolvedCredential, CredentialProgressPhase,
CredentialResolverProgressEvent, CredentialResolverOptions, CredentialIssueRecord,
} from '@meintest/cc-testframework';
const key = await getCredential('anthropic-api-key');
await setCredential('github-token', myFreshToken, { source: 'oauth-device', expiresAt: '2026-07-15T18:00:00Z' });
const status = await checkCredentialStatus('anthropic-api-key');
if (status.expired) { /* neu authentifizieren und einen frischen Wert setzen */ }
getCredential(name, options?)— liest den rohen Wert einer Zugangsdaten aus dem OS-Store (erst der projekt-gescopte Eintrag, dann der global-gescopte, je nach Default-Scope des Typs). Liefertnull, wenn nichts gespeichert ist oder der OS-Store auf dieser Maschine nicht verfügbar ist — wirft nie für “nicht vorhanden”.setCredential(name, value, options?)— validiert den Wert gegen die Format-Regel des Credential-Typs und speichert ihn als JSON-Envelope.optionsakzeptiertproject/scope/expiresAt/source. Wirft, wenn ein projekt-gescopter Typ keinen auflösbaren Projekt-Kontext hat (nicht innerhalb eines Git-Repositorys mitorigin-Remote) und keiner explizit übergeben wurde.deleteCredential(name, options?)— entfernt eine gespeicherte Zugangsdaten. Lieferttrue, wenn tatsächlich ein Eintrag gelöscht wurde,falsebei einem No-op (nichts war dort).listCredentials()— listet jede gespeicherte Zugangsdaten als{ name, scope, projectId? }-Tupel, unabhängig davon, obnameein aktuell bekannter Credential-Typ ist.getCredentialEnvelope(name, options?)— wiegetCredential, liefert aber das vollständigeCredentialEnvelope(Wert plus Ablauf-/Source-Metadaten) statt nur den Wert.checkCredentialStatus(name, options?)— prüft Existenz und Ablauf, ohne den Wert offenzulegen — sicher zu loggen oder in einen Report aufzunehmen. Liefert einCredentialStatus.detectProjectId(cwd?)— löst die Id des aktuellen Projekts ausgit config --get remote.origin.urlauf, normalisiert übernormalizeGitRemoteUrl. Liefertnullaußerhalb eines Git-Repositorys oder ohneorigin-Remote — wirft nie.normalizeGitRemoteUrl(url)— normalisiert eine SSH-/HTTPS-/git://-Remote-URL in die stabile<host>/<owner>/<repo>-Form, die als Projekt-Scoping-Key genutzt wird.KNOWN_CREDENTIAL_TYPES— die statische Registry der zwei Credential-Typen, die das Framework heute kennt (anthropic-api-key,github-token), jeweils einCredentialTypeSpec. Siehe Credential Management — Bekannte Credential-Typen.CredentialScope(nur Typ) —'global' | 'project'.CredentialTypeSpec(nur Typ) —name,defaultScope,description, optionalenvVar, optionalvalidate(value).CredentialStore(nur Typ) — der{ get, set, delete, list }-Contract, den ein eigener Backing-Store implementieren müsste; die meisten Kunden brauchen das nie, existiert für fortgeschrittenes Tooling/Tests.CredentialEnvelope(nur Typ) — die On-Disk-Form: erforderlichesv(der Wert), optionalexp(ISO-8601-Ablauf),src(informativer Source-Tag),meta(für künftige Erweiterungen reserviert).CredentialStatus(nur Typ) —exists, optionalexpired/expiresAt/secondsUntilExpiry/withinGracePeriod, optionalsource/scope/projectId.resolveCredentialWithPrompt(name, options?)— die 5-stufige Priority-Chain, beschrieben in Credential Management (Abschnitt “Priority-Chain für die automatische Auflösung”): expliziter CLI-Arg-Wert, Env-Var, OS-Store (projekt-gescoped), OS-Store (global-gescoped), dann ein interaktiver First-Run-Prompt (nur TTY). Liefertnull, wenn nirgends etwas aufgelöst werden konnte, auch in einem Non-TTY-Kontext, wo der Prompt nicht laufen kann.CredentialSource(nur Typ) —'cli-arg' | 'env' | 'store' | 'prompt', identifiziert, aus welcher Stufe einResolvedCredentialstammt.ResolvedCredential(nur Typ) —{ value, source: CredentialSource }.CredentialProgressPhase(nur Typ) — die sechs Credential-bezogenen Progress-Phasen:'credential-expired' | 'credential-expiring-soon' | 'credential-missing' | 'credential-invalid' | 'interactive-prompt-required' | 'interactive-prompt-shown'.CredentialResolverProgressEvent(nur Typ) — ein gestreamtes Ereignis:phase: CredentialProgressPhase,credential,message, optionalexpiredAt/secondsUntilExpiry/secondsExpired/source.CredentialResolverOptions(nur Typ) — vonresolveCredentialWithPromptakzeptierte Optionen: optionalcliArgValue/project/onProgress.CredentialIssueRecord(nur Typ) — ein bemerkenswertes Problem, das inAuthorTestResult.credentialIssuesfestgehalten wird (siehe Sektion 12):kind('credential-expired' | 'credential-expiring-soon' | 'credential-missing' | 'credential-invalid' | 'interactive-prompt-required' | 'playwright-0-tests'),message, sowie je nachkindoptionale Felder —credential/expiredAt/sourcefür die Credential-bezogenen Kinds, oderpattern(der--test-Pfad/das Pattern, das null Dateien getroffen hat) für'playwright-0-tests'. Das Array dient diesem Runner als allgemeiner “bemerkenswertes Problem entdeckt”-Sammeltopf statt ein zweites, paralleles Array wachsen zu lassen.
14. Appium-URL-Bestimmung (resolveAppiumUrl)
Für eine Desktop-AUT (Windows, via Appium) löst das Framework die Appium-Server-URL intern auf, bevor eine Session eröffnet wird — dieser Export legt dieselbe Logik für fortgeschrittene Setups offen, z.B. einen eigenen Pre-Flight-Check.
import { resolveAppiumUrl } from '@meintest/cc-testframework';
import type { AppiumUrlResolutionResult } from '@meintest/cc-testframework';
const resolution = resolveAppiumUrl(myAppConfig.appiumUrl);
console.log(resolution.url, resolution.source, resolution.platform);
resolveAppiumUrl(explicitAppiumUrl?)— löst die effektive Appium-Server-URL über eine dreistufige Priority-Chain auf: der explizit übergebene Wert (dasappiumUrldeiner AUT inGlobalConfig.apps, falls gesetzt), dann die Umgebungs-VariableAPPIUM_URL, dann ein plattform-basierter Default (http://localhost:4723, wenn der Test-Prozess selbst nativ auf Windows läuft, sonsthttp://host.docker.internal:4723). Siehe FAQ — Wie findet das Framework den Appium-Server bei Desktop-Tests?.AppiumUrlResolutionResult(nur Typ) —{ url, source, platform };sourceist'explicit-config' | 'env-var' | 'platform-default'.
15. Step-Description-i18n-Kataloge (.i18n.json-Konvention + Validator)
Kein TypeScript-Export — eine Datei-Konvention plus ein eigenständiges Validator-Skript, beide vom Paket @meintest/cc-testframework-templates ausgeliefert. Jede Step-Datei <StepFile>.ts kann eine gleichnamige Sibling-Datei <StepFile>.i18n.json haben, geschlüsselt nach exportiertem Step-Funktionsnamen, die Locale-Kürzel auf übersetzte Kopien des numberedStep/description/logTitle-Texts dieses Steps abbildet:
{
"TS_Main_Button_Click": {
"en": "On Main, click button '${label}'",
"de": "Auf 'Main', Schaltfläche '${label}' klicken"
}
}
Jeder Locale-Eintrag muss exakt dieselben ${paramName}-Platzhalter enthalten wie der en-Eintrag — die Quelle der Wahrheit des Katalogs. Ein fehlender Katalog, oder eine fehlende Locale darin, fällt auf Englisch zurück — das ist der normale Nicht-Fehler-Fall.
Aus pm/ heraus (sobald @meintest/cc-testframework-templates dort als Dev-Dependency installiert ist):
node ./node_modules/@meintest/cc-testframework-templates/bin/validate-i18n.js <Pfad>
Validiert die in jeder Step-Datei referenzierten KEYs gegen ihren Sibling-.i18n.json-Katalog: Jeder referenzierte KEY braucht einen en-Eintrag (fehlt er ganz, ist das ein Fehler; ein nicht referenzierter Katalog-Schlüssel ist eine Warnung), und jede andere Locale’s Platzhalter-Menge muss exakt mit der von en übereinstimmen. Exit-Code 0 bei Erfolg (auch “keine Kataloge gefunden” und reine Warnungs-Befunde), 1 bei jedem Fehler-Befund, mit einer nach Datei/Schlüssel/Locale aufgeschlüsselten Fehlerliste. Siehe Step-Description Localization für die vollständige Konvention, ein durchgerechnetes Beispiel und wie ein programmatischer Consumer den lokalisierten Text rendert.
Core.i18n — Laufzeit-Lokalisierungs-API
Anders als die Datei-Konvention oben ist Core.i18n ein echter TypeScript-Export — die Ausführung des Frameworks selbst liest ihn, um zu lokalisieren, was es selbst rendert (Playwrights Reports, Konsolen-Ausgabe, den Self-Healing-Writeback-Report). Siehe Laufzeit-Lokalisierung für die vollständige Prioritätskette und das Verhalten.
import { i18n } from '@meintest/cc-testframework';
import type { SupportedLocale, TranslateOptions } from '@meintest/cc-testframework';
i18n.setLocale('de');
i18n.getLocale(); // 'de'
const text = i18n.t('TS_Main_Button_Click', { label: 'Save' });
Core.i18n.getLocale(): SupportedLocale— löst die effektive Locale über die Prioritätskette auf:Core.i18n.setLocale(...)-Override, dann die UmgebungsvariableCC_TESTFRAMEWORK_LOCALE, dannGlobalConfig.language, dann der Standard'en'.Core.i18n.setLocale(locale: SupportedLocale): void— setzt einen expliziten In-Process-Override, vor allem für Tests oder eine einmalige Laufzeit-Umschaltung; gewinnt gegen die Umgebungsvariable undGlobalConfig.language.Core.i18n.t(key: string, values?: Record<string, unknown>, options?: TranslateOptions): string— löstkeygegen den Sibling-.i18n.json-Katalog der aufrufenden Step-Datei auf (automatisch aus dem Call-Stack erkannt, oder explizit viaoptions.callerFile) und ersetzt jeden invaluesgefundenen${paramName}-Platzhalter.options.fallbackist optional und wird NUR verwendet, wenn für den Aufrufer gar kein Katalog zu erwarten ist — z.B. zur Laufzeit generierte Custom-Steps (sieheTS_Custom.tsfür das kanonische Muster). Nach der Standard-Konvention ist deren-Eintrag des Sibling-Katalogs die Quelle der Wahrheit, undfallbacksollte weggelassen werden; fehlen für einen Schlüssel sowohl Katalog als auchfallback, loggtt()einmal pro fehlendem Schlüssel eine Warnung und gibt den rohenkeyliteral zurück. Wirft nie.SupportedLocale(nur Typ) —'de' | 'en'.TranslateOptions(nur Typ) —{ callerFile?: string; fallback?: string }.fallbackist ein Custom-Step-only-Notausgang — siehe Wann fallback verwenden.
Core.defineTestStep und Core.defineExecutionStep akzeptieren ein optionales descriptionI18n-Feld als Alternative zu logTitle/description — { key, values(...args), fallback?(...args) } (typisiert als TestStepDescriptionI18nSpec / ExecutionStepDescriptionI18nSpec). fallback ist optional und, wie TranslateOptions.fallback oben, ein Custom-Step-only-Notausgang — ein Factory-basierter Step mit Katalog lässt es weg und verlässt sich stattdessen auf den en-Eintrag des Katalogs. Siehe Neue Steps mit i18n ausstatten für durchgerechnete Beispiele beider Formen — Factory-basiert und direkter t()-Aufruf.
16. Core.defineExecutionStep
App-Lifecycle-Steps. Baut aus einer deklarativen Factory einen tester-facing TS_Execution_<Action>-Step (Browser-Start/-Close/-Restart/-Navigate bei einer Web-AUT, Prozess-Start/-Close bei einer Desktop-AUT), ohne eine Playwright-page oder eine hartcodierte URL von Hand zu verdrahten. Siehe Deinen ersten TestCase schreiben — Step-Naming-Konvention dafür, wo das in die Gesamt-Namenskonvention passt.
import * as Core from '@meintest/cc-testframework';
export const TS_Execution_Start = Core.defineExecutionStep(
'MyApp',
'Start',
(env) => ({
descriptionI18n: {
key: 'TS_Execution_Start',
values: () => ({ url: env.url }),
},
run: () => Core.I_BrowserHandler.start(env.page, env.url, { waitForReady: true }),
}),
);
defineExecutionStep(appName, action, factory)—appNameist der Schlüssel der App inGlobalConfig.apps, nicht Teil des Namens der generierten Funktion (der bleibtTS_Execution_Start, nichtTS_MyApp_Execution_Start— siehe Deinen ersten TestCase schreiben für das Warum); er sagt dem Framework, aus welchem App-Eintragenvaufzulösen ist.actionist ein Freiform-Label ('Start','Close','Restart','NavigateTo', …), das zur Lesbarkeit in die Identität der generierten Funktion einfließt — das Framework interpretiert den Wert nicht.factory(env)bekommt einenv-Objekt, das das Framework für dich zusammenstellt — ausGlobalConfig.apps[appName]— kein manuellespage-/url-/Playwright-Fixture-Verdrahten in deiner Step-Datei.
Family-aware env-Form, aufgelöst aus dem passenden GlobalConfig.apps[appName]-Eintrag:
| App-Family | env-Felder |
|---|---|
| Web (Playwright) | page: Core.Page, url: string, appConfig: WebPlaywrightAppConfig |
| Desktop (Appium-Windows) | executable: string, appiumUrl: string, appConfig: DesktopAppiumWindowsAppConfig |
env.appConfig ist der vollständige, family-typisierte App-Eintrag aus GlobalConfig.apps[appName] — greif darauf zu, wenn ein Step ein Feld braucht, das die beiden Formen oben nicht direkt zeigen.
Warum die env-basierte Form: sie erlaubt es der UI eines Test-Management-Tools — oder einem Tester ohne TypeScript-Erfahrung —, einen App-Lifecycle-Step für eine gegebene App zu scaffolden, ohne je page, eine Playwright-Fixture oder eine hartcodierte URL zu tippen; das Framework löst das alles aus dem eigenen GlobalConfig-Eintrag der App auf. Siehe Custom Steps — Was ist ein Custom Step? dafür, wie sich das von einem handgeschriebenen oder Agent-generierten Custom Step unterscheidet.
Abwärtskompatibilität: die ältere 2-Argument-Form funktioniert unverändert weiter:
export const TS_Execution_Start = Core.defineExecutionStep(
'MyApp',
(page, url) => ({
description: `Start browser and navigate to '${url}'`,
run: () => Core.I_BrowserHandler.start(page, url, { waitForReady: true }),
}),
);
Dieser Aufruf funktioniert weiterhin genau wie zuvor und gibt einmalig pro Call-Site eine Deprecation-Warnung aus (console.warn, dedupliziert nach Aufrufer-Datei:Zeile), die zur Migration auf die env-basierte Form rät — keine funktionale Änderung, kein erzwungenes Umschreiben.
17. Debug-Session-Exports (resolveDebugSession, runSessionCli)
Infrastruktur für die persistente Debug-Session — siehe Persistente Debug-Session fürs vollständige Setup, dieser Abschnitt listet nur die Exports selbst.
import { resolveDebugSession, runSessionCli } from '@meintest/cc-testframework';
import type { DebugSessionResolution, SessionCliDeps, SessionCliResult } from '@meintest/cc-testframework';
resolveDebugSession()— führt die Umgebungs-VariableCC_DEBUG_SESSIONmit demdebugSession-Schlüssel der Config-Datei zu einerDebugSessionResolutionzusammen, nach derselben Umgebungs-Variable-vor-Config-Datei-vor-Default-Prioritäts-Kette wieresolveSelfHealingConfigoben. Die meisten Kunden rufen das nie direkt auf — es treibt die eigene Attach-oder-Start-Entscheidung des Frameworks beim Start des Test-Runners.DebugSessionResolution(nur Typ) — das zusammengeführte Ergebnis:enabled: booleanplussource: 'env' | 'config' | 'default'.runSessionCli(argv, deps)— die Implementierung hinternpx cc-testframework session status/close(siehe Persistente Debug-Session — Die Session per CLI verwalten). Exportiert für fortgeschrittenes Tooling, das dieselbe Status-/Close-Logik programmatisch ansteuern will; die meisten Kunden nutzen direkt die CLI.SessionCliDeps(nur Typ) — die injizierbare Dependency-Oberfläche, dierunSessionClientgegennimmt (Zustand lesen/löschen, Endpoint-Erreichbarkeits-Check, Prozess-Terminierung, Ausgabe-Senken); nur relevant, wennrunSessionClidirekt aufgerufen wird.SessionCliResult(nur Typ) —{ exitCode: number }, das Ergebnis einesrunSessionCli-Aufrufs.
Re-Exports zur Bequemlichkeit
Das Framework re-exportiert auch gängige Playwright- und Node-Teile, damit du keine separaten Imports in deinen Test-Dateien brauchst:
import { test, expect, fs, path, moment, pdfParse, csvParser, authenticator, crypto }
from '@meintest/cc-testframework';
Heißt: ein typischer TestCase hat eine Import-Zeile — @GlobalRef (dein Barrel) — und alles ist via Project.Core.* und Project.<DeineApp>.* verfügbar.
Vollständige Oberfläche entdecken
Wenn du einen Export brauchst, der oben nicht aufgeführt ist: die TypeScript-Deklarationen unter pm/node_modules/@meintest/cc-testframework/dist/References.d.ts sind die maßgebliche Liste. Deine IDE (VS Code, WebStorm, etc.) wird von dort auto-vervollständigen.
📧 Brauchst du eine Funktion, die’s nicht gibt? Vorschlag per jens.szelag@itsbusiness.ch.
itsbusiness AG · Bern · Schweiz