Dependencies & Prerequisites
@@ -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 = `
+
+
+
+
+ `;
+ 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);
diff --git a/editor/scripts/action-catalog/catalog.json b/editor/scripts/action-catalog/catalog.json
new file mode 100644
index 0000000..3f9658b
--- /dev/null
+++ b/editor/scripts/action-catalog/catalog.json
@@ -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.)"
+ }
+ }
+}
diff --git a/editor/scripts/action-catalog/index.js b/editor/scripts/action-catalog/index.js
new file mode 100644
index 0000000..00d39a4
--- /dev/null
+++ b/editor/scripts/action-catalog/index.js
@@ -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 };
diff --git a/editor/scripts/action-catalog/index.ts b/editor/scripts/action-catalog/index.ts
new file mode 100644
index 0000000..1e5595b
--- /dev/null
+++ b/editor/scripts/action-catalog/index.ts
@@ -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
;
+}
+
+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];
+}
diff --git a/editor/scripts/generate-playwright-tests.js b/editor/scripts/generate-playwright-tests.js
new file mode 100644
index 0000000..e765ea0
--- /dev/null
+++ b/editor/scripts/generate-playwright-tests.js
@@ -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();
diff --git a/editor/scripts/types/automated-generation.ts b/editor/scripts/types/automated-generation.ts
new file mode 100644
index 0000000..2d7725b
--- /dev/null
+++ b/editor/scripts/types/automated-generation.ts
@@ -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;
+}
+
+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;
diff --git a/editor/server.js b/editor/server.js
index e51fb3a..fe99a34 100644
--- a/editor/server.js
+++ b/editor/server.js
@@ -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' }));
diff --git a/editor/tasks/automated-code-generation.md b/editor/tasks/automated-code-generation.md
new file mode 100644
index 0000000..cc29026
--- /dev/null
+++ b/editor/tasks/automated-code-generation.md
@@ -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.