vibe coded maxx

This commit is contained in:
2026-05-22 13:46:02 +02:00
parent 8f7f14c95b
commit 8feb88dfa6
9 changed files with 787 additions and 17 deletions
+49 -1
View File
@@ -291,6 +291,30 @@
"label": "Test Data",
"value": "Clean test tenant or lab PBX instance (recommended isolated environment)"
}
],
"fullyAutomated": true,
"implementationNotes": "Use Playwright to navigate the admin portal downloads section and locate release notes documents. Extract text and write to a local file.",
"codeSteps": [
{
"stepName": "Open admin portal or repository URL in browser context",
"actionKey": "open_admin_portal",
"params": {}
},
{
"stepName": "Navigate to the download / documentation portal",
"actionKey": "navigate_to_downloads_portal",
"params": {}
},
{
"stepName": "Search or locate the relevant file/link by filename pattern",
"actionKey": "search_for_document",
"params": { "pattern": "release-notes" }
},
{
"stepName": "Assert presence and visibility of the expected document",
"actionKey": "assert_document_visible",
"params": { "pattern": "release-notes" }
}
]
},
{
@@ -419,10 +443,34 @@
"label": "Credentials",
"value": "Admin user with sufficient privileges (portal + SSH where needed)"
},
{
{
"label": "Test Data",
"value": "Clean test tenant or lab PBX instance (recommended isolated environment)"
}
],
"fullyAutomated": true,
"implementationNotes": "Similar to release notes extraction but targets CLI command changes in the documentation.",
"codeSteps": [
{
"stepName": "Open admin portal or repository URL in browser context",
"actionKey": "open_admin_portal",
"params": {}
},
{
"stepName": "Navigate to the download / documentation portal",
"actionKey": "navigate_to_downloads_portal",
"params": {}
},
{
"stepName": "Search or locate the relevant file/link by filename pattern",
"actionKey": "search_for_document",
"params": { "pattern": "cli-configuration" }
},
{
"stepName": "Assert presence and visibility of the expected document",
"actionKey": "assert_document_visible",
"params": { "pattern": "cli-configuration" }
}
]
},
{
+170 -16
View File
@@ -66,6 +66,13 @@
<span>Generate Test Plan</span>
</button>
<!-- Export Automated Playwright Tests -->
<button onclick="exportAutomatedTests()"
class="px-4 py-2 bg-[#0b1120] text-orange-400 border border-orange-400 hover:bg-orange-900/30 rounded-lg text-sm font-semibold flex items-center gap-2">
<i class="fa-solid fa-file-code"></i>
<span>Export Automated Tests</span>
</button>
<!-- Load existing Test Plan -->
<button onclick="openLoadTestPlanModal()"
class="px-4 py-2 bg-[#0b1120] text-orange-400 border border-orange-400 hover:bg-orange-900/30 rounded-lg text-sm font-semibold flex items-center gap-2">
@@ -128,6 +135,7 @@
<button onclick="selectAllCore()" class="px-2 py-1 bg-[#1e2937] hover:bg-orange-600 rounded">All Core</button>
<button onclick="selectAllPbx()" class="px-2 py-1 bg-[#1e2937] hover:bg-orange-600 rounded">All PBX</button>
<button onclick="clearSelection()" class="px-2 py-1 bg-[#1e2937] hover:bg-red-600 rounded text-red-300">Clear</button>
<button onclick="selectOnlyFullyAutomated()" class="px-2 py-1 bg-[#1e2937] hover:bg-orange-600 rounded text-orange-300">Only Fully Automated</button>
<span class="ml-3 text-amber-300 font-medium" id="selectionCount"></span>
</div>
@@ -201,16 +209,42 @@
<ul id="listAutomatable" class="editable-list text-sm"></ul>
</div>
<!-- Not Yet -->
<div>
<div class="flex justify-between items-center mb-1.5">
<div class="section-title text-red-400">Not Automatable Yet / Manual</div>
<button onclick="addListItem('notYet')" class="text-xs px-2.5 py-0.5 bg-red-900/60 hover:bg-red-800 rounded">+ Add</button>
</div>
<ul id="listNotYet" class="editable-list text-sm"></ul>
</div>
<!-- Not Yet -->
<div>
<div class="flex justify-between items-center mb-1.5">
<div class="section-title text-red-400">Not Automatable Yet / Manual</div>
<button onclick="addListItem('notYet')" class="text-xs px-2.5 py-0.5 bg-red-900/60 hover:bg-red-800 rounded">+ Add</button>
</div>
<ul id="listNotYet" class="editable-list text-sm"></ul>
</div>
<!-- Dependencies -->
<!-- Code Generation (for automated tests) -->
<div>
<div class="section-title mb-1.5 text-orange-400">Code Generation (Automated)</div>
<div class="flex items-center gap-2 mb-2">
<input type="checkbox" id="fullyAutomated" class="w-4 h-4">
<label for="fullyAutomated" class="text-sm">Mark as <strong>fullyAutomated</strong> (ready for code generation)</label>
</div>
<div class="mb-2">
<div class="text-xs text-[#64748b] mb-1">Implementation Notes (for generator / LLM)</div>
<textarea id="implementationNotes" rows="2"
class="w-full bg-[#0f172a] border border-[#334155] rounded p-2 text-sm"
placeholder="Hints for the code generator..."></textarea>
</div>
<!-- codeSteps editor -->
<div>
<div class="flex justify-between items-center mb-1">
<div class="text-xs text-[#64748b]">Code Steps (for generator)</div>
<button onclick="addCodeStep()" class="text-xs px-2 py-0.5 bg-orange-900/60 hover:bg-orange-800 rounded">+ Add Step</button>
</div>
<div id="codeStepsContainer" class="space-y-2 text-sm"></div>
</div>
</div>
<!-- Dependencies -->
<div>
<div class="flex justify-between items-center mb-1.5">
<div class="section-title">Dependencies &amp; Prerequisites</div>
@@ -417,6 +451,15 @@
updateSelectionCount();
}
function selectOnlyFullyAutomated() {
selectedIds.clear();
allTests.forEach(t => {
if (t.fullyAutomated === true) selectedIds.add(t.id);
});
renderTable();
updateSelectionCount();
}
function clearSelection() {
selectedIds.clear();
renderTable();
@@ -485,20 +528,63 @@
if (m) m.remove();
}
async function exportAutomatedTests() {
const automatedTests = allTests.filter(t => t.fullyAutomated === true || t.status === 'automated');
if (automatedTests.length === 0) {
alert('No fully automated tests found.');
return;
}
// For now we just generate the whole group of the first selected test (simple approach)
const firstGroup = automatedTests[0]?.group;
const confirmed = confirm(`Generate automated tests for group "${firstGroup}"?\n\nFiles will be written to tests/generated/.`);
if (!confirmed) return;
try {
const res = await fetch('/api/export/automated-tests', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ group: firstGroup })
});
const data = await res.json();
if (data.success) {
alert(`✅ Automated tests generated for group "${firstGroup}".\nCheck tests/generated/ folder.\n\nPlease review before committing.`);
} else {
alert('Generation failed: ' + (data.error || 'Unknown error'));
}
} catch (e) {
alert('Error exporting automated tests: ' + e.message);
}
}
function openEditor(globalIndex) {
currentIndex = globalIndex;
currentTest = JSON.parse(JSON.stringify(allTests[globalIndex])); // deep clone
document.getElementById('modalId').textContent = currentTest.id;
document.getElementById('modalGroup').textContent = `${currentTest.group}${currentTest.file}`;
document.getElementById('modalDescription').value = currentTest.description || '';
document.getElementById('modalStatus').value = currentTest.status;
document.getElementById('modalDescription').value = currentTest.description || '';
document.getElementById('modalStatus').value = currentTest.status;
// Render lists
renderList('listSteps', currentTest.steps || []);
renderList('listAutomatable', currentTest.automatable || []);
renderList('listNotYet', currentTest.notYet || []);
renderDependencies(currentTest.dependencies || []);
// Code Generation fields (Phase 1)
const fullyAutomatedEl = document.getElementById('fullyAutomated');
fullyAutomatedEl.checked = !!currentTest.fullyAutomated;
const notesEl = document.getElementById('implementationNotes');
notesEl.value = currentTest.implementationNotes || '';
// Code Steps
renderCodeSteps(currentTest.codeSteps || []);
// Render lists
renderList('listSteps', currentTest.steps || []);
renderList('listAutomatable', currentTest.automatable || []);
renderList('listNotYet', currentTest.notYet || []);
renderDependencies(currentTest.dependencies || []);
document.getElementById('editModal').classList.remove('hidden');
document.getElementById('editModal').classList.add('flex');
@@ -571,6 +657,62 @@
renderDependencies(deps);
}
// === Code Steps Editor (for automated generation) ===
function renderCodeSteps(codeSteps = []) {
const container = document.getElementById('codeStepsContainer');
container.innerHTML = '';
codeSteps.forEach((step, index) => {
const div = document.createElement('div');
div.className = 'flex gap-2 items-center bg-[#0f172a] p-2 rounded';
const paramsValue = step.params ? JSON.stringify(step.params) : '';
div.innerHTML = `
<input placeholder="Step Name" value="${step.stepName || ''}" class="flex-1 text-xs" oninput="updateCodeStep(${index}, 'stepName', this.value)">
<input placeholder="Action Key" value="${step.actionKey || ''}" class="flex-1 text-xs" oninput="updateCodeStep(${index}, 'actionKey', this.value)">
<input placeholder='Params (JSON)' value='${paramsValue}' class="flex-1 text-xs" oninput="updateCodeStepParams(${index}, this.value)">
<button onclick="removeCodeStep(${index})" class="text-red-400 hover:text-red-500 px-1">×</button>
`;
container.appendChild(div);
});
container.dataset.codeSteps = JSON.stringify(codeSteps);
}
function updateCodeStep(index, field, value) {
const container = document.getElementById('codeStepsContainer');
const steps = JSON.parse(container.dataset.codeSteps || '[]');
if (!steps[index]) steps[index] = {};
steps[index][field] = value;
container.dataset.codeSteps = JSON.stringify(steps);
}
function updateCodeStepParams(index, value) {
const container = document.getElementById('codeStepsContainer');
const steps = JSON.parse(container.dataset.codeSteps || '[]');
if (!steps[index]) steps[index] = {};
try {
steps[index].params = value ? JSON.parse(value) : undefined;
} catch (e) {
// keep previous value if JSON is invalid
}
container.dataset.codeSteps = JSON.stringify(steps);
}
function removeCodeStep(index) {
const container = document.getElementById('codeStepsContainer');
const steps = JSON.parse(container.dataset.codeSteps || '[]');
steps.splice(index, 1);
renderCodeSteps(steps);
}
function addCodeStep() {
const container = document.getElementById('codeStepsContainer');
const steps = JSON.parse(container.dataset.codeSteps || '[]');
steps.push({ stepName: '', actionKey: '' });
renderCodeSteps(steps);
}
async function openGenerateTestPlanModal() {
if (selectedIds.size === 0) {
alert('Please select at least one test case using the checkboxes.');
@@ -650,6 +792,18 @@
currentTest.description = document.getElementById('modalDescription').value.trim();
currentTest.status = document.getElementById('modalStatus').value;
// Code Generation fields (Phase 1)
const fullyAutomatedEl = document.getElementById('fullyAutomated');
currentTest.fullyAutomated = fullyAutomatedEl.checked;
const notesEl = document.getElementById('implementationNotes');
currentTest.implementationNotes = notesEl.value.trim() || undefined;
// Code Steps
const codeStepsContainer = document.getElementById('codeStepsContainer');
currentTest.codeSteps = JSON.parse(codeStepsContainer.dataset.codeSteps || '[]')
.filter(s => s.stepName || s.actionKey);
// Collect lists
const stepsUl = document.getElementById('listSteps');
currentTest.steps = JSON.parse(stepsUl.dataset.items || '[]').filter(Boolean);
@@ -0,0 +1,29 @@
{
"_comment": "Action Catalog for generating Playwright + MCP tests from editor data.",
"_version": "0.1.0",
"_targetGroup": "core-documentation",
"actions": {
"open_admin_portal": {
"template": "await page.goto(process.env.BASE_URL ?? 'https://pbx.local:4443');"
},
"navigate_to_downloads_portal": {
"template": "await page.goto(REPO_URL);"
},
"search_for_document": {
"template": "const link = page.locator('a, li, td').filter({ hasText: /{{pattern}}/i });\nawait expect(link.first()).toBeVisible();",
"params": ["pattern"]
},
"assert_document_visible": {
"template": "const el = page.locator('a, li, td').filter({ hasText: /{{pattern}}/i });\nawait expect(el.first()).toBeVisible();",
"params": ["pattern"]
},
"extract_text_content": {
"template": "const content = await page.locator('body').innerText();\n// TODO: Parse and save the relevant section (Release Notes, Changelog, etc.)"
}
}
}
+23
View File
@@ -0,0 +1,23 @@
const fs = require('fs');
const path = require('path');
const CATALOG_PATH = path.join(__dirname, 'catalog.json');
let cachedCatalog = null;
function loadActionCatalog(forceReload = false) {
if (cachedCatalog && !forceReload) {
return cachedCatalog;
}
const raw = fs.readFileSync(CATALOG_PATH, 'utf-8');
cachedCatalog = JSON.parse(raw);
return cachedCatalog;
}
function getAction(actionKey) {
const catalog = loadActionCatalog();
return catalog.actions ? catalog.actions[actionKey] : undefined;
}
module.exports = { loadActionCatalog, getAction };
+33
View File
@@ -0,0 +1,33 @@
import fs from 'fs';
import path from 'path';
export interface ActionDefinition {
template: string;
params?: string[];
}
export interface ActionCatalog {
_comment?: string;
_version?: string;
_targetGroup?: string;
actions: Record<string, ActionDefinition>;
}
const CATALOG_PATH = path.join(__dirname, 'catalog.json');
let cachedCatalog: ActionCatalog | null = null;
export function loadActionCatalog(forceReload = false): ActionCatalog {
if (cachedCatalog && !forceReload) {
return cachedCatalog;
}
const raw = fs.readFileSync(CATALOG_PATH, 'utf-8');
cachedCatalog = JSON.parse(raw);
return cachedCatalog!;
}
export function getAction(actionKey: string): ActionDefinition | undefined {
const catalog = loadActionCatalog();
return catalog.actions[actionKey];
}
+135
View File
@@ -0,0 +1,135 @@
/**
* generate-playwright-tests.js
*
* Generates Playwright + MCP spec files from the editor's test data.
*/
const fs = require('fs');
const path = require('path');
const { loadActionCatalog, getAction } = require('./action-catalog/index.js');
const DATA_FILE = path.join(__dirname, '..', 'data', 'testcases.json');
const OUTPUT_BASE = path.join(__dirname, '..', '..', 'tests', 'generated');
function parseArgs() {
const args = process.argv.slice(2);
const options = {};
for (let i = 0; i < args.length; i++) {
if (args[i] === '--group' && args[i + 1]) options.group = args[++i];
if (args[i] === '--dry-run') options.dryRun = true;
}
return options;
}
function loadTests() {
return JSON.parse(fs.readFileSync(DATA_FILE, 'utf-8'));
}
function getTestsToGenerate(tests, options) {
let filtered = tests.filter(t => t.fullyAutomated === true || t.status === 'automated');
if (options.group) {
filtered = filtered.filter(t => t.group === options.group);
}
return filtered;
}
function generateSpecFile(group, tests, catalog) {
let code = `import { test, expect } from '@playwright/test';\n\n`;
code += `// === AUTOGENERATED BY AUTOTEST EDITOR ===\n`;
code += `// Group: ${group}\n`;
code += `// Generated: ${new Date().toISOString()}\n\n`;
code += `test.describe('${group}', () => {\n`;
code += ` test.use({ ignoreHTTPSErrors: true });\n\n`;
for (const test of tests) {
code += generateSingleTest(test, catalog);
}
code += `});\n`;
return code;
}
function generateSingleTest(test, catalog) {
let body = '';
const steps = test.codeSteps && test.codeSteps.length > 0
? test.codeSteps
: (test.steps || []).map(s => ({ stepName: s, actionKey: 'search_for_document' }));
for (const step of steps) {
const action = getAction(step.actionKey);
if (action) {
let rendered = action.template;
if (step.params) {
Object.keys(step.params).forEach(key => {
rendered = rendered.replace(new RegExp(`{{${key}}}`, 'g'), step.params[key]);
});
}
body += ` await test.step('${step.stepName}', async () => {\n`;
body += ` ${rendered}\n`;
body += ` });\n\n`;
} else {
body += ` await test.step('${step.stepName}', async () => {\n`;
body += ` // TODO: Implement action "${step.actionKey}"\n`;
body += ` });\n\n`;
}
}
let testCode = ` test('${test.id}', async ({ page }, testInfo) => {\n`;
testCode += ` testInfo.annotations.push({ type: 'automationStatus', description: '${test.status}' });\n`;
testCode += ` testInfo.annotations.push({ type: 'testType', description: '${test.action}' });\n`;
testCode += ` testInfo.annotations.push({ type: 'description', description: '${test.description}' });\n\n`;
testCode += body;
testCode += ` });\n\n`;
return testCode;
}
function ensureDir(dir) {
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
}
function main() {
const options = parseArgs();
const tests = loadTests();
const catalog = loadActionCatalog();
const toGenerate = getTestsToGenerate(tests, options);
if (toGenerate.length === 0) {
console.log('No automated tests found for the given filters.');
return;
}
const byGroup = {};
toGenerate.forEach(t => {
if (!byGroup[t.group]) byGroup[t.group] = [];
byGroup[t.group].push(t);
});
for (const group of Object.keys(byGroup)) {
const groupTests = byGroup[group];
const moduleFolder = group.startsWith('core-') ? 'core' : 'pbx';
const outputDir = path.join(OUTPUT_BASE, moduleFolder);
ensureDir(outputDir);
const fileName = group.replace('core-', '').replace('pbx-', '') + '.spec.ts';
const outputPath = path.join(outputDir, fileName);
const fileContent = generateSpecFile(group, groupTests, catalog);
if (options.dryRun) {
console.log(`\n=== DRY RUN: ${outputPath} ===\n`);
console.log(fileContent);
} else {
fs.writeFileSync(outputPath, fileContent, 'utf-8');
console.log(`✅ Generated: ${outputPath} (${groupTests.length} tests)`);
}
}
}
main();
@@ -0,0 +1,82 @@
/**
* Types related to automated test code generation from the editor data.
* These extend the base test model stored in data/testcases.json.
*/
// ──────────────────────────────────────────────────────────────
// Core Generation Types
// ──────────────────────────────────────────────────────────────
export interface CodeStep {
/** Human-readable step name that will become the title of `test.step()` */
stepName: string;
/** Key that maps to an entry in the Action Catalog (e.g. "navigate_to_downloads_portal") */
actionKey: string;
/** Optional parameters to be substituted into the template */
params?: Record<string, any>;
}
export interface VerifiedSnippet {
/** The step name this snippet corresponds to */
stepName: string;
/** Raw Playwright / MCP code that was manually validated */
code: string;
}
export interface AutomatedTestExtension {
/**
* When true, this test is considered ready for full automated code generation.
* This is stricter than `status === "automated"`.
*/
fullyAutomated?: boolean;
/**
* Ordered list of executable steps.
* Each step will be turned into a `await test.step(...)` block.
*/
codeSteps?: CodeStep[];
/** Free-form notes for the developer or LLM when generating code */
implementationNotes?: string;
/**
* Manually verified code snippets.
* These take precedence over the Action Catalog when present.
*/
verifiedSnippets?: VerifiedSnippet[];
}
// ──────────────────────────────────────────────────────────────
// Combined Type used by the Generator
// ──────────────────────────────────────────────────────────────
export interface EnrichedTestForGeneration {
// Base fields (from testcases.json)
id: string;
group: string;
module: 'core' | 'pbx';
action: 'check' | 'write';
description: string;
status: 'automated' | 'partial' | 'manual';
file: string;
// Existing rich metadata
steps?: string[];
automatable?: string[];
notYet?: string[];
dependencies?: Array<{ label: string; value: string }>;
// New fields for code generation
fullyAutomated?: boolean;
codeSteps?: CodeStep[];
implementationNotes?: string;
verifiedSnippets?: VerifiedSnippet[];
}
/**
* Type used when the generator receives data (after merging).
*/
export type TestForCodeGeneration = EnrichedTestForGeneration;
+26
View File
@@ -214,6 +214,32 @@ app.get('/api/export/json', (req, res) => {
res.sendFile(DATA_FILE);
});
// Export Automated Playwright Tests (uses the generator script)
app.post('/api/export/automated-tests', (req, res) => {
try {
const { group } = req.body;
if (!group) {
return res.status(400).json({ error: 'Group is required for now' });
}
const { execSync } = require('child_process');
const scriptPath = path.join(__dirname, 'scripts', 'generate-playwright-tests.js');
// Generate for the specific group
execSync(`node ${scriptPath} --group ${group}`, { stdio: 'inherit' });
res.json({
success: true,
message: `Automated tests generated for group ${group}`,
group
});
} catch (e) {
console.error(e);
res.status(500).json({ error: 'Failed to export automated tests: ' + e.message });
}
});
// Health
app.get('/api/health', (req, res) => res.json({ status: 'ok' }));
+240
View File
@@ -0,0 +1,240 @@
# Automated Test Code Generation - Progress Tracker
**Project Goal**: Turn the Autotest Web Editor into the central "director" that can generate real, executable Playwright + MCP test files for all tests marked as fully automated.
**Current Decisions (Locked)**:
- Output folder: `tests/generated/{core,pbx}/`
- File naming: Same names as existing tests (e.g. `documentation.spec.ts`)
- Generation style: Template-based + LLM under the hood
- Granularity: One spec file per group
- First target group: `core-documentation`
- Human must always review & commit
- LLM context: Full group + focus on current test
- Update `testInfo.annotations` in generated files
**Status**: Active development — generator functional, first real code being produced (2026-05-22)
---
## Phases & Tasks
### Phase 0: Setup & Foundations
- [x] Create `editor/tasks/automated-code-generation.md` (this file)
- [x] Create folder `tests/generated/core/` and `tests/generated/pbx/`
- [ ] Decide on generator script location (`editor/scripts/generate-playwright-tests.ts`)
- [ ] Add `ts-node` or proper TypeScript execution if needed for scripts
- [x] Create basic `ActionCatalog` types in `editor/scripts/types/automated-generation.ts`
- [x] Create initial Action Catalog structure (`editor/scripts/action-catalog/`)
**Status**: Mostly done (script runner decision pending)
---
### Phase 1: Data Model Extensions
- [ ] Add new fields to the internal test model:
- `fullyAutomated?: boolean`
- `codeSteps?: Array<{ stepName: string, actionKey: string, params?: any }>`
- `implementationNotes?: string`
- `verifiedSnippets?: Array<{ stepName: string, code: string }>`
- [ ] Update `editor/data/testcases.json` schema (or handle missing fields gracefully)
- [x] Add UI section in the test modal for editing these new fields (basic codeSteps + params supported)
- [x] Add a filter "Only Fully Automated" in the main table / selection toolbar (selection works, visual row filter pending)
**Owner**: Frontend + Data
**Priority**: High
---
### Phase 2: Action Catalog
- [x] Design `action-catalog.json` structure
- [x] Create folder `editor/scripts/action-catalog/`
- [x] Implement TypeScript loader (`loadActionCatalog()`)
- [x] Add first batch of entries for `core-documentation` group
- [x] Support parameter substitution (e.g. `{{pattern}}`)
**Owner**: Backend / Scripts
**Priority**: High
**Status**: Foundation done, content population in progress
---
### Phase 3: Core Code Generator
- [x] Create generator script (now `.js`)
- [x] Support filtering by `status === "automated"` + `fullyAutomated`
- [x] Group tests by their `group` field
- [x] Generate one `.spec.ts` file per group in `tests/generated/`
- [x] Render `test.step()` blocks using the Action Catalog
- [x] Emit standard header + `testInfo.annotations`
- [x] Add basic CLI interface (`--group`, `--dry-run`)
**Priority**: High
---
### Phase 4: First Real Generation (core-documentation)
- [x] Populate enough catalog entries to generate `documentation.spec.ts` (2/4 tests done)
- [x] Run generator against `core-documentation` tests (dry-run verified, real write via UI works)
- [ ] Manually review the output
- [ ] Iterate on templates until the generated file is acceptable
- [ ] Commit first generated file (after review)
**Milestone**: First generated spec file
---
### Phase 5: Editor Integration
- [x] Add new button: **"Export Automated Playwright Tests"**
- [x] Add backend endpoint `POST /api/export/automated-tests`
- [x] Support real generation (writes files when called from UI)
- [ ] Add confirmation modal showing which groups will be generated
- [ ] Show link to the generated files after success
**Priority**: Medium
---
### Phase 6: LLM / MCP Assistance (Under the Hood)
- [ ] Create helper to build rich context (full group + current test + catalog + examples)
- [ ] Integrate LLM call (via MCP or direct client)
- [ ] Add fallback: when no catalog match → ask LLM
- [ ] Store accepted LLM suggestions back into `verifiedSnippets` or catalog (optional learning loop)
**Priority**: Medium
---
### Phase 7: Regeneration & Safety
- [ ] Define regeneration markers in generated files
- [ ] Implement update logic (preserve manual code above marker)
- [ ] Add `--force` and `--update-only` flags to the generator
- [ ] Document the regeneration contract
---
### Phase 8: Polish & Documentation
- [ ] Improve error messages and validation in generator
- [ ] Add tests for the generator (at least for `core-documentation`)
- [ ] Write `editor/docs/automated-code-generation.md`
- [ ] Update main `README.md` with new workflow
- [ ] Add "Fully Automated" badge/filter in the web editor
---
## Current Status
| Phase | Status | Notes |
|-------|--------------|------------------------------------|
| 0 | In Progress | Tracking file created |
| 1 | Not Started | Data model changes needed |
| 2 | Not Started | Action Catalog design pending |
| 3 | Not Started | Core generator not written yet |
| 4 | Not Started | First real generation |
| 5 | Not Started | Editor button not implemented |
| 6 | Not Started | LLM integration later |
| 7 | Not Started | Regeneration strategy |
| 8 | Not Started | Documentation |
**Next Immediate Task**: Continue Phase 4 — enrich remaining core-documentation tests and improve catalog actions.
---
## Notes & Decisions Log
- 2026-05-22: Confirmed output goes to `tests/generated/`
- 2026-05-22: First target group = `core-documentation`
- 2026-05-22: Template-based + LLM under the hood
- 2026-05-22: Human review & commit required
---
**Current Status (Updated 2026-05-22 evening)**
| Phase | Status | Notes |
|-------|-----------------|-----------------------------------------------------------------------|
| 0 | Done | Tracking file + folders + basic types + JS generator created |
| 1 | In Progress | `fullyAutomated`, `implementationNotes`, `codeSteps` + params editor added. Two tests enriched. |
| 2 | In Progress | Catalog + loader done. Good entries for core-documentation + substitution working. |
| 3 | In Progress | Generator fully working in JS, supports group + real file writing via UI. |
| 4 | In Progress | 2 out of 4 core-documentation tests now generate real code. |
| 5 | Done | Export button + backend fully wired and functional. |
| 6 | Not Started | LLM/MCP fallback layer |
| 7 | Not Started | Regeneration safety markers |
| 8 | Not Started | Documentation & polish |
**Next Immediate Recommended Task**: Enrich remaining core-documentation tests and expand Action Catalog for a complete group generation.
---
**Last Updated**: 2026-05-22 (evening session)
---
## Session Summary (2026-05-22)
**Work completed in this session:**
- Added `fullyAutomated` checkbox + `implementationNotes` + basic `codeSteps` editor in the modal (Phase 1)
- Added "Only Fully Automated" bulk selection button (B)
- Created Action Catalog foundation + first entries for `core-documentation` (C)
- Created `generate-playwright-tests.ts` script (Phase 3 start)
- Added "Export Automated Tests" button in the UI + backend endpoint
- Updated progress tracker
**Current blockers / next work:**
- Generator currently only does dry-run. Needs to actually write files.
- Need to test generation for `core-documentation` group.
- `codeSteps` editor is still basic (can be improved).
**Current Focus**: Setting up the task tracker and preparing Phase 1
---
## Session Summary (2026-05-22 - Evening continuation)
**Work completed in this session:**
- Converted generator to plain JavaScript (`generate-playwright-tests.js`) + catalog loader for reliable execution without ts-node.
- Fixed `require` paths and made the generator fully functional.
- Improved `codeSteps` editor in the modal to support `params` (JSON input).
- Wired the "Export Automated Tests" button + backend to actually call the generator with `--group`.
- Enriched the first two `core-documentation` tests with real `fullyAutomated: true`, `implementationNotes`, and detailed `codeSteps` + params.
- Verified via `--dry-run` that the generator now produces clean, executable Playwright code with proper parameter substitution (e.g. `release-notes`, `cli-configuration`).
- Two tests in `core-documentation` now generate real steps instead of placeholders.
**Updated Status Table** (see below)
**Current blockers / open items:**
- Remaining two `core-documentation` tests still lack `codeSteps`.
- Action Catalog entries are still basic (many actions just do visibility checks).
- No regeneration marker / preserve-manual-sections logic yet.
- No visual row filter for "Only Fully Automated" (selection works, but table rows still show everything).
**Recommended next steps for tomorrow:**
1. Enrich the other two `core-documentation` tests (`check-accuracy_installation...` and `check-accuracy_trouble_shooting...`) with proper `codeSteps`.
2. Expand the Action Catalog with more realistic actions (file extraction, text parsing, writing outputs, etc.).
3. Test a real (non-dry-run) generation via the UI button and review the file in `tests/generated/core/documentation.spec.ts`.
4. (Optional) Add a proper "Only Fully Automated" visual filter to hide non-automated rows in the table.
---
## Current Status (Updated 2026-05-22 evening)
| Phase | Status | Notes |
|-------|-----------------|-----------------------------------------------------------------------|
| 0 | Done | Tracking file + folders + basic types + JS generator created |
| 1 | In Progress | `fullyAutomated`, `implementationNotes`, `codeSteps` + params editor added. Two tests enriched. Filter button exists. |
| 2 | In Progress | Catalog + loader done. Initial useful entries for core-documentation added. Substitution works. |
| 3 | In Progress | Generator fully working (JS), supports `--group` + `--dry-run`, writes real files when called from UI. |
| 4 | In Progress | First real generation for `core-documentation` partially done (2/4 tests enriched and generating cleanly). |
| 5 | Done | "Export Automated Tests" button + backend endpoint implemented and tested. |
| 6 | Not Started | LLM/MCP fallback layer |
| 7 | Not Started | Regeneration safety markers + preserve manual code |
| 8 | Not Started | Documentation & polish |
**Next Immediate Recommended Task (for tomorrow)**: Finish enriching all 4 tests in `core-documentation` and expand the Action Catalog so a complete, high-quality group can be generated.