lib-e2e-cypress-for-dummys-ts 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -1
- package/dist/index.cjs +1622 -152
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +213 -5
- package/dist/index.d.ts +213 -5
- package/dist/index.js +1605 -153
- package/dist/index.js.map +1 -1
- package/package.json +8 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/selector-quality.utils.ts","../src/components/selector-picker/selector-picker.styles.ts","../src/utils/html.utils.ts","../src/components/selector-picker/selector-picker.template.ts","../src/components/selector-picker/selector-picker.ts","../src/index.ts","../src/models/lang.model.ts","../src/models/input-types.model.ts","../src/models/db-schema.model.ts","../src/models/active-session.model.ts","../src/utils/subject.ts","../src/i18n/es.ts","../src/i18n/en.ts","../src/i18n/fr.ts","../src/i18n/it.ts","../src/i18n/de.ts","../src/services/translation.service.ts","../src/utils/code-format.utils.ts","../src/services/transformation.service.ts","../src/services/advanced-test.transformation.service.ts","../src/services/recording.service.ts","../src/services/persistence.service.ts","../src/services/http-monitor.ts","../src/utils/styles.utils.ts","../src/utils/modal.utils.ts","../src/utils/toast.utils.ts","../src/utils/export-selection.utils.ts","../src/utils/host.utils.ts","../src/utils/widget-position.utils.ts","../src/components/test-previsualizer/test-previsualizer.styles.ts","../src/components/test-previsualizer/test-previsualizer.template.ts","../src/components/test-previsualizer/test-previsualizer.ts","../src/components/save-test/save-test.styles.ts","../src/components/save-test/save-test.template.ts","../src/components/save-test/save-test.ts","../src/components/test-editor/test-editor.styles.ts","../src/components/test-editor/test-editor.template.ts","../src/utils/syntax-highlight.utils.ts","../src/components/test-editor/test-editor.ts","../src/components/configuration/configuration.styles.ts","../src/components/configuration/configuration.template.ts","../src/components/configuration/configuration.ts","../src/components/advanced-test-editor/advanced-test-editor.styles.ts","../src/components/advanced-test-editor/advanced-test-editor.template.ts","../src/components/advanced-test-editor/advanced-test-editor.ts","../src/components/file-preview/file-preview.styles.ts","../src/components/file-preview/file-preview.template.ts","../src/components/file-preview/file-preview.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.styles.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.template.ts"],"sourcesContent":["export type SelectorQuality = 'excellent' | 'good' | 'acceptable' | 'poor';\n\nexport const FORBIDDEN_ID_PREFIXES = [\n 'cdk-', 'mat-', 'p-', 'ng-', 'mdc-',\n 'primeng-', 'auto-', 'field-', 'input-', 'select-',\n];\n\nexport function getSelectorQuality(el: HTMLElement): SelectorQuality {\n if (\n el.hasAttribute('data-cy') ||\n el.hasAttribute('data-testid') ||\n el.hasAttribute('aria-label')\n ) {\n return 'excellent';\n }\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return 'good';\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n return 'acceptable';\n }\n\n return 'poor';\n}\n\n/** Returns the best cy.get() selector string for a given element. */\nexport function buildPickerSelector(el: HTMLElement): string {\n const dataCy = el.getAttribute('data-cy');\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\n\n const dataTestid = el.getAttribute('data-testid');\n if (dataTestid) return `[data-testid=\"${dataTestid}\"]`;\n\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return `[aria-label=\"${ariaLabel}\"]`;\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return `#${rawId}`;\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n const classes = el.className.trim().split(/\\s+/);\n return classes.map((c) => `.${c}`).join('');\n }\n\n return el.tagName.toLowerCase();\n}\n\n/** Human-readable key attribute/selector preview for a picker row (raw, unescaped). */\nexport function keyAttrDisplay(el: HTMLElement): string {\n for (const attr of ['data-cy', 'data-testid', 'aria-label']) {\n const v = el.getAttribute(attr);\n if (v) return `${attr}=\"${v}\"`;\n }\n if (el.id) return `id=\"${el.id}\"`;\n if (el.className && el.className.trim()) {\n return el.className.trim().split(/\\s+/).map((c) => `.${c}`).join('');\n }\n return '';\n}\n\n/** Plain, serializable view-model for one picker row — no DOM held. */\nexport interface PickerRow {\n quality: SelectorQuality;\n selector: string;\n tag: string;\n attr: string;\n}\n\n/** Reads an element once and returns the plain data a picker row needs to render. */\nexport function describePickerRow(el: HTMLElement): PickerRow {\n return {\n quality: getSelectorQuality(el),\n selector: buildPickerSelector(el),\n tag: el.tagName.toLowerCase(),\n attr: keyAttrDisplay(el),\n };\n}\n","export const SELECTOR_PICKER_STYLES = `\r\n :host {\r\n position: fixed;\r\n z-index: 2147483647;\r\n top: 0;\r\n left: 0;\r\n width: 100vw;\r\n height: 100vh;\r\n pointer-events: none;\r\n }\r\n\r\n .overlay {\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n pointer-events: all;\r\n background: #161b22;\r\n border: 1px solid #30363d;\r\n border-radius: 10px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\r\n min-width: 420px;\r\n max-width: 600px;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n color: #e6edf3;\r\n font-size: 13px;\r\n }\r\n\r\n .header {\r\n padding: 12px 16px 8px;\r\n border-bottom: 1px solid #21262d;\r\n font-weight: 600;\r\n font-size: 13px;\r\n color: #8b949e;\r\n letter-spacing: 0.04em;\r\n text-transform: uppercase;\r\n }\r\n\r\n .list {\r\n max-height: 320px;\r\n overflow-y: auto;\r\n padding: 6px 0;\r\n }\r\n\r\n .row {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 7px 14px;\r\n cursor: pointer;\r\n border-radius: 6px;\r\n margin: 1px 6px;\r\n transition: background 0.1s;\r\n }\r\n\r\n .row:hover,\r\n .row.selected {\r\n background: #21262d;\r\n }\r\n\r\n .row.selected {\r\n outline: 2px solid #388bfd;\r\n outline-offset: -2px;\r\n }\r\n\r\n .quality-badge {\r\n width: 18px;\r\n height: 18px;\r\n border-radius: 50%;\r\n flex-shrink: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 10px;\r\n }\r\n\r\n .badge-excellent { background: #238636; }\r\n .badge-good { background: #1f6feb; }\r\n .badge-acceptable{ background: #9e6a03; }\r\n .badge-poor { background: #da3633; }\r\n\r\n .tag-name {\r\n font-family: monospace;\r\n font-size: 12px;\r\n color: #8b949e;\r\n flex-shrink: 0;\r\n }\r\n\r\n .attr-value {\r\n font-family: monospace;\r\n font-size: 12px;\r\n color: #c9d1d9;\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n .selector-preview {\r\n font-family: monospace;\r\n font-size: 11px;\r\n color: #58a6ff;\r\n flex-shrink: 0;\r\n max-width: 180px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n .poor-warning {\r\n font-size: 10px;\r\n color: #f85149;\r\n margin-left: auto;\r\n }\r\n\r\n .footer {\r\n padding: 8px 14px 10px;\r\n border-top: 1px solid #21262d;\r\n display: flex;\r\n gap: 16px;\r\n font-size: 11px;\r\n color: #484f58;\r\n }\r\n\r\n .hint kbd {\r\n background: #21262d;\r\n border: 1px solid #30363d;\r\n border-radius: 3px;\r\n padding: 1px 5px;\r\n font-size: 10px;\r\n color: #8b949e;\r\n }\r\n`;\r\n","export function escHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\nexport function escAttr(s: string): string {\n return s.replace(/\"/g, '"').replace(/</g, '<');\n}\n","import type { PickerRow, SelectorQuality } from '../../utils/selector-quality.utils';\r\nimport { escHtml } from '../../utils/html.utils';\r\n\r\nconst QUALITY_EMOJI: Record<SelectorQuality, string> = {\r\n excellent: '🟢',\r\n good: '🔵',\r\n acceptable: '🟡',\r\n poor: '🔴',\r\n};\r\n\r\nconst QUALITY_CLASS: Record<SelectorQuality, string> = {\r\n excellent: 'badge-excellent',\r\n good: 'badge-good',\r\n acceptable: 'badge-acceptable',\r\n poor: 'badge-poor',\r\n};\r\n\r\nexport function renderPickerRows(\r\n rows: PickerRow[],\r\n selectedIndex: number,\r\n t: (key: string) => string,\r\n): string {\r\n return rows.map((row, i) => {\r\n const isSelected = i === selectedIndex;\r\n const isPoor = row.quality === 'poor';\r\n\r\n return `\r\n <div class=\"row${isSelected ? ' selected' : ''}\" data-idx=\"${i}\" role=\"option\" aria-selected=\"${isSelected}\">\r\n <span class=\"quality-badge ${QUALITY_CLASS[row.quality]}\" title=\"${escHtml(t(`SELECTOR_PICKER.QUALITY_${row.quality.toUpperCase()}`))}\">\r\n ${QUALITY_EMOJI[row.quality]}\r\n </span>\r\n <span class=\"tag-name\"><${escHtml(row.tag)}></span>\r\n ${row.attr ? `<span class=\"attr-value\">${escHtml(row.attr)}</span>` : '<span class=\"attr-value\"></span>'}\r\n <span class=\"selector-preview\">${escHtml(row.selector)}</span>\r\n ${isPoor ? `<span class=\"poor-warning\" title=\"${escHtml(t('SELECTOR_PICKER.QUALITY_POOR'))}\">⚠</span>` : ''}\r\n </div>`;\r\n }).join('');\r\n}\r\n\r\nexport function renderPicker(\r\n rows: PickerRow[],\r\n selectedIndex: number,\r\n t: (key: string) => string,\r\n): string {\r\n return `\r\n <div class=\"overlay\" role=\"listbox\">\r\n <div class=\"header\">${escHtml(t('SELECTOR_PICKER.TITLE'))}</div>\r\n <div class=\"list\">\r\n ${renderPickerRows(rows, selectedIndex, t)}\r\n </div>\r\n <div class=\"footer\">\r\n <span class=\"hint\"><kbd>↑↓</kbd> ${escHtml(t('SELECTOR_PICKER.PREVIEW_LABEL'))}</span>\r\n <span class=\"hint\"><kbd>Enter</kbd> ${escHtml(t('SELECTOR_PICKER.CONFIRM_HINT'))}</span>\r\n <span class=\"hint\"><kbd>Esc</kbd> ${escHtml(t('SELECTOR_PICKER.CANCEL_HINT'))}</span>\r\n </div>\r\n </div>`;\r\n}\r\n","import type { RecordingService } from '../../services/recording.service';\r\nimport type { TranslationService } from '../../services/translation.service';\r\nimport { describePickerRow, type PickerRow } from '../../utils/selector-quality.utils';\r\nimport { SELECTOR_PICKER_STYLES } from './selector-picker.styles';\r\nimport { renderPicker } from './selector-picker.template';\r\n\r\nconst OWN_DATA_CY = 'lib-e2e-cypress-for-dummys';\r\nconst MAX_ANCESTORS = 10;\r\n\r\nexport class SelectorPickerElement extends HTMLElement {\r\n targetElement: HTMLElement | null = null;\r\n recording!: RecordingService;\r\n translation!: TranslationService;\r\n\r\n private shadow: ShadowRoot;\r\n private ancestors: HTMLElement[] = [];\r\n private rows: PickerRow[] = [];\r\n private selectedIndex = 0;\r\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\r\n private unsubRecording: (() => void) | null = null;\r\n private unsubPause: (() => void) | null = null;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\r\n this.ancestors = this.buildAncestors();\r\n this.rows = this.ancestors.map(describePickerRow);\r\n this.selectedIndex = this.findBestIndex();\r\n this.render();\r\n this.attachKeyListener();\r\n this.attachRowClickListeners();\r\n this.subscribeToRecordingChanges();\r\n }\r\n\r\n disconnectedCallback(): void {\r\n this.detachKeyListener();\r\n this.unsubRecording?.();\r\n this.unsubPause?.();\r\n }\r\n\r\n private t(key: string): string {\r\n return this.translation?.translate(key) ?? key;\r\n }\r\n\r\n // ── Ancestor chain ──────────────────────────────────────────────────────────\r\n\r\n private buildAncestors(): HTMLElement[] {\r\n const chain: HTMLElement[] = [];\r\n let current: HTMLElement | null = this.targetElement;\r\n\r\n while (current && current.tagName.toLowerCase() !== 'html' && chain.length < MAX_ANCESTORS) {\r\n if (current.getAttribute('data-cy') === OWN_DATA_CY) {\r\n current = current.parentElement;\r\n continue;\r\n }\r\n chain.push(current);\r\n current = current.parentElement;\r\n }\r\n\r\n return chain;\r\n }\r\n\r\n private findBestIndex(): number {\r\n for (let i = 0; i < this.rows.length; i++) {\r\n const q = this.rows[i].quality;\r\n if (q === 'excellent' || q === 'good' || q === 'acceptable') return i;\r\n }\r\n return 0;\r\n }\r\n\r\n // ── Rendering ───────────────────────────────────────────────────────────────\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${SELECTOR_PICKER_STYLES}</style>${renderPicker(\r\n this.rows,\r\n this.selectedIndex,\r\n this.t.bind(this),\r\n )}`;\r\n }\r\n\r\n // ── Keyboard ────────────────────────────────────────────────────────────────\r\n\r\n private attachKeyListener(): void {\r\n this.keyHandler = (e: KeyboardEvent) => {\r\n if (e.key === 'ArrowDown') {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n this.selectedIndex = (this.selectedIndex + 1) % this.ancestors.length;\r\n this.render();\r\n this.attachRowClickListeners();\r\n } else if (e.key === 'ArrowUp') {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n this.selectedIndex = (this.selectedIndex - 1 + this.ancestors.length) % this.ancestors.length;\r\n this.render();\r\n this.attachRowClickListeners();\r\n } else if (e.key === 'Enter') {\r\n e.stopPropagation();\r\n this.confirm(this.selectedIndex);\r\n } else if (e.key === 'Escape') {\r\n e.stopPropagation();\r\n this.cancel();\r\n }\r\n };\r\n window.addEventListener('keydown', this.keyHandler, { capture: true });\r\n }\r\n\r\n private detachKeyListener(): void {\r\n if (this.keyHandler) {\r\n window.removeEventListener('keydown', this.keyHandler, { capture: true });\r\n this.keyHandler = null;\r\n }\r\n }\r\n\r\n // ── Row click listeners ─────────────────────────────────────────────────────\r\n\r\n private attachRowClickListeners(): void {\r\n this.shadow.querySelectorAll('[data-idx]').forEach((row) => {\r\n (row as HTMLElement).addEventListener('click', () => {\r\n const idx = parseInt((row as HTMLElement).dataset['idx'] ?? '0', 10);\r\n this.confirm(idx);\r\n });\r\n });\r\n }\r\n\r\n // ── Recording auto-close ────────────────────────────────────────────────────\r\n\r\n private subscribeToRecordingChanges(): void {\r\n this.unsubRecording = this.recording.onRecordingChange((isRecording) => {\r\n if (!isRecording) this.closeSilently();\r\n });\r\n this.unsubPause = this.recording.onPauseChange((isPaused) => {\r\n if (isPaused) this.closeSilently();\r\n });\r\n }\r\n\r\n // ── Actions ─────────────────────────────────────────────────────────────────\r\n\r\n private confirm(index: number): void {\r\n const row = this.rows[index];\r\n if (!row) return;\r\n const command = `cy.get('${row.selector}').click()`;\r\n this.recording.appendCommand(command);\r\n this.dispatchEvent(new CustomEvent('selectorchosen', { detail: command, bubbles: true, composed: true }));\r\n this.closeSilently();\r\n }\r\n\r\n private cancel(): void {\r\n this.dispatchEvent(new CustomEvent('pickercancelled', { bubbles: true, composed: true }));\r\n this.closeSilently();\r\n }\r\n\r\n private closeSilently(): void {\r\n this.detachKeyListener();\r\n this.unsubRecording?.();\r\n this.unsubPause?.();\r\n this.unsubRecording = null;\r\n this.unsubPause = null;\r\n this.remove();\r\n }\r\n}\r\n\r\nif (!customElements.get('selector-picker')) {\r\n customElements.define('selector-picker', SelectorPickerElement);\r\n}\r\n","// Public API — populated as migration phases are completed\r\n// Keep in sync with package.json \"version\" (asserted in specs/public-api.spec.ts).\r\nexport const VERSION = '0.6.0';\r\n\r\n// Phase 1 — Models\r\nexport * from './models/lang.model';\r\nexport * from './models/input-types.model';\r\nexport * from './models/db-schema.model';\r\nexport * from './models/active-session.model';\r\n\r\n// Phase 2 — TranslationService\r\nexport * from './services/translation.service';\r\n\r\n// Phase 3 — Transformation Services\r\nexport * from './services/transformation.service';\r\nexport * from './services/advanced-test.transformation.service';\r\n\r\n// Phase 4 — RecordingService\r\nexport * from './utils/subject';\r\nexport * from './services/recording.service';\r\n\r\n// Phase 5 — PersistenceService\r\nexport * from './services/persistence.service';\r\n\r\n// Phase 6 — HttpMonitor\r\nexport * from './services/http-monitor';\r\n\r\n// Phase 7 — UI Utilities\r\nexport * from './utils/styles.utils';\r\nexport * from './utils/modal.utils';\r\nexport * from './utils/toast.utils';\r\nexport * from './utils/export-selection.utils';\r\nexport * from './utils/host.utils';\r\nexport * from './utils/widget-position.utils';\r\n\r\n// Phase 8 — Web Components\r\nexport * from './components/selector-picker/selector-picker';\r\nexport * from './components/test-previsualizer/test-previsualizer';\r\nexport * from './components/save-test/save-test';\r\nexport * from './components/test-editor/test-editor';\r\nexport * from './components/configuration/configuration';\r\nexport * from './components/advanced-test-editor/advanced-test-editor';\r\nexport * from './components/file-preview/file-preview';\r\nexport * from './components/lib-e2e-recorder/lib-e2e-recorder';\r\n","export type Lang = 'es' | 'en' | 'fr' | 'it' | 'de';\r\n\r\nexport const SUPPORTED_LANGS: Lang[] = ['es', 'en', 'fr', 'it', 'de'];\r\n\r\nexport function isLang(value: string): value is Lang {\r\n return SUPPORTED_LANGS.includes(value as Lang);\r\n}\r\n\r\n/** BCP-47 locale used for date/number formatting per UI language. */\r\nexport const LOCALE_BY_LANG: Record<Lang, string> = {\r\n es: 'es-ES',\r\n en: 'en-GB',\r\n fr: 'fr-FR',\r\n it: 'it-IT',\r\n de: 'de-DE',\r\n};\r\n\r\n/** Returns the formatting locale for a UI language (falls back to es-ES). */\r\nexport function localeForLang(lang: string): string {\r\n return isLang(lang) ? LOCALE_BY_LANG[lang] : 'es-ES';\r\n}\r\n","export const INPUT_TYPES = [\r\n 'text',\r\n 'password',\r\n 'email',\r\n 'search',\r\n 'tel',\r\n 'url',\r\n 'number',\r\n 'textarea',\r\n] as const;\r\n\r\nexport type InputType = (typeof INPUT_TYPES)[number];\r\n","export interface DBStoreIndex {\r\n name: string;\r\n keyPath: string;\r\n unique: boolean;\r\n}\r\n\r\nexport interface DBStore {\r\n name: string;\r\n keyPath: string;\r\n autoIncrement: boolean;\r\n indexes: DBStoreIndex[];\r\n}\r\n\r\nexport interface DBSchema {\r\n name: string;\r\n version: number;\r\n stores: DBStore[];\r\n}\r\n\r\nexport const DB_SCHEMA: DBSchema = {\r\n name: 'E2ECypressDB',\r\n version: 11,\r\n stores: [\r\n {\r\n name: 'tests',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'name', keyPath: 'name', unique: false },\r\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\r\n ],\r\n },\r\n {\r\n name: 'commands',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'command', keyPath: 'command', unique: false },\r\n { name: 'testId', keyPath: 'testId', unique: false },\r\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\r\n ],\r\n },\r\n {\r\n name: 'interceptors',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'interceptor', keyPath: 'interceptor', unique: false },\r\n { name: 'testId', keyPath: 'testId', unique: false },\r\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\r\n ],\r\n },\r\n {\r\n name: 'configuration',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'language', keyPath: 'language', unique: false },\r\n { name: 'extendedHttpCommands', keyPath: 'extendedHttpCommands', unique: false },\r\n { name: 'allowReadWriteFiles', keyPath: 'allowReadWriteFiles', unique: false },\r\n ],\r\n },\r\n {\r\n // Single-record store (fixed key id=1) holding the live, in-progress\r\n // recording session so it survives a micro-frontend crossing or reload.\r\n // See docs/specs/006-cross-app-recording-continuity.md.\r\n name: 'activeSession',\r\n keyPath: 'id',\r\n autoIncrement: false,\r\n indexes: [],\r\n },\r\n ],\r\n};\r\n\r\nexport const DB_STORE_NAMES = DB_SCHEMA.stores.map(s => s.name) as [\r\n 'tests',\r\n 'commands',\r\n 'interceptors',\r\n 'configuration',\r\n 'activeSession',\r\n];\r\n","import type { SelectorStrategy } from '../services/recording.service';\r\n\r\n/**\r\n * A live, in-progress recording session, persisted so it can survive a\r\n * micro-frontend crossing (single-spa app swap) or an accidental same-origin\r\n * reload. Only an actively-recording session is ever stored/resumed.\r\n *\r\n * The full payload lives in IndexedDB; a lightweight breadcrumb (sessionId +\r\n * isRecording + updatedAt) is mirrored to localStorage for synchronous detection.\r\n *\r\n * See docs/specs/006-cross-app-recording-continuity.md.\r\n */\r\nexport interface ActiveSessionState {\r\n /** Stable id for the session, generated when recording starts. */\r\n sessionId: string;\r\n isRecording: boolean;\r\n isPaused: boolean;\r\n commands: string[];\r\n interceptors: string[];\r\n selectorStrategy: SelectorStrategy;\r\n /** Epoch ms when the session started recording. */\r\n startedAt: number;\r\n /** Epoch ms of the last mutation — acts as the recency heartbeat. */\r\n updatedAt: number;\r\n}\r\n\r\n/** localStorage key for the synchronous \"is a session active?\" breadcrumb. */\r\nexport const ACTIVE_SESSION_BREADCRUMB_KEY = 'e2e-active-session';\r\n\r\n/** Configuration key (in the `configuration` store) for the resume recency TTL. */\r\nexport const RESUME_TTL_CONFIG_KEY = 'resumeRecencyTtlMinutes';\r\n\r\n/** Default minutes within which an active session resumes silently. */\r\nexport const DEFAULT_RESUME_TTL_MINUTES = 30;\r\n","export class Subject<T> {\r\n private _value: T;\r\n private listeners = new Set<(v: T) => void>();\r\n\r\n constructor(initialValue: T) {\r\n this._value = initialValue;\r\n }\r\n\r\n next(value: T): void {\r\n this._value = value;\r\n this.listeners.forEach((l) => l(value));\r\n }\r\n\r\n getValue(): T {\r\n return this._value;\r\n }\r\n\r\n subscribe(fn: (v: T) => void): () => void {\r\n this.listeners.add(fn);\r\n return () => this.listeners.delete(fn);\r\n }\r\n}\r\n","export const I18N_ES = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Configuración',\r\n SHOW_ADVANCED_EDITOR: 'Editor avanzado',\r\n DIALOG_SAVED_TESTS: 'Pruebas guardadas',\r\n DIALOG_COMMANDS: 'Previsualizador de comandos Cypress',\r\n DIALOG_SAVE: '¿Guardar la grabación?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Descripción de la prueba',\r\n CANCEL: 'Cancelar',\r\n ASK: '¿Guardar el test grabado?',\r\n YES_CONTINUE: 'Sí, continuar',\r\n NO_DISCARD: 'No, descartar',\r\n DESC_PLACEHOLDER: 'Ej: Login correcto con credenciales válidas',\r\n TAGS_LABEL: 'Etiquetas (opcional, para filtrar después):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regresión…',\r\n ADD_TAG: '+ Añadir',\r\n NO_TAGS: 'Sin etiquetas',\r\n SAVE_BTN: '💾 Guardar',\r\n SAVE_AND_EDIT: '📝 Guardar y editar',\r\n REMOVE_TAG_TITLE: 'Quitar',\r\n NOTES_LABEL: 'Descripción / Notas (opcional):',\r\n NOTES_PLACEHOLDER: 'Qué valida este test, condiciones previas, etc.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Sin etiquetas',\r\n SELECTED_SINGULAR: 'seleccionado',\r\n SELECTED_PLURAL: 'seleccionados',\r\n DESCRIBE_PLACEHOLDER: 'Nombre del describe (opcional)',\r\n COPY_DESCRIBE: '🗂 Copiar describe()',\r\n MULTI_SELECT: '🗂 Multi-select',\r\n CANCEL_SELECT: '✕ Cancelar',\r\n COPY_CMDS_BTN: '📋 Copiar comandos',\r\n COPY_ICPS_BTN: '📋 Copiar interceptores',\r\n DEFAULT_DESCRIBE: 'Suite de tests',\r\n NO_TESTS: 'No hay tests guardados',\r\n DELETE_TITLE: 'Eliminar',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Idioma',\r\n LANG_FIELD: 'Interfaz',\r\n HTTP_SECTION: '⚡ HTTP Avanzado',\r\n HTTP_TITLE: 'Validaciones de body',\r\n HTTP_SUB: 'GET → response · POST/PUT → request',\r\n SELECTOR_SECTION: '🎯 Estrategia de selector',\r\n SELECTOR_LABEL: 'Atributo preferido para cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (por defecto)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#elemento)',\r\n SELECTOR_HINT: 'El grabador buscará este atributo primero. Si no existe, intentará los demás.',\r\n FOLDER_SECTION: '📁 Carpeta Cypress',\r\n FOLDER_CONNECTED: 'conectado —',\r\n FOLDER_NOT_SET: 'sin configurar',\r\n FOLDER_CHANGE_BTN: '📁 Cambiar carpeta',\r\n FOLDER_SELECT_BTN: '📁 Seleccionar carpeta',\r\n FOLDER_REVOKE_BTN: '✕ Quitar acceso',\r\n DATA_SECTION: '💾 Datos',\r\n DATA_DESC: 'Exporta todos tus tests a JSON o importa una copia de seguridad.',\r\n EXPORT_BTN: '⬆️ Exportar tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Exportar tests',\r\n EXPORT_MODE_ALL: 'Todo',\r\n EXPORT_MODE_MANUAL: 'Selección manual',\r\n EXPORT_MODE_TAGS: 'Por tags',\r\n EXPORT_ALL_DESC: 'Se exportarán todos los tests guardados.',\r\n EXPORT_COUNT: 'A exportar:',\r\n EXPORT_CONFIRM: '⬆️ Exportar',\r\n EXPORT_CANCEL: 'Cancelar',\r\n EXPORT_EMPTY: 'No hay tests para exportar.',\r\n EXPORT_NO_TAGS: 'No hay tags disponibles.',\r\n EXPORT_TAGS_HINT: 'Selecciona uno o más tags para ver qué pruebas se exportarán.',\r\n EXPORT_RESULT_LABEL: 'Pruebas que se exportarán:',\r\n IMPORT_BTN: '⬇️ Importar tests',\r\n FOLDER_UPDATED_TOAST: '✓ Carpeta de Cypress actualizada',\r\n FOLDER_ERROR_TOAST: 'Error al acceder a la carpeta',\r\n IMPORT_SUCCESS: 'Datos importados correctamente.',\r\n IMPORT_ERROR: 'Error al importar.',\r\n JSON_INVALID: 'El archivo no es un JSON válido.',\r\n JSON_BAD_FORMAT: 'El archivo no tiene el formato esperado.',\r\n SMART_SELECTOR_SECTION: '🔍 Selector inteligente',\r\n SMART_SELECTOR_TITLE: 'Selector inteligente',\r\n SMART_SELECTOR_SUB: 'Muestra un picker al hacer click en elementos sin selector válido.',\r\n START_HIDDEN_SECTION: '👁 Visibilidad del widget',\r\n START_HIDDEN_TITLE: 'Iniciar oculto',\r\n START_HIDDEN_SUB: 'El widget arranca invisible. Usa Ctrl+Shift+E para mostrarlo u ocultarlo.',\r\n RESUME_TTL_SECTION: '⏱ Continuidad de grabación',\r\n RESUME_TTL_LABEL: 'Reanudar sin preguntar (minutos)',\r\n RESUME_TTL_HINT: 'Si recargas o cambias de proyecto, una grabación activa se reanuda sin preguntar dentro de este margen. Pasado ese tiempo, te preguntará si continuar o descartar.',\r\n WIDGET_POSITION_SECTION: '🧲 Posición del widget',\r\n WIDGET_POSITION_HINT: 'Arrastra el botón de grabar para moverlo donde no estorbe. Se recuerda su posición.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Restablecer posición',\r\n WIDGET_POSITION_RESET_DONE: '✓ Posición restablecida',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Selecciona un elemento del DOM',\r\n PREVIEW_LABEL: 'navegar',\r\n CONFIRM_HINT: 'confirmar',\r\n CANCEL_HINT: 'cancelar',\r\n QUALITY_EXCELLENT: 'Excelente — tiene atributo de prueba (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Bueno — tiene un id válido',\r\n QUALITY_ACCEPTABLE: 'Aceptable — solo tiene clases CSS',\r\n QUALITY_POOR: 'No recomendado — solo tag o estilo inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptores',\r\n COPY_CMDS_BTN: '📋 Copiar comandos',\r\n SHOW_INTERCEPTORS: '▼ Ver interceptores',\r\n HIDE_INTERCEPTORS: '▲ Ocultar interceptores',\r\n SECTION_COMMANDS: 'Comandos',\r\n NO_CMDS_YET: 'Sin comandos aún',\r\n NO_ICP_SHORT: 'Sin interceptores',\r\n COPY_ICP_BTN: '📋 Copiar interceptores',\r\n UP_TITLE: 'Subir',\r\n DOWN_TITLE: 'Bajar',\r\n DEL_TITLE: 'Eliminar',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Reactivar acceso',\r\n PERMISSION_EXPIRED: '🔑 El permiso ha caducado',\r\n PERMISSION_EXPIRED_HINT: 'Haz clic para reactivar el acceso a tu carpeta de Cypress.',\r\n NO_ACCESS: '🔒 Sin acceso a archivos locales',\r\n NO_ACCESS_HINT: 'Configura el acceso en ⚙️ Config.',\r\n NO_FILES: 'Sin archivos',\r\n SELECT_FILE: '← Selecciona un archivo del árbol',\r\n IT_LABEL: '🧪 it() a insertar:',\r\n COPY_IT_BTN: '📋 Copiar it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptores:',\r\n COPY_ICP_BTN: '📋 Copiar interceptores',\r\n INSERT_BTN: '💾 Insertar en archivo',\r\n EDIT_MANUAL_BTN: '✏️ Editar manualmente',\r\n CLOSE_BTN: '✕ Cerrar',\r\n NEW_FILE_BTN: '+ Nuevo archivo',\r\n NEW_FOLDER_BTN: '+ Nueva carpeta',\r\n REFRESH_BTN: '↻ Actualizar',\r\n NEW_FILE_PLACEHOLDER: 'nombre-del-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nombre-de-carpeta',\r\n NEW_FILE_CONFIRM: 'Crear',\r\n NEW_FILE_CANCEL: 'Cancelar',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Sin archivo',\r\n COPY_TITLE: 'Copiar contenido del editor',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copiar',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'Sin cambios respecto al original',\r\n NO_CHANGES_SHORT: 'Sin cambios',\r\n LAUNCH_BTN: '▶ Lanzar test',\r\n LAUNCH_LOCAL_ONLY: 'Muévelo a local para poder probar',\r\n LAUNCH_RUNNING: '⏳ Ejecutando…',\r\n LAUNCH_PASSED: '✓ Prueba superada',\r\n LAUNCH_FAILED: '✗ Prueba fallida',\r\n LAUNCH_NO_RUNNER: 'No se detectó el runner local (¿lo has arrancado?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Guardar',\r\n CLOSE_BTN: '✕ Cerrar',\r\n BACK_TO_EDITOR: '← Volver al editor',\r\n INSERT_BTN: '🪄 Insertar bloques',\r\n INSERT_TITLE: 'Insertar it() y beforeEach() en el contenido del editor',\r\n INSERT_DONE: 'Bloques insertados en el editor',\r\n INSERT_ERROR: 'No se encontró un bloque describe() válido en el archivo',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Acceso a ficheros',\r\n FS_LATER_BTN: 'Ahora no',\r\n FS_SELECT_BTN: '📁 Seleccionar carpeta',\r\n FS_SUCCESS_TOAST: '✓ Carpeta de Cypress configurada',\r\n FS_ERROR_TOAST: 'Error al acceder a la carpeta',\r\n FS_INTRO_HTML: 'El <strong style=\"color:#e6edf3\">editor avanzado</strong> puede insertar tus tests directamente en los archivos <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Selecciona la carpeta que contiene la subcarpeta <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. La extensión espera esta estructura:',\r\n FS_TREE_PICK_HINT: '← selecciona esta carpeta',\r\n FS_TREE_READ_HINT: '← la extensión leerá aquí',\r\n FS_PERMISSION_NOTE: 'El permiso se guarda en el navegador y no se vuelve a solicitar.',\r\n ASSERTION_SECTION: '➕ Añadir aserción',\r\n ASSERT_SELECTOR_PH: 'selector, ej: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valor esperado',\r\n ASSERT_ADD_BTN: '➕ Añadir',\r\n FILE_EDITOR_TITLE: '✏️ Editor de archivo',\r\n FILE_SAVED_TOAST: '✓ Archivo guardado',\r\n FILE_SAVE_ERROR_TOAST: 'Error al guardar el archivo',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Ficheros',\r\n BTN_COMMANDS: 'Comandos',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pausar (Ctrl+P)',\r\n RESUME_TITLE: 'Reanudar (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSA',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Detener (Ctrl+R)',\r\n START_TITLE: 'Grabar (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Grabación en curso',\r\n SESSION_RESUME_TEXT: 'Hay una grabación activa sin terminar.',\r\n SESSION_RESUME_COUNT: 'comandos capturados',\r\n SESSION_CONTINUE_BTN: 'Continuar grabando',\r\n SESSION_DISCARD_BTN: 'Descartar',\r\n },\r\n};\r\n","export const I18N_EN = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Settings',\r\n SHOW_ADVANCED_EDITOR: 'Advanced editor',\r\n DIALOG_SAVED_TESTS: 'Saved tests',\r\n DIALOG_COMMANDS: 'Cypress commands previewer',\r\n DIALOG_SAVE: 'Save recording?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Test description',\r\n CANCEL: 'Cancel',\r\n ASK: 'Save the recorded test?',\r\n YES_CONTINUE: 'Yes, continue',\r\n NO_DISCARD: 'No, discard',\r\n DESC_PLACEHOLDER: 'E.g.: Successful login with valid credentials',\r\n TAGS_LABEL: 'Tags (optional, for later filtering):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\r\n ADD_TAG: '+ Add',\r\n NO_TAGS: 'No tags',\r\n SAVE_BTN: '💾 Save',\r\n SAVE_AND_EDIT: '📝 Save and edit',\r\n REMOVE_TAG_TITLE: 'Remove',\r\n NOTES_LABEL: 'Description / Notes (optional):',\r\n NOTES_PLACEHOLDER: 'What this test validates, preconditions, etc.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'No tags',\r\n SELECTED_SINGULAR: 'selected',\r\n SELECTED_PLURAL: 'selected',\r\n DESCRIBE_PLACEHOLDER: 'describe name (optional)',\r\n COPY_DESCRIBE: '🗂 Copy describe()',\r\n MULTI_SELECT: '🗂 Multi-select',\r\n CANCEL_SELECT: '✕ Cancel',\r\n COPY_CMDS_BTN: '📋 Copy commands',\r\n COPY_ICPS_BTN: '📋 Copy interceptors',\r\n DEFAULT_DESCRIBE: 'Test suite',\r\n NO_TESTS: 'No saved tests',\r\n DELETE_TITLE: 'Delete',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Language',\r\n LANG_FIELD: 'Interface',\r\n HTTP_SECTION: '⚡ Advanced HTTP',\r\n HTTP_TITLE: 'Body validations',\r\n HTTP_SUB: 'GET → response · POST/PUT → request',\r\n SELECTOR_SECTION: '🎯 Selector strategy',\r\n SELECTOR_LABEL: 'Preferred attribute for cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (default)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#element)',\r\n SELECTOR_HINT: 'The recorder will look for this attribute first. If not found, it will try the others.',\r\n FOLDER_SECTION: '📁 Cypress Folder',\r\n FOLDER_CONNECTED: 'connected —',\r\n FOLDER_NOT_SET: 'not configured',\r\n FOLDER_CHANGE_BTN: '📁 Change folder',\r\n FOLDER_SELECT_BTN: '📁 Select folder',\r\n FOLDER_REVOKE_BTN: '✕ Revoke access',\r\n DATA_SECTION: '💾 Data',\r\n DATA_DESC: 'Export all your tests to JSON or import a backup.',\r\n EXPORT_BTN: '⬆️ Export tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Export tests',\r\n EXPORT_MODE_ALL: 'All',\r\n EXPORT_MODE_MANUAL: 'Manual selection',\r\n EXPORT_MODE_TAGS: 'By tags',\r\n EXPORT_ALL_DESC: 'All saved tests will be exported.',\r\n EXPORT_COUNT: 'To export:',\r\n EXPORT_CONFIRM: '⬆️ Export',\r\n EXPORT_CANCEL: 'Cancel',\r\n EXPORT_EMPTY: 'No tests to export.',\r\n EXPORT_NO_TAGS: 'No tags available.',\r\n EXPORT_TAGS_HINT: 'Select one or more tags to preview which tests will be exported.',\r\n EXPORT_RESULT_LABEL: 'Tests that will be exported:',\r\n IMPORT_BTN: '⬇️ Import tests',\r\n FOLDER_UPDATED_TOAST: '✓ Cypress folder updated',\r\n FOLDER_ERROR_TOAST: 'Error accessing the folder',\r\n IMPORT_SUCCESS: 'Data imported successfully.',\r\n IMPORT_ERROR: 'Error importing.',\r\n JSON_INVALID: 'The file is not valid JSON.',\r\n JSON_BAD_FORMAT: 'The file does not have the expected format.',\r\n SMART_SELECTOR_SECTION: '🔍 Smart selector',\r\n SMART_SELECTOR_TITLE: 'Smart selector',\r\n SMART_SELECTOR_SUB: 'Shows a picker when clicking elements with no valid selector.',\r\n START_HIDDEN_SECTION: '👁 Widget visibility',\r\n START_HIDDEN_TITLE: 'Start hidden',\r\n START_HIDDEN_SUB: 'The widget starts invisible. Use Ctrl+Shift+E to show or hide it.',\r\n RESUME_TTL_SECTION: '⏱ Recording continuity',\r\n RESUME_TTL_LABEL: 'Resume without asking (minutes)',\r\n RESUME_TTL_HINT: 'If you reload or switch projects, an active recording resumes without asking within this window. After that, you will be asked to continue or discard.',\r\n WIDGET_POSITION_SECTION: '🧲 Widget position',\r\n WIDGET_POSITION_HINT: 'Drag the record button to move it out of the way. Its position is remembered.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Reset position',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position reset',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Select a DOM element',\r\n PREVIEW_LABEL: 'navigate',\r\n CONFIRM_HINT: 'confirm',\r\n CANCEL_HINT: 'cancel',\r\n QUALITY_EXCELLENT: 'Excellent — has a testing attribute (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Good — has a valid id',\r\n QUALITY_ACCEPTABLE: 'Acceptable — CSS classes only',\r\n QUALITY_POOR: 'Not recommended — tag name or inline style only',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptors',\r\n COPY_CMDS_BTN: '📋 Copy commands',\r\n SHOW_INTERCEPTORS: '▼ Show interceptors',\r\n HIDE_INTERCEPTORS: '▲ Hide interceptors',\r\n SECTION_COMMANDS: 'Commands',\r\n NO_CMDS_YET: 'No commands yet',\r\n NO_ICP_SHORT: 'No interceptors',\r\n COPY_ICP_BTN: '📋 Copy interceptors',\r\n UP_TITLE: 'Move up',\r\n DOWN_TITLE: 'Move down',\r\n DEL_TITLE: 'Delete',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Reactivate access',\r\n PERMISSION_EXPIRED: '🔑 Permission expired',\r\n PERMISSION_EXPIRED_HINT: 'Click to reactivate access to your Cypress folder.',\r\n NO_ACCESS: '🔒 No access to local files',\r\n NO_ACCESS_HINT: 'Configure access in ⚙️ Config.',\r\n NO_FILES: 'No files',\r\n SELECT_FILE: '← Select a file from the tree',\r\n IT_LABEL: '🧪 it() to insert:',\r\n COPY_IT_BTN: '📋 Copy it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptors:',\r\n COPY_ICP_BTN: '📋 Copy interceptors',\r\n INSERT_BTN: '💾 Insert into file',\r\n EDIT_MANUAL_BTN: '✏️ Edit manually',\r\n CLOSE_BTN: '✕ Close',\r\n NEW_FILE_BTN: '+ New file',\r\n NEW_FOLDER_BTN: '+ New folder',\r\n REFRESH_BTN: '↻ Refresh',\r\n NEW_FILE_PLACEHOLDER: 'test-name',\r\n NEW_FOLDER_PLACEHOLDER: 'folder-name',\r\n NEW_FILE_CONFIRM: 'Create',\r\n NEW_FILE_CANCEL: 'Cancel',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'No file',\r\n COPY_TITLE: 'Copy editor content',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copy',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'No changes from original',\r\n NO_CHANGES_SHORT: 'No changes',\r\n LAUNCH_BTN: '▶ Run test',\r\n LAUNCH_LOCAL_ONLY: 'Move it to localhost to run tests',\r\n LAUNCH_RUNNING: '⏳ Running…',\r\n LAUNCH_PASSED: '✓ Test passed',\r\n LAUNCH_FAILED: '✗ Test failed',\r\n LAUNCH_NO_RUNNER: 'No local runner detected (did you start it?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Save',\r\n CLOSE_BTN: '✕ Close',\r\n BACK_TO_EDITOR: '← Back to editor',\r\n INSERT_BTN: '🪄 Insert blocks',\r\n INSERT_TITLE: 'Insert it() and beforeEach() into the editor content',\r\n INSERT_DONE: 'Blocks inserted into the editor',\r\n INSERT_ERROR: 'No valid describe() block found in the file',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 File access',\r\n FS_LATER_BTN: 'Not now',\r\n FS_SELECT_BTN: '📁 Select folder',\r\n FS_SUCCESS_TOAST: '✓ Cypress folder configured',\r\n FS_ERROR_TOAST: 'Error accessing the folder',\r\n FS_INTRO_HTML: 'The <strong style=\"color:#e6edf3\">advanced editor</strong> can insert your tests directly into the Cypress <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> files.',\r\n FS_STRUCTURE_HINT_HTML: 'Select the folder that contains the <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> subfolder. The extension expects this structure:',\r\n FS_TREE_PICK_HINT: '← select this folder',\r\n FS_TREE_READ_HINT: '← the extension will read here',\r\n FS_PERMISSION_NOTE: 'The permission is stored in the browser and will not be requested again.',\r\n ASSERTION_SECTION: '➕ Add assertion',\r\n ASSERT_SELECTOR_PH: 'selector, e.g.: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'expected value',\r\n ASSERT_ADD_BTN: '➕ Add',\r\n FILE_EDITOR_TITLE: '✏️ File editor',\r\n FILE_SAVED_TOAST: '✓ File saved',\r\n FILE_SAVE_ERROR_TOAST: 'Error saving the file',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Files',\r\n BTN_COMMANDS: 'Commands',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pause (Ctrl+P)',\r\n RESUME_TITLE: 'Resume (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSED',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Stop (Ctrl+R)',\r\n START_TITLE: 'Record (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Recording in progress',\r\n SESSION_RESUME_TEXT: 'There is an unfinished active recording.',\r\n SESSION_RESUME_COUNT: 'commands captured',\r\n SESSION_CONTINUE_BTN: 'Keep recording',\r\n SESSION_DISCARD_BTN: 'Discard',\r\n },\r\n};\r\n","export const I18N_FR = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Paramètres',\r\n SHOW_ADVANCED_EDITOR: 'Éditeur avancé',\r\n DIALOG_SAVED_TESTS: 'Tests enregistrés',\r\n DIALOG_COMMANDS: 'Aperçu des commandes Cypress',\r\n DIALOG_SAVE: \"Enregistrer l'enregistrement ?\",\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Description du test',\r\n CANCEL: 'Annuler',\r\n ASK: 'Enregistrer le test ?',\r\n YES_CONTINUE: 'Oui, continuer',\r\n NO_DISCARD: 'Non, ignorer',\r\n DESC_PLACEHOLDER: 'Ex : Connexion réussie avec identifiants valides',\r\n TAGS_LABEL: 'Étiquettes (optionnel, pour filtrer ensuite) :',\r\n TAGS_PLACEHOLDER: 'smoke, login, régression…',\r\n ADD_TAG: '+ Ajouter',\r\n NO_TAGS: 'Sans étiquettes',\r\n SAVE_BTN: '💾 Enregistrer',\r\n SAVE_AND_EDIT: '📝 Enregistrer et éditer',\r\n REMOVE_TAG_TITLE: 'Retirer',\r\n NOTES_LABEL: 'Description / Notes (optionnel) :',\r\n NOTES_PLACEHOLDER: 'Ce que ce test valide, conditions préalables, etc.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Sans étiquettes',\r\n SELECTED_SINGULAR: 'sélectionné',\r\n SELECTED_PLURAL: 'sélectionnés',\r\n DESCRIBE_PLACEHOLDER: 'Nom du describe (optionnel)',\r\n COPY_DESCRIBE: '🗂 Copier describe()',\r\n MULTI_SELECT: '🗂 Multi-sélection',\r\n CANCEL_SELECT: '✕ Annuler',\r\n COPY_CMDS_BTN: '📋 Copier les commandes',\r\n COPY_ICPS_BTN: '📋 Copier les intercepteurs',\r\n DEFAULT_DESCRIBE: 'Suite de tests',\r\n NO_TESTS: 'Aucun test enregistré',\r\n DELETE_TITLE: 'Supprimer',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Langue',\r\n LANG_FIELD: 'Interface',\r\n HTTP_SECTION: '⚡ HTTP Avancé',\r\n HTTP_TITLE: 'Validations du corps',\r\n HTTP_SUB: 'GET → réponse · POST/PUT → requête',\r\n SELECTOR_SECTION: '🎯 Stratégie de sélecteur',\r\n SELECTOR_LABEL: 'Attribut préféré pour cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (par défaut)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#élément)',\r\n SELECTOR_HINT: \"L'enregistreur cherchera d'abord cet attribut. Si absent, il essaiera les autres.\",\r\n FOLDER_SECTION: '📁 Dossier Cypress',\r\n FOLDER_CONNECTED: 'connecté —',\r\n FOLDER_NOT_SET: 'non configuré',\r\n FOLDER_CHANGE_BTN: '📁 Changer de dossier',\r\n FOLDER_SELECT_BTN: '📁 Sélectionner un dossier',\r\n FOLDER_REVOKE_BTN: \"✕ Révoquer l'accès\",\r\n DATA_SECTION: '💾 Données',\r\n DATA_DESC: 'Exportez tous vos tests en JSON ou importez une sauvegarde.',\r\n EXPORT_BTN: '⬆️ Exporter les tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Exporter les tests',\r\n EXPORT_MODE_ALL: 'Tout',\r\n EXPORT_MODE_MANUAL: 'Sélection manuelle',\r\n EXPORT_MODE_TAGS: 'Par tags',\r\n EXPORT_ALL_DESC: 'Tous les tests enregistrés seront exportés.',\r\n EXPORT_COUNT: 'À exporter :',\r\n EXPORT_CONFIRM: '⬆️ Exporter',\r\n EXPORT_CANCEL: 'Annuler',\r\n EXPORT_EMPTY: 'Aucun test à exporter.',\r\n EXPORT_NO_TAGS: 'Aucun tag disponible.',\r\n EXPORT_TAGS_HINT: 'Sélectionnez un ou plusieurs tags pour voir les tests qui seront exportés.',\r\n EXPORT_RESULT_LABEL: 'Tests qui seront exportés :',\r\n IMPORT_BTN: '⬇️ Importer les tests',\r\n FOLDER_UPDATED_TOAST: '✓ Dossier Cypress mis à jour',\r\n FOLDER_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\r\n IMPORT_SUCCESS: 'Données importées avec succès.',\r\n IMPORT_ERROR: \"Erreur lors de l'importation.\",\r\n JSON_INVALID: \"Le fichier n'est pas un JSON valide.\",\r\n JSON_BAD_FORMAT: \"Le fichier n'a pas le format attendu.\",\r\n SMART_SELECTOR_SECTION: '🔍 Sélecteur intelligent',\r\n SMART_SELECTOR_TITLE: 'Sélecteur intelligent',\r\n SMART_SELECTOR_SUB: 'Affiche un sélecteur lors du clic sur des éléments sans sélecteur valide.',\r\n START_HIDDEN_SECTION: '👁 Visibilité du widget',\r\n START_HIDDEN_TITLE: 'Démarrer masqué',\r\n START_HIDDEN_SUB: 'Le widget démarre invisible. Utilisez Ctrl+Shift+E pour l\\'afficher ou le masquer.',\r\n RESUME_TTL_SECTION: '⏱ Continuité d\\'enregistrement',\r\n RESUME_TTL_LABEL: 'Reprendre sans demander (minutes)',\r\n RESUME_TTL_HINT: 'Si vous rechargez ou changez de projet, un enregistrement actif reprend sans demander dans ce délai. Au-delà, il vous demandera de continuer ou d\\'ignorer.',\r\n WIDGET_POSITION_SECTION: '🧲 Position du widget',\r\n WIDGET_POSITION_HINT: 'Fais glisser le bouton d\\'enregistrement pour le déplacer. Sa position est mémorisée.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Réinitialiser la position',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position réinitialisée',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Sélectionnez un élément du DOM',\r\n PREVIEW_LABEL: 'naviguer',\r\n CONFIRM_HINT: 'confirmer',\r\n CANCEL_HINT: 'annuler',\r\n QUALITY_EXCELLENT: 'Excellent — attribut de test présent (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Bon — id valide',\r\n QUALITY_ACCEPTABLE: 'Acceptable — classes CSS uniquement',\r\n QUALITY_POOR: 'Déconseillé — seulement le nom de balise ou style inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Intercepteurs',\r\n COPY_CMDS_BTN: '📋 Copier les commandes',\r\n SHOW_INTERCEPTORS: '▼ Voir les intercepteurs',\r\n HIDE_INTERCEPTORS: '▲ Masquer les intercepteurs',\r\n SECTION_COMMANDS: 'Commandes',\r\n NO_CMDS_YET: 'Aucune commande encore',\r\n NO_ICP_SHORT: 'Aucun intercepteur',\r\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\r\n UP_TITLE: 'Monter',\r\n DOWN_TITLE: 'Descendre',\r\n DEL_TITLE: 'Supprimer',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: \"🔓 Réactiver l'accès\",\r\n PERMISSION_EXPIRED: '🔑 Autorisation expirée',\r\n PERMISSION_EXPIRED_HINT: \"Cliquez pour réactiver l'accès à votre dossier Cypress.\",\r\n NO_ACCESS: '🔒 Pas d\\'accès aux fichiers locaux',\r\n NO_ACCESS_HINT: \"Configurez l'accès dans ⚙️ Config.\",\r\n NO_FILES: 'Aucun fichier',\r\n SELECT_FILE: \"← Sélectionnez un fichier dans l'arborescence\",\r\n IT_LABEL: '🧪 it() à insérer :',\r\n COPY_IT_BTN: '📋 Copier it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() intercepteurs :',\r\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\r\n INSERT_BTN: '💾 Insérer dans le fichier',\r\n EDIT_MANUAL_BTN: '✏️ Éditer manuellement',\r\n CLOSE_BTN: '✕ Fermer',\r\n NEW_FILE_BTN: '+ Nouveau fichier',\r\n NEW_FOLDER_BTN: '+ Nouveau dossier',\r\n REFRESH_BTN: '↻ Actualiser',\r\n NEW_FILE_PLACEHOLDER: 'nom-du-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nom-du-dossier',\r\n NEW_FILE_CONFIRM: 'Créer',\r\n NEW_FILE_CANCEL: 'Annuler',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Sans fichier',\r\n COPY_TITLE: \"Copier le contenu de l'éditeur\",\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copier',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: \"Aucun changement par rapport à l'original\",\r\n NO_CHANGES_SHORT: 'Aucun changement',\r\n LAUNCH_BTN: '▶ Lancer le test',\r\n LAUNCH_LOCAL_ONLY: 'Passe en local pour pouvoir tester',\r\n LAUNCH_RUNNING: '⏳ Exécution…',\r\n LAUNCH_PASSED: '✓ Test réussi',\r\n LAUNCH_FAILED: '✗ Test échoué',\r\n LAUNCH_NO_RUNNER: \"Aucun runner local détecté (l'avez-vous démarré ?)\",\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Enregistrer',\r\n CLOSE_BTN: '✕ Fermer',\r\n BACK_TO_EDITOR: \"← Retour à l'éditeur\",\r\n INSERT_BTN: '🪄 Insérer les blocs',\r\n INSERT_TITLE: \"Insérer it() et beforeEach() dans le contenu de l'éditeur\",\r\n INSERT_DONE: \"Blocs insérés dans l'éditeur\",\r\n INSERT_ERROR: 'Aucun bloc describe() valide trouvé dans le fichier',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Accès aux fichiers',\r\n FS_LATER_BTN: 'Pas maintenant',\r\n FS_SELECT_BTN: '📁 Sélectionner un dossier',\r\n FS_SUCCESS_TOAST: '✓ Dossier Cypress configuré',\r\n FS_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\r\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">éditeur avancé</strong> peut insérer vos tests directement dans les fichiers <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Sélectionnez le dossier qui contient le sous-dossier <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'extension attend cette structure :',\r\n FS_TREE_PICK_HINT: '← sélectionnez ce dossier',\r\n FS_TREE_READ_HINT: '← l\\'extension lira ici',\r\n FS_PERMISSION_NOTE: 'L\\'autorisation est enregistrée dans le navigateur et ne sera plus demandée.',\r\n ASSERTION_SECTION: '➕ Ajouter une assertion',\r\n ASSERT_SELECTOR_PH: 'sélecteur, ex : [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valeur attendue',\r\n ASSERT_ADD_BTN: '➕ Ajouter',\r\n FILE_EDITOR_TITLE: '✏️ Éditeur de fichier',\r\n FILE_SAVED_TOAST: '✓ Fichier enregistré',\r\n FILE_SAVE_ERROR_TOAST: \"Erreur lors de l'enregistrement\",\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Fichiers',\r\n BTN_COMMANDS: 'Commandes',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pause (Ctrl+P)',\r\n RESUME_TITLE: 'Reprendre (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSE',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Arrêter (Ctrl+R)',\r\n START_TITLE: 'Enregistrer (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Enregistrement en cours',\r\n SESSION_RESUME_TEXT: 'Un enregistrement actif est inachevé.',\r\n SESSION_RESUME_COUNT: 'commandes capturées',\r\n SESSION_CONTINUE_BTN: 'Continuer l\\'enregistrement',\r\n SESSION_DISCARD_BTN: 'Ignorer',\r\n },\r\n};\r\n","export const I18N_IT = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Impostazioni',\r\n SHOW_ADVANCED_EDITOR: 'Editor avanzato',\r\n DIALOG_SAVED_TESTS: 'Test salvati',\r\n DIALOG_COMMANDS: 'Anteprima comandi Cypress',\r\n DIALOG_SAVE: 'Salvare la registrazione?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Descrizione del test',\r\n CANCEL: 'Annulla',\r\n ASK: 'Salvare il test registrato?',\r\n YES_CONTINUE: 'Sì, continua',\r\n NO_DISCARD: 'No, annulla',\r\n DESC_PLACEHOLDER: 'Es: Login riuscito con credenziali valide',\r\n TAGS_LABEL: 'Etichette (opzionale, per filtrare dopo):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regressione…',\r\n ADD_TAG: '+ Aggiungi',\r\n NO_TAGS: 'Nessuna etichetta',\r\n SAVE_BTN: '💾 Salva',\r\n SAVE_AND_EDIT: '📝 Salva e modifica',\r\n REMOVE_TAG_TITLE: 'Rimuovi',\r\n NOTES_LABEL: 'Descrizione / Note (opzionale):',\r\n NOTES_PLACEHOLDER: 'Cosa valida questo test, condizioni preliminari, ecc.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Nessuna etichetta',\r\n SELECTED_SINGULAR: 'selezionato',\r\n SELECTED_PLURAL: 'selezionati',\r\n DESCRIBE_PLACEHOLDER: 'Nome del describe (opzionale)',\r\n COPY_DESCRIBE: '🗂 Copia describe()',\r\n MULTI_SELECT: '🗂 Multi-selezione',\r\n CANCEL_SELECT: '✕ Annulla',\r\n COPY_CMDS_BTN: '📋 Copia comandi',\r\n COPY_ICPS_BTN: '📋 Copia interceptor',\r\n DEFAULT_DESCRIBE: 'Suite di test',\r\n NO_TESTS: 'Nessun test salvato',\r\n DELETE_TITLE: 'Elimina',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Lingua',\r\n LANG_FIELD: 'Interfaccia',\r\n HTTP_SECTION: '⚡ HTTP Avanzato',\r\n HTTP_TITLE: 'Validazioni del body',\r\n HTTP_SUB: 'GET → risposta · POST/PUT → richiesta',\r\n SELECTOR_SECTION: '🎯 Strategia selettore',\r\n SELECTOR_LABEL: 'Attributo preferito per cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (predefinito)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#elemento)',\r\n SELECTOR_HINT: 'Il registratore cercherà prima questo attributo. Se assente, proverà gli altri.',\r\n FOLDER_SECTION: '📁 Cartella Cypress',\r\n FOLDER_CONNECTED: 'connesso —',\r\n FOLDER_NOT_SET: 'non configurato',\r\n FOLDER_CHANGE_BTN: '📁 Cambia cartella',\r\n FOLDER_SELECT_BTN: '📁 Seleziona cartella',\r\n FOLDER_REVOKE_BTN: '✕ Revoca accesso',\r\n DATA_SECTION: '💾 Dati',\r\n DATA_DESC: 'Esporta tutti i tuoi test in JSON o importa un backup.',\r\n EXPORT_BTN: '⬆️ Esporta test',\r\n EXPORT_DIALOG_TITLE: '⬆️ Esporta test',\r\n EXPORT_MODE_ALL: 'Tutto',\r\n EXPORT_MODE_MANUAL: 'Selezione manuale',\r\n EXPORT_MODE_TAGS: 'Per tag',\r\n EXPORT_ALL_DESC: 'Verranno esportati tutti i test salvati.',\r\n EXPORT_COUNT: 'Da esportare:',\r\n EXPORT_CONFIRM: '⬆️ Esporta',\r\n EXPORT_CANCEL: 'Annulla',\r\n EXPORT_EMPTY: 'Nessun test da esportare.',\r\n EXPORT_NO_TAGS: 'Nessun tag disponibile.',\r\n EXPORT_TAGS_HINT: 'Seleziona uno o più tag per vedere quali test verranno esportati.',\r\n EXPORT_RESULT_LABEL: 'Test che verranno esportati:',\r\n IMPORT_BTN: '⬇️ Importa test',\r\n FOLDER_UPDATED_TOAST: '✓ Cartella Cypress aggiornata',\r\n FOLDER_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\r\n IMPORT_SUCCESS: 'Dati importati correttamente.',\r\n IMPORT_ERROR: \"Errore durante l'importazione.\",\r\n JSON_INVALID: 'Il file non è un JSON valido.',\r\n JSON_BAD_FORMAT: 'Il file non ha il formato previsto.',\r\n SMART_SELECTOR_SECTION: '🔍 Selettore intelligente',\r\n SMART_SELECTOR_TITLE: 'Selettore intelligente',\r\n SMART_SELECTOR_SUB: 'Mostra un selettore quando si fa clic su elementi senza selettore valido.',\r\n START_HIDDEN_SECTION: '👁 Visibilità del widget',\r\n START_HIDDEN_TITLE: 'Avvia nascosto',\r\n START_HIDDEN_SUB: 'Il widget si avvia invisibile. Usa Ctrl+Shift+E per mostrarlo o nasconderlo.',\r\n RESUME_TTL_SECTION: '⏱ Continuità di registrazione',\r\n RESUME_TTL_LABEL: 'Riprendi senza chiedere (minuti)',\r\n RESUME_TTL_HINT: 'Se ricarichi o cambi progetto, una registrazione attiva riprende senza chiedere entro questo intervallo. Trascorso, ti chiederà se continuare o annullare.',\r\n WIDGET_POSITION_SECTION: '🧲 Posizione del widget',\r\n WIDGET_POSITION_HINT: 'Trascina il pulsante di registrazione per spostarlo. La posizione viene ricordata.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Reimposta posizione',\r\n WIDGET_POSITION_RESET_DONE: '✓ Posizione reimpostata',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Seleziona un elemento DOM',\r\n PREVIEW_LABEL: 'navigare',\r\n CONFIRM_HINT: 'confermare',\r\n CANCEL_HINT: 'annullare',\r\n QUALITY_EXCELLENT: 'Eccellente — attributo di test presente (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Buono — id valido',\r\n QUALITY_ACCEPTABLE: 'Accettabile — solo classi CSS',\r\n QUALITY_POOR: 'Sconsigliato — solo tag o stile inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptor',\r\n COPY_CMDS_BTN: '📋 Copia comandi',\r\n SHOW_INTERCEPTORS: '▼ Vedi interceptor',\r\n HIDE_INTERCEPTORS: '▲ Nascondi interceptor',\r\n SECTION_COMMANDS: 'Comandi',\r\n NO_CMDS_YET: 'Ancora nessun comando',\r\n NO_ICP_SHORT: 'Nessun interceptor',\r\n COPY_ICP_BTN: '📋 Copia interceptor',\r\n UP_TITLE: 'Su',\r\n DOWN_TITLE: 'Giù',\r\n DEL_TITLE: 'Elimina',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Riattiva accesso',\r\n PERMISSION_EXPIRED: '🔑 Autorizzazione scaduta',\r\n PERMISSION_EXPIRED_HINT: \"Clicca per riattivare l'accesso alla cartella Cypress.\",\r\n NO_ACCESS: '🔒 Nessun accesso ai file locali',\r\n NO_ACCESS_HINT: \"Configura l'accesso in ⚙️ Config.\",\r\n NO_FILES: 'Nessun file',\r\n SELECT_FILE: \"← Seleziona un file dall'albero\",\r\n IT_LABEL: '🧪 it() da inserire:',\r\n COPY_IT_BTN: '📋 Copia it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptor:',\r\n COPY_ICP_BTN: '📋 Copia interceptor',\r\n INSERT_BTN: '💾 Inserisci nel file',\r\n EDIT_MANUAL_BTN: '✏️ Modifica manualmente',\r\n CLOSE_BTN: '✕ Chiudi',\r\n NEW_FILE_BTN: '+ Nuovo file',\r\n NEW_FOLDER_BTN: '+ Nuova cartella',\r\n REFRESH_BTN: '↻ Aggiorna',\r\n NEW_FILE_PLACEHOLDER: 'nome-del-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nome-cartella',\r\n NEW_FILE_CONFIRM: 'Crea',\r\n NEW_FILE_CANCEL: 'Annulla',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Nessun file',\r\n COPY_TITLE: \"Copia il contenuto dell'editor\",\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copia',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: \"Nessuna modifica rispetto all'originale\",\r\n NO_CHANGES_SHORT: 'Nessuna modifica',\r\n LAUNCH_BTN: '▶ Esegui test',\r\n LAUNCH_LOCAL_ONLY: 'Spostati in locale per poter testare',\r\n LAUNCH_RUNNING: '⏳ Esecuzione…',\r\n LAUNCH_PASSED: '✓ Test superato',\r\n LAUNCH_FAILED: '✗ Test fallito',\r\n LAUNCH_NO_RUNNER: \"Nessun runner locale rilevato (l'hai avviato?)\",\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Salva',\r\n CLOSE_BTN: '✕ Chiudi',\r\n BACK_TO_EDITOR: \"← Torna all'editor\",\r\n INSERT_BTN: '🪄 Inserisci blocchi',\r\n INSERT_TITLE: \"Inserisci it() e beforeEach() nel contenuto dell'editor\",\r\n INSERT_DONE: \"Blocchi inseriti nell'editor\",\r\n INSERT_ERROR: 'Nessun blocco describe() valido trovato nel file',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Accesso ai file',\r\n FS_LATER_BTN: 'Non ora',\r\n FS_SELECT_BTN: '📁 Seleziona cartella',\r\n FS_SUCCESS_TOAST: '✓ Cartella Cypress configurata',\r\n FS_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\r\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">editor avanzato</strong> può inserire i tuoi test direttamente nei file <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> di Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Seleziona la cartella che contiene la sottocartella <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'estensione si aspetta questa struttura:',\r\n FS_TREE_PICK_HINT: '← seleziona questa cartella',\r\n FS_TREE_READ_HINT: '← l\\'estensione leggerà qui',\r\n FS_PERMISSION_NOTE: 'Il permesso viene salvato nel browser e non sarà richiesto di nuovo.',\r\n ASSERTION_SECTION: '➕ Aggiungi asserzione',\r\n ASSERT_SELECTOR_PH: 'selettore, es: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valore atteso',\r\n ASSERT_ADD_BTN: '➕ Aggiungi',\r\n FILE_EDITOR_TITLE: '✏️ Editor di file',\r\n FILE_SAVED_TOAST: '✓ File salvato',\r\n FILE_SAVE_ERROR_TOAST: 'Errore durante il salvataggio',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'File',\r\n BTN_COMMANDS: 'Comandi',\r\n BTN_TESTS: 'Test',\r\n PAUSE_TITLE: 'Pausa (Ctrl+P)',\r\n RESUME_TITLE: 'Riprendi (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSA',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Ferma (Ctrl+R)',\r\n START_TITLE: 'Registra (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Registrazione in corso',\r\n SESSION_RESUME_TEXT: 'C\\'è una registrazione attiva non terminata.',\r\n SESSION_RESUME_COUNT: 'comandi catturati',\r\n SESSION_CONTINUE_BTN: 'Continua a registrare',\r\n SESSION_DISCARD_BTN: 'Annulla',\r\n },\r\n};\r\n","export const I18N_DE = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Einstellungen',\r\n SHOW_ADVANCED_EDITOR: 'Erweiterter Editor',\r\n DIALOG_SAVED_TESTS: 'Gespeicherte Tests',\r\n DIALOG_COMMANDS: 'Cypress-Befehle Vorschau',\r\n DIALOG_SAVE: 'Aufzeichnung speichern?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Testbeschreibung',\r\n CANCEL: 'Abbrechen',\r\n ASK: 'Aufgezeichneten Test speichern?',\r\n YES_CONTINUE: 'Ja, weiter',\r\n NO_DISCARD: 'Nein, verwerfen',\r\n DESC_PLACEHOLDER: 'Z. B.: Erfolgreiche Anmeldung mit gültigen Zugangsdaten',\r\n TAGS_LABEL: 'Tags (optional, zum späteren Filtern):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\r\n ADD_TAG: '+ Hinzufügen',\r\n NO_TAGS: 'Keine Tags',\r\n SAVE_BTN: '💾 Speichern',\r\n SAVE_AND_EDIT: '📝 Speichern und bearbeiten',\r\n REMOVE_TAG_TITLE: 'Entfernen',\r\n NOTES_LABEL: 'Beschreibung / Notizen (optional):',\r\n NOTES_PLACEHOLDER: 'Was dieser Test validiert, Voraussetzungen usw.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Keine Tags',\r\n SELECTED_SINGULAR: 'ausgewählt',\r\n SELECTED_PLURAL: 'ausgewählt',\r\n DESCRIBE_PLACEHOLDER: 'describe-Name (optional)',\r\n COPY_DESCRIBE: '🗂 describe() kopieren',\r\n MULTI_SELECT: '🗂 Mehrfachauswahl',\r\n CANCEL_SELECT: '✕ Abbrechen',\r\n COPY_CMDS_BTN: '📋 Befehle kopieren',\r\n COPY_ICPS_BTN: '📋 Interceptors kopieren',\r\n DEFAULT_DESCRIBE: 'Test-Suite',\r\n NO_TESTS: 'Keine gespeicherten Tests',\r\n DELETE_TITLE: 'Löschen',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Sprache',\r\n LANG_FIELD: 'Oberfläche',\r\n HTTP_SECTION: '⚡ Erweitertes HTTP',\r\n HTTP_TITLE: 'Body-Validierungen',\r\n HTTP_SUB: 'GET → Antwort · POST/PUT → Anfrage',\r\n SELECTOR_SECTION: '🎯 Selector-Strategie',\r\n SELECTOR_LABEL: 'Bevorzugtes Attribut für cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (Standard)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#element)',\r\n SELECTOR_HINT: 'Der Recorder sucht zuerst nach diesem Attribut. Falls nicht gefunden, versucht er die anderen.',\r\n FOLDER_SECTION: '📁 Cypress-Ordner',\r\n FOLDER_CONNECTED: 'verbunden —',\r\n FOLDER_NOT_SET: 'nicht konfiguriert',\r\n FOLDER_CHANGE_BTN: '📁 Ordner wechseln',\r\n FOLDER_SELECT_BTN: '📁 Ordner auswählen',\r\n FOLDER_REVOKE_BTN: '✕ Zugriff widerrufen',\r\n DATA_SECTION: '💾 Daten',\r\n DATA_DESC: 'Exportieren Sie alle Tests als JSON oder importieren Sie ein Backup.',\r\n EXPORT_BTN: '⬆️ Tests exportieren',\r\n EXPORT_DIALOG_TITLE: '⬆️ Tests exportieren',\r\n EXPORT_MODE_ALL: 'Alle',\r\n EXPORT_MODE_MANUAL: 'Manuelle Auswahl',\r\n EXPORT_MODE_TAGS: 'Nach Tags',\r\n EXPORT_ALL_DESC: 'Alle gespeicherten Tests werden exportiert.',\r\n EXPORT_COUNT: 'Zu exportieren:',\r\n EXPORT_CONFIRM: '⬆️ Exportieren',\r\n EXPORT_CANCEL: 'Abbrechen',\r\n EXPORT_EMPTY: 'Keine Tests zum Exportieren.',\r\n EXPORT_NO_TAGS: 'Keine Tags verfügbar.',\r\n EXPORT_TAGS_HINT: 'Wähle ein oder mehrere Tags, um zu sehen, welche Tests exportiert werden.',\r\n EXPORT_RESULT_LABEL: 'Diese Tests werden exportiert:',\r\n IMPORT_BTN: '⬇️ Tests importieren',\r\n FOLDER_UPDATED_TOAST: '✓ Cypress-Ordner aktualisiert',\r\n FOLDER_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\r\n IMPORT_SUCCESS: 'Daten erfolgreich importiert.',\r\n IMPORT_ERROR: 'Fehler beim Importieren.',\r\n JSON_INVALID: 'Die Datei ist kein gültiges JSON.',\r\n JSON_BAD_FORMAT: 'Die Datei hat nicht das erwartete Format.',\r\n SMART_SELECTOR_SECTION: '🔍 Intelligenter Selektor',\r\n SMART_SELECTOR_TITLE: 'Intelligenter Selektor',\r\n SMART_SELECTOR_SUB: 'Zeigt ein Auswahlfeld, wenn auf Elemente ohne gültigen Selektor geklickt wird.',\r\n START_HIDDEN_SECTION: '👁 Widget-Sichtbarkeit',\r\n START_HIDDEN_TITLE: 'Versteckt starten',\r\n START_HIDDEN_SUB: 'Das Widget startet unsichtbar. Verwenden Sie Ctrl+Shift+E zum Ein-/Ausblenden.',\r\n RESUME_TTL_SECTION: '⏱ Aufzeichnungskontinuität',\r\n RESUME_TTL_LABEL: 'Ohne Nachfrage fortsetzen (Minuten)',\r\n RESUME_TTL_HINT: 'Wenn Sie neu laden oder das Projekt wechseln, wird eine aktive Aufzeichnung innerhalb dieses Zeitfensters ohne Nachfrage fortgesetzt. Danach werden Sie gefragt, ob fortsetzen oder verwerfen.',\r\n WIDGET_POSITION_SECTION: '🧲 Widget-Position',\r\n WIDGET_POSITION_HINT: 'Ziehe den Aufnahme-Button, um ihn aus dem Weg zu schieben. Die Position wird gespeichert.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Position zurücksetzen',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position zurückgesetzt',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'DOM-Element auswählen',\r\n PREVIEW_LABEL: 'navigieren',\r\n CONFIRM_HINT: 'bestätigen',\r\n CANCEL_HINT: 'abbrechen',\r\n QUALITY_EXCELLENT: 'Ausgezeichnet — Test-Attribut vorhanden (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Gut — gültige ID',\r\n QUALITY_ACCEPTABLE: 'Akzeptabel — nur CSS-Klassen',\r\n QUALITY_POOR: 'Nicht empfohlen — nur Tag oder Inline-Style',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptors',\r\n COPY_CMDS_BTN: '📋 Befehle kopieren',\r\n SHOW_INTERCEPTORS: '▼ Interceptors anzeigen',\r\n HIDE_INTERCEPTORS: '▲ Interceptors ausblenden',\r\n SECTION_COMMANDS: 'Befehle',\r\n NO_CMDS_YET: 'Noch keine Befehle',\r\n NO_ICP_SHORT: 'Keine Interceptors',\r\n COPY_ICP_BTN: '📋 Interceptors kopieren',\r\n UP_TITLE: 'Nach oben',\r\n DOWN_TITLE: 'Nach unten',\r\n DEL_TITLE: 'Löschen',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Zugriff reaktivieren',\r\n PERMISSION_EXPIRED: '🔑 Berechtigung abgelaufen',\r\n PERMISSION_EXPIRED_HINT: 'Klicken Sie, um den Zugriff auf Ihren Cypress-Ordner zu reaktivieren.',\r\n NO_ACCESS: '🔒 Kein Zugriff auf lokale Dateien',\r\n NO_ACCESS_HINT: 'Konfigurieren Sie den Zugriff unter ⚙️ Config.',\r\n NO_FILES: 'Keine Dateien',\r\n SELECT_FILE: '← Wählen Sie eine Datei aus dem Baum',\r\n IT_LABEL: '🧪 it() zum Einfügen:',\r\n COPY_IT_BTN: '📋 it() kopieren',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() Interceptors:',\r\n COPY_ICP_BTN: '📋 Interceptors kopieren',\r\n INSERT_BTN: '💾 In Datei einfügen',\r\n EDIT_MANUAL_BTN: '✏️ Manuell bearbeiten',\r\n CLOSE_BTN: '✕ Schließen',\r\n NEW_FILE_BTN: '+ Neue Datei',\r\n NEW_FOLDER_BTN: '+ Neuer Ordner',\r\n REFRESH_BTN: '↻ Aktualisieren',\r\n NEW_FILE_PLACEHOLDER: 'test-name',\r\n NEW_FOLDER_PLACEHOLDER: 'ordnername',\r\n NEW_FILE_CONFIRM: 'Erstellen',\r\n NEW_FILE_CANCEL: 'Abbrechen',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Keine Datei',\r\n COPY_TITLE: 'Editor-Inhalt kopieren',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Kopieren',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'Keine Änderungen gegenüber dem Original',\r\n NO_CHANGES_SHORT: 'Keine Änderungen',\r\n LAUNCH_BTN: '▶ Test starten',\r\n LAUNCH_LOCAL_ONLY: 'Wechsle zu localhost, um Tests auszuführen',\r\n LAUNCH_RUNNING: '⏳ Läuft…',\r\n LAUNCH_PASSED: '✓ Test bestanden',\r\n LAUNCH_FAILED: '✗ Test fehlgeschlagen',\r\n LAUNCH_NO_RUNNER: 'Kein lokaler Runner erkannt (gestartet?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Speichern',\r\n CLOSE_BTN: '✕ Schließen',\r\n BACK_TO_EDITOR: '← Zurück zum Editor',\r\n INSERT_BTN: '🪄 Blöcke einfügen',\r\n INSERT_TITLE: 'it() und beforeEach() in den Editor-Inhalt einfügen',\r\n INSERT_DONE: 'Blöcke in den Editor eingefügt',\r\n INSERT_ERROR: 'Kein gültiger describe()-Block in der Datei gefunden',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Dateizugriff',\r\n FS_LATER_BTN: 'Nicht jetzt',\r\n FS_SELECT_BTN: '📁 Ordner auswählen',\r\n FS_SUCCESS_TOAST: '✓ Cypress-Ordner konfiguriert',\r\n FS_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\r\n FS_INTRO_HTML: 'Der <strong style=\"color:#e6edf3\">erweiterte Editor</strong> kann Ihre Tests direkt in die Cypress-Dateien <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> einfügen.',\r\n FS_STRUCTURE_HINT_HTML: 'Wählen Sie den Ordner, der den Unterordner <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> enthält. Die Erweiterung erwartet diese Struktur:',\r\n FS_TREE_PICK_HINT: '← diesen Ordner auswählen',\r\n FS_TREE_READ_HINT: '← die Erweiterung liest hier',\r\n FS_PERMISSION_NOTE: 'Die Berechtigung wird im Browser gespeichert und nicht erneut angefordert.',\r\n ASSERTION_SECTION: '➕ Assertion hinzufügen',\r\n ASSERT_SELECTOR_PH: 'Selektor, z. B.: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'erwarteter Wert',\r\n ASSERT_ADD_BTN: '➕ Hinzufügen',\r\n FILE_EDITOR_TITLE: '✏️ Datei-Editor',\r\n FILE_SAVED_TOAST: '✓ Datei gespeichert',\r\n FILE_SAVE_ERROR_TOAST: 'Fehler beim Speichern',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Dateien',\r\n BTN_COMMANDS: 'Befehle',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pausieren (Ctrl+P)',\r\n RESUME_TITLE: 'Fortsetzen (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSE',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Stopp (Ctrl+R)',\r\n START_TITLE: 'Aufzeichnen (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Aufzeichnung läuft',\r\n SESSION_RESUME_TEXT: 'Es gibt eine nicht abgeschlossene aktive Aufzeichnung.',\r\n SESSION_RESUME_COUNT: 'erfasste Befehle',\r\n SESSION_CONTINUE_BTN: 'Weiter aufzeichnen',\r\n SESSION_DISCARD_BTN: 'Verwerfen',\r\n },\r\n};\r\n","import { type Lang, isLang } from '../models/lang.model';\r\nimport { Subject } from '../utils/subject';\r\nimport { I18N_ES } from '../i18n/es';\r\nimport { I18N_EN } from '../i18n/en';\r\nimport { I18N_FR } from '../i18n/fr';\r\nimport { I18N_IT } from '../i18n/it';\r\nimport { I18N_DE } from '../i18n/de';\r\n\r\ntype Translations = typeof I18N_ES;\r\n\r\nexport class TranslationService {\r\n private readonly lang$: Subject<Lang>;\r\n\r\n private readonly translations: Record<Lang, Translations> = {\r\n es: I18N_ES,\r\n en: I18N_EN,\r\n fr: I18N_FR,\r\n it: I18N_IT,\r\n de: I18N_DE,\r\n };\r\n\r\n constructor() {\r\n this.lang$ = new Subject<Lang>(this.detectLang());\r\n }\r\n\r\n setLang(lang: Lang): void {\r\n this.lang$.next(lang);\r\n }\r\n\r\n getLang(): Lang {\r\n return this.lang$.getValue();\r\n }\r\n\r\n /** Subscribe to language changes; returns an unsubscribe function. */\r\n onLangChange(fn: (lang: Lang) => void): () => void {\r\n return this.lang$.subscribe(fn);\r\n }\r\n\r\n translate(key: string): string {\r\n const keys = key.split('.');\r\n let value: unknown = this.translations[this.lang$.getValue()];\r\n for (const k of keys) {\r\n value = (value as Record<string, unknown>)?.[k];\r\n if (value === undefined) return key;\r\n }\r\n return value as string;\r\n }\r\n\r\n detectLang(): Lang {\r\n const browserLang = navigator.language.split('-')[0];\r\n return isLang(browserLang) ? browserLang : 'es';\r\n }\r\n}\r\n\r\nexport const translationService = new TranslationService();\r\n","function gcd(a: number, b: number): number {\n while (b) { const t = b; b = a % b; a = t; }\n return a;\n}\n\n/**\n * Escapes backslashes and single quotes so a value can be safely embedded inside\n * a single-quoted JavaScript string literal — e.g. an `it('…')` / `describe('…')`\n * name. Without this, a test named `User's login` produces broken generated JS.\n */\nexport function escapeSingleQuotes(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n/**\n * Normalizes indentation in a code block and prefixes every line with baseIndent.\n *\n * Algorithm:\n * 1. Strip trailing whitespace from each line.\n * 2. Find the minimum leading-whitespace count of non-empty lines (dedent).\n * 3. Compute the indent step as the GCD of all non-zero relative indent values,\n * so the original indent unit (4-space, 8-space, etc.) maps to 2-space levels.\n * 4. Re-emit each line as: baseIndent + ' '.repeat(level) + trimmedContent.\n *\n * This handles multi-line interceptor/command blocks that were stored with\n * inconsistent or file-origin indentation.\n */\nexport function normalizeBlock(code: string, baseIndent: string): string {\n const lines = code.split('\\n').map(l => l.trimEnd());\n const nonEmpty = lines.filter(l => l.trim().length > 0);\n if (!nonEmpty.length) return '';\n\n const indents = nonEmpty.map(l => l.length - l.trimStart().length);\n const minIndent = Math.min(...indents);\n const relIndents = [...new Set(indents.map(n => n - minIndent).filter(n => n > 0))];\n const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;\n\n return lines\n .map(l => {\n if (!l.trim()) return '';\n const level = Math.round((l.length - l.trimStart().length - minIndent) / step);\n return baseIndent + ' '.repeat(level) + l.trimStart();\n })\n .join('\\n');\n}\n","import { type Lang, isLang } from '../models/lang.model';\r\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\r\n\r\nexport class TransformationService {\r\n toLang(lang: string): Lang {\r\n return isLang(lang) ? lang : 'en';\r\n }\r\n\r\n generateItDescription(description: string, commands: string[]): string {\r\n const commandsBlock = commands.map((cmd) => normalizeBlock(cmd, ' ')).join('\\n');\r\n return `it('${escapeSingleQuotes(description)}', () => {\\n${commandsBlock}\\n});`;\r\n }\r\n}\r\n\r\nexport const transformationService = new TransformationService();\r\n","export interface DirectoryNode {\r\n name: string;\r\n kind: 'directory';\r\n children: (DirectoryNode | FileNode)[];\r\n}\r\n\r\nexport interface FileNode {\r\n name: string;\r\n kind: 'file';\r\n}\r\n\r\nexport class AdvancedTestTransformationService {\r\n insertBeforeEach(content: string, interceptors: string, alertFn?: (msg: string) => void): string {\r\n const match = content.match(/(describe\\s*\\(.*?{)/s);\r\n if (!match) {\r\n alertFn?.('ADVANCED_EDITOR.NO_DESCRIBE');\r\n return '';\r\n }\r\n const insertPos = (match.index ?? 0) + match[0].length;\r\n const beforeEachBlock = `\\n beforeEach(() => {\\n${interceptors} })\\n`;\r\n return content.slice(0, insertPos) + beforeEachBlock + content.slice(insertPos);\r\n }\r\n\r\n insertItBlock(content: string, itBlock: string, alertFn?: (msg: string) => void): string {\r\n const idx = content.lastIndexOf('})');\r\n if (idx === -1) {\r\n alertFn?.('ADVANCED_EDITOR.NO_END');\r\n return '';\r\n }\r\n return content.slice(0, idx) + '\\n' + itBlock + '\\n' + content.slice(idx);\r\n }\r\n\r\n buildBlockComment(notes: string): string {\r\n if (!notes.trim()) return '';\r\n const lines = notes.split('\\n').map(l => ` * ${l}`).join('\\n');\r\n return `/**\\n${lines}\\n */`;\r\n }\r\n\r\n isFile(file: unknown): boolean {\r\n return !!file && (file as FileNode).kind === 'file';\r\n }\r\n\r\n async scanDirectory(dirHandle: FileSystemDirectoryHandle): Promise<DirectoryNode> {\r\n const result: DirectoryNode = { name: dirHandle.name, kind: 'directory', children: [] };\r\n for await (const entry of dirHandle.values()) {\r\n if (entry.kind === 'directory') {\r\n result.children.push(await this.scanDirectory(entry as FileSystemDirectoryHandle));\r\n } else {\r\n result.children.push({ name: entry.name, kind: 'file' });\r\n }\r\n }\r\n return result;\r\n }\r\n}\r\n\r\nexport const advancedTestTransformationService = new AdvancedTestTransformationService();\r\n","import { INPUT_TYPES } from '../models/input-types.model';\r\nimport type { ActiveSessionState } from '../models/active-session.model';\r\nimport { Subject } from '../utils/subject';\r\nimport { FORBIDDEN_ID_PREFIXES } from '../utils/selector-quality.utils';\r\n\r\nconst OWN_SELECTOR = '[data-cy=\"lib-e2e-cypress-for-dummys\"]';\r\n\r\nexport type SelectorStrategy = 'data-cy' | 'data-testid' | 'aria-label' | 'id';\r\n\r\n/** Generates a stable, collision-resistant session id (browser + jsdom safe). */\r\nfunction createSessionId(): string {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return crypto.randomUUID();\r\n }\r\n return `sess-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;\r\n}\r\n\r\nexport class RecordingService {\r\n private readonly commands$ = new Subject<string[]>([]);\r\n private readonly interceptors$ = new Subject<string[]>([]);\r\n private readonly isRecording$ = new Subject<boolean>(false);\r\n private readonly isPaused$ = new Subject<boolean>(false);\r\n private readonly selectorNotFound$ = new Subject<{ target: HTMLElement; action: 'click' } | null>(null);\r\n private readonly inputDebounceTimers = new Map<HTMLElement, ReturnType<typeof setTimeout>>();\r\n private readonly abort = new AbortController();\r\n\r\n selectorStrategy: SelectorStrategy = 'data-cy';\r\n\r\n /** Stable id of the current live session (null when none has started). */\r\n sessionId: string | null = null;\r\n private startedAt = 0;\r\n\r\n // Stored originals for history patching cleanup\r\n private readonly origPushState = history.pushState.bind(history);\r\n private readonly origReplaceState = history.replaceState.bind(history);\r\n\r\n constructor() {\r\n this.listenToClicks();\r\n this.listenToInput();\r\n this.listenToSelect();\r\n this.listenToRouteChanges();\r\n }\r\n\r\n // ── Public API ────────────────────────────────────────────────────────────\r\n\r\n startRecording(): void {\r\n this.sessionId = createSessionId();\r\n this.startedAt = Date.now();\r\n this.isPaused$.next(false);\r\n this.isRecording$.next(true);\r\n this.addCommand(`cy.viewport(1900, 1200)`);\r\n this.addCommand(`cy.visit('${window.location.pathname}')`);\r\n this.addCommand(`cy.get('[data-cy=\"lib-e2e-cypress-for-dummys\"]').invoke('hide');`);\r\n }\r\n\r\n /**\r\n * Rehydrates a previously persisted session WITHOUT running the startRecording\r\n * bootstrap (no viewport/visit/hide). Used to continue a recording across a\r\n * micro-frontend crossing or a same-origin reload.\r\n * See docs/specs/006-cross-app-recording-continuity.md.\r\n */\r\n restoreSession(state: ActiveSessionState): void {\r\n this.sessionId = state.sessionId;\r\n this.startedAt = state.startedAt;\r\n this.selectorStrategy = state.selectorStrategy;\r\n this.commands$.next([...state.commands]);\r\n this.interceptors$.next([...state.interceptors]);\r\n this.isPaused$.next(state.isPaused);\r\n // isRecording last so subscribers observe a fully-populated buffer.\r\n this.isRecording$.next(state.isRecording);\r\n }\r\n\r\n /** Full snapshot of the live session for persistence. */\r\n getSessionSnapshot(): ActiveSessionState {\r\n return {\r\n sessionId: this.sessionId ?? createSessionId(),\r\n isRecording: this.isRecording$.getValue(),\r\n isPaused: this.isPaused$.getValue(),\r\n commands: this.commands$.getValue(),\r\n interceptors: this.interceptors$.getValue(),\r\n selectorStrategy: this.selectorStrategy,\r\n startedAt: this.startedAt,\r\n updatedAt: Date.now(),\r\n };\r\n }\r\n\r\n stopRecording(): void {\r\n this.isPaused$.next(false);\r\n this.isRecording$.next(false);\r\n }\r\n\r\n toggleRecording(): void {\r\n if (this.isRecording$.getValue()) {\r\n this.stopRecording();\r\n } else {\r\n this.startRecording();\r\n }\r\n }\r\n\r\n pauseRecording(): void {\r\n if (!this.isRecording$.getValue()) return;\r\n this.isPaused$.next(true);\r\n }\r\n\r\n resumeRecording(): void {\r\n this.isPaused$.next(false);\r\n }\r\n\r\n togglePause(): void {\r\n if (this.isPaused$.getValue()) {\r\n this.resumeRecording();\r\n } else {\r\n this.pauseRecording();\r\n }\r\n }\r\n\r\n addCommand(cmd: string): void {\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n this.commands$.next([...this.commands$.getValue(), cmd]);\r\n }\r\n\r\n /** Appends a command regardless of recording/paused state (e.g. assertions added manually). */\r\n appendCommand(cmd: string): void {\r\n this.commands$.next([...this.commands$.getValue(), cmd]);\r\n }\r\n\r\n removeCommand(index: number): void {\r\n const cmds = this.commands$.getValue();\r\n if (index < 0 || index >= cmds.length) return;\r\n this.commands$.next([...cmds.slice(0, index), ...cmds.slice(index + 1)]);\r\n }\r\n\r\n moveCommand(from: number, to: number): void {\r\n const cmds = [...this.commands$.getValue()];\r\n if (from < 0 || to < 0 || from >= cmds.length || to >= cmds.length || from === to) return;\r\n const [item] = cmds.splice(from, 1);\r\n cmds.splice(to, 0, item);\r\n this.commands$.next(cmds);\r\n }\r\n\r\n removeInterceptor(index: number): void {\r\n const ints = this.interceptors$.getValue();\r\n if (index < 0 || index >= ints.length) return;\r\n this.interceptors$.next([...ints.slice(0, index), ...ints.slice(index + 1)]);\r\n }\r\n\r\n registerInterceptor(method: string, url: string, alias: string): void {\r\n if (this.isPaused$.getValue()) return;\r\n const command = `cy.intercept('${method}', '${this.urlToWildcard(url, method)}').as('${alias}')`;\r\n const current = this.interceptors$.getValue();\r\n if (!current.includes(command)) {\r\n this.interceptors$.next([...current, command]);\r\n }\r\n }\r\n\r\n clearCommands(): void {\r\n this.commands$.next([]);\r\n this.interceptors$.next([]);\r\n }\r\n\r\n clearInterceptors(): void {\r\n this.interceptors$.next([]);\r\n }\r\n\r\n getCommandsSnapshot(): string[] { return this.commands$.getValue(); }\r\n getInterceptorsSnapshot(): string[] { return this.interceptors$.getValue(); }\r\n getPausedSnapshot(): boolean { return this.isPaused$.getValue(); }\r\n\r\n onCommandsChange(fn: (cmds: string[]) => void): () => void {\r\n return this.commands$.subscribe(fn);\r\n }\r\n\r\n onInterceptorsChange(fn: (ints: string[]) => void): () => void {\r\n return this.interceptors$.subscribe(fn);\r\n }\r\n\r\n onRecordingChange(fn: (isRecording: boolean) => void): () => void {\r\n return this.isRecording$.subscribe(fn);\r\n }\r\n\r\n onPauseChange(fn: (isPaused: boolean) => void): () => void {\r\n return this.isPaused$.subscribe(fn);\r\n }\r\n\r\n /**\r\n * Fires a full session snapshot whenever any persisted field changes\r\n * (commands, interceptors, recording or paused state). Drives the debounced\r\n * persistence of the live session. Returns a combined unsubscribe.\r\n */\r\n onSessionChange(fn: (state: ActiveSessionState) => void): () => void {\r\n const emit = (): void => fn(this.getSessionSnapshot());\r\n const unsubs = [\r\n this.commands$.subscribe(emit),\r\n this.interceptors$.subscribe(emit),\r\n this.isRecording$.subscribe(emit),\r\n this.isPaused$.subscribe(emit),\r\n ];\r\n return () => unsubs.forEach((u) => u());\r\n }\r\n\r\n onSelectorNotFound(fn: (target: HTMLElement, action: 'click') => void): () => void {\r\n return this.selectorNotFound$.subscribe((v) => {\r\n if (v) fn(v.target, v.action);\r\n });\r\n }\r\n\r\n destroy(): void {\r\n this.abort.abort();\r\n history.pushState = this.origPushState;\r\n history.replaceState = this.origReplaceState;\r\n this.inputDebounceTimers.forEach((t) => clearTimeout(t));\r\n this.inputDebounceTimers.clear();\r\n }\r\n\r\n // ── DOM listeners ─────────────────────────────────────────────────────────\r\n\r\n private listenToClicks(): void {\r\n document.addEventListener(\r\n 'click',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue()) return;\r\n const target = e.target as HTMLElement;\r\n if (!target || this.isOwnElement(target)) return;\r\n const tag = target.tagName?.toLowerCase();\r\n if (tag === 'body' || tag === 'html') return;\r\n this.handleClickEvent(target);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToInput(): void {\r\n document.addEventListener(\r\n 'input',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue()) return;\r\n const target = e.target as HTMLInputElement | HTMLTextAreaElement;\r\n if (!target || this.isOwnElement(target)) return;\r\n this.handleInputEvent(target);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToSelect(): void {\r\n document.addEventListener(\r\n 'change',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue()) return;\r\n const target = e.target as HTMLSelectElement;\r\n if (!target || this.isOwnElement(target)) return;\r\n if (target.tagName.toLowerCase() === 'select') {\r\n this.handleSelectEvent(target);\r\n }\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToRouteChanges(): void {\r\n let lastUrl = window.location.pathname + window.location.search + window.location.hash;\r\n\r\n const addUrlCommand = (newUrl: string): void => {\r\n if (!this.isRecording$.getValue()) return;\r\n if (newUrl === lastUrl) return;\r\n this.addCommand(`cy.url().should('include', '${newUrl}')`);\r\n lastUrl = newUrl;\r\n };\r\n\r\n const wrapMethod = (type: 'pushState' | 'replaceState'): void => {\r\n const orig = history[type].bind(history);\r\n history[type] = (data: unknown, unused: string, url?: string | URL | null) => {\r\n const result = orig(data, unused, url);\r\n let newUrl = window.location.pathname + window.location.search + window.location.hash;\r\n if (typeof url === 'string' && url.length > 0) {\r\n const a = document.createElement('a');\r\n a.href = url;\r\n newUrl = a.pathname + a.search + a.hash;\r\n } else if (url instanceof URL) {\r\n newUrl = url.pathname + url.search + url.hash;\r\n }\r\n addUrlCommand(newUrl);\r\n return result;\r\n };\r\n };\r\n\r\n wrapMethod('pushState');\r\n wrapMethod('replaceState');\r\n\r\n window.addEventListener(\r\n 'popstate',\r\n () => {\r\n const newUrl = window.location.pathname + window.location.search + window.location.hash;\r\n addUrlCommand(newUrl);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n // ── Click helpers ─────────────────────────────────────────────────────────\r\n\r\n private handleClickEvent(target: HTMLElement): void {\r\n // Bubble up from non-interactive span/div inside button or mat-option\r\n if (!this.isInteractiveElement(target)) {\r\n const tag = target.tagName.toLowerCase();\r\n if (\r\n (tag === 'span' || tag === 'div') &&\r\n target.parentElement &&\r\n (target.parentElement.tagName.toLowerCase() === 'button' ||\r\n target.parentElement.tagName.toLowerCase() === 'mat-option') &&\r\n (target.parentElement.hasAttribute('data-cy') || target.parentElement.hasAttribute('id'))\r\n ) {\r\n target = target.parentElement;\r\n }\r\n const matSelect = target.closest('mat-select');\r\n if (matSelect) {\r\n const sel = this.getReliableSelector(matSelect as HTMLElement);\r\n if (sel) {\r\n this.addCommand(`cy.get('${sel}').click()`);\r\n } else {\r\n this.selectorNotFound$.next({ target: matSelect as HTMLElement, action: 'click' });\r\n }\r\n return;\r\n }\r\n }\r\n\r\n const tag = target.tagName.toLowerCase();\r\n if (tag === 'input' || tag === 'textarea' || tag === 'select') {\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) this.selectorNotFound$.next({ target, action: 'click' });\r\n return;\r\n }\r\n\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) {\r\n this.selectorNotFound$.next({ target, action: 'click' });\r\n return;\r\n }\r\n\r\n const selector = this.getReliableSelector(container);\r\n if (selector === OWN_SELECTOR) return;\r\n\r\n if (tag === 'mat-option') {\r\n this.handleMatOptionClick(target, selector);\r\n return;\r\n }\r\n\r\n this.addGenericCommand({\r\n selector,\r\n action: (s) => `cy.get('${s}').click()`,\r\n });\r\n }\r\n\r\n private handleMatOptionClick(target: HTMLElement, selector: string | null): void {\r\n const matSelect = target.closest('mat-select');\r\n let dataCy: string | null = null;\r\n if (matSelect) dataCy = matSelect.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\r\n if (!dataCy) dataCy = target.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\r\n if (dataCy) {\r\n this.addCommand(`cy.get('[data-cy=\"${dataCy}\"]').click()`);\r\n return;\r\n }\r\n if (selector) {\r\n this.addCommand(`cy.get('${selector}').eq(0).click()`);\r\n } else {\r\n this.selectorNotFound$.next({ target, action: 'click' });\r\n }\r\n }\r\n\r\n // ── Input helpers ─────────────────────────────────────────────────────────\r\n\r\n private handleInputEvent(target: HTMLInputElement | HTMLTextAreaElement): void {\r\n const tag = target.tagName.toLowerCase();\r\n const isText = tag === 'textarea' || (tag === 'input' && (INPUT_TYPES as readonly string[]).includes(target.type));\r\n if (!isText) return;\r\n\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) return;\r\n\r\n if (this.inputDebounceTimers.has(target)) {\r\n clearTimeout(this.inputDebounceTimers.get(target));\r\n }\r\n this.inputDebounceTimers.set(\r\n target,\r\n setTimeout(() => {\r\n const selector = this.getReliableSelector(container);\r\n const value = target.value.replace(/'/g, \"\\\\'\");\r\n this.addGenericCommand({\r\n selector,\r\n action: (s) => `cy.get('${s}').clear().type('${value}')`,\r\n });\r\n this.inputDebounceTimers.delete(target);\r\n }, 1000)\r\n );\r\n }\r\n\r\n // ── Select helpers ────────────────────────────────────────────────────────\r\n\r\n private handleSelectEvent(target: HTMLSelectElement): void {\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) return;\r\n const selector = this.getReliableSelector(container);\r\n const value = target.value.replace(/'/g, \"\\\\'\");\r\n this.addGenericCommand({\r\n selector,\r\n action: (s) => `cy.get('${s}').select('${value}')`,\r\n });\r\n }\r\n\r\n // ── Shared helpers ────────────────────────────────────────────────────────\r\n\r\n private addGenericCommand(opts: {\r\n selector: string | null;\r\n action: (s: string) => string;\r\n }): void {\r\n if (!opts.selector || this.isOwnSelector(opts.selector)) return;\r\n this.addCommand(opts.action(opts.selector));\r\n }\r\n\r\n private getReliableSelector(el: HTMLElement): string | null {\r\n const strategy = this.selectorStrategy;\r\n const dataCy = el.getAttribute('data-cy');\r\n const dataTestid = el.getAttribute('data-testid');\r\n const ariaLabel = el.getAttribute('aria-label');\r\n const dataDotCy = el.getAttribute('data.cy');\r\n\r\n const rawId = el.id;\r\n const validId = rawId &&\r\n rawId.length < 25 &&\r\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\r\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\r\n !/^\\d+$/.test(rawId) ? rawId : null;\r\n\r\n switch (strategy) {\r\n case 'data-testid':\r\n if (dataTestid) return `[data-testid=\"${dataTestid}\"]`;\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n return validId ? `#${validId}` : null;\r\n case 'aria-label':\r\n if (ariaLabel) return `[aria-label=\"${ariaLabel}\"]`;\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n return validId ? `#${validId}` : null;\r\n case 'id':\r\n if (validId) return `#${validId}`;\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n return dataTestid ? `[data-testid=\"${dataTestid}\"]` : null;\r\n default: // 'data-cy'\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n if (dataDotCy) return `[data.cy=\"${dataDotCy}\"]`;\r\n return validId ? `#${validId}` : null;\r\n }\r\n }\r\n\r\n private isInteractiveElement(target: EventTarget | null): boolean {\r\n if (!(target instanceof HTMLElement)) return false;\r\n const tag = target.tagName.toLowerCase();\r\n return ['select', 'option', 'input', 'textarea', 'button'].includes(tag);\r\n }\r\n\r\n private isOwnSelector(selector: string | null): boolean {\r\n return selector === OWN_SELECTOR;\r\n }\r\n\r\n private isOwnElement(target: HTMLElement): boolean {\r\n return !!target.closest('[data-cy=\"lib-e2e-cypress-for-dummys\"]');\r\n }\r\n\r\n private urlToWildcard(url: string, method: string): string {\r\n const u = new URL(url, 'http://localhost');\r\n if (method.toUpperCase() === 'GET' && u.search) {\r\n return `**${u.pathname}/**`;\r\n }\r\n return `**${u.pathname}`;\r\n }\r\n}\r\n","import { openDB, type IDBPDatabase } from 'idb';\r\nimport { DB_SCHEMA } from '../models/db-schema.model';\r\nimport type { ActiveSessionState } from '../models/active-session.model';\r\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\r\n\r\n/** Fixed primary key for the single active-session record. */\r\nconst ACTIVE_SESSION_ID = 1;\r\n\r\ninterface TestRecord { id: number; name: string; createdAt: number; tags?: string[]; notes?: string; }\r\ninterface CommandRecord { id: number; command: string; testId: number; createdAt: number; }\r\ninterface InterceptorRecord { id: number; interceptor: string; testId: number; createdAt: number; }\r\ninterface ConfigRecord { id: number; [key: string]: unknown; }\r\n\r\nexport interface TestWithDetails extends TestRecord {\r\n commands: string[];\r\n interceptors: string[];\r\n}\r\n\r\nexport interface TestDetail extends TestWithDetails {\r\n cypressCommands: string[];\r\n itBlock: string;\r\n interceptorsBlock: string;\r\n}\r\n\r\nexport class PersistenceService {\r\n private _db: Promise<IDBPDatabase> | null = null;\r\n\r\n // dbName is overridable so tests can use unique names for isolation.\r\n constructor(private readonly dbName: string = DB_SCHEMA.name) {}\r\n\r\n private getDB(): Promise<IDBPDatabase> {\r\n if (!this._db) {\r\n this._db = openDB(this.dbName, DB_SCHEMA.version, {\r\n upgrade(database) {\r\n for (const store of DB_SCHEMA.stores) {\r\n if (!database.objectStoreNames.contains(store.name)) {\r\n const os = database.createObjectStore(store.name, {\r\n keyPath: store.keyPath,\r\n autoIncrement: store.autoIncrement,\r\n });\r\n for (const index of store.indexes) {\r\n os.createIndex(index.name, index.keyPath, { unique: index.unique });\r\n }\r\n }\r\n }\r\n },\r\n });\r\n }\r\n return this._db;\r\n }\r\n\r\n // ── Tests ─────────────────────────────────────────────────────────────────\r\n\r\n async insertTest(name: string, commands: string[] = [], interceptors: string[] = [], tags: string[] = [], notes?: string): Promise<number> {\r\n const db = await this.getDB();\r\n const record: Omit<TestRecord, 'id'> = { name, createdAt: Date.now(), ...(tags.length ? { tags } : {}), ...(notes ? { notes } : {}) };\r\n const id = await db.add('tests', record) as number;\r\n if (commands.length) await this.insertCommands(commands, id);\r\n if (interceptors.length) await this.insertInterceptors(interceptors, id);\r\n return id;\r\n }\r\n\r\n async getAllTests(): Promise<TestWithDetails[]> {\r\n const db = await this.getDB();\r\n const tests = await db.getAll('tests') as TestRecord[];\r\n return Promise.all(\r\n tests.map(async (test) => ({\r\n ...test,\r\n commands: await this.getCommandStrings(test.id),\r\n interceptors: await this.getInterceptorStrings(test.id),\r\n }))\r\n );\r\n }\r\n\r\n async getTestById(testId: number): Promise<TestDetail | null> {\r\n const db = await this.getDB();\r\n const record = await db.get('tests', testId) as TestRecord | undefined;\r\n if (!record) return null;\r\n\r\n const commands = await this.getCommandStrings(testId);\r\n const interceptors = await this.getInterceptorStrings(testId);\r\n const itBlock = `it('${escapeSingleQuotes(record.name)}', () => {\\n${commands.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\r\n const interceptorsBlock = interceptors.length\r\n ? ' // Auto-generated Cypress interceptors\\n' +\r\n interceptors.map(i => normalizeBlock(i, ' ')).join('\\n') + '\\n'\r\n : '';\r\n\r\n return { ...record, commands, interceptors, cypressCommands: commands, itBlock, interceptorsBlock };\r\n }\r\n\r\n async deleteTest(id: number): Promise<void> {\r\n const db = await this.getDB();\r\n await db.delete('tests', id);\r\n await this.deleteCommandsByTestId(id);\r\n await this.deleteInterceptorsByTestId(id);\r\n }\r\n\r\n // ── Commands ──────────────────────────────────────────────────────────────\r\n\r\n async insertCommands(commands: string[], testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n await Promise.all(\r\n commands.map((command) => db.add('commands', { command, testId, createdAt: Date.now() }))\r\n );\r\n }\r\n\r\n async getCommandsByTestId(testId: number): Promise<CommandRecord[]> {\r\n const db = await this.getDB();\r\n return db.getAllFromIndex('commands', 'testId', testId) as Promise<CommandRecord[]>;\r\n }\r\n\r\n private async getCommandStrings(testId: number): Promise<string[]> {\r\n return (await this.getCommandsByTestId(testId)).map((r) => r.command).filter(Boolean);\r\n }\r\n\r\n private async deleteCommandsByTestId(testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n const rows = await this.getCommandsByTestId(testId);\r\n const tx = db.transaction('commands', 'readwrite');\r\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\r\n await tx.done;\r\n }\r\n\r\n // ── Interceptors ──────────────────────────────────────────────────────────\r\n\r\n async insertInterceptors(interceptors: string[], testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n await Promise.all(\r\n interceptors.map((interceptor) => db.add('interceptors', { interceptor, testId, createdAt: Date.now() }))\r\n );\r\n }\r\n\r\n async getInterceptorsByTestId(testId: number): Promise<InterceptorRecord[]> {\r\n const db = await this.getDB();\r\n return db.getAllFromIndex('interceptors', 'testId', testId) as Promise<InterceptorRecord[]>;\r\n }\r\n\r\n private async getInterceptorStrings(testId: number): Promise<string[]> {\r\n return (await this.getInterceptorsByTestId(testId)).map((r) => r.interceptor).filter(Boolean);\r\n }\r\n\r\n async deleteInterceptorsByTestId(testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n const rows = await this.getInterceptorsByTestId(testId);\r\n const tx = db.transaction('interceptors', 'readwrite');\r\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\r\n await tx.done;\r\n }\r\n\r\n // ── Configuration ─────────────────────────────────────────────────────────\r\n\r\n async setConfig(config: Record<string, unknown>): Promise<void> {\r\n const db = await this.getDB();\r\n const records = await db.getAll('configuration') as ConfigRecord[];\r\n const current = records[0] ?? {};\r\n const merged = { ...current, ...config };\r\n if ((current as ConfigRecord).id) {\r\n await db.put('configuration', merged);\r\n } else {\r\n await db.add('configuration', merged);\r\n }\r\n }\r\n\r\n async setConfigKey(key: string, value: unknown): Promise<void> {\r\n return this.setConfig({ [key]: value });\r\n }\r\n\r\n async getConfig(key: string): Promise<Record<string, unknown> | null> {\r\n const db = await this.getDB();\r\n const records = await db.getAll('configuration') as ConfigRecord[];\r\n if (!records.length) return null;\r\n const config = records[0];\r\n return Object.prototype.hasOwnProperty.call(config, key) ? { [key]: config[key] } : null;\r\n }\r\n\r\n async getGeneralConfig(): Promise<ConfigRecord | null> {\r\n const db = await this.getDB();\r\n const records = await db.getAll('configuration') as ConfigRecord[];\r\n return records[0] ?? null;\r\n }\r\n\r\n // ── Active recording session ──────────────────────────────────────────────\r\n\r\n /** Upserts the live recording session (single record, fixed key). */\r\n async saveActiveSession(state: ActiveSessionState): Promise<void> {\r\n const db = await this.getDB();\r\n await db.put('activeSession', { ...state, id: ACTIVE_SESSION_ID });\r\n }\r\n\r\n /** Returns the persisted live session, or null when none is stored. */\r\n async getActiveSession(): Promise<ActiveSessionState | null> {\r\n const db = await this.getDB();\r\n const record = await db.get('activeSession', ACTIVE_SESSION_ID) as (ActiveSessionState & { id: number }) | undefined;\r\n if (!record) return null;\r\n const { id: _id, ...state } = record;\r\n return state as ActiveSessionState;\r\n }\r\n\r\n /** Removes the live session record. Safe to call when none exists. */\r\n async clearActiveSession(): Promise<void> {\r\n const db = await this.getDB();\r\n await db.delete('activeSession', ACTIVE_SESSION_ID);\r\n }\r\n\r\n // ── Bulk operations ───────────────────────────────────────────────────────\r\n\r\n async clearAllData(): Promise<void> {\r\n const db = await this.getDB();\r\n await Promise.all([\r\n db.clear('tests'),\r\n db.clear('commands'),\r\n db.clear('interceptors'),\r\n ]);\r\n }\r\n\r\n async ingestFileData(tests: Record<string, unknown>[], interceptors: Record<string, unknown>[]): Promise<void> {\r\n if (Array.isArray(tests)) {\r\n const db = await this.getDB();\r\n for (const test of tests) {\r\n // Split the nested commands/interceptors back into their own stores,\r\n // keyed by the freshly-assigned testId — otherwise they would be stored\r\n // as stray fields and silently lost on read (getAllTests reads them by\r\n // testId from the commands/interceptors stores).\r\n const { id: _id, commands, interceptors: testInterceptors, ...record } = test;\r\n const newId = await db.add('tests', record) as number;\r\n const cmds = Array.isArray(commands) ? commands as string[] : [];\r\n const icps = Array.isArray(testInterceptors) ? testInterceptors as string[] : [];\r\n if (cmds.length) await this.insertCommands(cmds, newId);\r\n if (icps.length) await this.insertInterceptors(icps, newId);\r\n }\r\n }\r\n // Back-compat: legacy files may carry top-level interceptors with their own testId.\r\n await this.bulkInsertWithoutId('interceptors', interceptors);\r\n }\r\n\r\n async requestDirectoryPermissions(): Promise<void> {\r\n if (!('showDirectoryPicker' in window)) {\r\n throw new Error('File System Access API not supported');\r\n }\r\n const dirHandle = await window.showDirectoryPicker();\r\n await this.setConfigKey('cypressDirectoryHandle', dirHandle);\r\n await this.setConfigKey('allowReadWriteFiles', 'true');\r\n }\r\n\r\n private async bulkInsertWithoutId(store: string, items: Record<string, unknown>[]): Promise<void> {\r\n if (!Array.isArray(items)) return;\r\n const db = await this.getDB();\r\n for (const item of items) {\r\n const { id: _id, ...rest } = item;\r\n await db.add(store, rest);\r\n }\r\n }\r\n}\r\n\r\nexport const persistenceService = new PersistenceService();\r\n","import { type RecordingService } from './recording.service';\r\n\r\nconst INTERCEPTED_METHODS = ['GET', 'POST', 'PUT'] as const;\r\ntype InterceptedMethod = (typeof INTERCEPTED_METHODS)[number];\r\n\r\nexport function generateAlias(method: string, url: string): string {\r\n try {\r\n const u = new URL(url, 'http://localhost');\r\n const path = u.pathname\r\n .replace(/[^a-zA-Z0-9]/g, '-')\r\n .replace(/-+/g, '-')\r\n .replace(/(^-)|(-$)/g, '');\r\n return `${method.toLowerCase()}-${path}`;\r\n } catch {\r\n return `${method.toLowerCase()}-intercepted-request`;\r\n }\r\n}\r\n\r\nfunction buildValidations(base: string, obj: Record<string, unknown>): string {\r\n return Object.keys(obj)\r\n .filter((key) => key !== 'id' && key !== 'uid')\r\n .map((key) => `expect(${base}.${key}).to.equal(${JSON.stringify(obj[key])});`)\r\n .join('\\n');\r\n}\r\n\r\nfunction buildCyWaitCommand(\r\n method: string,\r\n alias: string,\r\n extendedHttp: boolean,\r\n requestBody: Record<string, unknown> | null,\r\n responseBody: Record<string, unknown> | null\r\n): string {\r\n if (extendedHttp && method === 'GET' && responseBody) {\r\n const validations = buildValidations('interception.response.body', responseBody);\r\n return `cy.wait('@${alias}').then((interception) => {\\n if (interception.response) {\\n${validations}\\n }\\n})`;\r\n }\r\n if (extendedHttp && (method === 'POST' || method === 'PUT') && requestBody) {\r\n const validations = buildValidations('interception.request.body', requestBody);\r\n return `cy.wait('@${alias}').then((interception) => {\\n${validations}\\n})`;\r\n }\r\n return `cy.wait('@${alias}').then((interception) => { })`;\r\n}\r\n\r\nfunction parseJsonObject(text: string): Record<string, unknown> | null {\r\n try {\r\n const parsed = JSON.parse(text);\r\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\r\n return parsed as Record<string, unknown>;\r\n }\r\n } catch {\r\n // Non-JSON or array — fall through\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseRequestBody(init?: RequestInit): Record<string, unknown> | null {\r\n const body = init?.body;\r\n if (typeof body === 'string') return parseJsonObject(body);\r\n return null;\r\n}\r\n\r\nfunction resolveUrl(input: RequestInfo | URL): string {\r\n if (typeof input === 'string') return input;\r\n if (input instanceof URL) return input.href;\r\n return input.url;\r\n}\r\n\r\nfunction resolveMethod(input: RequestInfo | URL, init?: RequestInit): string {\r\n if (init?.method) return init.method.toUpperCase();\r\n if (input instanceof Request) return input.method.toUpperCase();\r\n return 'GET';\r\n}\r\n\r\nexport class HttpMonitor {\r\n private originalFetch: typeof window.fetch | null = null;\r\n private originalXHR: typeof XMLHttpRequest | null = null;\r\n\r\n constructor(private readonly recording: RecordingService) {}\r\n\r\n install(): void {\r\n this.installFetch();\r\n this.installXhr();\r\n }\r\n\r\n uninstall(): void {\r\n this.uninstallFetch();\r\n this.uninstallXhr();\r\n }\r\n\r\n isExtendedHttpEnabled(): boolean {\r\n return localStorage.getItem('extendedHttpCommands') === 'true';\r\n }\r\n\r\n private installFetch(): void {\r\n if (this.originalFetch) return;\r\n const originalFetch = window.fetch;\r\n this.originalFetch = originalFetch;\r\n\r\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\r\n const response = await originalFetch(input, init);\r\n try {\r\n await this.handleFetchInterception(input, init, response.clone());\r\n } catch {\r\n // Never let monitoring errors break the actual request\r\n }\r\n return response;\r\n };\r\n }\r\n\r\n private uninstallFetch(): void {\r\n if (!this.originalFetch) return;\r\n window.fetch = this.originalFetch;\r\n this.originalFetch = null;\r\n }\r\n\r\n private installXhr(): void {\r\n if (this.originalXHR) return;\r\n this.originalXHR = window.XMLHttpRequest;\r\n const OrigXHR = this.originalXHR;\r\n const handleXhrInterception = this.handleXhrInterception.bind(this);\r\n\r\n window.XMLHttpRequest = class extends OrigXHR {\r\n private _xhrMethod = 'GET';\r\n private _xhrUrl = '';\r\n private _xhrRequestBody: Record<string, unknown> | null = null;\r\n\r\n override open(\r\n method: string,\r\n url: string | URL,\r\n async = true,\r\n user?: string | null,\r\n password?: string | null\r\n ): void {\r\n this._xhrMethod = method.toUpperCase();\r\n this._xhrUrl = url instanceof URL ? url.href : url;\r\n super.open(method, url as string, async, user, password);\r\n }\r\n\r\n override send(body?: Document | XMLHttpRequestBodyInit | null): void {\r\n if (typeof body === 'string') {\r\n this._xhrRequestBody = parseJsonObject(body);\r\n }\r\n this.addEventListener('load', () => {\r\n try {\r\n handleXhrInterception(\r\n this._xhrMethod,\r\n this._xhrUrl,\r\n this._xhrRequestBody,\r\n this.responseText\r\n );\r\n } catch {\r\n // Never let monitoring errors surface\r\n }\r\n });\r\n super.send(body);\r\n }\r\n } as unknown as typeof XMLHttpRequest;\r\n }\r\n\r\n private uninstallXhr(): void {\r\n if (!this.originalXHR) return;\r\n window.XMLHttpRequest = this.originalXHR;\r\n this.originalXHR = null;\r\n }\r\n\r\n private async handleFetchInterception(\r\n input: RequestInfo | URL,\r\n init: RequestInit | undefined,\r\n responseClone: Response\r\n ): Promise<void> {\r\n const method = resolveMethod(input, init);\r\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method)) return;\r\n\r\n const url = resolveUrl(input);\r\n const alias = generateAlias(method, url);\r\n\r\n this.recording.registerInterceptor(method, url, alias);\r\n\r\n const extendedHttp = this.isExtendedHttpEnabled();\r\n const requestBody = extendedHttp ? parseRequestBody(init) : null;\r\n let responseBody: Record<string, unknown> | null = null;\r\n if (extendedHttp) {\r\n try {\r\n responseBody = parseJsonObject(await responseClone.text());\r\n } catch {\r\n // Unreadable body — continue without validations\r\n }\r\n }\r\n\r\n const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);\r\n this.recording.addCommand(cmd);\r\n }\r\n\r\n private handleXhrInterception(\r\n method: string,\r\n url: string,\r\n requestBody: Record<string, unknown> | null,\r\n responseText: string\r\n ): void {\r\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method as InterceptedMethod)) return;\r\n\r\n const alias = generateAlias(method, url);\r\n this.recording.registerInterceptor(method, url, alias);\r\n\r\n const extendedHttp = this.isExtendedHttpEnabled();\r\n const responseBody = extendedHttp ? parseJsonObject(responseText) : null;\r\n\r\n const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);\r\n this.recording.addCommand(cmd);\r\n }\r\n}\r\n\r\n","export const SCROLLBAR_STYLES = `\r\n.swal2-popup::-webkit-scrollbar,\r\n.swal2-html-container::-webkit-scrollbar,\r\n.swal2-content::-webkit-scrollbar,\r\n.swal2-container::-webkit-scrollbar {\r\n width: 5px;\r\n height: 5px;\r\n background: transparent;\r\n}\r\n.swal2-popup::-webkit-scrollbar-thumb,\r\n.swal2-html-container::-webkit-scrollbar-thumb,\r\n.swal2-content::-webkit-scrollbar-thumb,\r\n.swal2-container::-webkit-scrollbar-thumb {\r\n background: #30363d;\r\n border-radius: 3px;\r\n}\r\n.swal2-popup::-webkit-scrollbar-thumb:hover,\r\n.swal2-html-container::-webkit-scrollbar-thumb:hover,\r\n.swal2-content::-webkit-scrollbar-thumb:hover {\r\n background: #484f58;\r\n}\r\n.swal2-popup::-webkit-scrollbar-track,\r\n.swal2-html-container::-webkit-scrollbar-track,\r\n.swal2-content::-webkit-scrollbar-track,\r\n.swal2-container::-webkit-scrollbar-track {\r\n background: transparent;\r\n}\r\n.swal2-popup, .swal2-html-container, .swal2-content, .swal2-container {\r\n scrollbar-width: thin;\r\n scrollbar-color: #30363d transparent;\r\n}\r\n`;\r\n\r\nexport const LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES = `\r\n.swal2-container, .swal2-popup {\r\n z-index: 99999 !important;\r\n}\r\n.swal2-container {\r\n padding: 0 !important;\r\n align-items: center !important;\r\n justify-content: center !important;\r\n}\r\n.swal2-popup {\r\n background: #161b22 !important;\r\n color: #e6edf3 !important;\r\n border-radius: 12px !important;\r\n box-shadow: 0 24px 64px rgba(0,0,0,0.72), 0 0 0 1px #30363d !important;\r\n border: none !important;\r\n padding: 0 !important;\r\n min-width: 400px;\r\n max-width: 90vw;\r\n min-height: 200px;\r\n max-height: 90vh;\r\n}\r\n/* Override SweetAlert2 v11's display:grid on .swal2-popup.swal2-modal */\r\n.swal2-popup.swal2-modal {\r\n display: flex !important;\r\n flex-direction: column !important;\r\n align-items: stretch !important;\r\n overflow: hidden !important;\r\n}\r\n.swal2-header {\r\n flex-shrink: 0 !important;\r\n flex-grow: 0 !important;\r\n overflow: hidden !important;\r\n}\r\n.swal2-title {\r\n color: #e6edf3 !important;\r\n font-weight: 600 !important;\r\n font-size: 14px !important;\r\n background: #161b22;\r\n padding: 14px 48px 13px 18px !important;\r\n margin: 0 !important;\r\n border-bottom: 1px solid #21262d;\r\n text-align: left !important;\r\n letter-spacing: 0.1px;\r\n white-space: nowrap !important;\r\n overflow: hidden !important;\r\n text-overflow: ellipsis !important;\r\n}\r\n.swal2-close {\r\n position: absolute !important;\r\n top: 10px !important;\r\n right: 12px !important;\r\n color: #8b949e !important;\r\n font-size: 1.1rem !important;\r\n z-index: 1 !important;\r\n border-radius: 6px !important;\r\n width: 28px !important;\r\n height: 28px !important;\r\n line-height: 28px !important;\r\n transition: background 0.15s, color 0.15s !important;\r\n}\r\n.swal2-close:hover {\r\n background: #21262d !important;\r\n color: #e6edf3 !important;\r\n}\r\n/* In SweetAlert2 v11, .swal2-html-container is a direct child of .swal2-popup */\r\n.swal2-html-container {\r\n flex: 1 !important;\r\n min-height: 0 !important;\r\n background: #161b22;\r\n padding: 0 !important;\r\n margin: 0 !important;\r\n width: 100%;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n align-items: stretch;\r\n box-sizing: border-box;\r\n overflow: hidden !important;\r\n}\r\n/* The single wrapper div we inject inside each modal fills the container */\r\n.swal2-html-container > div {\r\n flex: 1 !important;\r\n min-height: 0 !important;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n overflow: hidden !important;\r\n}\r\n.swal2-actions, .swal2-footer {\r\n flex-shrink: 0 !important;\r\n flex-grow: 0 !important;\r\n}\r\n`;\r\n\r\nexport function injectStyles(css: string, id: string): void {\r\n if (document.getElementById(id)) return;\r\n const style = document.createElement('style');\r\n style.id = id;\r\n style.innerHTML = css;\r\n document.head.appendChild(style);\r\n}\r\n","export function makeModalResizable(\r\n modal: HTMLElement,\r\n options?: { minWidth?: number; minHeight?: number }\r\n): () => void {\r\n if (!modal || modal.querySelector('.modal-resizer')) return () => { /* no-op */ };\r\n\r\n const rect = modal.getBoundingClientRect();\r\n modal.style.position = 'fixed';\r\n modal.style.top = `${rect.top}px`;\r\n modal.style.left = `${rect.left}px`;\r\n modal.style.width = `${rect.width}px`;\r\n modal.style.margin = '0';\r\n modal.style.resize = 'both';\r\n modal.style.overflow = 'hidden';\r\n modal.style.minWidth = (options?.minWidth ?? 320) + 'px';\r\n modal.style.minHeight = (options?.minHeight ?? 180) + 'px';\r\n\r\n const resizer = document.createElement('div');\r\n resizer.className = 'modal-resizer';\r\n resizer.style.position = 'absolute';\r\n resizer.style.width = '16px';\r\n resizer.style.height = '16px';\r\n resizer.style.right = '2px';\r\n resizer.style.bottom = '2px';\r\n resizer.style.cursor = 'nwse-resize';\r\n resizer.style.background = 'rgba(0,0,0,0.1)';\r\n resizer.style.zIndex = '10';\r\n modal.appendChild(resizer);\r\n\r\n let isResizing = false;\r\n let lastX = 0;\r\n let lastY = 0;\r\n\r\n const mouseMove = (e: MouseEvent): void => {\r\n if (!isResizing) return;\r\n const dx = e.clientX - lastX;\r\n const dy = e.clientY - lastY;\r\n lastX = e.clientX;\r\n lastY = e.clientY;\r\n const rect = modal.getBoundingClientRect();\r\n modal.style.width = rect.width + dx + 'px';\r\n modal.style.height = rect.height + dy + 'px';\r\n };\r\n\r\n const mouseUp = (): void => {\r\n isResizing = false;\r\n document.body.style.userSelect = '';\r\n };\r\n\r\n resizer.addEventListener('mousedown', (e) => {\r\n e.preventDefault();\r\n isResizing = true;\r\n lastX = e.clientX;\r\n lastY = e.clientY;\r\n document.body.style.userSelect = 'none';\r\n });\r\n\r\n window.addEventListener('mousemove', mouseMove);\r\n window.addEventListener('mouseup', mouseUp);\r\n\r\n return () => {\r\n window.removeEventListener('mousemove', mouseMove);\r\n window.removeEventListener('mouseup', mouseUp);\r\n if (resizer.parentNode) resizer.parentNode.removeChild(resizer);\r\n };\r\n}\r\n\r\nfunction applyDraggable(swal: HTMLElement, dragArea: HTMLElement): void {\r\n let isDragging = false;\r\n let offsetX = 0;\r\n let offsetY = 0;\r\n\r\n dragArea.style.cursor = 'move';\r\n dragArea.onmousedown = (e: MouseEvent) => {\r\n isDragging = true;\r\n const rect = swal.getBoundingClientRect();\r\n offsetX = e.clientX - rect.left;\r\n offsetY = e.clientY - rect.top;\r\n document.onmousemove = (ev: MouseEvent) => {\r\n if (isDragging) {\r\n swal.style.position = 'fixed';\r\n swal.style.margin = '0';\r\n swal.style.left = `${ev.clientX - offsetX}px`;\r\n swal.style.top = `${ev.clientY - offsetY}px`;\r\n }\r\n };\r\n document.onmouseup = () => {\r\n isDragging = false;\r\n document.onmousemove = null;\r\n document.onmouseup = null;\r\n };\r\n };\r\n}\r\n\r\nfunction resolveDragArea(swal: HTMLElement): HTMLElement | null {\r\n return (swal.querySelector('.swal2-header') as HTMLElement | null)\r\n ?? (swal.querySelector('.swal2-title') as HTMLElement | null);\r\n}\r\n\r\nexport function makeSwalDraggable(): void {\r\n const popups = document.querySelectorAll('.swal2-popup');\r\n if (!popups.length) return;\r\n const swal = popups[popups.length - 1] as HTMLElement;\r\n const dragArea = resolveDragArea(swal);\r\n if (!dragArea) return;\r\n applyDraggable(swal, dragArea);\r\n}\r\n\r\nexport function makeSwalDraggableByContentId(contentId: string): void {\r\n const content = document.getElementById(contentId);\r\n if (!content) {\r\n makeSwalDraggable();\r\n return;\r\n }\r\n const swal = (content.closest('.swal2-popup') as HTMLElement | null)\r\n ?? (document.querySelector('.swal2-popup') as HTMLElement | null);\r\n if (!swal) return;\r\n const dragArea = resolveDragArea(swal);\r\n if (!dragArea) return;\r\n applyDraggable(swal, dragArea);\r\n}\r\n\r\nexport function setSwal2DataCyAttribute(dataCy = 'lib-e2e-cypress-for-dummys'): void {\r\n document.querySelector('.swal2-container')?.setAttribute('data-cy', dataCy);\r\n document.querySelector('.swal2-html-container')?.setAttribute('data-cy', dataCy);\r\n document.querySelector('.swal2-title')?.setAttribute('data-cy', dataCy);\r\n}\r\n","export function showToast(message: string, isSuccess = true): void {\r\n const toast = document.createElement('div');\r\n toast.textContent = message;\r\n toast.style.position = 'fixed';\r\n toast.style.top = '30px';\r\n toast.style.right = '30px';\r\n toast.style.padding = '16px 24px';\r\n toast.style.background = isSuccess ? '#4caf50' : '#f44336';\r\n toast.style.color = '#fff';\r\n toast.style.borderRadius = '8px';\r\n toast.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)';\r\n toast.style.zIndex = '9999';\r\n toast.style.fontSize = '1rem';\r\n toast.style.fontWeight = 'bold';\r\n toast.style.pointerEvents = 'none';\r\n document.body.appendChild(toast);\r\n setTimeout(() => toast.remove(), 3000);\r\n}\r\n","import type { TestWithDetails } from '../services/persistence.service';\n\n/** How the user chose which tests to export. */\nexport type ExportMode = 'all' | 'manual' | 'tags';\n\nexport interface ExportSelectionOptions {\n /** Test ids to include in `manual` mode. */\n ids?: Iterable<number>;\n /** Tags to match in `tags` mode. */\n tags?: Iterable<string>;\n}\n\n/**\n * Returns the subset of tests to export for a given selection mode.\n *\n * - `all` → every test (a shallow copy).\n * - `manual` → tests whose id is in `opts.ids`. Empty/absent ids → none.\n * - `tags` → tests carrying at least one of `opts.tags` (OR semantics).\n * Empty/absent tags → none.\n *\n * Pure: never mutates its inputs.\n */\nexport function selectTestsForExport(\n tests: TestWithDetails[],\n mode: ExportMode,\n opts: ExportSelectionOptions = {},\n): TestWithDetails[] {\n if (mode === 'all') return [...tests];\n\n if (mode === 'manual') {\n const ids = new Set(opts.ids ?? []);\n return tests.filter((t) => ids.has(t.id));\n }\n\n // 'tags' — include a test if it carries ANY of the selected tags (OR).\n const tags = new Set(opts.tags ?? []);\n if (tags.size === 0) return [];\n return tests.filter((t) => (t.tags ?? []).some((tag) => tags.has(tag)));\n}\n","/**\n * True when a hostname refers to the local machine — used to gate dev-only\n * features (e.g. launching a Cypress run via the local runner) so they are\n * offered only when the app is served locally, not from a deployed environment.\n *\n * Treats as local: localhost, *.localhost, 127.0.0.1, ::1, 0.0.0.0, and the\n * empty hostname (e.g. file:// URLs). Case-insensitive.\n */\nexport function isLocalHost(hostname: string): boolean {\n if (!hostname) return true;\n const h = hostname.toLowerCase();\n return (\n h === 'localhost' ||\n h.endsWith('.localhost') ||\n h === '127.0.0.1' ||\n h === '::1' ||\n h === '0.0.0.0'\n );\n}\n","/**\r\n * Geometry helpers for the draggable recording widget (spec 007).\r\n * Pure functions — no DOM — so the drag/clamp/expansion logic is unit-testable\r\n * without real layout (jsdom returns 0-sized rects).\r\n */\r\n\r\nexport type ExpandDirection = 'up-left' | 'up-right' | 'down-left' | 'down-right';\r\n\r\nexport interface Point {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/** Toggle radius (44/2) + small gap, so the toggle never touches the edge. */\r\nexport const TOGGLE_MARGIN = 30;\r\n\r\n/** Pixels the pointer must travel before a press becomes a drag (vs a click). */\r\nexport const DRAG_THRESHOLD = 5;\r\n\r\n/** Distance, in px, from the bottom-right edges of the original (default) anchor. */\r\nconst DEFAULT_EDGE_OFFSET = 46;\r\n\r\n/**\r\n * Toggle-centre offset inside the 190×190 widget box, per expansion direction.\r\n * The toggle sits at the box corner nearest the screen edge so the arc always\r\n * expands toward the viewport interior (and stays inside the box / on screen).\r\n */\r\nexport function boxOffsetForDirection(dir: ExpandDirection): Point {\r\n return {\r\n x: dir.endsWith('left') ? 144 : 46,\r\n y: dir.startsWith('up') ? 144 : 46,\r\n };\r\n}\r\n\r\n/** Clamps the toggle-centre so the toggle button stays fully on screen. */\r\nexport function clampTogglePosition(\r\n x: number,\r\n y: number,\r\n vw: number,\r\n vh: number,\r\n margin: number = TOGGLE_MARGIN,\r\n): Point {\r\n const maxX = Math.max(margin, vw - margin);\r\n const maxY = Math.max(margin, vh - margin);\r\n return {\r\n x: Math.min(Math.max(x, margin), maxX),\r\n y: Math.min(Math.max(y, margin), maxY),\r\n };\r\n}\r\n\r\n/**\r\n * Chooses the radial expansion direction so the menu opens toward the centre of\r\n * the viewport (top half → expand down; left half → expand right).\r\n */\r\nexport function resolveExpandDirection(x: number, y: number, vw: number, vh: number): ExpandDirection {\r\n const vertical = y < vh / 2 ? 'down' : 'up';\r\n const horizontal = x < vw / 2 ? 'right' : 'left';\r\n return `${vertical}-${horizontal}` as ExpandDirection;\r\n}\r\n\r\n/** Default toggle-centre (bottom-right corner), matching the original CSS anchor. */\r\nexport function defaultTogglePosition(vw: number, vh: number): Point {\r\n return { x: vw - DEFAULT_EDGE_OFFSET, y: vh - DEFAULT_EDGE_OFFSET };\r\n}\r\n\r\n/** Box top-left for a given (clamped) toggle-centre and direction. */\r\nexport function boxTopLeftFor(toggleCentre: Point, dir: ExpandDirection): Point {\r\n const off = boxOffsetForDirection(dir);\r\n return { x: toggleCentre.x - off.x, y: toggleCentre.y - off.y };\r\n}\r\n","export const TEST_PREVISUALIZER_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; gap: 6px; padding: 10px 12px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d;\n }\n button {\n padding: 5px 12px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s; letter-spacing: 0.1px;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button.active { background: #2f81f7; color: #fff; }\n .section { padding: 10px 12px; flex-shrink: 0; }\n .section.section-cmds { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .section-title {\n font-size: 10px; font-weight: 600; color: #484f58; text-transform: uppercase;\n letter-spacing: 0.8px; margin-bottom: 7px; flex-shrink: 0;\n }\n .list {\n overflow-y: auto; background: #0d1117;\n border-radius: 8px; padding: 6px 8px;\n border: 1px solid #21262d;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .section-cmds .list { flex: 1; min-height: 0; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .item {\n display: flex; align-items: flex-start; gap: 6px;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n color: #c9d1d9; padding: 4px 8px; border-radius: 4px;\n word-break: break-all; line-height: 1.65;\n border-left: 2px solid transparent;\n transition: background 0.1s, border-color 0.1s;\n }\n .item:hover { background: #161b22; border-left-color: #2f81f7; }\n .cmd-text { flex: 1; }\n .item-actions {\n display: flex; gap: 3px; flex-shrink: 0;\n opacity: 0; transition: opacity 0.15s;\n }\n .item:hover .item-actions { opacity: 1; }\n .btn-step {\n width: 20px; height: 20px; border: none; border-radius: 3px; cursor: pointer;\n font-size: 12px; background: transparent; color: #484f58;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; justify-content: center;\n padding: 0; line-height: 1;\n }\n .btn-step:hover { background: #30363d; color: #e6edf3; }\n .btn-step-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n .empty { color: #484f58; font-size: 12px; padding: 20px 8px; text-align: center; }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport function renderTestPrevisualizer(\n commands: string[],\n interceptors: string[],\n showInterceptors: boolean,\n editable: boolean,\n t: (key: string) => string,\n): string {\n const editControls = (idx: number, total: number) => editable ? `\n <span class=\"item-actions\">\n <button class=\"btn-step\" data-move-up=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.UP_TITLE')}\" ${idx === 0 ? 'disabled style=\"opacity:.3\"' : ''}>↑</button>\n <button class=\"btn-step\" data-move-dn=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DOWN_TITLE')}\" ${idx === total - 1 ? 'disabled style=\"opacity:.3\"' : ''}>↓</button>\n <button class=\"btn-step btn-step-del\" data-del=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button>\n </span>` : '';\n\n const cmdItems = commands.length\n ? commands.map((c, i) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(c)}</span>\n ${editControls(i, commands.length)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_CMDS_YET')}</div>`;\n\n const icpEditControls = (idx: number) => editable\n ? `<span class=\"item-actions\"><button class=\"btn-step btn-step-del\" data-del-icp=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button></span>`\n : '';\n\n const icpSection = showInterceptors\n ? `<div class=\"section\" data-section=\"interceptors\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.INTERCEPTORS')}</div>\n <div class=\"list\">\n ${\n interceptors.length\n ? interceptors.map((ic, idx) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(ic)}</span>\n ${icpEditControls(idx)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_ICP_SHORT')}</div>`\n }\n </div>\n <button style=\"margin-top:6px\" data-action=\"copy-icp\">${t('TEST_PREVISUALIZER.COPY_ICP_BTN')}</button>\n </div>`\n : '';\n\n return `\n <div class=\"toolbar\">\n <button data-action=\"copy\">${t('TEST_PREVISUALIZER.COPY_CMDS_BTN')}</button>\n <button data-action=\"toggle-icp\" class=\"${showInterceptors ? 'active' : ''}\">\n ${showInterceptors ? t('TEST_PREVISUALIZER.HIDE_INTERCEPTORS') : t('TEST_PREVISUALIZER.SHOW_INTERCEPTORS')} (${interceptors.length})\n </button>\n </div>\n <div class=\"section section-cmds\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.SECTION_COMMANDS')} (${commands.length})</div>\n <div class=\"list\" data-ref=\"cmds\">${cmdItems}</div>\n </div>\n ${icpSection}`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\r\nimport { TEST_PREVISUALIZER_STYLES } from './test-previsualizer.styles';\r\nimport { renderTestPrevisualizer } from './test-previsualizer.template';\r\n\r\nexport class TestPrevisualizerElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private _commands: string[] = [];\r\n private _interceptors: string[] = [];\r\n private _showInterceptors = false;\r\n editable = false;\r\n translation: TranslationService = translationService;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n this.render();\r\n }\r\n\r\n get commands(): string[] {\r\n return this._commands;\r\n }\r\n set commands(v: string[]) {\r\n this._commands = v;\r\n this.render();\r\n }\r\n\r\n get interceptors(): string[] {\r\n return this._interceptors;\r\n }\r\n set interceptors(v: string[]) {\r\n this._interceptors = v;\r\n this.render();\r\n }\r\n\r\n get showInterceptors(): boolean {\r\n return this._showInterceptors;\r\n }\r\n\r\n toggleInterceptors(): void {\r\n this._showInterceptors = !this._showInterceptors;\r\n this.render();\r\n }\r\n\r\n copyToClipboard(): void {\r\n const text = this._commands.join('\\n');\r\n if (!text) return;\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n copyInterceptorsToClipboard(): void {\r\n const text = this._interceptors.join('\\n');\r\n if (!text) return;\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private dispatchDelete(index: number): void {\r\n this.dispatchEvent(new CustomEvent('deletecommand', { detail: index, bubbles: true, composed: true }));\r\n }\r\n\r\n private dispatchMove(from: number, to: number): void {\r\n this.dispatchEvent(new CustomEvent('movecommand', { detail: { from, to }, bubbles: true, composed: true }));\r\n }\r\n\r\n private dispatchDeleteInterceptor(index: number): void {\r\n this.dispatchEvent(new CustomEvent('deleteinterceptor', { detail: index, bubbles: true, composed: true }));\r\n }\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${TEST_PREVISUALIZER_STYLES}</style>${renderTestPrevisualizer(\r\n this._commands,\r\n this._interceptors,\r\n this._showInterceptors,\r\n this.editable,\r\n this.t.bind(this),\r\n )}`;\r\n\r\n const cmdsEl = this.shadow.querySelector<HTMLElement>('[data-ref=\"cmds\"]');\r\n if (cmdsEl) cmdsEl.scrollTop = cmdsEl.scrollHeight;\r\n\r\n this.shadow.querySelector('[data-action=\"copy\"]')?.addEventListener('click', () => this.copyToClipboard());\r\n this.shadow.querySelector('[data-action=\"toggle-icp\"]')?.addEventListener('click', () => this.toggleInterceptors());\r\n this.shadow.querySelector('[data-action=\"copy-icp\"]')?.addEventListener('click', () => this.copyInterceptorsToClipboard());\r\n\r\n if (this.editable) {\r\n this.shadow.querySelectorAll('[data-del]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.dispatchDelete(Number((btn as HTMLElement).dataset['del']));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-move-up]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n const idx = Number((btn as HTMLElement).dataset['moveUp']);\r\n this.dispatchMove(idx, idx - 1);\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-move-dn]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n const idx = Number((btn as HTMLElement).dataset['moveDn']);\r\n this.dispatchMove(idx, idx + 1);\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-del-icp]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.dispatchDeleteInterceptor(Number((btn as HTMLElement).dataset['delIcp']));\r\n });\r\n });\r\n }\r\n }\r\n}\r\n\r\nif (!customElements.get('test-previsualizer')) {\r\n customElements.define('test-previsualizer', TestPrevisualizerElement);\r\n}\r\n","export const SAVE_TEST_STYLES = `\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n .container { padding: 24px 28px; text-align: left; }\n .btn-row, p { text-align: center; }\n p { margin: 0 0 20px; font-size: 14px; color: #8b949e; line-height: 1.5; }\n .btn-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }\n button {\n padding: 7px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; transition: filter 0.15s, transform 0.1s;\n letter-spacing: 0.1px;\n }\n button:hover { filter: brightness(1.1); }\n button:active { transform: scale(0.97); }\n .btn-primary { background: #2f81f7; color: #fff; }\n .btn-success { background: #3fb950; color: #fff; }\n .btn-danger { background: transparent; color: #f85149; border: 1px solid rgba(248,81,73,0.5); }\n .btn-danger:hover { background: rgba(248,81,73,0.08); filter: none; }\n input[type=\"text\"] {\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\n border-radius: 8px; background: #0d1117; color: #e6edf3;\n font-size: 14px; outline: none; margin-bottom: 4px;\n transition: border-color 0.15s, box-shadow 0.15s;\n }\n input[type=\"text\"]:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\n input[type=\"text\"]::placeholder { color: #484f58; }\n textarea {\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\n border-radius: 8px; background: #0d1117; color: #e6edf3;\n font-size: 14px; outline: none; margin-bottom: 4px;\n font-family: inherit; resize: vertical; line-height: 1.5;\n transition: border-color 0.15s, box-shadow 0.15s;\n }\n textarea:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\n textarea::placeholder { color: #484f58; }\n .tag-label {\n font-size: 11px; color: #484f58; text-align: left; margin-bottom: 5px; display: block;\n }\n .tag-input-row { display: flex; gap: 6px; margin-bottom: 8px; }\n .tag-input-row input[type=\"text\"] {\n font-size: 12px; padding: 6px 10px; margin: 0;\n }\n .btn-tag-add {\n padding: 6px 12px; font-size: 12px; background: #21262d; color: #8b949e;\n border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n transition: background 0.15s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-tag-add:hover { background: #30363d; color: #e6edf3; filter: none; }\n .chips { display: flex; flex-wrap: wrap; gap: 5px; min-height: 24px; text-align: left; }\n .chip {\n display: inline-flex; align-items: center; gap: 5px;\n background: rgba(47,129,247,0.15); color: #2f81f7;\n border: 1px solid rgba(47,129,247,0.3); border-radius: 20px;\n padding: 2px 10px 2px 10px; font-size: 11px; font-weight: 500;\n }\n .chip-del {\n cursor: pointer; color: #8b949e; font-size: 12px; line-height: 1;\n transition: color 0.12s; padding: 0; background: none; border: none;\n }\n .chip-del:hover { color: #f85149; filter: none; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\n\nexport function renderSaveTestAsk(t: (key: string) => string): string {\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.ASK')}</p>\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-yes\">${t('SAVE_TEST.YES_CONTINUE')}</button>\n <button class=\"btn-danger\" id=\"btn-no\">${t('SAVE_TEST.NO_DISCARD')}</button>\n </div>\n </div>`;\n}\n\nexport function renderSaveTestDesc(description: string, notes: string, tags: string[], t: (key: string) => string): string {\n const chipsHtml = tags.map((tag) =>\n `<span class=\"chip\">${escHtml(tag)}<button class=\"chip-del\" data-tag=\"${escAttr(tag)}\" title=\"${t('SAVE_TEST.REMOVE_TAG_TITLE')}\">✕</button></span>`\n ).join('');\n\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.DESC_LABEL')} (<code>it()</code>):</p>\n <input id=\"desc-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.DESC_PLACEHOLDER')}\"\n value=\"${escAttr(description)}\" autocomplete=\"off\" />\n <span class=\"tag-label\">${t('SAVE_TEST.NOTES_LABEL')}</span>\n <textarea id=\"notes-input\" rows=\"3\" placeholder=\"${escAttr(t('SAVE_TEST.NOTES_PLACEHOLDER'))}\">${escHtml(notes)}</textarea>\n <span class=\"tag-label\">${t('SAVE_TEST.TAGS_LABEL')}</span>\n <div class=\"tag-input-row\">\n <input id=\"tag-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.TAGS_PLACEHOLDER')}\" autocomplete=\"off\" />\n <button class=\"btn-tag-add\" id=\"btn-add-tag\">${t('SAVE_TEST.ADD_TAG')}</button>\n </div>\n <div class=\"chips\" id=\"chips-container\">${chipsHtml || `<span style=\"color:#484f58;font-size:11px\">${t('SAVE_TEST.NO_TAGS')}</span>`}</div>\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-confirm\">${t('SAVE_TEST.SAVE_BTN')}</button>\n <button class=\"btn-success\" id=\"btn-export\">${t('SAVE_TEST.SAVE_AND_EDIT')}</button>\n <button class=\"btn-danger\" id=\"btn-cancel\">${t('SAVE_TEST.CANCEL')}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { SAVE_TEST_STYLES } from './save-test.styles';\nimport { renderSaveTestAsk, renderSaveTestDesc } from './save-test.template';\n\nexport class SaveTestElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _step: 'ask' | 'desc' = 'ask';\n description = '';\n notes = '';\n tags: string[] = [];\n translation: TranslationService = translationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void { this.render(); }\n\n get step(): 'ask' | 'desc' { return this._step; }\n\n askSave(): void { this._step = 'desc'; this.render(); }\n\n confirmSave(): void { this.dispatch('savetest', { description: this.description.trim(), notes: this.notes, tags: [...this.tags] }); }\n\n confirmSaveAndExport(): void { this.dispatch('saveandexport', { description: this.description.trim(), notes: this.notes, tags: [...this.tags] }); }\n\n cancel(): void { this.dispatch('savetest', { description: null, notes: '', tags: [] }); }\n\n restartComponent(): void { this._step = 'ask'; this.description = ''; this.notes = ''; this.tags = []; this.render(); }\n\n addTag(tag: string): void {\n const t = tag.trim().replace(/[,;]/g, '');\n if (t && !this.tags.includes(t)) {\n this.tags = [...this.tags, t];\n this.render();\n }\n }\n\n removeTag(tag: string): void {\n this.tags = this.tags.filter((t) => t !== tag);\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private dispatch(type: string, detail: { description: string | null; notes: string; tags: string[] }): void {\n this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));\n }\n\n private render(): void {\n if (this._step === 'ask') {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestAsk(this.t.bind(this))}`;\n this.shadow.getElementById('btn-yes')?.addEventListener('click', () => this.askSave());\n this.shadow.getElementById('btn-no')?.addEventListener('click', () => this.cancel());\n } else {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.t.bind(this))}`;\n\n const descInput = this.shadow.getElementById('desc-input') as HTMLInputElement;\n const notesInput = this.shadow.getElementById('notes-input') as HTMLTextAreaElement;\n const tagInput = this.shadow.getElementById('tag-input') as HTMLInputElement;\n\n descInput.addEventListener('input', () => { this.description = descInput.value; });\n notesInput.addEventListener('input', () => { this.notes = notesInput.value; });\n\n const tryAddTag = () => {\n this.addTag(tagInput.value);\n tagInput.value = '';\n };\n this.shadow.getElementById('btn-add-tag')?.addEventListener('click', tryAddTag);\n tagInput.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ',') { e.preventDefault(); tryAddTag(); }\n });\n\n this.shadow.querySelectorAll<HTMLButtonElement>('.chip-del').forEach((btn) => {\n btn.addEventListener('click', () => this.removeTag(btn.dataset['tag'] ?? ''));\n });\n\n this.shadow.getElementById('btn-confirm')?.addEventListener('click', () => this.confirmSave());\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.confirmSaveAndExport());\n this.shadow.getElementById('btn-cancel')?.addEventListener('click', () => this.cancel());\n setTimeout(() => descInput.focus(), 60);\n }\n }\n}\n\nif (!customElements.get('save-test')) {\n customElements.define('save-test', SaveTestElement);\n}\n","export const TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; align-items: center; gap: 6px; padding: 8px 10px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d; flex-wrap: wrap;\n }\n .tag-filter { display: flex; gap: 5px; flex-wrap: wrap; flex: 1; }\n .tag-chip {\n padding: 2px 10px; border-radius: 20px; cursor: pointer; font-size: 11px; font-weight: 500;\n border: 1px solid #30363d; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s, border-color 0.12s;\n }\n .tag-chip:hover { background: #30363d; color: #e6edf3; }\n .tag-chip.active { background: rgba(47,129,247,0.2); color: #2f81f7; border-color: rgba(47,129,247,0.4); }\n .btn-select {\n padding: 4px 12px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-select:hover { background: #30363d; color: #e6edf3; }\n .btn-select.active { background: rgba(47,129,247,0.15); color: #2f81f7; border-color: rgba(47,129,247,0.3); }\n .describe-bar {\n display: flex; align-items: center; gap: 8px; padding: 8px 10px;\n background: rgba(47,129,247,0.06); border-bottom: 1px solid rgba(47,129,247,0.2);\n flex-wrap: wrap;\n }\n .describe-bar input {\n flex: 1; min-width: 150px; padding: 5px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px; color: #e6edf3;\n font-size: 12px; outline: none;\n }\n .describe-bar input:focus { border-color: #2f81f7; }\n .btn-gen-describe {\n padding: 5px 14px; border: 1px solid #2f81f7; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: rgba(47,129,247,0.15); color: #2f81f7;\n transition: background 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-gen-describe:hover { background: rgba(47,129,247,0.25); }\n .selected-count { font-size: 11px; color: #8b949e; }\n .describe-bar { flex-shrink: 0; }\n .list { padding: 8px; flex: 1; min-height: 0; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .empty { color: #484f58; text-align: center; padding: 32px; font-size: 13px; }\n .row {\n background: #0d1117; border-radius: 8px; margin-bottom: 6px;\n overflow: hidden; border: 1px solid #21262d;\n transition: border-color 0.15s;\n }\n .row:hover { border-color: #30363d; }\n .row.selected-row { border-color: rgba(47,129,247,0.5); }\n .row-header {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px; cursor: pointer; user-select: none;\n }\n .row-header:hover { background: rgba(48,54,61,0.3); }\n .test-name { flex: 1; font-size: 13px; font-weight: 500; color: #e6edf3; }\n .test-date { font-size: 10.5px; color: #484f58; margin-right: 4px; }\n .test-tags { display: flex; gap: 4px; margin-right: 4px; }\n .test-tag {\n padding: 1px 7px; border-radius: 20px; font-size: 10px;\n background: rgba(47,129,247,0.1); color: #8b949e; border: 1px solid rgba(47,129,247,0.2);\n }\n .btn-icon {\n padding: 3px 8px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n .btn-icon:hover { background: #30363d; color: #e6edf3; }\n .btn-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n input[type=\"checkbox\"] {\n width: 14px; height: 14px; accent-color: #2f81f7; cursor: pointer; flex-shrink: 0;\n }\n .row-body {\n background: #0d1117; padding: 10px 14px;\n border-top: 1px solid #21262d;\n }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .code-preview {\n margin: 0; padding: 10px 12px; background: #161b22;\n border-radius: 6px; border: 1px solid #21262d;\n font-size: 11px; color: #c9d1d9; line-height: 1.7;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n overflow-x: auto; white-space: pre;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .code-preview::-webkit-scrollbar { height: 4px; }\n .code-preview::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .code-preview-icp { margin-top: 8px; }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport { normalizeBlock, escapeSingleQuotes } from '../../utils/code-format.utils';\nimport type { TestWithDetails } from '../../services/persistence.service';\n\nexport interface TestEditorState {\n tags: string[];\n visible: TestWithDetails[];\n selectedVisible: TestWithDetails[];\n activeTag: string | null;\n selectMode: boolean;\n selectedIds: Set<number>;\n describeName: string;\n expandedIndex: number | null;\n interceptorsByTest: Record<number, string[]>;\n locale: string;\n}\n\nexport function renderTestEditor(state: TestEditorState, t: (key: string) => string): string {\n const { tags, visible, selectedVisible, activeTag, selectMode, selectedIds, describeName, expandedIndex, interceptorsByTest, locale } = state;\n\n const tagFilterHtml = tags.length\n ? `<div class=\"tag-filter\">\n ${tags.map((tag) => `<button class=\"tag-chip${activeTag === tag ? ' active' : ''}\" data-filter-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}\n </div>`\n : `<div class=\"tag-filter\" style=\"color:#484f58;font-size:11px\">${t('TEST_EDITOR.NO_TAGS')}</div>`;\n\n const describeBarHtml = selectMode && selectedVisible.length > 0\n ? `<div class=\"describe-bar\">\n <span class=\"selected-count\">${selectedVisible.length} ${selectedVisible.length !== 1 ? t('TEST_EDITOR.SELECTED_PLURAL') : t('TEST_EDITOR.SELECTED_SINGULAR')}</span>\n <input id=\"describe-name\" type=\"text\" placeholder=\"${t('TEST_EDITOR.DESCRIBE_PLACEHOLDER')}\" value=\"${escAttr(describeName)}\" />\n <button class=\"btn-gen-describe\" id=\"btn-gen-describe\">${t('TEST_EDITOR.COPY_DESCRIBE')}</button>\n </div>`\n : '';\n\n const rows = visible.map((test, i) => {\n const expanded = expandedIndex === i;\n const date = new Date(test.createdAt).toLocaleString(locale, { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });\n const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];\n const tagsHtml = (test.tags ?? []).length\n ? `<span class=\"test-tags\">${(test.tags ?? []).map((tag) => `<span class=\"test-tag\">${escHtml(tag)}</span>`).join('')}</span>`\n : '';\n const checkbox = selectMode\n ? `<input type=\"checkbox\" ${selectedIds.has(test.id) ? 'checked' : ''} data-select=\"${test.id}\" />`\n : '';\n const hasIcps = (test.interceptors ?? []).length > 0;\n const itBlockCode = `it('${escapeSingleQuotes(test.name)}', () => {\\n${(test.commands ?? []).map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\n const icpBlockCode = icps.length ? `beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n${icps.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});` : '';\n const notesHtml = (expanded && test.notes)\n ? `<p class=\"test-notes\">${escHtml(test.notes)}</p>`\n : '';\n const body = expanded ? `\n <div class=\"row-body\">\n ${notesHtml}\n <pre class=\"code-preview\">${syntaxHighlight(itBlockCode)}</pre>\n ${icpBlockCode ? `<pre class=\"code-preview code-preview-icp\">${syntaxHighlight(icpBlockCode)}</pre>` : ''}\n </div>` : '';\n return `\n <div class=\"row${selectedIds.has(test.id) ? ' selected-row' : ''}\">\n <div class=\"row-header\" data-action=\"expand\" data-idx=\"${i}\">\n ${checkbox}\n <span class=\"test-name\">${escHtml(test.name)}</span>\n ${tagsHtml}\n <span class=\"test-date\">${date}</span>\n <button class=\"btn-icon\" data-action=\"copy-cmds\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_CMDS_BTN')}\">${t('TEST_EDITOR.COPY_CMDS_BTN')}</button>\n ${hasIcps ? `<button class=\"btn-icon\" data-action=\"copy-icps\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_ICPS_BTN')}\">${t('TEST_EDITOR.COPY_ICPS_BTN')}</button>` : ''}\n <button class=\"btn-icon btn-del\" data-action=\"delete\" data-id=\"${test.id}\" title=\"${t('TEST_EDITOR.DELETE_TITLE')}\">🗑</button>\n </div>\n ${body}\n </div>`;\n }).join('');\n\n return `\n <div class=\"toolbar\">\n ${tagFilterHtml}\n <button class=\"btn-select${selectMode ? ' active' : ''}\" id=\"btn-select-mode\">\n ${selectMode ? t('TEST_EDITOR.CANCEL_SELECT') : t('TEST_EDITOR.MULTI_SELECT')}\n </button>\n </div>\n ${describeBarHtml}\n <div class=\"list\">\n ${visible.length ? rows : `<div class=\"empty\">${t('TEST_EDITOR.NO_TESTS')}</div>`}\n </div>`;\n}\n","import { escHtml } from './html.utils';\n\nconst KEYWORDS = new Set([\n 'describe', 'it', 'xit', 'fit', 'xdescribe', 'fdescribe',\n 'beforeEach', 'afterEach', 'before', 'after', 'context',\n 'const', 'let', 'var', 'function', 'return', 'if', 'else',\n 'import', 'export', 'from', 'new', 'this', 'null', 'undefined',\n 'true', 'false', 'async', 'await', 'of', 'in', 'typeof', 'void',\n]);\n\nconst BUILTINS = new Set(['cy', 'expect', 'assert', 'Cypress', 'chai']);\n\nexport function syntaxHighlight(code: string): string {\n return code.split('\\n').map(highlightLine).join('\\n');\n}\n\nfunction highlightLine(line: string): string {\n let result = '';\n let i = 0;\n const len = line.length;\n\n while (i < len) {\n // Single-line comment\n if (line[i] === '/' && i + 1 < len && line[i + 1] === '/') {\n result += `<span class=\"sh-cmt\">${escHtml(line.slice(i))}</span>`;\n return result;\n }\n // String literal (single, double, or template)\n const q = line[i];\n if (q === \"'\" || q === '\"' || q === '`') {\n let j = i + 1;\n while (j < len) {\n if (line[j] === '\\\\') { j += 2; continue; }\n if (line[j] === q) { j++; break; }\n j++;\n }\n result += `<span class=\"sh-str\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Number (not preceded by identifier character)\n if (/[0-9]/.test(line[i]) && (i === 0 || !/[a-zA-Z_$]/.test(line[i - 1]))) {\n let j = i;\n while (j < len && /[0-9.]/.test(line[j])) j++;\n result += `<span class=\"sh-num\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Identifier, keyword, or builtin\n if (/[a-zA-Z_$]/.test(line[i])) {\n let j = i;\n while (j < len && /[a-zA-Z0-9_$]/.test(line[j])) j++;\n const word = line.slice(i, j);\n if (KEYWORDS.has(word)) {\n result += `<span class=\"sh-kw\">${escHtml(word)}</span>`;\n } else if (BUILTINS.has(word)) {\n result += `<span class=\"sh-bi\">${escHtml(word)}</span>`;\n } else {\n result += escHtml(word);\n }\n i = j;\n continue;\n }\n result += escHtml(line[i]);\n i++;\n }\n return result;\n}\n","import { PersistenceService } from '../../services/persistence.service';\r\nimport type { TestWithDetails } from '../../services/persistence.service';\r\nimport { translationService, type TranslationService } from '../../services/translation.service';\r\nimport { localeForLang } from '../../models/lang.model';\r\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\r\nimport { TEST_EDITOR_STYLES } from './test-editor.styles';\r\nimport { renderTestEditor } from './test-editor.template';\r\n\r\nexport class TestEditorElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n persistence!: PersistenceService;\r\n translation: TranslationService = translationService;\r\n tests: TestWithDetails[] = [];\r\n expandedIndex: number | null = null;\r\n interceptorsByTest: Record<number, string[]> = {};\r\n activeTag: string | null = null;\r\n selectMode = false;\r\n selectedIds: Set<number> = new Set();\r\n describeName = '';\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n this.loadTests();\r\n }\r\n\r\n async loadTests(): Promise<void> {\r\n this.tests = await this.persistence.getAllTests();\r\n this.render();\r\n }\r\n\r\n async deleteTest(id: number): Promise<void> {\r\n await this.persistence.deleteTest(id);\r\n this.selectedIds.delete(id);\r\n await this.loadTests();\r\n }\r\n\r\n toggleExpand(index: number): void {\r\n this.expandedIndex = this.expandedIndex === index ? null : index;\r\n if (this.expandedIndex !== null) {\r\n const test = this.tests[this.expandedIndex];\r\n if (test?.id && !this.interceptorsByTest[test.id]) {\r\n this.interceptorsByTest[test.id] = Array.isArray(test.interceptors) ? test.interceptors : [];\r\n }\r\n }\r\n this.render();\r\n }\r\n\r\n hasInterceptors(testId: number): boolean {\r\n return Array.isArray(this.interceptorsByTest[testId]) && this.interceptorsByTest[testId].length > 0;\r\n }\r\n\r\n toggleSelectMode(): void {\r\n this.selectMode = !this.selectMode;\r\n if (!this.selectMode) this.selectedIds.clear();\r\n this.render();\r\n }\r\n\r\n toggleSelectTest(id: number): void {\r\n if (this.selectedIds.has(id)) this.selectedIds.delete(id);\r\n else this.selectedIds.add(id);\r\n this.render();\r\n }\r\n\r\n generateDescribe(): void {\r\n const selected = this.tests.filter((t) => this.selectedIds.has(t.id));\r\n if (!selected.length) return;\r\n\r\n const name = this.describeName.trim() || this.t('TEST_EDITOR.DEFAULT_DESCRIBE');\r\n\r\n const allInterceptors = [...new Set(\r\n selected.flatMap((t) => this.interceptorsByTest[t.id] ?? t.interceptors ?? [])\r\n )];\r\n\r\n const beforeEach = allInterceptors.length\r\n ? ` beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n ${allInterceptors.join('\\n ')}\\n });\\n\\n`\r\n : '';\r\n\r\n const itBlocks = selected\r\n .map((t) => {\r\n const cmds = (t.commands ?? []).map((c) => ` ${c}`).join('\\n');\r\n return ` it('${escapeSingleQuotes(t.name ?? '')}', () => {\\n${cmds}\\n });`;\r\n })\r\n .join('\\n\\n');\r\n\r\n const block = `describe('${escapeSingleQuotes(name)}', () => {\\n${beforeEach}${itBlocks}\\n});`;\r\n navigator.clipboard?.writeText(block);\r\n }\r\n\r\n copyToClipboard(text: string): void {\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n get allTags(): string[] {\r\n const tagSet = new Set<string>();\r\n this.tests.forEach((t) => (t.tags ?? []).forEach((tag) => tagSet.add(tag)));\r\n return [...tagSet].sort();\r\n }\r\n\r\n get visibleTests(): TestWithDetails[] {\r\n const tag = this.activeTag;\r\n if (!tag) return this.tests;\r\n return this.tests.filter((t) => (t.tags ?? []).includes(tag));\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private render(): void {\r\n const tags = this.allTags;\r\n const visible = this.visibleTests;\r\n const selectedVisible = visible.filter((t) => this.selectedIds.has(t.id));\r\n\r\n this.shadow.innerHTML = `<style>${TEST_EDITOR_STYLES}</style>${renderTestEditor({\r\n tags,\r\n visible,\r\n selectedVisible,\r\n activeTag: this.activeTag,\r\n selectMode: this.selectMode,\r\n selectedIds: this.selectedIds,\r\n describeName: this.describeName,\r\n expandedIndex: this.expandedIndex,\r\n interceptorsByTest: this.interceptorsByTest,\r\n locale: localeForLang(this.translation.getLang()),\r\n }, this.t.bind(this))}`;\r\n\r\n this.shadow.getElementById('btn-select-mode')?.addEventListener('click', () => this.toggleSelectMode());\r\n\r\n this.shadow.querySelectorAll('[data-filter-tag]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n const tag = (el as HTMLElement).dataset['filterTag'] ?? '';\r\n if (!tag) return;\r\n this.activeTag = this.activeTag === tag ? null : tag;\r\n this.render();\r\n });\r\n });\r\n\r\n const descInput = this.shadow.getElementById('describe-name') as HTMLInputElement | null;\r\n if (descInput) {\r\n descInput.addEventListener('input', () => { this.describeName = descInput.value; });\r\n }\r\n this.shadow.getElementById('btn-gen-describe')?.addEventListener('click', () => {\r\n this.describeName = descInput?.value ?? this.describeName;\r\n this.generateDescribe();\r\n });\r\n\r\n this.shadow.querySelectorAll('[data-select]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n this.toggleSelectTest(Number((el as HTMLElement).dataset['select']));\r\n });\r\n });\r\n\r\n this.shadow.querySelectorAll('[data-action=\"expand\"]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n if (this.selectMode) {\r\n const row = visible[Number((el as HTMLElement).dataset['idx'])];\r\n if (row) this.toggleSelectTest(row.id);\r\n } else {\r\n this.toggleExpand(Number((el as HTMLElement).dataset['idx']));\r\n }\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-action=\"delete\"]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n this.deleteTest(Number((el as HTMLElement).dataset['id']));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-action=\"copy-cmds\"]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n const idx = Number((el as HTMLElement).dataset['idx']);\r\n this.copyToClipboard((visible[idx]?.commands ?? []).join('\\n'));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-action=\"copy-icps\"]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n const idx = Number((el as HTMLElement).dataset['idx']);\r\n const t = visible[idx];\r\n this.copyToClipboard((this.interceptorsByTest[t?.id] ?? t?.interceptors ?? []).join('\\n'));\r\n });\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('test-editor')) {\r\n customElements.define('test-editor', TestEditorElement);\r\n}\r\n","export const CONFIGURATION_STYLES = `\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n\n /* ── Grid container ───────────────────────────────────── */\n .cfg-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n padding: 14px;\n }\n\n /* ── Cards ────────────────────────────────────────────── */\n .card {\n background: #161b22;\n border: 1px solid #21262d;\n border-radius: 10px;\n padding: 14px 16px;\n transition: border-color 0.15s;\n }\n .card:hover { border-color: #30363d; }\n .card-wide { grid-column: 1 / -1; }\n\n /* ── Card header ──────────────────────────────────────── */\n .card-hd {\n display: flex; align-items: center; gap: 7px;\n font-size: 10px; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.8px; color: #484f58; margin-bottom: 12px;\n }\n .card-hd-icon { font-size: 13px; }\n\n /* ── Language ─────────────────────────────────────────── */\n .field-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\n .field-label { font-size: 12px; color: #8b949e; }\n select {\n background: #0d1117; color: #e6edf3; border: 1px solid #30363d;\n border-radius: 6px; padding: 6px 10px; font-size: 12px; outline: none;\n cursor: pointer; transition: border-color 0.15s; flex-shrink: 0;\n }\n select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n /* ── HTTP toggle ──────────────────────────────────────── */\n .check-row {\n display: flex; align-items: flex-start; gap: 10px;\n cursor: pointer; user-select: none;\n }\n input[type=\"checkbox\"] { width: 15px; height: 15px; margin-top: 2px; cursor: pointer; accent-color: #2f81f7; flex-shrink: 0; }\n .check-title { font-size: 12px; color: #c9d1d9; margin-bottom: 3px; }\n .check-sub { font-size: 10px; color: #484f58; line-height: 1.5; }\n\n /* ── Cypress folder ───────────────────────────────────── */\n .fs-layout { display: flex; gap: 12px; align-items: flex-start; }\n .fs-tree {\n flex-shrink: 0;\n margin: 0; padding: 8px 10px;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n font-size: 10px; color: #c9d1d9; line-height: 1.8;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n }\n .fs-right { display: flex; flex-direction: column; gap: 10px; flex: 1; }\n .fs-status {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: #8b949e;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n padding: 8px 10px;\n }\n .fs-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }\n .fs-dot.on { background: #3fb950; box-shadow: 0 0 6px rgba(63,185,80,.5); }\n .fs-dot.off { background: #484f58; }\n .fs-folder { color: #e6edf3; font-family: 'Cascadia Code','Fira Code','Consolas',monospace; font-size: 11px; }\n\n /* ── Buttons ──────────────────────────────────────────── */\n .btn-row { display: flex; gap: 8px; flex-wrap: wrap; }\n button {\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n button:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-import {\n display: inline-block;\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n .btn-import:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-danger { border-color: rgba(248,81,73,.4); color: #f85149; background: transparent; }\n .btn-danger:hover { background: rgba(248,81,73,.08); border-color: #f85149; color: #f85149; }\n .file-input { display: none; }\n\n /* ── Data section desc ────────────────────────────────── */\n .data-desc { font-size: 11px; color: #484f58; margin-bottom: 10px; line-height: 1.5; }\n\n /* ── Export overlay (modal) ───────────────────────────── */\n .export-overlay {\n position: fixed; inset: 0; z-index: 100000;\n background: rgba(1,4,9,0.7);\n display: flex; align-items: center; justify-content: center; padding: 20px;\n }\n .export-modal {\n width: 640px; max-width: 100%; max-height: 86vh;\n display: flex; flex-direction: column;\n background: #161b22; border: 1px solid #30363d; border-radius: 12px;\n box-shadow: 0 12px 40px rgba(0,0,0,0.5); overflow: hidden;\n }\n .export-hd {\n padding: 14px 18px; font-size: 13px; font-weight: 700;\n border-bottom: 1px solid #21262d; color: #e6edf3;\n }\n .export-modes { display: flex; gap: 6px; padding: 12px 18px 0; }\n .export-mode {\n flex: 1; padding: 7px 10px; font-size: 11px; border-radius: 6px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-mode:hover { background: #21262d; color: #e6edf3; }\n .export-mode.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-body {\n padding: 14px 18px; overflow-y: auto; flex: 1; min-height: 160px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .export-tag-hint { font-size: 12px; color: #484f58; margin-top: 12px; }\n .export-result-label {\n font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px;\n font-weight: 600; margin: 14px 0 6px;\n }\n .export-row-static { cursor: default; }\n .export-row-static:hover { background: transparent; }\n .export-all-desc { font-size: 12px; color: #8b949e; }\n .export-empty { font-size: 12px; color: #484f58; text-align: center; padding: 20px; }\n .export-list { display: flex; flex-direction: column; gap: 4px; }\n .export-row {\n display: flex; align-items: center; gap: 8px;\n padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 12px; color: #c9d1d9;\n }\n .export-row:hover { background: #0d1117; }\n .export-row-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .export-row-tag {\n font-size: 9px; color: #8b949e; background: #0d1117;\n border: 1px solid #30363d; border-radius: 10px; padding: 1px 7px; flex-shrink: 0;\n }\n .export-tags { display: flex; flex-wrap: wrap; gap: 6px; }\n .export-tag {\n padding: 4px 10px; font-size: 11px; border-radius: 12px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-tag:hover { background: #21262d; color: #e6edf3; }\n .export-tag.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-ft {\n display: flex; align-items: center; justify-content: space-between; gap: 10px;\n padding: 12px 18px; border-top: 1px solid #21262d;\n }\n .export-count { font-size: 11px; color: #8b949e; }\n .export-count b { color: #e6edf3; }\n .export-ft-actions { display: flex; gap: 8px; }\n .btn-export-confirm { background: #238636; border-color: #238636; color: #fff; }\n .btn-export-confirm:hover:not(:disabled) { background: #2ea043; border-color: #2ea043; }\n .btn-export-confirm:disabled { opacity: 0.45; cursor: not-allowed; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\r\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\r\nimport type { TestWithDetails } from '../../services/persistence.service';\r\n\r\nexport const LANGS = [\r\n { value: 'es', label: 'Español' },\r\n { value: 'en', label: 'English' },\r\n { value: 'fr', label: 'Français' },\r\n { value: 'it', label: 'Italiano' },\r\n { value: 'de', label: 'Deutsch' },\r\n];\r\n\r\nexport interface ConfigurationState {\r\n selectedLanguage: string;\r\n advancedHttpConfig: boolean;\r\n selectorStrategy: string;\r\n filesystemGranted: boolean;\r\n cypressFolderName: string | null;\r\n smartSelectorEnabled: boolean;\r\n startHidden: boolean;\r\n resumeTtlMinutes: number;\r\n isExporting: boolean;\r\n exportMode: ExportMode;\r\n exportTests: TestWithDetails[];\r\n exportSelectedIds: Set<number>;\r\n exportSelectedTags: Set<string>;\r\n}\r\n\r\nexport function renderExportOverlay(state: ConfigurationState, t: (key: string) => string): string {\r\n const { isExporting, exportMode, exportTests, exportSelectedIds, exportSelectedTags } = state;\r\n if (!isExporting) return '';\r\n\r\n const count = selectTestsForExport(exportTests, exportMode, {\r\n ids: exportSelectedIds,\r\n tags: exportSelectedTags,\r\n }).length;\r\n\r\n const modeBtn = (mode: ExportMode, key: string) =>\r\n `<button class=\"export-mode ${exportMode === mode ? 'active' : ''}\" data-export-mode=\"${mode}\">${t(key)}</button>`;\r\n\r\n let body: string;\r\n if (exportTests.length === 0) {\r\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_EMPTY')}</div>`;\r\n } else if (exportMode === 'all') {\r\n body = `<div class=\"export-all-desc\">${t('CONFIG.EXPORT_ALL_DESC')}</div>`;\r\n } else if (exportMode === 'manual') {\r\n body = `<div class=\"export-list\">${exportTests.map((test) => `\r\n <label class=\"export-row\">\r\n <input type=\"checkbox\" data-export-test=\"${test.id}\" ${exportSelectedIds.has(test.id) ? 'checked' : ''} />\r\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\r\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\r\n </label>`).join('')}</div>`;\r\n } else {\r\n const allTags = [...new Set(exportTests.flatMap((test) => test.tags ?? []))].sort();\r\n if (!allTags.length) {\r\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_NO_TAGS')}</div>`;\r\n } else {\r\n const chips = `<div class=\"export-tags\">${allTags.map((tag) =>\r\n `<button class=\"export-tag ${exportSelectedTags.has(tag) ? 'active' : ''}\" data-export-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}</div>`;\r\n // Preview the tests that the selected tags resolve to, so QA sees exactly\r\n // what will be exported.\r\n const matched = selectTestsForExport(exportTests, 'tags', { tags: exportSelectedTags });\r\n const preview = exportSelectedTags.size === 0\r\n ? `<div class=\"export-tag-hint\">${t('CONFIG.EXPORT_TAGS_HINT')}</div>`\r\n : `<div class=\"export-result-label\">${t('CONFIG.EXPORT_RESULT_LABEL')}</div>\r\n <div class=\"export-list\">${matched.map((test) => `\r\n <div class=\"export-row export-row-static\">\r\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\r\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\r\n </div>`).join('')}</div>`;\r\n body = chips + preview;\r\n }\r\n }\r\n\r\n return `\r\n <div class=\"export-overlay\" id=\"export-overlay\">\r\n <div class=\"export-modal\">\r\n <div class=\"export-hd\">${t('CONFIG.EXPORT_DIALOG_TITLE')}</div>\r\n ${exportTests.length ? `<div class=\"export-modes\">\r\n ${modeBtn('all', 'CONFIG.EXPORT_MODE_ALL')}\r\n ${modeBtn('manual', 'CONFIG.EXPORT_MODE_MANUAL')}\r\n ${modeBtn('tags', 'CONFIG.EXPORT_MODE_TAGS')}\r\n </div>` : ''}\r\n <div class=\"export-body\">${body}</div>\r\n <div class=\"export-ft\">\r\n <span class=\"export-count\">${t('CONFIG.EXPORT_COUNT')} <b>${count}</b></span>\r\n <span class=\"export-ft-actions\">\r\n <button id=\"btn-export-confirm\" class=\"btn-export-confirm\" ${count === 0 ? 'disabled' : ''}>${t('CONFIG.EXPORT_CONFIRM')}</button>\r\n <button id=\"btn-export-cancel\">${t('CONFIG.EXPORT_CANCEL')}</button>\r\n </span>\r\n </div>\r\n </div>\r\n </div>`;\r\n}\r\n\r\nexport function renderConfiguration(state: ConfigurationState, t: (key: string) => string): string {\r\n const { selectedLanguage, advancedHttpConfig, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes } = state;\r\n\r\n const langOptions = LANGS.map(\r\n (l) => `<option value=\"${l.value}\" ${selectedLanguage === l.value ? 'selected' : ''}>${l.label}</option>`,\r\n ).join('');\r\n\r\n return `\r\n <div class=\"cfg-grid\">\r\n\r\n <!-- Language -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.LANG_SECTION')}</div>\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${t('CONFIG.LANG_FIELD')}</span>\r\n <select id=\"lang-select\">${langOptions}</select>\r\n </div>\r\n </div>\r\n\r\n <!-- HTTP Advanced -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.HTTP_SECTION')}</div>\r\n <label class=\"check-row\">\r\n <input type=\"checkbox\" id=\"http-toggle\" ${advancedHttpConfig ? 'checked' : ''} />\r\n <div>\r\n <div class=\"check-title\">${t('CONFIG.HTTP_TITLE')}</div>\r\n <div class=\"check-sub\">${t('CONFIG.HTTP_SUB')}</div>\r\n </div>\r\n </label>\r\n </div>\r\n\r\n <!-- Smart Selector -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.SMART_SELECTOR_SECTION')}</div>\r\n <label class=\"check-row\">\r\n <input type=\"checkbox\" id=\"smart-selector-toggle\" ${smartSelectorEnabled ? 'checked' : ''} />\r\n <div>\r\n <div class=\"check-title\">${t('CONFIG.SMART_SELECTOR_TITLE')}</div>\r\n <div class=\"check-sub\">${t('CONFIG.SMART_SELECTOR_SUB')}</div>\r\n </div>\r\n </label>\r\n </div>\r\n\r\n <!-- Start Hidden -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.START_HIDDEN_SECTION')}</div>\r\n <label class=\"check-row\">\r\n <input type=\"checkbox\" id=\"start-hidden-toggle\" ${startHidden ? 'checked' : ''} />\r\n <div>\r\n <div class=\"check-title\">${t('CONFIG.START_HIDDEN_TITLE')}</div>\r\n <div class=\"check-sub\">${t('CONFIG.START_HIDDEN_SUB')}</div>\r\n </div>\r\n </label>\r\n </div>\r\n\r\n <!-- Widget position (draggable widget) -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.WIDGET_POSITION_SECTION')}</div>\r\n <div class=\"check-sub\" style=\"margin-bottom:10px\">${t('CONFIG.WIDGET_POSITION_HINT')}</div>\r\n <div class=\"btn-row\">\r\n <button id=\"btn-reset-position\">${t('CONFIG.WIDGET_POSITION_RESET_BTN')}</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Recording continuity (cross-app resume TTL) -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.RESUME_TTL_SECTION')}</div>\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${t('CONFIG.RESUME_TTL_LABEL')}</span>\r\n <input type=\"number\" id=\"resume-ttl-input\" min=\"1\" step=\"1\" value=\"${resumeTtlMinutes}\"\r\n style=\"width:80px;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none\" />\r\n </div>\r\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.RESUME_TTL_HINT')}</div>\r\n </div>\r\n\r\n <!-- Selector Strategy -->\r\n <div class=\"card card-wide\">\r\n <div class=\"card-hd\">${t('CONFIG.SELECTOR_SECTION')}</div>\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${t('CONFIG.SELECTOR_LABEL')}</span>\r\n <select id=\"selector-strategy\">\r\n <option value=\"data-cy\" ${selectorStrategy === 'data-cy' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_DATACY')}</option>\r\n <option value=\"data-testid\" ${selectorStrategy === 'data-testid' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_TESTID')}</option>\r\n <option value=\"aria-label\" ${selectorStrategy === 'aria-label' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ARIA')}</option>\r\n <option value=\"id\" ${selectorStrategy === 'id' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ID')}</option>\r\n </select>\r\n </div>\r\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.SELECTOR_HINT')}</div>\r\n </div>\r\n\r\n <!-- Cypress Folder -->\r\n <div class=\"card card-wide\">\r\n <div class=\"card-hd\">${t('CONFIG.FOLDER_SECTION')}</div>\r\n <div class=\"fs-layout\">\r\n <pre class=\"fs-tree\">cypress/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_PICK_HINT')}</span>\r\n└── e2e/\r\n └── *.cy.ts</pre>\r\n <div class=\"fs-right\">\r\n <div class=\"fs-status\">\r\n <span class=\"fs-dot ${filesystemGranted ? 'on' : 'off'}\"></span>\r\n ${filesystemGranted && cypressFolderName\r\n ? `<span>${t('CONFIG.FOLDER_CONNECTED')}</span> <span class=\"fs-folder\">📁 ${escHtml(cypressFolderName)}</span>`\r\n : `<span>${t('CONFIG.FOLDER_NOT_SET')}</span>`}\r\n </div>\r\n <div class=\"btn-row\">\r\n <button id=\"btn-change-folder\">\r\n ${filesystemGranted ? t('CONFIG.FOLDER_CHANGE_BTN') : t('CONFIG.FOLDER_SELECT_BTN')}\r\n </button>\r\n ${filesystemGranted\r\n ? `<button id=\"btn-revoke\" class=\"btn-danger\">${t('CONFIG.FOLDER_REVOKE_BTN')}</button>`\r\n : ''}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Data -->\r\n <div class=\"card card-wide\">\r\n <div class=\"card-hd\">${t('CONFIG.DATA_SECTION')}</div>\r\n <p class=\"data-desc\">${t('CONFIG.DATA_DESC')}</p>\r\n <div class=\"btn-row\">\r\n <button id=\"btn-export\">${t('CONFIG.EXPORT_BTN')}</button>\r\n <label style=\"cursor:pointer;margin:0\">\r\n <span class=\"btn-import\">${t('CONFIG.IMPORT_BTN')}</span>\r\n <input type=\"file\" class=\"file-input\" id=\"file-input\" accept=\".json\" />\r\n </label>\r\n </div>\r\n </div>\r\n\r\n </div>${renderExportOverlay(state, t)}`;\r\n}\r\n","import { PersistenceService } from '../../services/persistence.service';\r\nimport type { TestWithDetails } from '../../services/persistence.service';\r\nimport { TranslationService } from '../../services/translation.service';\r\nimport type { Lang } from '../../models/lang.model';\r\nimport type { SelectorStrategy } from '../../services/recording.service';\r\nimport { RESUME_TTL_CONFIG_KEY, DEFAULT_RESUME_TTL_MINUTES } from '../../models/active-session.model';\r\nimport { showToast } from '../../utils/toast.utils';\r\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\r\nimport { CONFIGURATION_STYLES } from './configuration.styles';\r\nimport { renderConfiguration } from './configuration.template';\r\n\r\nexport class ConfigurationElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n persistence!: PersistenceService;\r\n translation!: TranslationService;\r\n selectedLanguage = 'es';\r\n advancedHttpConfig = false;\r\n selectorStrategy: SelectorStrategy = 'data-cy';\r\n smartSelectorEnabled = true;\r\n startHidden = false;\r\n resumeTtlMinutes = DEFAULT_RESUME_TTL_MINUTES;\r\n isExporting = false;\r\n exportMode: ExportMode = 'all';\r\n exportTests: TestWithDetails[] = [];\r\n exportSelectedIds: Set<number> = new Set();\r\n exportSelectedTags: Set<string> = new Set();\r\n private filesystemGranted = false;\r\n private cypressFolderName: string | null = null;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n if (!this.translation) this.translation = new TranslationService();\r\n this.loadConfig();\r\n this.render();\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private async loadConfig(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n if (config?.['language']) {\r\n this.selectedLanguage = config['language'] as string;\r\n this.translation.setLang(this.selectedLanguage as Lang);\r\n }\r\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\r\n this.selectorStrategy = (config?.['selectorStrategy'] as SelectorStrategy) ?? 'data-cy';\r\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\r\n this.startHidden = config?.['startHidden'] === 'true';\r\n // Only override when the key exists — otherwise an async load could clobber a\r\n // value just set via onResumeTtlChange (same pattern as `language`).\r\n const ttlRaw = config?.[RESUME_TTL_CONFIG_KEY];\r\n if (ttlRaw !== undefined && ttlRaw !== null) {\r\n const ttl = Number(ttlRaw);\r\n this.resumeTtlMinutes = Number.isFinite(ttl) && ttl > 0 ? ttl : DEFAULT_RESUME_TTL_MINUTES;\r\n }\r\n this.filesystemGranted = config?.['allowReadWriteFiles'] === 'true';\r\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\r\n this.cypressFolderName = handle?.name ?? null;\r\n this.render();\r\n }\r\n\r\n async onLanguageChange(lang: string): Promise<void> {\r\n this.selectedLanguage = lang;\r\n this.translation.setLang(lang as Lang);\r\n await this.persistence.setConfig({ language: lang });\r\n this.render();\r\n }\r\n\r\n onAdvancedHttpConfigChange(checked: boolean): void {\r\n this.advancedHttpConfig = checked;\r\n localStorage.setItem('extendedHttpCommands', checked ? 'true' : 'false');\r\n this.persistence.setConfig({ extendedHttpCommands: checked ? 'true' : 'false' });\r\n this.render();\r\n }\r\n\r\n async onStartHiddenChange(checked: boolean): Promise<void> {\r\n this.startHidden = checked;\r\n await this.persistence.setConfig({ startHidden: checked ? 'true' : 'false' });\r\n this.dispatchEvent(new CustomEvent('starthiddenchange', { detail: checked, bubbles: true, composed: true }));\r\n this.render();\r\n }\r\n\r\n async onResumeTtlChange(minutes: number): Promise<void> {\r\n const safe = Number.isFinite(minutes) && minutes > 0 ? Math.round(minutes) : DEFAULT_RESUME_TTL_MINUTES;\r\n this.resumeTtlMinutes = safe;\r\n await this.persistence.setConfig({ [RESUME_TTL_CONFIG_KEY]: safe });\r\n this.render();\r\n }\r\n\r\n onResetWidgetPosition(): void {\r\n this.dispatchEvent(new CustomEvent('resetwidgetposition', { bubbles: true, composed: true }));\r\n showToast(this.t('CONFIG.WIDGET_POSITION_RESET_DONE'));\r\n }\r\n\r\n async onSmartSelectorChange(enabled: boolean): Promise<void> {\r\n this.smartSelectorEnabled = enabled;\r\n await this.persistence.setConfig({ smartSelectorEnabled: enabled ? 'true' : 'false' });\r\n this.dispatchEvent(new CustomEvent('smartselectorchange', { detail: enabled, bubbles: true, composed: true }));\r\n this.render();\r\n }\r\n\r\n async onSelectorStrategyChange(strategy: SelectorStrategy): Promise<void> {\r\n this.selectorStrategy = strategy;\r\n await this.persistence.setConfig({ selectorStrategy: strategy });\r\n this.dispatchEvent(new CustomEvent('selectorstrategychange', { detail: strategy, bubbles: true, composed: true }));\r\n this.render();\r\n }\r\n\r\n async changeFolder(): Promise<void> {\r\n try {\r\n await this.persistence.requestDirectoryPermissions();\r\n await this.loadConfig();\r\n showToast(this.t('CONFIG.FOLDER_UPDATED_TOAST'));\r\n } catch (e: unknown) {\r\n if ((e as DOMException)?.name !== 'AbortError') {\r\n showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\r\n }\r\n }\r\n }\r\n\r\n async revokeAccess(): Promise<void> {\r\n await this.persistence.setConfig({ allowReadWriteFiles: 'false', cypressDirectoryHandle: null });\r\n this.filesystemGranted = false;\r\n this.cypressFolderName = null;\r\n this.render();\r\n }\r\n\r\n private downloadTests(tests: TestWithDetails[]): void {\r\n const blob = new Blob([JSON.stringify({ tests, interceptors: [] }, null, 2)], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = 'e2e-cypress-export.json';\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n /** Downloads every saved test (used by the \"Todo\" mode and as a direct API). */\r\n async exportAllData(): Promise<void> {\r\n const tests = await this.persistence.getAllTests();\r\n this.downloadTests(tests);\r\n }\r\n\r\n /** Opens the export selection dialog, loading the current tests. */\r\n async openExportDialog(): Promise<void> {\r\n this.exportTests = await this.persistence.getAllTests();\r\n this.exportMode = 'all';\r\n this.exportSelectedIds = new Set();\r\n this.exportSelectedTags = new Set();\r\n this.isExporting = true;\r\n this.render();\r\n }\r\n\r\n cancelExport(): void {\r\n this.isExporting = false;\r\n this.exportSelectedIds.clear();\r\n this.exportSelectedTags.clear();\r\n this.render();\r\n }\r\n\r\n setExportMode(mode: ExportMode): void {\r\n this.exportMode = mode;\r\n this.render();\r\n }\r\n\r\n toggleExportTest(id: number): void {\r\n if (this.exportSelectedIds.has(id)) this.exportSelectedIds.delete(id);\r\n else this.exportSelectedIds.add(id);\r\n this.render();\r\n }\r\n\r\n toggleExportTag(tag: string): void {\r\n if (this.exportSelectedTags.has(tag)) this.exportSelectedTags.delete(tag);\r\n else this.exportSelectedTags.add(tag);\r\n this.render();\r\n }\r\n\r\n /** Downloads the tests resolved by the current mode + selection. No-op if empty. */\r\n confirmExport(): void {\r\n const subset = selectTestsForExport(this.exportTests, this.exportMode, {\r\n ids: this.exportSelectedIds,\r\n tags: this.exportSelectedTags,\r\n });\r\n if (!subset.length) return;\r\n this.downloadTests(subset);\r\n this.isExporting = false;\r\n this.exportSelectedIds.clear();\r\n this.exportSelectedTags.clear();\r\n this.render();\r\n }\r\n\r\n async importAllData(file: File): Promise<void> {\r\n const text = await file.text();\r\n let data: { tests: Record<string, unknown>[]; interceptors: Record<string, unknown>[] };\r\n try {\r\n data = JSON.parse(text);\r\n } catch {\r\n throw new Error(this.t('CONFIG.JSON_INVALID'));\r\n }\r\n if (!data || !Array.isArray(data.tests) || !Array.isArray(data.interceptors)) {\r\n throw new Error(this.t('CONFIG.JSON_BAD_FORMAT'));\r\n }\r\n // Merge: append the imported tests to whatever is already stored — never wipe\r\n // existing data (see docs/specs/004-merge-on-import.md).\r\n await this.persistence.ingestFileData(data.tests, data.interceptors);\r\n }\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${CONFIGURATION_STYLES}</style>${renderConfiguration({\r\n selectedLanguage: this.selectedLanguage,\r\n advancedHttpConfig: this.advancedHttpConfig,\r\n selectorStrategy: this.selectorStrategy,\r\n filesystemGranted: this.filesystemGranted,\r\n cypressFolderName: this.cypressFolderName,\r\n smartSelectorEnabled: this.smartSelectorEnabled,\r\n startHidden: this.startHidden,\r\n resumeTtlMinutes: this.resumeTtlMinutes,\r\n isExporting: this.isExporting,\r\n exportMode: this.exportMode,\r\n exportTests: this.exportTests,\r\n exportSelectedIds: this.exportSelectedIds,\r\n exportSelectedTags: this.exportSelectedTags,\r\n }, this.t.bind(this))}`;\r\n ;(this.shadow.getElementById('lang-select') as HTMLSelectElement).addEventListener('change', (e) =>\r\n this.onLanguageChange((e.target as HTMLSelectElement).value),\r\n )\r\n ;(this.shadow.getElementById('http-toggle') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onAdvancedHttpConfigChange((e.target as HTMLInputElement).checked),\r\n )\r\n ;(this.shadow.getElementById('smart-selector-toggle') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onSmartSelectorChange((e.target as HTMLInputElement).checked),\r\n )\r\n ;(this.shadow.getElementById('start-hidden-toggle') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onStartHiddenChange((e.target as HTMLInputElement).checked),\r\n )\r\n ;(this.shadow.getElementById('resume-ttl-input') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onResumeTtlChange(Number((e.target as HTMLInputElement).value)),\r\n )\r\n ;this.shadow.getElementById('btn-reset-position')?.addEventListener('click', () => this.onResetWidgetPosition())\r\n ;(this.shadow.getElementById('selector-strategy') as HTMLSelectElement).addEventListener('change', (e) =>\r\n this.onSelectorStrategyChange((e.target as HTMLSelectElement).value as SelectorStrategy),\r\n );\r\n\r\n this.shadow.getElementById('btn-change-folder')?.addEventListener('click', () => this.changeFolder());\r\n this.shadow.getElementById('btn-revoke')?.addEventListener('click', () => this.revokeAccess());\r\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.openExportDialog());\r\n\r\n this.shadow.getElementById('btn-export-confirm')?.addEventListener('click', () => this.confirmExport());\r\n this.shadow.getElementById('btn-export-cancel')?.addEventListener('click', () => this.cancelExport());\r\n this.shadow.querySelectorAll('[data-export-mode]').forEach((el) =>\r\n el.addEventListener('click', () => this.setExportMode((el as HTMLElement).dataset['exportMode'] as ExportMode)),\r\n );\r\n this.shadow.querySelectorAll('[data-export-test]').forEach((el) =>\r\n el.addEventListener('change', () => this.toggleExportTest(Number((el as HTMLElement).dataset['exportTest']))),\r\n );\r\n this.shadow.querySelectorAll('[data-export-tag]').forEach((el) =>\r\n el.addEventListener('click', () => this.toggleExportTag((el as HTMLElement).dataset['exportTag'] ?? '')),\r\n )\r\n ;(this.shadow.getElementById('file-input') as HTMLInputElement).addEventListener('change', async (e) => {\r\n const file = (e.target as HTMLInputElement).files?.[0];\r\n if (!file) return;\r\n try {\r\n await this.importAllData(file);\r\n alert(this.t('CONFIG.IMPORT_SUCCESS'));\r\n } catch (err: unknown) {\r\n alert((err as Error).message ?? this.t('CONFIG.IMPORT_ERROR'));\r\n }\r\n const target = e.target as HTMLInputElement | null;\r\n if (target) target.value = '';\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('e2e-configuration')) {\r\n customElements.define('e2e-configuration', ConfigurationElement);\r\n}\r\n","export const ADVANCED_TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .layout { display: flex; flex: 1; min-height: 0; }\n .sidebar {\n border-right: none; display: flex; flex-direction: column;\n background: #0d1117; flex-shrink: 0; min-width: 140px; max-width: 500px;\n }\n .tree-scroll {\n flex: 1; overflow-y: auto; padding: 6px 4px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .tree-scroll::-webkit-scrollbar { width: 4px; }\n .tree-scroll::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .resize-handle {\n width: 4px; background: #21262d; cursor: col-resize; flex-shrink: 0;\n transition: background 0.15s;\n }\n .resize-handle:hover, .resize-handle.dragging { background: #2f81f7; }\n .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #161b22; min-width: 0; }\n .no-perm {\n padding: 28px; color: #484f58; font-size: 13px; text-align: center;\n display: flex; flex-direction: column; align-items: center; gap: 12px; line-height: 1.6;\n }\n .tree-item {\n padding: 4px 6px; border-radius: 4px; cursor: pointer;\n font-size: 12px; color: #8b949e; white-space: nowrap;\n overflow: hidden; text-overflow: ellipsis;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; gap: 4px; user-select: none;\n }\n .tree-item:hover { background: #161b22; color: #c9d1d9; }\n .tree-item.selected { background: rgba(47,129,247,0.12); color: #2f81f7; }\n .tree-item.dir { color: #e3b341; font-weight: 600; }\n .tree-item.dir:hover { background: rgba(227,179,65,0.08); color: #f0c040; }\n .dir-arrow { font-size: 8px; color: #484f58; width: 10px; flex-shrink: 0; line-height: 1; }\n .tree-connector { display: block; width: 1px; background: #21262d; margin-left: 13px; height: 100%; }\n .content-area {\n flex: 1; padding: 12px 14px; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .content-area::-webkit-scrollbar { width: 4px; }\n .content-area::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .file-name { font-size: 11px; color: #484f58; margin-bottom: 8px; font-family: monospace; }\n pre {\n background: #0d1117; padding: 12px; border-radius: 8px;\n font-size: 11px; color: #c9d1d9; margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n line-height: 1.7; border: 1px solid #21262d;\n white-space: pre; overflow-x: auto; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n pre::-webkit-scrollbar { width: 4px; height: 4px; }\n pre::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .pre-block { font-size: 10.5px; }\n .pre-icp .sh-str { color: #85e89d; }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n .footer {\n padding: 10px 14px; border-top: 1px solid #21262d;\n display: flex; gap: 8px; justify-content: flex-end; background: #161b22;\n }\n button {\n padding: 6px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button:disabled { opacity: 0.35; cursor: default; }\n .btn-save { background: #2f81f7; border-color: #2f81f7; color: #fff; }\n .btn-save:hover { background: #1f6feb; border-color: #1f6feb; color: #fff; }\n .btn-save:disabled { background: #21262d; border-color: #30363d; color: #8b949e; }\n .placeholder { color: #484f58; font-size: 13px; padding: 28px; text-align: center; }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .block-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }\n .btn-copy {\n padding: 3px 10px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-copy:hover { background: #30363d; color: #e6edf3; }\n .sidebar-toolbar {\n display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 6px 4px;\n border-bottom: 1px solid #21262d; flex-shrink: 0; background: #0d1117;\n }\n .btn-toolbar {\n flex: 1 1 calc(50% - 2px); padding: 4px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #161b22; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; overflow: hidden;\n text-overflow: ellipsis;\n }\n .btn-toolbar.btn-full { flex: 1 1 100%; }\n .btn-toolbar:hover { background: #30363d; color: #e6edf3; }\n .btn-toolbar.btn-new { color: #3fb950; border-color: #238636; }\n .btn-toolbar.btn-new:hover { background: #238636; color: #fff; }\n .btn-toolbar.btn-new-folder { color: #d29922; border-color: #9e6a03; }\n .btn-toolbar.btn-new-folder:hover { background: #9e6a03; color: #fff; }\n .new-file-form {\n padding: 6px; border-bottom: 1px solid #21262d; display: flex; flex-direction: column; gap: 4px;\n }\n .new-file-form input {\n width: 100%; padding: 4px 7px; background: #0d1117; border: 1px solid #30363d;\n border-radius: 5px; color: #e6edf3; font-size: 11px; font-family: monospace;\n outline: none;\n }\n .new-file-form input:focus { border-color: #2f81f7; }\n .new-file-form .ext { font-size: 9px; color: #484f58; padding: 0 2px; }\n .new-file-actions { display: flex; gap: 4px; }\n .btn-confirm { flex: 1; padding: 3px 6px; border: 1px solid #238636; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #238636; color: #fff; transition: background 0.12s; }\n .btn-confirm:hover { background: #2ea043; }\n .btn-cancel-form { flex: 1; padding: 3px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e; transition: background 0.12s; }\n .btn-cancel-form:hover { background: #30363d; color: #e6edf3; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\n\nexport interface AdvancedEditorState {\n e2eTree: Array<DirectoryNode | FileNode>;\n selectedFile: unknown;\n selectedFileContent: string | null;\n testItBlock: string;\n interceptorsBlock: string;\n testNotes: string;\n saveButtonEnabled: boolean;\n isCreatingFile: boolean;\n isCreatingFolder: boolean;\n collapsedDirs: Set<string>;\n sidebarWidth: number;\n}\n\nexport function renderNoPermission(needsReauth: boolean, t: (key: string) => string): string {\n const reauthBtn = needsReauth\n ? `<button id=\"btn-reauth\"\n style=\"margin-top:14px;padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\n ${t('ADVANCED_EDITOR.REAUTH_BTN')}\n </button>`\n : '';\n\n return `\n <div class=\"no-perm\">\n <div>${needsReauth ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED') : t('ADVANCED_EDITOR.NO_ACCESS')}</div>\n <div style=\"font-size:11px\">${needsReauth\n ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED_HINT')\n : t('ADVANCED_EDITOR.NO_ACCESS_HINT')}</div>\n ${reauthBtn}\n </div>`;\n}\n\nexport function renderAdvancedEditor(state: AdvancedEditorState, t: (key: string) => string): string {\n const { e2eTree, selectedFile, selectedFileContent, testItBlock, interceptorsBlock, testNotes, saveButtonEnabled, isCreatingFile, isCreatingFolder, collapsedDirs, sidebarWidth } = state;\n\n const treeHtml = e2eTree.length\n ? renderTree(e2eTree, selectedFile, collapsedDirs)\n : `<div class=\"tree-item\" style=\"color:#6c7a99\">${t('ADVANCED_EDITOR.NO_FILES')}</div>`;\n\n const contentHtml = selectedFileContent\n ? `<div class=\"file-name\">📄 ${escHtml((selectedFile as { name?: string } | null)?.name ?? '')}</div>\n <pre class=\"pre-file\">${syntaxHighlight(selectedFileContent.slice(0, 6000))}${selectedFileContent.length > 6000 ? '\\n...' : ''}</pre>`\n : `<div class=\"placeholder\">${t('ADVANCED_EDITOR.SELECT_FILE')}</div>`;\n\n const notesHtml = (testItBlock && testNotes)\n ? `<p class=\"test-notes\">${escHtml(testNotes)}</p>`\n : '';\n\n const itHtml = testItBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.IT_LABEL')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_IT_BTN')}</button>\n </div>\n <pre class=\"pre-block\">${syntaxHighlight(testItBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const interceptorsHtml = interceptorsBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.BEFORE_EACH_LABEL')}</span>\n <button id=\"btn-copy-interceptors\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_ICP_BTN')}</button>\n </div>\n <pre class=\"pre-block pre-icp\">${syntaxHighlight(interceptorsBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const newFileForm = isCreatingFile\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-file\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FILE_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <span class=\"ext\">.cy.ts</span>\n <div class=\"new-file-actions\">\n <button id=\"btn-new-file-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-file-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const newFolderForm = isCreatingFolder\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-folder\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FOLDER_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <div class=\"new-file-actions\">\n <button id=\"btn-new-folder-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-folder-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const toolbar = `\n <div class=\"sidebar-toolbar\">\n <button id=\"btn-new-file\" class=\"btn-toolbar btn-new\">${t('ADVANCED_EDITOR.NEW_FILE_BTN')}</button>\n <button id=\"btn-new-folder\" class=\"btn-toolbar btn-new-folder\">${t('ADVANCED_EDITOR.NEW_FOLDER_BTN')}</button>\n <button id=\"btn-refresh\" class=\"btn-toolbar btn-full\">${t('ADVANCED_EDITOR.REFRESH_BTN')}</button>\n </div>`;\n\n return `\n <div class=\"layout\">\n <div class=\"sidebar\" style=\"width:${sidebarWidth}px\">\n ${toolbar}\n ${newFileForm}\n ${newFolderForm}\n <div class=\"tree-scroll\">${treeHtml}</div>\n </div>\n <div id=\"resize-handle\" class=\"resize-handle\"></div>\n <div class=\"main\">\n <div class=\"content-area\">${contentHtml}${notesHtml}${itHtml}${interceptorsHtml}</div>\n <div class=\"footer\">\n <button id=\"btn-save\" class=\"btn-save\"\n ${!saveButtonEnabled || !testItBlock ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.INSERT_BTN')}\n </button>\n <button id=\"btn-edit\" ${!saveButtonEnabled ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.EDIT_MANUAL_BTN')}\n </button>\n <button id=\"btn-close\">${t('ADVANCED_EDITOR.CLOSE_BTN')}</button>\n </div>\n </div>\n </div>`;\n}\n\nexport function renderTree(\n nodes: Array<DirectoryNode | FileNode>,\n selected: unknown,\n collapsedDirs: Set<string>,\n indent = 0,\n parentPath = '',\n): string {\n return nodes.map((n) => {\n const currentPath = parentPath ? `${parentPath}/${n.name}` : n.name;\n const isFile = n.kind === 'file';\n const pad = `padding-left:${6 + indent * 14}px`;\n\n if (!isFile) {\n const dir = n as DirectoryNode;\n const hasChildren = (dir.children?.length ?? 0) > 0;\n const isCollapsed = collapsedDirs.has(currentPath);\n const arrow = hasChildren ? (isCollapsed ? '▶' : '▼') : '·';\n const dirHtml = `<div class=\"tree-item dir\" style=\"${pad}\" data-dir-path=\"${escAttr(currentPath)}\">\n <span class=\"dir-arrow\">${arrow}</span>📁 ${escHtml(n.name)}\n </div>`;\n if (!hasChildren || isCollapsed) return dirHtml;\n return dirHtml + renderTree(dir.children, selected, collapsedDirs, indent + 1, currentPath);\n }\n\n const isSel = (selected as { name?: string } | null)?.name === n.name;\n const cls = `tree-item${isSel ? ' selected' : ''}`;\n const data = JSON.stringify({ kind: n.kind, name: n.name }).replace(/\"/g, '"');\n return `<div class=\"${cls}\" style=\"${pad}\" data-file=\"${data}\">📄 ${escHtml(n.name)}</div>`;\n }).join('');\n}\n\nexport async function findFileHandleRecursive(\n dir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemFileHandle | null> {\n for await (const entry of dir.values()) {\n if (entry.kind === 'file' && entry.name === name) return entry as FileSystemFileHandle;\n if (entry.kind === 'directory') {\n const found = await findFileHandleRecursive(entry as FileSystemDirectoryHandle, name);\n if (found) return found;\n }\n }\n return null;\n}\n","import { PersistenceService } from '../../services/persistence.service';\r\nimport { TranslationService } from '../../services/translation.service';\r\nimport { AdvancedTestTransformationService } from '../../services/advanced-test.transformation.service';\r\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\r\nimport { ADVANCED_TEST_EDITOR_STYLES } from './advanced-test-editor.styles';\r\nimport { renderNoPermission, renderAdvancedEditor, findFileHandleRecursive } from './advanced-test-editor.template';\r\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\r\n\r\nexport class AdvancedTestEditorElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private readonly transformationService = new AdvancedTestTransformationService();\r\n\r\n persistence!: PersistenceService;\r\n translation!: TranslationService;\r\n testId?: number;\r\n\r\n e2eTree: Array<DirectoryNode | FileNode> = [];\r\n selectedFile: unknown = null;\r\n saveButtonEnabled = false;\r\n selectedFileHandle: FileSystemFileHandle | null = null;\r\n selectedFileContent: string | null = null;\r\n testItBlock = '';\r\n interceptorsBlock = '';\r\n testNotes = '';\r\n isPreviewMode = false;\r\n previewFileName: string | null = null;\r\n previewFileContent: string | null = null;\r\n isCreatingFile = false;\r\n isCreatingFolder = false;\r\n collapsedDirs: Set<string> = new Set();\r\n sidebarWidth = 220;\r\n private hasPermission = false;\r\n private needsReauth = false;\r\n private _dirHandle: FileSystemDirectoryHandle | null = null;\r\n private _e2eHandle: FileSystemDirectoryHandle | null = null;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n if (!this.translation) this.translation = new TranslationService();\r\n this.init();\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private async init(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n const allowed = config?.['allowReadWriteFiles'] === 'true';\r\n\r\n if (!allowed) {\r\n this.hasPermission = false;\r\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\r\n this.render();\r\n return;\r\n }\r\n\r\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | null;\r\n if (!handle) {\r\n this.hasPermission = false;\r\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\r\n this.render();\r\n return;\r\n }\r\n\r\n // queryPermission does NOT require a user gesture\r\n const perm = await (handle as unknown as FileSystemHandleWithPermission).queryPermission({ mode: 'readwrite' });\r\n this._dirHandle = handle;\r\n this.hasPermission = perm === 'granted';\r\n this.needsReauth = perm === 'prompt';\r\n\r\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\r\n if (this.hasPermission) await this.getFoldersData();\r\n this.render();\r\n }\r\n\r\n async getFoldersData(): Promise<void> {\r\n if (!this.hasPermission || !this._dirHandle) return;\r\n try {\r\n for await (const entry of this._dirHandle.values()) {\r\n if (entry.kind === 'directory' && entry.name === 'e2e') {\r\n this._e2eHandle = entry as FileSystemDirectoryHandle;\r\n const tree = await this.transformationService.scanDirectory(this._e2eHandle);\r\n this.e2eTree = tree.children ?? [];\r\n this.render();\r\n return;\r\n }\r\n }\r\n } catch { /* silently skip permission errors */ }\r\n }\r\n\r\n async createNewFile(rawName: string): Promise<void> {\r\n if (!this._e2eHandle) return;\r\n const name = rawName.trim().replace(/\\.cy\\.ts$/, '');\r\n if (!name) return;\r\n const fileName = `${name}.cy.ts`;\r\n const template = `describe('${escapeSingleQuotes(name)}', () => {\\n\\n it('should ', () => {\\n\\n });\\n\\n});\\n`;\r\n try {\r\n const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });\r\n const writable = await fileHandle.createWritable();\r\n await writable.write(template);\r\n await writable.close();\r\n } catch { /* silently ignore if file already exists or permission denied */ }\r\n this.isCreatingFile = false;\r\n await this.getFoldersData();\r\n }\r\n\r\n async createNewFolder(rawName: string): Promise<void> {\r\n if (!this._e2eHandle) return;\r\n const name = rawName.trim().replace(/[/\\\\]/g, '');\r\n if (!name) return;\r\n try {\r\n await this._e2eHandle.getDirectoryHandle(name, { create: true });\r\n } catch { /* silently ignore if folder already exists or permission denied */ }\r\n this.isCreatingFolder = false;\r\n await this.getFoldersData();\r\n }\r\n\r\n async refreshTree(): Promise<void> {\r\n await this.getFoldersData();\r\n }\r\n\r\n async saveCommandsToFile(): Promise<void> {\r\n if (!this.selectedFileHandle || !this.selectedFileContent || !this.testItBlock) return;\r\n let content = this.selectedFileContent;\r\n if (this.interceptorsBlock) {\r\n content = this.transformationService.insertBeforeEach(content, this.interceptorsBlock);\r\n }\r\n const comment = this.testNotes ? this.transformationService.buildBlockComment(this.testNotes) + '\\n' : '';\r\n content = this.transformationService.insertItBlock(content, comment + this.testItBlock);\r\n if (!content) return;\r\n const writable = await this.selectedFileHandle.createWritable();\r\n await writable.write(content);\r\n await writable.close();\r\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\r\n }\r\n\r\n async onFileClick(file: unknown): Promise<void> {\r\n if (!this.transformationService.isFile(file)) return;\r\n this.selectedFile = file;\r\n this.saveButtonEnabled = true;\r\n\r\n if (!this._dirHandle) return;\r\n const handle = await findFileHandleRecursive(this._dirHandle, (file as { name: string }).name);\r\n if (!handle) return;\r\n this.selectedFileHandle = handle;\r\n const fileObj = await handle.getFile();\r\n this.selectedFileContent = await fileObj.text();\r\n this.render();\r\n }\r\n\r\n markFileAsSelected(file: unknown): void {\r\n this.selectedFile = file;\r\n }\r\n\r\n async loadCypressCommandsForTest(testId: number): Promise<void> {\r\n const test = await this.persistence.getTestById(testId);\r\n if (test) {\r\n this.testItBlock = test.itBlock ?? '';\r\n this.interceptorsBlock = test.interceptorsBlock ?? '';\r\n this.testNotes = test.notes ?? '';\r\n } else {\r\n this.testItBlock = '';\r\n this.interceptorsBlock = '';\r\n this.testNotes = '';\r\n }\r\n this.render();\r\n }\r\n\r\n copyToClipboard(text: string): void {\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n openEditManually(): void {\r\n if (!this.selectedFileHandle || !this.selectedFileContent) return;\r\n this.dispatchEvent(new CustomEvent('openfileeditor', {\r\n detail: {\r\n handle: this.selectedFileHandle,\r\n content: this.selectedFileContent,\r\n fileName: (this.selectedFile as { name?: string } | null)?.name ?? '',\r\n testId: this.testId,\r\n itBlock: this.testItBlock,\r\n interceptorsBlock: this.interceptorsBlock,\r\n notes: this.testNotes,\r\n },\r\n bubbles: true,\r\n composed: true,\r\n }));\r\n }\r\n\r\n toggleDir(path: string): void {\r\n if (this.collapsedDirs.has(path)) {\r\n this.collapsedDirs.delete(path);\r\n } else {\r\n this.collapsedDirs.add(path);\r\n }\r\n this.render();\r\n }\r\n\r\n private setupResizeHandle(): void {\r\n const handle = this.shadow.getElementById('resize-handle');\r\n const sidebar = this.shadow.querySelector('.sidebar') as HTMLElement | null;\r\n if (!handle || !sidebar) return;\r\n\r\n let startX = 0;\r\n let startWidth = 0;\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n const delta = e.clientX - startX;\r\n const newWidth = Math.max(140, Math.min(500, startWidth + delta));\r\n this.sidebarWidth = newWidth;\r\n sidebar.style.width = `${newWidth}px`;\r\n };\r\n\r\n const onMouseUp = () => {\r\n document.removeEventListener('mousemove', onMouseMove);\r\n document.removeEventListener('mouseup', onMouseUp);\r\n document.body.style.cursor = '';\r\n document.body.style.userSelect = '';\r\n handle.classList.remove('dragging');\r\n };\r\n\r\n handle.addEventListener('mousedown', (e: MouseEvent) => {\r\n startX = e.clientX;\r\n startWidth = sidebar.offsetWidth;\r\n document.addEventListener('mousemove', onMouseMove);\r\n document.addEventListener('mouseup', onMouseUp);\r\n document.body.style.cursor = 'col-resize';\r\n document.body.style.userSelect = 'none';\r\n handle.classList.add('dragging');\r\n e.preventDefault();\r\n });\r\n }\r\n\r\n closePreview(): void {\r\n this.isPreviewMode = false;\r\n this.previewFileName = null;\r\n this.previewFileContent = null;\r\n if (this.testId !== undefined) {\r\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\r\n }\r\n this.render();\r\n }\r\n\r\n private render(): void {\r\n if (!this.hasPermission) {\r\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderNoPermission(this.needsReauth, this.t.bind(this))}`;\r\n\r\n this.shadow.getElementById('btn-reauth')?.addEventListener('click', async () => {\r\n if (!this._dirHandle) return;\r\n const perm = await (this._dirHandle as unknown as FileSystemHandleWithPermission).requestPermission({ mode: 'readwrite' });\r\n if (perm === 'granted') {\r\n this.hasPermission = true;\r\n this.needsReauth = false;\r\n await this.getFoldersData();\r\n this.render();\r\n }\r\n });\r\n return;\r\n }\r\n\r\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderAdvancedEditor({\r\n e2eTree: this.e2eTree,\r\n selectedFile: this.selectedFile,\r\n selectedFileContent: this.selectedFileContent,\r\n testItBlock: this.testItBlock,\r\n interceptorsBlock: this.interceptorsBlock,\r\n testNotes: this.testNotes,\r\n saveButtonEnabled: this.saveButtonEnabled,\r\n isCreatingFile: this.isCreatingFile,\r\n isCreatingFolder: this.isCreatingFolder,\r\n collapsedDirs: this.collapsedDirs,\r\n sidebarWidth: this.sidebarWidth,\r\n }, this.t.bind(this))}`;\r\n\r\n this.shadow.querySelectorAll('[data-file]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n const data = (el as HTMLElement).dataset['file'];\r\n if (data) this.onFileClick(JSON.parse(data));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-dir-path]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n const path = (el as HTMLElement).dataset['dirPath'];\r\n if (path) this.toggleDir(path);\r\n });\r\n });\r\n this.setupResizeHandle();\r\n this.shadow.getElementById('btn-save')\r\n ?.addEventListener('click', () => this.saveCommandsToFile());\r\n this.shadow.getElementById('btn-edit')\r\n ?.addEventListener('click', () => this.openEditManually());\r\n this.shadow.getElementById('btn-copy-it')\r\n ?.addEventListener('click', () => this.copyToClipboard(this.testItBlock));\r\n this.shadow.getElementById('btn-copy-interceptors')\r\n ?.addEventListener('click', () => this.copyToClipboard(this.interceptorsBlock));\r\n this.shadow.getElementById('btn-close')\r\n ?.addEventListener('click', () => this.closePreview());\r\n this.shadow.getElementById('btn-new-file')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFile = !this.isCreatingFile;\r\n this.isCreatingFolder = false;\r\n this.render();\r\n if (this.isCreatingFile) this.shadow.getElementById('input-new-file')?.focus();\r\n });\r\n this.shadow.getElementById('btn-new-folder')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFolder = !this.isCreatingFolder;\r\n this.isCreatingFile = false;\r\n this.render();\r\n if (this.isCreatingFolder) this.shadow.getElementById('input-new-folder')?.focus();\r\n });\r\n this.shadow.getElementById('btn-refresh')\r\n ?.addEventListener('click', () => this.refreshTree());\r\n this.shadow.getElementById('btn-new-file-confirm')\r\n ?.addEventListener('click', () => {\r\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\r\n this.createNewFile(input?.value ?? '');\r\n });\r\n this.shadow.getElementById('btn-new-file-cancel')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFile = false;\r\n this.render();\r\n });\r\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\r\n input?.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') {\r\n this.createNewFile(input.value);\r\n } else if (e.key === 'Escape') {\r\n this.isCreatingFile = false;\r\n this.render();\r\n }\r\n });\r\n this.shadow.getElementById('btn-new-folder-confirm')\r\n ?.addEventListener('click', () => {\r\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\r\n this.createNewFolder(folderInput?.value ?? '');\r\n });\r\n this.shadow.getElementById('btn-new-folder-cancel')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFolder = false;\r\n this.render();\r\n });\r\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\r\n folderInput?.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') {\r\n this.createNewFolder(folderInput.value);\r\n } else if (e.key === 'Escape') {\r\n this.isCreatingFolder = false;\r\n this.render();\r\n }\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('advanced-test-editor')) {\r\n customElements.define('advanced-test-editor', AdvancedTestEditorElement);\r\n}\r\n","export const FILE_PREVIEW_STYLES = `\n :host { display: block; height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n .container { display: flex; flex-direction: column; height: 100%; }\n .header {\n display: flex; align-items: center; gap: 8px;\n padding: 8px 12px; border-bottom: 1px solid #21262d;\n background: #161b22;\n }\n .file-name { flex: 1; font-size: 12px; color: #8b949e;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; }\n .body { display: flex; flex: 1; overflow: hidden; min-height: 0; }\n .editor {\n flex: 1; min-width: 0; padding: 14px;\n background: #0d1117; color: #c9d1d9; border: none; outline: none;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 12px;\n line-height: 1.7; resize: none;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .editor::-webkit-scrollbar { width: 5px; }\n .editor::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .blocks-panel {\n width: 260px; flex-shrink: 0; border-left: 1px solid #21262d;\n background: #0d1117; padding: 10px 12px; overflow-y: auto;\n display: flex; flex-direction: column; gap: 10px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .blocks-panel::-webkit-scrollbar { width: 4px; }\n .blocks-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .block-section { display: flex; flex-direction: column; gap: 4px; }\n .block-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }\n .block-label { font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600; }\n .btn-copy-sm {\n padding: 2px 8px; border: 1px solid #30363d; border-radius: 4px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap;\n }\n .btn-copy-sm:hover { background: #30363d; color: #e6edf3; }\n .block-pre {\n margin: 0; padding: 6px 8px; background: #161b22;\n border-radius: 5px; border: 1px solid #21262d;\n font-size: 10px; color: #c9d1d9; line-height: 1.6;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n max-height: 280px; overflow-y: auto; white-space: pre-wrap; word-break: break-all;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel {\n flex: 1; overflow-y: auto; background: #0d1117; border-left: 1px solid #21262d;\n padding: 8px 0; min-width: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n line-height: 1.6;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel::-webkit-scrollbar { width: 5px; }\n .diff-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .diff-line {\n display: flex; gap: 0; white-space: pre; padding: 0 12px;\n }\n .diff-line.added { background: rgba(63,185,80,0.12); color: #3fb950; }\n .diff-line.removed { background: rgba(248,81,73,0.1); color: #f85149; }\n .diff-line.same { color: #484f58; }\n .diff-sign { width: 14px; flex-shrink: 0; user-select: none; }\n .diff-empty { color: #484f58; font-size: 12px; padding: 20px; text-align: center; }\n .footer {\n display: flex; gap: 8px; padding: 8px 12px;\n border-top: 1px solid #21262d; justify-content: flex-end;\n background: #161b22;\n }\n button {\n padding: 6px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n .btn-save { background: #3fb950; border-color: #3fb950; color: #fff; }\n .btn-save:hover { background: #2ea043; border-color: #2ea043; }\n .btn-launch { background: transparent; border-color: #e3b341; color: #e3b341; }\n .btn-launch:hover { background: rgba(227,179,65,0.1); }\n .btn-launch:disabled { opacity: 0.45; cursor: not-allowed; }\n .btn-launch:disabled:hover { background: transparent; }\n .launch-hint { font-size: 10px; color: #8b6d3b; align-self: center; }\n .btn-insert { background: transparent; border-color: #a371f7; color: #a371f7; }\n .btn-insert:hover { background: rgba(163,113,247,0.12); color: #c8a8ff; }\n .btn-diff-active { background: rgba(47,129,247,0.15); border-color: rgba(47,129,247,0.4); color: #2f81f7; }\n\n /* ── Run result panel ─────────────────────────────────── */\n .run-result {\n border-top: 1px solid #21262d; padding: 8px 12px; background: #0d1117;\n max-height: 220px; overflow-y: auto; flex-shrink: 0;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .run-status { font-size: 12px; font-weight: 600; }\n .run-passed .run-status { color: #3fb950; }\n .run-failed .run-status { color: #f85149; }\n .run-running .run-status { color: #e3b341; }\n .run-error .run-status { color: #f85149; }\n .run-output {\n margin: 6px 0 0; padding: 8px 10px; background: #161b22; border: 1px solid #21262d;\n border-radius: 5px; font-size: 10px; color: #c9d1d9; line-height: 1.5;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto;\n }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport type DiffEntry = { type: 'same' | 'added' | 'removed'; line: string };\n\nexport function computeDiff(original: string, modified: string): DiffEntry[] {\n const MAX_LINES = 600;\n const a = original.split('\\n').slice(0, MAX_LINES);\n const b = modified.split('\\n').slice(0, MAX_LINES);\n const m = a.length, n = b.length;\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]);\n }\n }\n\n const result: DiffEntry[] = [];\n let i = m, j = n;\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {\n result.unshift({ type: 'same', line: a[i - 1] });\n i--; j--;\n } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {\n result.unshift({ type: 'added', line: b[j - 1] });\n j--;\n } else {\n result.unshift({ type: 'removed', line: a[i - 1] });\n i--;\n }\n }\n return result;\n}\n\nexport function buildDiffHtml(original: string, current: string, t: (key: string) => string): string {\n if (original === current) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES')}</div>`;\n\n const diff = computeDiff(original, current);\n if (!diff.length) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES_SHORT')}</div>`;\n\n const CONTEXT = 2;\n const compressed: DiffEntry[] = [];\n let sameRun = 0;\n for (let idx = 0; idx < diff.length; idx++) {\n if (diff[idx].type === 'same') {\n sameRun++;\n if (sameRun <= CONTEXT) compressed.push(diff[idx]);\n else if (idx + 1 < diff.length && diff[idx + 1].type !== 'same') {\n if (sameRun > CONTEXT * 2) compressed.push({ type: 'same', line: '…' });\n compressed.push(diff[idx]);\n }\n } else {\n sameRun = 0;\n compressed.push(diff[idx]);\n }\n }\n\n return compressed.map(({ type, line }) => {\n const sign = type === 'added' ? '+' : type === 'removed' ? '−' : ' ';\n return `<div class=\"diff-line ${type}\"><span class=\"diff-sign\">${sign}</span><span>${escHtml(line)}</span></div>`;\n }).join('');\n}\n\nexport type RunState = 'idle' | 'running' | 'passed' | 'failed' | 'error';\n\nexport interface FilePreviewState {\n fileName: string | null;\n showDiff: boolean;\n fileContent: string | null;\n originalContent: string | null;\n currentContent: string;\n itBlock: string;\n interceptorsBlock: string;\n closeLabel: string;\n isLocal: boolean;\n runState: RunState;\n runOutput: string;\n}\n\nconst RUN_STATUS_KEY: Record<Exclude<RunState, 'idle'>, string> = {\n running: 'FILE_PREVIEW.LAUNCH_RUNNING',\n passed: 'FILE_PREVIEW.LAUNCH_PASSED',\n failed: 'FILE_PREVIEW.LAUNCH_FAILED',\n error: 'FILE_PREVIEW.LAUNCH_NO_RUNNER',\n};\n\nexport function renderFilePreview(state: FilePreviewState, t: (key: string) => string): string {\n const { fileName, showDiff, fileContent, originalContent, currentContent, itBlock, interceptorsBlock, closeLabel, isLocal, runState, runOutput } = state;\n\n const blocksPanelHtml = (itBlock || interceptorsBlock) ? `\n <div class=\"blocks-panel\">\n ${itBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_IT')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\">${escHtml(itBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n ${interceptorsBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_BEFORE_EACH')}</span>\n <button id=\"btn-copy-icp\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\" style=\"color:#3fb950\">${escHtml(interceptorsBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n </div>` : '';\n\n const hasChanges = originalContent !== null && originalContent !== (fileContent ?? '');\n const hasBlocks = !!(itBlock || interceptorsBlock);\n\n const launchBtnHtml = isLocal\n ? `<button id=\"btn-launch\" class=\"btn-launch\" ${runState === 'running' ? 'disabled' : ''}>${runState === 'running' ? t('FILE_PREVIEW.LAUNCH_RUNNING') : t('FILE_PREVIEW.LAUNCH_BTN')}</button>`\n : `<button class=\"btn-launch\" disabled title=\"${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}\">${t('FILE_PREVIEW.LAUNCH_BTN')}</button>\n <span class=\"launch-hint\">${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}</span>`;\n\n const runResultHtml = runState !== 'idle'\n ? `<div class=\"run-result run-${runState}\">\n <span class=\"run-status\">${t(RUN_STATUS_KEY[runState])}</span>\n ${runOutput ? `<pre class=\"run-output\">${escHtml(runOutput.slice(0, 8000))}</pre>` : ''}\n </div>`\n : '';\n\n return `\n <div class=\"container\">\n <div class=\"header\">\n <span class=\"file-name\">📄 ${fileName ? escHtml(fileName) : t('FILE_PREVIEW.NO_FILE')}</span>\n <button id=\"btn-copy\" title=\"${t('FILE_PREVIEW.COPY_TITLE')}\">📋</button>\n </div>\n <div class=\"body\">\n ${showDiff\n ? `<div class=\"diff-panel\" id=\"diff-panel\">${buildDiffHtml(originalContent ?? '', currentContent, t)}</div>`\n : `<textarea class=\"editor\" id=\"editor\" spellcheck=\"false\">${escHtml(fileContent ?? '')}</textarea>`}\n ${blocksPanelHtml}\n </div>\n ${runResultHtml}\n <div class=\"footer\">\n ${launchBtnHtml}\n ${hasChanges ? `<button id=\"btn-diff\" class=\"${showDiff ? 'btn-diff-active' : ''}\">${t('FILE_PREVIEW.DIFF_BTN')}</button>` : ''}\n ${hasBlocks && !showDiff ? `<button id=\"btn-insert\" class=\"btn-insert\" title=\"${t('FILE_PREVIEW.INSERT_TITLE')}\">${t('FILE_PREVIEW.INSERT_BTN')}</button>` : ''}\n <button id=\"btn-save\" class=\"btn-save\">${t('FILE_PREVIEW.SAVE_BTN')}</button>\n <button id=\"btn-close\">${escHtml(closeLabel || t('FILE_PREVIEW.CLOSE_BTN'))}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\r\nimport { advancedTestTransformationService } from '../../services/advanced-test.transformation.service';\r\nimport { showToast } from '../../utils/toast.utils';\r\nimport { isLocalHost } from '../../utils/host.utils';\r\nimport { FILE_PREVIEW_STYLES } from './file-preview.styles';\r\nimport { renderFilePreview, type RunState } from './file-preview.template';\r\n\r\nexport class FilePreviewElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private textarea: HTMLTextAreaElement | null = null;\r\n\r\n fileName: string | null = null;\r\n closeLabel = '';\r\n translation: TranslationService = translationService;\r\n itBlock = '';\r\n interceptorsBlock = '';\r\n notes = '';\r\n commands: string[] = [];\r\n interceptors: string[] = [];\r\n /** Endpoint of the local Cypress runner. Configurable; defaults to the bundled runner's port. */\r\n runnerUrl = 'http://localhost:8123/run-test';\r\n /** Whether the app is served locally — gates the launch button. Overridable for tests. */\r\n isLocal = isLocalHost(window.location.hostname);\r\n private _fileContent: string | null = null;\r\n private _originalContent: string | null = null;\r\n private _showDiff = false;\r\n private _runState: RunState = 'idle';\r\n private _runOutput = '';\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.closeLabel) this.closeLabel = this.translation.translate('FILE_PREVIEW.CLOSE_BTN');\r\n this.render();\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n get fileContent(): string | null { return this._fileContent; }\r\n set fileContent(v: string | null) {\r\n if (this._originalContent === null) this._originalContent = v;\r\n this._fileContent = v;\r\n if (this.textarea) this.textarea.value = v ?? '';\r\n else this.render();\r\n }\r\n\r\n saveFile(): void {\r\n const content = this.textarea?.value ?? this._fileContent ?? '';\r\n this.dispatchEvent(new CustomEvent('save', { detail: content, bubbles: true, composed: true }));\r\n }\r\n\r\n onClose(): void {\r\n this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));\r\n }\r\n\r\n /**\r\n * Runs the current spec headless via the local runner and shows the result.\r\n * No-op off localhost. Never throws — connection failures surface as an\r\n * \"error\" state + toast instead of an unhandled rejection.\r\n */\r\n async launchTest(specPath?: string): Promise<void> {\r\n if (!this.isLocal) return;\r\n const path = specPath ?? this.fileName ?? '';\r\n if (!path) return;\r\n\r\n this._runState = 'running';\r\n this._runOutput = '';\r\n this.render();\r\n\r\n try {\r\n const response = await fetch(this.runnerUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ specPath: path }),\r\n });\r\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\r\n const result = await response.json() as { success?: boolean; output?: string };\r\n this._runOutput = result.output ?? '';\r\n this._runState = result.success ? 'passed' : 'failed';\r\n } catch {\r\n this._runState = 'error';\r\n this._runOutput = '';\r\n showToast(this.t('FILE_PREVIEW.LAUNCH_NO_RUNNER'), false);\r\n }\r\n this.render();\r\n }\r\n\r\n copyToClipboard(text: string): void {\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n toggleDiff(): void {\r\n this._showDiff = !this._showDiff;\r\n this.render();\r\n }\r\n\r\n /**\r\n * Merges the it() and beforeEach() blocks into the current editor content\r\n * using the same logic as the automatic \"Insert into file\" action, so the\r\n * user does not have to copy/paste manually. Leaves the content untouched\r\n * (and warns) when the file has no valid describe() block to insert into.\r\n */\r\n insertBlocks(): void {\r\n const base = this.textarea?.value ?? this._fileContent ?? '';\r\n let content = base;\r\n if (this.interceptorsBlock) {\r\n const merged = advancedTestTransformationService.insertBeforeEach(content, this.interceptorsBlock);\r\n if (merged) content = merged;\r\n }\r\n if (this.itBlock) {\r\n const comment = this.notes ? advancedTestTransformationService.buildBlockComment(this.notes) + '\\n' : '';\r\n const merged = advancedTestTransformationService.insertItBlock(content, comment + this.itBlock);\r\n if (merged) content = merged;\r\n }\r\n if (content === base) {\r\n showToast(this.t('FILE_PREVIEW.INSERT_ERROR'), false);\r\n return;\r\n }\r\n this._fileContent = content;\r\n this.render();\r\n showToast(this.t('FILE_PREVIEW.INSERT_DONE'));\r\n }\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${FILE_PREVIEW_STYLES}</style>${renderFilePreview({\r\n fileName: this.fileName,\r\n showDiff: this._showDiff,\r\n fileContent: this._fileContent,\r\n originalContent: this._originalContent,\r\n currentContent: this.textarea?.value ?? this._fileContent ?? '',\r\n itBlock: this.itBlock,\r\n interceptorsBlock: this.interceptorsBlock,\r\n closeLabel: this.closeLabel,\r\n isLocal: this.isLocal,\r\n runState: this._runState,\r\n runOutput: this._runOutput,\r\n }, this.t.bind(this))}`;\r\n\r\n this.textarea = this.shadow.getElementById('editor') as HTMLTextAreaElement | null;\r\n if (this.textarea) {\r\n const ta = this.textarea;\r\n this.textarea.addEventListener('input', () => {\r\n this._fileContent = ta.value;\r\n });\r\n }\r\n this.shadow.getElementById('btn-save')?.addEventListener('click', () => this.saveFile());\r\n this.shadow.getElementById('btn-close')?.addEventListener('click', () => this.onClose());\r\n this.shadow.getElementById('btn-launch')?.addEventListener('click', () => this.launchTest());\r\n this.shadow.getElementById('btn-copy')?.addEventListener('click', () => {\r\n this.copyToClipboard(this.textarea?.value ?? this._fileContent ?? '');\r\n });\r\n this.shadow.getElementById('btn-diff')?.addEventListener('click', () => this.toggleDiff());\r\n this.shadow.getElementById('btn-insert')?.addEventListener('click', () => this.insertBlocks());\r\n this.shadow.getElementById('btn-copy-it')?.addEventListener('click', () => {\r\n this.copyToClipboard(this.itBlock);\r\n });\r\n this.shadow.getElementById('btn-copy-icp')?.addEventListener('click', () => {\r\n this.copyToClipboard(this.interceptorsBlock);\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('file-preview')) {\r\n customElements.define('file-preview', FilePreviewElement);\r\n}\r\n","import Swal from 'sweetalert2';\r\nimport { getRecorderStyles } from './lib-e2e-recorder.styles';\r\nimport { renderRecorderWidget } from './lib-e2e-recorder.template';\r\nimport { RecordingService, type SelectorStrategy } from '../../services/recording.service';\r\nimport { PersistenceService } from '../../services/persistence.service';\r\nimport { TranslationService } from '../../services/translation.service';\r\nimport { HttpMonitor } from '../../services/http-monitor';\r\nimport {\r\n injectStyles,\r\n LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,\r\n SCROLLBAR_STYLES,\r\n} from '../../utils/styles.utils';\r\nimport {\r\n makeModalResizable,\r\n makeSwalDraggable,\r\n setSwal2DataCyAttribute,\r\n} from '../../utils/modal.utils';\r\nimport type { Lang } from '../../models/lang.model';\r\nimport {\r\n type ActiveSessionState,\r\n ACTIVE_SESSION_BREADCRUMB_KEY,\r\n RESUME_TTL_CONFIG_KEY,\r\n DEFAULT_RESUME_TTL_MINUTES,\r\n} from '../../models/active-session.model';\r\nimport {\r\n type ExpandDirection,\r\n type Point,\r\n DRAG_THRESHOLD,\r\n clampTogglePosition,\r\n resolveExpandDirection,\r\n defaultTogglePosition,\r\n boxTopLeftFor,\r\n} from '../../utils/widget-position.utils';\r\nimport { showToast } from '../../utils/toast.utils';\r\n\r\n/**\r\n * Minimal property/event shapes for dynamically-created child custom elements.\r\n * Not extending HTMLElement avoids conflicts with the strict EventListener signature;\r\n * cast to Node/HTMLElement only for actual DOM insertion.\r\n */\r\ninterface PrevisualizerEl {\r\n translation: TranslationService; commands: string[]; interceptors: string[]; editable: boolean;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\r\n}\r\ninterface TestEditorEl { persistence: PersistenceService; translation: TranslationService }\r\ninterface SaveTestEl {\r\n translation: TranslationService;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\r\n}\r\ninterface ConfigEl {\r\n persistence: PersistenceService; translation: TranslationService;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\r\n}\r\ninterface AdvancedEditorEl {\r\n persistence: PersistenceService; translation: TranslationService; testId?: number;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\r\n}\r\ninterface FilePreviewEl {\r\n translation: TranslationService; fileContent: string | null; fileName: string | null;\r\n closeLabel: string; itBlock: string; interceptorsBlock: string; notes: string;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\r\n}\r\ninterface SelectorPickerEl {\r\n targetElement: HTMLElement; recording: RecordingService; translation: TranslationService;\r\n}\r\n\r\nexport class LibE2eRecorderElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private _isDisabled = false;\r\n private keydownHandler!: (e: KeyboardEvent) => void;\r\n private recordingUnsub?: () => void;\r\n private commandsUnsub?: () => void;\r\n private interceptorsUnsub?: () => void;\r\n private pauseUnsub?: () => void;\r\n private selectorNotFoundUnsub?: () => void;\r\n private langUnsub?: () => void;\r\n private sessionUnsub?: () => void;\r\n private sessionSaveTimer?: ReturnType<typeof setTimeout>;\r\n private controlFirstTimeData = true;\r\n\r\n // ── draggable widget (spec 007) ──\r\n private togglePos: Point | null = null;\r\n private expandDir: ExpandDirection = 'up-left';\r\n private dragState?: { startX: number; startY: number; origX: number; origY: number; moved: boolean };\r\n private suppressNextToggleClick = false;\r\n private widgetPointerMove?: (e: MouseEvent) => void;\r\n private widgetPointerUp?: () => void;\r\n private widgetResize?: () => void;\r\n private _previsualizerRef: { commands: string[]; interceptors: string[] } | null = null;\r\n private httpMonitor?: HttpMonitor;\r\n private smartSelectorEnabled = true;\r\n\r\n recording!: RecordingService;\r\n persistence!: PersistenceService;\r\n translation!: TranslationService;\r\n\r\n isVisible = false;\r\n isRecording = false;\r\n isPaused = false;\r\n cypressCommands: string[] = [];\r\n interceptors: string[] = [];\r\n\r\n isCommandsDialogOpen = false;\r\n isSavedTestsDialogOpen = false;\r\n isSaveTestDialogOpen = false;\r\n isSettingsDialogOpen = false;\r\n isAdvancedEditorDialogOpen = false;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if ('Cypress' in window) {\r\n this._isDisabled = true;\r\n return;\r\n }\r\n if (!this.getAttribute('data-cy')) {\r\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\r\n }\r\n if (!this.recording) this.recording = new RecordingService();\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n if (!this.translation) this.translation = new TranslationService();\r\n\r\n this.httpMonitor = new HttpMonitor(this.recording);\r\n this.httpMonitor.install();\r\n\r\n injectStyles(LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, 'lib-e2e-swal2-styles');\r\n injectStyles(SCROLLBAR_STYLES, 'lib-e2e-scrollbar-styles');\r\n\r\n this.initHttpConfig();\r\n this.initLanguage();\r\n this.initFilesystemAccess();\r\n this.initSelectorStrategy();\r\n this.initSubscriptions();\r\n this.render();\r\n this.initVisibility();\r\n this.initSessionContinuity();\r\n this.initWidgetPosition();\r\n\r\n this.keydownHandler = (e: KeyboardEvent) => this.handleKeyboardEvent(e);\r\n window.addEventListener('keydown', this.keydownHandler);\r\n\r\n // Draggable widget (spec 007): pointer move/up tracked at window level so the\r\n // drag keeps working even if the cursor leaves the toggle button.\r\n this.widgetPointerMove = (e: MouseEvent) => this.onWidgetPointerMove(e);\r\n this.widgetPointerUp = () => this.onWidgetPointerUp();\r\n this.widgetResize = () => this.applyWidgetPosition();\r\n window.addEventListener('pointermove', this.widgetPointerMove as EventListener);\r\n window.addEventListener('pointerup', this.widgetPointerUp);\r\n window.addEventListener('resize', this.widgetResize);\r\n }\r\n\r\n disconnectedCallback(): void {\r\n if (this._isDisabled) return;\r\n window.removeEventListener('keydown', this.keydownHandler);\r\n // Final flush: if a recording is in progress, persist it synchronously-ish\r\n // before tearing the service down, so an unmount (single-spa per-sub-project\r\n // placement) does not lose the last commands. The realm survives client-side\r\n // navigation, so this async write completes even after the element is gone.\r\n this.flushActiveSessionOnDisconnect();\r\n this.recordingUnsub?.();\r\n this.commandsUnsub?.();\r\n this.interceptorsUnsub?.();\r\n this.pauseUnsub?.();\r\n this.selectorNotFoundUnsub?.();\r\n this.langUnsub?.();\r\n this.sessionUnsub?.();\r\n if (this.widgetPointerMove) window.removeEventListener('pointermove', this.widgetPointerMove as EventListener);\r\n if (this.widgetPointerUp) window.removeEventListener('pointerup', this.widgetPointerUp);\r\n if (this.widgetResize) window.removeEventListener('resize', this.widgetResize);\r\n this.httpMonitor?.uninstall();\r\n this.recording.destroy();\r\n }\r\n\r\n private async initHttpConfig(): Promise<void> {\r\n const config = await this.persistence.getConfig('extendedHttpCommands');\r\n if (config === null) {\r\n await this.persistence.setConfig({ extendedHttpCommands: 'true' });\r\n localStorage.setItem('extendedHttpCommands', 'true');\r\n } else {\r\n localStorage.setItem('extendedHttpCommands', (config['extendedHttpCommands'] as string) ?? 'true');\r\n }\r\n }\r\n\r\n private async initLanguage(): Promise<void> {\r\n const config = await this.persistence.getConfig('language');\r\n const lang = config?.['language'] as Lang | undefined;\r\n this.translation.setLang(lang ?? this.translation.detectLang());\r\n }\r\n\r\n private initSubscriptions(): void {\r\n this.recordingUnsub = this.recording.onRecordingChange((val) => {\r\n this.isRecording = val;\r\n if (!val && !this.controlFirstTimeData) {\r\n this.saveRecordingHistory();\r\n // Stopping the recording ends the cross-app session: only an actively\r\n // recording session is ever persisted/resumed (spec 006, Q2).\r\n this.clearSessionPersistence();\r\n this.showSaveTestDialog();\r\n }\r\n this.controlFirstTimeData = false;\r\n this.render();\r\n });\r\n // Persist the live session incrementally so it survives a micro-frontend\r\n // crossing or a same-origin reload (spec 006).\r\n this.sessionUnsub = this.recording.onSessionChange((state) => this.persistActiveSession(state));\r\n this.commandsUnsub = this.recording.onCommandsChange((cmds) => {\r\n this.cypressCommands = cmds;\r\n if (this._previsualizerRef) this._previsualizerRef.commands = cmds;\r\n });\r\n this.interceptorsUnsub = this.recording.onInterceptorsChange((icps) => {\r\n this.interceptors = icps;\r\n if (this._previsualizerRef) this._previsualizerRef.interceptors = icps;\r\n });\r\n this.pauseUnsub = this.recording.onPauseChange((paused) => {\r\n this.isPaused = paused;\r\n this.render();\r\n });\r\n this.selectorNotFoundUnsub = this.recording.onSelectorNotFound((target) => {\r\n if (this.smartSelectorEnabled) this.showSelectorPicker(target);\r\n });\r\n // Re-render the widget chrome when the UI language changes so labels update live.\r\n this.langUnsub = this.translation.onLangChange(() => this.render());\r\n }\r\n\r\n private showSelectorPicker(target: HTMLElement): void {\r\n import('../../components/selector-picker/selector-picker').then(() => {\r\n const existing = document.querySelector('selector-picker');\r\n if (existing) existing.remove();\r\n\r\n const picker = document.createElement('selector-picker') as unknown as SelectorPickerEl;\r\n picker.targetElement = target;\r\n picker.recording = this.recording;\r\n picker.translation = this.translation;\r\n document.body.appendChild(picker as unknown as Node);\r\n });\r\n }\r\n\r\n private async initVisibility(): Promise<void> {\r\n if (this.hasAttribute('start-hidden')) {\r\n // Attribute overrides DB: presence → hidden, explicit \"false\" → visible\r\n this.isVisible = this.getAttribute('start-hidden') === 'false';\r\n this.style.display = this.isVisible ? '' : 'none';\r\n return;\r\n }\r\n const config = await this.persistence.getGeneralConfig();\r\n this.isVisible = config?.['startHidden'] !== 'true';\r\n this.style.display = this.isVisible ? '' : 'none';\r\n }\r\n\r\n private async initSelectorStrategy(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n const strategy = config?.['selectorStrategy'] as string | undefined;\r\n if (strategy) this.recording.selectorStrategy = strategy as SelectorStrategy;\r\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\r\n }\r\n\r\n // ── cross-app session continuity (spec 006) ───────────────────────────────\r\n\r\n /**\r\n * On mount, detect a persisted live recording session and either resume it\r\n * silently (recent) or prompt continue/discard (stale). No-op when there is\r\n * no actively-recording session.\r\n */\r\n private async initSessionContinuity(): Promise<void> {\r\n if (this._isDisabled) return;\r\n const session = await this.persistence.getActiveSession();\r\n if (!session || !session.isRecording) return;\r\n const ttlMin = await this.getResumeTtlMinutes();\r\n const ageMs = Date.now() - session.updatedAt;\r\n if (ageMs <= ttlMin * 60_000) {\r\n this.resumeSessionState(session);\r\n } else {\r\n this.promptResumeOrDiscard(session);\r\n }\r\n }\r\n\r\n private async getResumeTtlMinutes(): Promise<number> {\r\n const config = await this.persistence.getConfig(RESUME_TTL_CONFIG_KEY);\r\n const raw = config?.[RESUME_TTL_CONFIG_KEY];\r\n const n = typeof raw === 'number' ? raw : Number(raw);\r\n return Number.isFinite(n) && n > 0 ? n : DEFAULT_RESUME_TTL_MINUTES;\r\n }\r\n\r\n /** Rehydrates the recorder from a persisted session (no bootstrap re-emitted). */\r\n private resumeSessionState(session: ActiveSessionState): void {\r\n this.recording.restoreSession(session);\r\n this.cypressCommands = session.commands;\r\n this.interceptors = session.interceptors;\r\n this.controlFirstTimeData = false;\r\n this.render();\r\n }\r\n\r\n private async promptResumeOrDiscard(session: ActiveSessionState): Promise<void> {\r\n const t = this.translation.translate.bind(this.translation);\r\n const result = await Swal.fire({\r\n title: t('RECORDER.SESSION_RESUME_TITLE'),\r\n html:\r\n `<div style=\"padding:8px 4px;color:#8b949e;font-size:13px;line-height:1.6\">` +\r\n `<p>${t('RECORDER.SESSION_RESUME_TEXT')}</p>` +\r\n `<p style=\"margin-top:6px;color:#c9d1d9\"><b>${session.commands.length}</b> ${t('RECORDER.SESSION_RESUME_COUNT')}</p>` +\r\n `</div>`,\r\n showCancelButton: true,\r\n confirmButtonText: t('RECORDER.SESSION_CONTINUE_BTN'),\r\n cancelButtonText: t('RECORDER.SESSION_DISCARD_BTN'),\r\n color: '#e6edf3',\r\n });\r\n if (result && (result as { isConfirmed?: boolean }).isConfirmed) {\r\n this.resumeSessionState(session);\r\n } else {\r\n this.discardSession();\r\n }\r\n }\r\n\r\n /** Debounced persistence of the live session; clears it the moment recording stops. */\r\n private persistActiveSession(state: ActiveSessionState): void {\r\n if (this._isDisabled) return;\r\n if (!state.isRecording) {\r\n this.clearSessionPersistence();\r\n return;\r\n }\r\n this.writeSessionBreadcrumb(state);\r\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\r\n this.sessionSaveTimer = setTimeout(() => {\r\n const snap = this.recording.getSessionSnapshot();\r\n if (snap.isRecording) this.persistence.saveActiveSession(snap).catch(() => { /* storage errors are non-fatal */ });\r\n }, 300);\r\n }\r\n\r\n private writeSessionBreadcrumb(state: ActiveSessionState): void {\r\n try {\r\n localStorage.setItem(ACTIVE_SESSION_BREADCRUMB_KEY, JSON.stringify({\r\n sessionId: state.sessionId,\r\n isRecording: state.isRecording,\r\n updatedAt: state.updatedAt,\r\n }));\r\n } catch { /* ignore storage errors */ }\r\n }\r\n\r\n private flushActiveSessionOnDisconnect(): void {\r\n const snap = this.recording.getSessionSnapshot();\r\n if (!snap.isRecording) return;\r\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\r\n this.writeSessionBreadcrumb(snap);\r\n this.persistence.saveActiveSession(snap).catch(() => { /* non-fatal */ });\r\n }\r\n\r\n private clearSessionPersistence(): void {\r\n if (this.sessionSaveTimer) { clearTimeout(this.sessionSaveTimer); this.sessionSaveTimer = undefined; }\r\n try { localStorage.removeItem(ACTIVE_SESSION_BREADCRUMB_KEY); } catch { /* ignore */ }\r\n this.persistence.clearActiveSession().catch(() => { /* non-fatal */ });\r\n }\r\n\r\n /** True when a synchronous breadcrumb marks an active recording session. */\r\n hasActiveSession(): boolean {\r\n try {\r\n const raw = localStorage.getItem(ACTIVE_SESSION_BREADCRUMB_KEY);\r\n if (!raw) return false;\r\n return !!(JSON.parse(raw) as { isRecording?: boolean }).isRecording;\r\n } catch { return false; }\r\n }\r\n\r\n /** Programmatically resume the persisted session, if any. */\r\n resumeSession(): void {\r\n this.persistence.getActiveSession().then((s) => { if (s) this.resumeSessionState(s); });\r\n }\r\n\r\n /** Discard the persisted live session (breadcrumb + DB record). */\r\n discardSession(): void {\r\n this.clearSessionPersistence();\r\n }\r\n\r\n // ── draggable widget (spec 007) ────────────────────────────────────────────\r\n\r\n /** Loads a previously saved widget position and applies it. */\r\n private async initWidgetPosition(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n const pos = config?.['widgetPosition'] as Partial<Point> | null | undefined;\r\n if (pos && typeof pos.x === 'number' && typeof pos.y === 'number') {\r\n this.togglePos = { x: pos.x, y: pos.y };\r\n }\r\n this.applyWidgetPosition();\r\n }\r\n\r\n /** Positions the `.widget` box from the (clamped) toggle centre and orients the arc. */\r\n private applyWidgetPosition(): void {\r\n const widget = this.shadow.querySelector('.widget') as HTMLElement | null;\r\n if (!widget) return;\r\n const vw = window.innerWidth;\r\n const vh = window.innerHeight;\r\n const centre = this.togglePos ?? defaultTogglePosition(vw, vh);\r\n const clamped = clampTogglePosition(centre.x, centre.y, vw, vh);\r\n this.expandDir = resolveExpandDirection(clamped.x, clamped.y, vw, vh);\r\n const topLeft = boxTopLeftFor(clamped, this.expandDir);\r\n widget.style.left = `${topLeft.x}px`;\r\n widget.style.top = `${topLeft.y}px`;\r\n widget.style.right = 'auto';\r\n widget.style.bottom = 'auto';\r\n widget.setAttribute('data-expand', this.expandDir);\r\n }\r\n\r\n private beginWidgetDrag(e: MouseEvent): void {\r\n const origin = this.togglePos ?? defaultTogglePosition(window.innerWidth, window.innerHeight);\r\n this.dragState = { startX: e.clientX, startY: e.clientY, origX: origin.x, origY: origin.y, moved: false };\r\n }\r\n\r\n private onWidgetPointerMove(e: MouseEvent): void {\r\n if (!this.dragState) return;\r\n const dx = e.clientX - this.dragState.startX;\r\n const dy = e.clientY - this.dragState.startY;\r\n if (!this.dragState.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\r\n this.dragState.moved = true;\r\n this.togglePos = { x: this.dragState.origX + dx, y: this.dragState.origY + dy };\r\n this.applyWidgetPosition();\r\n }\r\n\r\n private onWidgetPointerUp(): void {\r\n if (!this.dragState) return;\r\n const moved = this.dragState.moved;\r\n this.dragState = undefined;\r\n if (!moved || !this.togglePos) return;\r\n // It was a drag, not a click: suppress the click that fires next and persist.\r\n this.suppressNextToggleClick = true;\r\n const clamped = clampTogglePosition(this.togglePos.x, this.togglePos.y, window.innerWidth, window.innerHeight);\r\n this.togglePos = clamped;\r\n this.persistence.setConfig({ widgetPosition: clamped }).catch(() => { /* non-fatal */ });\r\n }\r\n\r\n /** Resets the widget to its default corner and clears the saved position. */\r\n resetWidgetPosition(): void {\r\n this.togglePos = null;\r\n this.persistence.setConfig({ widgetPosition: null }).catch(() => { /* non-fatal */ });\r\n this.applyWidgetPosition();\r\n }\r\n\r\n toggle(): void {\r\n this.recording.toggleRecording();\r\n }\r\n\r\n togglePause(): void {\r\n this.recording.togglePause();\r\n }\r\n\r\n setLanguage(lang?: string): void {\r\n const resolved = lang ? (lang as Lang) : this.translation.detectLang();\r\n this.translation.setLang(resolved);\r\n }\r\n\r\n handleKeyboardEvent(event: KeyboardEvent): void {\r\n if (!event.ctrlKey) return;\r\n const key = event.key.toLowerCase();\r\n if (key === 'e' && event.shiftKey) { event.preventDefault(); this.toggleVisibility(); return; }\r\n if (!this.isVisible) return;\r\n if (key === 'r') { event.preventDefault(); this.toggle(); }\r\n else if (key === 'p') { event.preventDefault(); this.togglePause(); }\r\n else if (key === '1') { event.preventDefault(); this.showSavedTestsDialog(); }\r\n else if (key === '2') { event.preventDefault(); this.showCommandsDialog(); }\r\n else if (key === '3') { event.preventDefault(); this.showSettingsDialog(); }\r\n }\r\n\r\n toggleVisibility(): void {\r\n this.isVisible = !this.isVisible;\r\n this.style.display = this.isVisible ? '' : 'none';\r\n }\r\n\r\n // ── recording history (task 5) ────────────────────────────────────────────\r\n\r\n private saveRecordingHistory(): void {\r\n if (!this.cypressCommands.length) return;\r\n try {\r\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\r\n existing.unshift({ commands: this.cypressCommands, interceptors: this.interceptors, savedAt: Date.now() });\r\n if (existing.length > 5) existing.splice(5);\r\n localStorage.setItem('e2e-recording-history', JSON.stringify(existing));\r\n } catch { /* ignore storage errors */ }\r\n }\r\n\r\n recoverLastRecording(): void {\r\n try {\r\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\r\n if (!existing.length) return;\r\n const { commands, interceptors } = existing[0];\r\n commands.forEach((cmd: string) => this.recording.appendCommand(cmd));\r\n (interceptors as string[]).forEach((_icp: string) => { /* interceptors are not appendable the same way */ });\r\n } catch { /* ignore */ }\r\n }\r\n\r\n clearRecordingHistory(): void {\r\n localStorage.removeItem('e2e-recording-history');\r\n }\r\n\r\n getRecordingHistory(): Array<{ commands: string[]; interceptors: string[]; savedAt: number }> {\r\n try {\r\n return JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\r\n } catch { return []; }\r\n }\r\n\r\n // ── filesystem setup ─────────────────────────────────────────────────────\r\n\r\n private async initFilesystemAccess(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n // Only show if the user has never made a choice (key doesn't exist yet)\r\n if (config && 'allowReadWriteFiles' in config) return;\r\n this.showFilesystemSetupDialog();\r\n }\r\n\r\n private showFilesystemSetupDialog(): void {\r\n Swal.fire({\r\n title: this.translation.translate('RECORDER.FS_TITLE'),\r\n html: '<div id=\"fs-setup-content\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('fs-setup-content');\r\n if (!container) return;\r\n container.innerHTML = `\r\n <div style=\"padding:16px 20px 20px;color:#8b949e;font-size:13px;line-height:1.7\">\r\n <p>${this.translation.translate('RECORDER.FS_INTRO_HTML')}</p>\r\n <p style=\"margin-top:10px;margin-bottom:6px;font-size:11px;color:#8b949e\">\r\n ${this.translation.translate('RECORDER.FS_STRUCTURE_HINT_HTML')}\r\n </p>\r\n <pre style=\"margin:0;padding:10px 14px;background:#0d1117;border:1px solid #21262d;\r\n border-radius:8px;font-size:11px;color:#c9d1d9;line-height:1.8;\r\n font-family:'Cascadia Code','Fira Code','Consolas',monospace\">\r\ncypress/ <span style=\"color:#484f58\">${this.translation.translate('RECORDER.FS_TREE_PICK_HINT')}</span>\r\n└── e2e/ <span style=\"color:#484f58\">${this.translation.translate('RECORDER.FS_TREE_READ_HINT')}</span>\r\n └── *.cy.ts</pre>\r\n <p style=\"margin-top:8px;font-size:11px;color:#484f58\">\r\n ${this.translation.translate('RECORDER.FS_PERMISSION_NOTE')}\r\n </p>\r\n <div style=\"display:flex;gap:8px;justify-content:flex-end;margin-top:20px\">\r\n <button id=\"fs-skip\"\r\n style=\"padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;\r\n font-size:12px;font-weight:500;background:transparent;color:#8b949e\">\r\n ${this.translation.translate('RECORDER.FS_LATER_BTN')}\r\n </button>\r\n <button id=\"fs-select\"\r\n style=\"padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\r\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\r\n ${this.translation.translate('RECORDER.FS_SELECT_BTN')}\r\n </button>\r\n </div>\r\n </div>`;\r\n\r\n document.getElementById('fs-skip')?.addEventListener('click', async () => {\r\n await this.persistence.setConfigKey('allowReadWriteFiles', 'false');\r\n Swal.close();\r\n });\r\n\r\n document.getElementById('fs-select')?.addEventListener('click', async () => {\r\n try {\r\n await this.persistence.requestDirectoryPermissions();\r\n Swal.close();\r\n showToast(this.translation.translate('RECORDER.FS_SUCCESS_TOAST'));\r\n } catch (e: unknown) {\r\n if ((e as DOMException)?.name !== 'AbortError') {\r\n showToast(this.translation.translate('RECORDER.FS_ERROR_TOAST'), false);\r\n }\r\n // AbortError = user cancelled the picker, leave dialog open\r\n }\r\n });\r\n },\r\n });\r\n }\r\n\r\n // ── dialogs ──────────────────────────────────────────────────────────────\r\n\r\n showCommandsDialog(): void {\r\n this.toggleModal('isCommandsDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.DIALOG_COMMANDS'),\r\n html: '<div id=\"commands-modal-content\" style=\"min-height:250px;padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n backdrop: false,\r\n width: 640,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n // Make the container click-through so the page underneath remains interactive\r\n const swalContainer = document.querySelector('.swal2-container') as HTMLElement | null;\r\n if (swalContainer) {\r\n swalContainer.style.pointerEvents = 'none';\r\n const popup = swalContainer.querySelector('.swal2-popup') as HTMLElement | null;\r\n if (popup) popup.style.pointerEvents = 'all';\r\n }\r\n const container = document.getElementById('commands-modal-content');\r\n if (!container) return;\r\n\r\n const child = document.createElement('test-previsualizer') as unknown as PrevisualizerEl;\r\n child.translation = this.translation;\r\n child.commands = this.cypressCommands;\r\n child.interceptors = this.interceptors;\r\n child.editable = true;\r\n container.appendChild(child as unknown as Node);\r\n this._previsualizerRef = child;\r\n\r\n child.addEventListener('deletecommand', (e: CustomEvent) => {\r\n this.recording.removeCommand(e.detail);\r\n });\r\n child.addEventListener('movecommand', (e: CustomEvent) => {\r\n this.recording.moveCommand(e.detail.from, e.detail.to);\r\n });\r\n child.addEventListener('deleteinterceptor', (e: CustomEvent) => {\r\n this.recording.removeInterceptor(e.detail);\r\n });\r\n\r\n // ── Assertion builder panel ──────────────────────────────────────\r\n const assertionHtml = `\r\n <div id=\"assertion-builder\"\r\n style=\"padding:10px 12px;border-top:1px solid #21262d;background:#0d1117\">\r\n <div style=\"font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px\">\r\n ${this.translation.translate('RECORDER.ASSERTION_SECTION')}\r\n </div>\r\n <div style=\"display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end\">\r\n <input id=\"assert-selector\" type=\"text\"\r\n placeholder=\"${this.translation.translate('RECORDER.ASSERT_SELECTOR_PH').replace(/\"/g, '"')}\"\r\n style=\"flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\r\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;\r\n font-family:'Cascadia Code','Fira Code',monospace\"/>\r\n <select id=\"assert-type\"\r\n style=\"padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;\r\n color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0\">\r\n <option value=\"be.visible\">be.visible</option>\r\n <option value=\"not.exist\">not.exist</option>\r\n <option value=\"be.disabled\">be.disabled</option>\r\n <option value=\"be.checked\">be.checked</option>\r\n <option value=\"contain.text\">contain.text</option>\r\n <option value=\"have.value\">have.value</option>\r\n <option value=\"have.length\">have.length</option>\r\n <option value=\"have.class\">have.class</option>\r\n <option value=\"have.attr\">have.attr</option>\r\n </select>\r\n <input id=\"assert-value\" type=\"text\" placeholder=\"${this.translation.translate('RECORDER.ASSERT_VALUE_PH')}\"\r\n style=\"flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\r\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none\"/>\r\n <button id=\"btn-add-assertion\"\r\n style=\"padding:5px 12px;border:none;border-radius:5px;cursor:pointer;\r\n font-size:11px;font-weight:500;background:#2f81f7;color:#fff;\r\n white-space:nowrap;flex-shrink:0\">\r\n ${this.translation.translate('RECORDER.ASSERT_ADD_BTN')}\r\n </button>\r\n </div>\r\n </div>`;\r\n container.insertAdjacentHTML('beforeend', assertionHtml);\r\n\r\n const NO_VALUE_ASSERTIONS = new Set(['be.visible', 'not.exist', 'be.disabled', 'be.checked']);\r\n document.getElementById('btn-add-assertion')?.addEventListener('click', () => {\r\n const sel = (document.getElementById('assert-selector') as HTMLInputElement).value.trim();\r\n const type = (document.getElementById('assert-type') as HTMLSelectElement).value;\r\n const val = (document.getElementById('assert-value') as HTMLInputElement).value.trim();\r\n if (!sel) return;\r\n const cmd = NO_VALUE_ASSERTIONS.has(type) || !val\r\n ? `cy.get('${sel}').should('${type}')`\r\n : `cy.get('${sel}').should('${type}', '${val}')`;\r\n this.recording.appendCommand(cmd);\r\n (document.getElementById('assert-selector') as HTMLInputElement).value = '';\r\n (document.getElementById('assert-value') as HTMLInputElement).value = '';\r\n });\r\n },\r\n willClose: () => {\r\n this.isCommandsDialogOpen = false;\r\n this._previsualizerRef = null;\r\n },\r\n });\r\n this.resizePopup();\r\n });\r\n }\r\n\r\n showSavedTestsDialog(): void {\r\n this.toggleModal('isSavedTestsDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVED_TESTS'),\r\n html: '<div id=\"saved-tests-modal-content\" style=\"min-height:250px;padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n width: 680,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('saved-tests-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('test-editor') as unknown as TestEditorEl;\r\n child.persistence = this.persistence;\r\n child.translation = this.translation;\r\n container.appendChild(child as unknown as Node);\r\n },\r\n willClose: () => { this.isSavedTestsDialogOpen = false; },\r\n });\r\n this.resizePopup();\r\n });\r\n }\r\n\r\n showSaveTestDialog(): void {\r\n this.toggleModal('isSaveTestDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVE'),\r\n html: '<div id=\"save-test-modal-content\" style=\"padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('save-test-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('save-test') as unknown as SaveTestEl;\r\n child.translation = this.translation;\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('savetest', (e: CustomEvent) => {\r\n const { description, notes, tags } = e.detail ?? {};\r\n this.onSaveTest(description ?? null, tags ?? [], notes ?? '');\r\n Swal.close();\r\n });\r\n child.addEventListener('saveandexport', (e: CustomEvent) => {\r\n const { description, notes, tags } = e.detail ?? {};\r\n this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? '');\r\n Swal.close();\r\n });\r\n },\r\n willClose: () => { this.isSaveTestDialogOpen = false; },\r\n });\r\n });\r\n }\r\n\r\n showSettingsDialog(): void {\r\n this.toggleModal('isSettingsDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.SETTINGS'),\r\n html: '<div id=\"settings-modal-content\" style=\"padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n width: 520,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('settings-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('e2e-configuration') as unknown as ConfigEl;\r\n child.persistence = this.persistence;\r\n child.translation = this.translation;\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('smartselectorchange', (e: CustomEvent) => {\r\n this.smartSelectorEnabled = e.detail;\r\n });\r\n child.addEventListener('starthiddenchange', (e: CustomEvent) => {\r\n this.isVisible = !e.detail;\r\n this.style.display = this.isVisible ? '' : 'none';\r\n });\r\n child.addEventListener('resetwidgetposition', () => this.resetWidgetPosition());\r\n },\r\n willClose: () => { this.isSettingsDialogOpen = false; },\r\n });\r\n this.resizePopup();\r\n });\r\n }\r\n\r\n showAdvancedEditorDialog(testId?: number): void {\r\n this.toggleModal('isAdvancedEditorDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.SHOW_ADVANCED_EDITOR'),\r\n html: '<div id=\"advanced-editor-modal-content\" style=\"flex:1;min-height:0;display:flex;flex-direction:column;padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n width: 780,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const popup = Swal.getPopup();\r\n if (popup) {\r\n popup.style.height = '600px';\r\n const htmlContainer = popup.querySelector('.swal2-html-container') as HTMLElement | null;\r\n if (htmlContainer) {\r\n htmlContainer.style.flex = '1';\r\n htmlContainer.style.minHeight = '0';\r\n htmlContainer.style.overflow = 'hidden';\r\n htmlContainer.style.padding = '0';\r\n htmlContainer.style.margin = '0';\r\n htmlContainer.style.display = 'flex';\r\n htmlContainer.style.flexDirection = 'column';\r\n }\r\n }\r\n const container = document.getElementById('advanced-editor-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('advanced-test-editor') as unknown as AdvancedEditorEl;\r\n child.persistence = this.persistence;\r\n child.translation = this.translation;\r\n if (testId !== undefined) child.testId = testId;\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('selectorstrategychange', (e: CustomEvent) => {\r\n this.recording.selectorStrategy = e.detail;\r\n });\r\n child.addEventListener('closemodal', () => Swal.close());\r\n child.addEventListener('openfileeditor', (e: CustomEvent) => {\r\n Swal.close();\r\n setTimeout(() => this.showFileEditorDialog(\r\n e.detail.handle, e.detail.content, e.detail.fileName, e.detail.testId,\r\n e.detail.itBlock, e.detail.interceptorsBlock, e.detail.notes,\r\n ), 150);\r\n });\r\n },\r\n willClose: () => { this.isAdvancedEditorDialogOpen = false; },\r\n });\r\n setTimeout(() => {\r\n const popup = Swal.getPopup();\r\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 0 });\r\n }, 0);\r\n });\r\n }\r\n\r\n private showFileEditorDialog(\r\n handle: FileSystemFileHandle,\r\n content: string,\r\n fileName: string,\r\n testId?: number,\r\n itBlock = '',\r\n interceptorsBlock = '',\r\n notes = '',\r\n ): void {\r\n Swal.fire({\r\n title: this.translation.translate('RECORDER.FILE_EDITOR_TITLE'),\r\n html: '<div id=\"file-editor-modal-content\" style=\"padding:0;height:540px\"></div>',\r\n showCloseButton: false,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n width: 1100,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('file-editor-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('file-preview') as unknown as FilePreviewEl;\r\n child.translation = this.translation;\r\n child.fileContent = content;\r\n child.fileName = fileName;\r\n child.closeLabel = this.translation.translate('FILE_PREVIEW.BACK_TO_EDITOR');\r\n child.itBlock = itBlock;\r\n child.interceptorsBlock = interceptorsBlock;\r\n child.notes = notes;\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('close', () => {\r\n Swal.close();\r\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\r\n });\r\n child.addEventListener('save', async (e: CustomEvent) => {\r\n try {\r\n const writable = await handle.createWritable();\r\n await writable.write(e.detail);\r\n await writable.close();\r\n showToast(this.translation.translate('RECORDER.FILE_SAVED_TOAST'));\r\n } catch {\r\n showToast(this.translation.translate('RECORDER.FILE_SAVE_ERROR_TOAST'), false);\r\n }\r\n Swal.close();\r\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\r\n });\r\n },\r\n });\r\n this.resizePopup();\r\n }\r\n\r\n // ── save handlers ─────────────────────────────────────────────────────────\r\n\r\n private async onSaveTest(description: string | null, tags: string[] = [], notes = ''): Promise<void> {\r\n if (description) {\r\n await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes);\r\n this.recording.clearCommands();\r\n this.clearRecordingHistory();\r\n this.cypressCommands = [];\r\n this.interceptors = [];\r\n }\r\n }\r\n\r\n private async onSaveAndExportTest(description: string | null, tags: string[] = [], notes = ''): Promise<void> {\r\n if (description) {\r\n const id = await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes);\r\n this.recording.clearCommands();\r\n this.clearRecordingHistory();\r\n this.cypressCommands = [];\r\n this.interceptors = [];\r\n setTimeout(() => this.showAdvancedEditorDialog(id), 300);\r\n }\r\n }\r\n\r\n // ── helpers ───────────────────────────────────────────────────────────────\r\n\r\n private toggleModal(flag: keyof this, openFn: () => void): void {\r\n if (this[flag]) {\r\n Swal.close();\r\n (this as Record<string, unknown>)[flag as string] = false;\r\n return;\r\n }\r\n (this as Record<string, unknown>)[flag as string] = true;\r\n openFn();\r\n }\r\n\r\n private resizePopup(): void {\r\n setTimeout(() => {\r\n const popup = Swal.getPopup();\r\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 200 });\r\n }, 0);\r\n }\r\n\r\n private render(): void {\r\n const rec = this.isRecording;\r\n const paused = this.isPaused;\r\n this.style.display = this.isVisible ? '' : 'none';\r\n this.shadow.innerHTML = `<style>${getRecorderStyles(rec, paused)}</style>${renderRecorderWidget(rec, paused, this.translation.translate.bind(this.translation))}`;\r\n const toggleBtn = this.shadow.querySelector('[data-action=\"toggle\"]');\r\n toggleBtn?.addEventListener('click', () => {\r\n // A drag ends with a click event we must swallow so it doesn't toggle recording.\r\n if (this.suppressNextToggleClick) { this.suppressNextToggleClick = false; return; }\r\n this.toggle();\r\n });\r\n toggleBtn?.addEventListener('pointerdown', (e) => this.beginWidgetDrag(e as MouseEvent));\r\n this.shadow.querySelector('[data-action=\"pause\"]')\r\n ?.addEventListener('click', () => this.togglePause());\r\n this.shadow.querySelector('[data-action=\"tests\"]')\r\n ?.addEventListener('click', () => this.showSavedTestsDialog());\r\n this.shadow.querySelector('[data-action=\"commands\"]')\r\n ?.addEventListener('click', () => this.showCommandsDialog());\r\n this.shadow.querySelector('[data-action=\"config\"]')\r\n ?.addEventListener('click', () => this.showSettingsDialog());\r\n this.shadow.querySelector('[data-action=\"browse\"]')\r\n ?.addEventListener('click', () => this.showAdvancedEditorDialog());\r\n // Re-apply the dragged position/orientation after every re-render.\r\n this.applyWidgetPosition();\r\n }\r\n}\r\n\r\nif (!customElements.get('lib-e2e-recorder')) {\r\n customElements.define('lib-e2e-recorder', LibE2eRecorderElement);\r\n}\r\n","import type { ExpandDirection } from '../../utils/widget-position.utils';\r\n\r\nconst DIRECTIONS: ExpandDirection[] = ['up-left', 'up-right', 'down-left', 'down-right'];\r\n\r\n/**\r\n * Per-direction anchors + label placement. The toggle sits at the box corner\r\n * nearest the screen edge so the radial arc always expands toward the viewport\r\n * interior (spec 007). --sx/--sy drive the arc transforms; the actual widget\r\n * position (left/top) is set imperatively from JS.\r\n */\r\nfunction directionBlocks(): string {\r\n return DIRECTIONS.map((dir) => {\r\n const sx = dir.endsWith('left') ? -1 : 1;\r\n const sy = dir.startsWith('up') ? -1 : 1;\r\n const tv = dir.startsWith('up') ? 'bottom' : 'top'; // toggle vertical side\r\n const th = dir.endsWith('left') ? 'right' : 'left'; // toggle horizontal side\r\n const ov = tv === 'bottom' ? 'top' : 'bottom'; // interior vertical side\r\n const oh = th === 'right' ? 'left' : 'right'; // interior (arc) horizontal side\r\n const sel = `.widget[data-expand=\"${dir}\"]`;\r\n\r\n // Diagonal labels (n2/n3) sit on the arc's horizontal side; vertical-extreme\r\n // (n1) and horizontal-extreme (n4) labels sit on the interior vertical side.\r\n const labelGeneral = `${sel} .btn-action::after { ${oh}: calc(100% + 9px); ${th}: auto; top: 50%; bottom: auto; transform: translateY(-50%); }`;\r\n const labelEnds = `${sel} .btn-action[data-n=\"1\"]::after, ${sel} .btn-action[data-n=\"4\"]::after { ${ov}: calc(100% + 9px); ${tv}: auto; left: 50%; right: auto; transform: translateX(-50%); }`;\r\n\r\n return `\r\n ${sel} { --sx: ${sx}; --sy: ${sy}; }\r\n ${sel} .btn-toggle { ${tv}: 24px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\r\n ${sel} .btn-pause { ${tv}: 78px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\r\n ${sel} .btn-action { ${tv}: 28px; ${th}: 28px; ${ov}: auto; ${oh}: auto; }\r\n ${labelGeneral}\r\n ${labelEnds}\r\n `;\r\n }).join('\\n');\r\n}\r\n\r\nexport function getRecorderStyles(rec: boolean, paused: boolean): string {\r\n return `\r\n :host { all: initial; }\r\n *, *::before, *::after { box-sizing: border-box; }\r\n\r\n /*\r\n * Invisible 190×190 hit area. Position (left/top) is set from JS so the\r\n * widget can be dragged; --sx/--sy + data-expand orient the radial menu so\r\n * it always expands toward the viewport interior. Defaults to bottom-right.\r\n */\r\n .widget {\r\n position: fixed;\r\n bottom: 0;\r\n right: 0;\r\n width: 190px;\r\n height: 190px;\r\n z-index: 2147483647;\r\n --sx: -1;\r\n --sy: -1;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\r\n }\r\n\r\n /* ── Toggle ──────────────────────────────────────── */\r\n .btn-toggle {\r\n position: absolute;\r\n bottom: 24px;\r\n right: 24px;\r\n width: 44px;\r\n height: 44px;\r\n border-radius: 50%;\r\n border: none;\r\n cursor: grab;\r\n touch-action: none;\r\n font-size: 19px;\r\n background: ${rec\r\n ? 'linear-gradient(135deg,#f85149 0%,#da3633 100%)'\r\n : 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'};\r\n color: #fff;\r\n box-shadow: ${rec\r\n ? '0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13)'\r\n : '0 4px 20px rgba(47,129,247,.45),0 0 0 4px rgba(47,129,247,.11)'};\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transition: transform .18s, box-shadow .2s;\r\n z-index: 2;\r\n ${rec ? 'animation: toggle-pulse 2s ease-in-out infinite;' : ''}\r\n }\r\n .btn-toggle:hover { transform: scale(1.1); }\r\n .btn-toggle:active { transform: scale(0.93); cursor: grabbing; }\r\n\r\n @keyframes toggle-pulse {\r\n 0%,100% { box-shadow: 0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13); }\r\n 50% { box-shadow: 0 6px 28px rgba(248,81,73,.75),0 0 0 8px rgba(248,81,73,.06); }\r\n }\r\n\r\n /* ── Pause button ────────────────────────────────── */\r\n .btn-pause {\r\n position: absolute;\r\n bottom: 78px;\r\n right: 24px;\r\n width: 34px;\r\n height: 34px;\r\n border-radius: 50%;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 15px;\r\n display: ${rec ? 'flex' : 'none'};\r\n align-items: center;\r\n justify-content: center;\r\n background: ${paused\r\n ? 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'\r\n : 'rgba(13,17,23,0.85)'};\r\n color: ${paused ? '#fff' : '#e3b341'};\r\n box-shadow: 0 2px 12px rgba(0,0,0,.4), 0 0 0 1px rgba(48,54,61,.8);\r\n transition: transform .15s, background .2s, color .2s;\r\n z-index: 2;\r\n }\r\n .btn-pause:hover { transform: scale(1.12); }\r\n .btn-pause:active { transform: scale(0.93); }\r\n\r\n /* ── Action buttons ──────────────────────────────── */\r\n .btn-action {\r\n position: absolute;\r\n bottom: 28px;\r\n right: 28px;\r\n width: 36px;\r\n height: 36px;\r\n border-radius: 50%;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 16px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: rgba(13,17,23,.92);\r\n backdrop-filter: blur(14px);\r\n -webkit-backdrop-filter: blur(14px);\r\n color: #8b949e;\r\n box-shadow: 0 4px 18px rgba(0,0,0,.45), 0 0 0 1px rgba(48,54,61,.75);\r\n opacity: 0;\r\n transform: scale(0.35);\r\n pointer-events: none;\r\n transition: opacity .15s, transform .18s ease-in,\r\n background .15s, color .12s, box-shadow .15s;\r\n }\r\n\r\n /* Label chip */\r\n .btn-action::after {\r\n content: attr(data-label);\r\n position: absolute;\r\n right: calc(100% + 9px);\r\n top: 50%;\r\n transform: translateY(-50%);\r\n background: rgba(13,17,23,.95);\r\n color: #e6edf3;\r\n font-size: 11px;\r\n font-weight: 500;\r\n padding: 3px 9px;\r\n border-radius: 6px;\r\n white-space: nowrap;\r\n pointer-events: none;\r\n opacity: 0;\r\n transition: opacity .15s .05s;\r\n border: 1px solid rgba(48,54,61,.8);\r\n box-shadow: 0 2px 8px rgba(0,0,0,.35);\r\n }\r\n .btn-action:hover::after { opacity: 1; }\r\n .btn-action:hover { background: #21262d; color: #e6edf3; }\r\n .btn-action:active { background: #30363d !important; }\r\n\r\n /* Expand: spring + stagger */\r\n .widget:hover .btn-action {\r\n opacity: 1;\r\n pointer-events: all;\r\n transition: opacity .2s, transform .32s cubic-bezier(.34,1.56,.64,1),\r\n background .15s, color .12s, box-shadow .15s;\r\n }\r\n\r\n /* Arc positions — signs come from --sx/--sy (data-expand) */\r\n .widget:hover .btn-action[data-n=\"1\"] { /* vertical extreme */\r\n transform: translateY(calc(var(--sy) * 90px)) scale(1);\r\n transition-delay: .03s;\r\n }\r\n .widget:hover .btn-action[data-n=\"2\"] { /* diagonal near-vertical */\r\n transform: translate(calc(var(--sx) * 45px), calc(var(--sy) * 78px)) scale(1);\r\n transition-delay: .07s;\r\n }\r\n .widget:hover .btn-action[data-n=\"3\"] { /* diagonal near-horizontal */\r\n transform: translate(calc(var(--sx) * 78px), calc(var(--sy) * 45px)) scale(1);\r\n transition-delay: .11s;\r\n }\r\n .widget:hover .btn-action[data-n=\"4\"] { /* horizontal extreme */\r\n transform: translateX(calc(var(--sx) * 90px)) scale(1);\r\n transition-delay: .15s;\r\n }\r\n\r\n /* Per-direction anchors + label sides */\r\n ${directionBlocks()}\r\n\r\n /* ── REC / PAUSED badge ──────────────────────────── */\r\n .rec-badge {\r\n position: fixed;\r\n top: 14px;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n background: ${paused\r\n ? 'linear-gradient(90deg,#e3b341,#d29922)'\r\n : 'linear-gradient(90deg,#f85149,#da3633)'};\r\n color: #fff;\r\n padding: 3px 16px;\r\n border-radius: 20px;\r\n font-size: 10px;\r\n font-weight: 700;\r\n letter-spacing: 2px;\r\n text-transform: uppercase;\r\n z-index: 2147483647;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\r\n box-shadow: ${paused\r\n ? '0 4px 16px rgba(227,179,65,.4)'\r\n : '0 4px 16px rgba(248,81,73,.4)'};\r\n display: ${rec ? 'block' : 'none'};\r\n ${!paused ? 'animation: rec-pulse 1.8s ease-in-out infinite;' : ''}\r\n }\r\n @keyframes rec-pulse {\r\n 0%,100% { opacity: 1; }\r\n 50% { opacity: 0.6; }\r\n }\r\n `;\r\n}\r\n","export function renderRecorderWidget(rec: boolean, paused: boolean, t: (key: string) => string): string {\n return `\n <div class=\"widget\">\n <button class=\"btn-action\" data-n=\"1\" data-action=\"config\"\n data-label=\"${t('RECORDER.BTN_CONFIG')}\">⚙️</button>\n <button class=\"btn-action\" data-n=\"2\" data-action=\"browse\"\n data-label=\"${t('RECORDER.BTN_FILES')}\">📁</button>\n <button class=\"btn-action\" data-n=\"3\" data-action=\"commands\"\n data-label=\"${t('RECORDER.BTN_COMMANDS')}\">⌨️</button>\n <button class=\"btn-action\" data-n=\"4\" data-action=\"tests\"\n data-label=\"${t('RECORDER.BTN_TESTS')}\">📋</button>\n <button class=\"btn-pause\" data-action=\"pause\"\n title=\"${paused ? t('RECORDER.RESUME_TITLE') : t('RECORDER.PAUSE_TITLE')}\">\n ${paused ? '▶' : '⏸'}\n </button>\n <button class=\"btn-toggle\" data-action=\"toggle\"\n title=\"${rec ? t('RECORDER.STOP_TITLE') : t('RECORDER.START_TITLE')}\">\n ${rec ? '⏹' : '⏺'}\n </button>\n </div>\n <div class=\"rec-badge\">${paused ? t('RECORDER.BADGE_PAUSED') : t('RECORDER.BADGE_REC')}</div>`;\n}\n"],"mappings":"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","names":["tag","container","rect","input","folderInput","i","j","Swal"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/selector-quality.utils.ts","../src/components/selector-picker/selector-picker.styles.ts","../src/utils/html.utils.ts","../src/components/selector-picker/selector-picker.template.ts","../src/components/selector-picker/selector-picker.ts","../src/index.ts","../src/models/lang.model.ts","../src/models/input-types.model.ts","../src/models/db-schema.model.ts","../src/models/active-session.model.ts","../src/models/issue-tracker.model.ts","../src/utils/subject.ts","../src/i18n/es.ts","../src/i18n/en.ts","../src/i18n/fr.ts","../src/i18n/it.ts","../src/i18n/de.ts","../src/services/translation.service.ts","../src/utils/code-format.utils.ts","../src/services/transformation.service.ts","../src/services/advanced-test.transformation.service.ts","../src/services/recording.service.ts","../src/utils/assertion.utils.ts","../src/services/persistence.service.ts","../src/utils/ticket.utils.ts","../src/services/http-monitor.ts","../src/utils/styles.utils.ts","../src/utils/modal.utils.ts","../src/utils/toast.utils.ts","../src/utils/export-selection.utils.ts","../src/utils/host.utils.ts","../src/utils/widget-position.utils.ts","../src/utils/cypress-completions.ts","../src/utils/code-editor.ts","../src/components/test-previsualizer/test-previsualizer.styles.ts","../src/components/test-previsualizer/test-previsualizer.template.ts","../src/components/test-previsualizer/test-previsualizer.ts","../src/components/save-test/save-test.styles.ts","../src/components/save-test/save-test.template.ts","../src/components/save-test/save-test.ts","../src/components/test-editor/test-editor.styles.ts","../src/components/test-editor/test-editor.template.ts","../src/utils/syntax-highlight.utils.ts","../src/components/test-editor/test-editor.ts","../src/components/configuration/configuration.styles.ts","../src/components/configuration/configuration.template.ts","../src/components/configuration/configuration.ts","../src/components/advanced-test-editor/advanced-test-editor.styles.ts","../src/components/advanced-test-editor/advanced-test-editor.template.ts","../src/components/advanced-test-editor/advanced-test-editor.ts","../src/components/file-preview/file-preview.styles.ts","../src/components/file-preview/file-preview.template.ts","../src/components/file-preview/file-preview.ts","../src/components/help-panel/help-panel.styles.ts","../src/components/help-panel/help-panel.template.ts","../src/components/help-panel/help-panel.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.styles.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.template.ts"],"sourcesContent":["export type SelectorQuality = 'excellent' | 'good' | 'acceptable' | 'poor';\n\nexport const FORBIDDEN_ID_PREFIXES = [\n 'cdk-', 'mat-', 'p-', 'ng-', 'mdc-',\n 'primeng-', 'auto-', 'field-', 'input-', 'select-',\n];\n\nexport function getSelectorQuality(el: HTMLElement): SelectorQuality {\n if (\n el.hasAttribute('data-cy') ||\n el.hasAttribute('data-testid') ||\n el.hasAttribute('aria-label')\n ) {\n return 'excellent';\n }\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return 'good';\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n return 'acceptable';\n }\n\n return 'poor';\n}\n\n/** Returns the best cy.get() selector string for a given element. */\nexport function buildPickerSelector(el: HTMLElement): string {\n const dataCy = el.getAttribute('data-cy');\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\n\n const dataTestid = el.getAttribute('data-testid');\n if (dataTestid) return `[data-testid=\"${dataTestid}\"]`;\n\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return `[aria-label=\"${ariaLabel}\"]`;\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return `#${rawId}`;\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n const classes = el.className.trim().split(/\\s+/);\n return classes.map((c) => `.${c}`).join('');\n }\n\n return el.tagName.toLowerCase();\n}\n\n/** Human-readable key attribute/selector preview for a picker row (raw, unescaped). */\nexport function keyAttrDisplay(el: HTMLElement): string {\n for (const attr of ['data-cy', 'data-testid', 'aria-label']) {\n const v = el.getAttribute(attr);\n if (v) return `${attr}=\"${v}\"`;\n }\n if (el.id) return `id=\"${el.id}\"`;\n if (el.className && el.className.trim()) {\n return el.className.trim().split(/\\s+/).map((c) => `.${c}`).join('');\n }\n return '';\n}\n\n/** Plain, serializable view-model for one picker row — no DOM held. */\nexport interface PickerRow {\n quality: SelectorQuality;\n selector: string;\n tag: string;\n attr: string;\n}\n\n/** Reads an element once and returns the plain data a picker row needs to render. */\nexport function describePickerRow(el: HTMLElement): PickerRow {\n return {\n quality: getSelectorQuality(el),\n selector: buildPickerSelector(el),\n tag: el.tagName.toLowerCase(),\n attr: keyAttrDisplay(el),\n };\n}\n","export const SELECTOR_PICKER_STYLES = `\r\n :host {\r\n position: fixed;\r\n z-index: 2147483647;\r\n top: 0;\r\n left: 0;\r\n width: 100vw;\r\n height: 100vh;\r\n pointer-events: none;\r\n }\r\n\r\n .overlay {\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n pointer-events: all;\r\n background: #161b22;\r\n border: 1px solid #30363d;\r\n border-radius: 10px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\r\n min-width: 420px;\r\n max-width: 600px;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n color: #e6edf3;\r\n font-size: 13px;\r\n }\r\n\r\n .header {\r\n padding: 12px 16px 8px;\r\n border-bottom: 1px solid #21262d;\r\n font-weight: 600;\r\n font-size: 13px;\r\n color: #8b949e;\r\n letter-spacing: 0.04em;\r\n text-transform: uppercase;\r\n }\r\n\r\n .list {\r\n max-height: 320px;\r\n overflow-y: auto;\r\n padding: 6px 0;\r\n }\r\n\r\n .row {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 7px 14px;\r\n cursor: pointer;\r\n border-radius: 6px;\r\n margin: 1px 6px;\r\n transition: background 0.1s;\r\n }\r\n\r\n .row:hover,\r\n .row.selected {\r\n background: #21262d;\r\n }\r\n\r\n .row.selected {\r\n outline: 2px solid #388bfd;\r\n outline-offset: -2px;\r\n }\r\n\r\n .quality-badge {\r\n width: 18px;\r\n height: 18px;\r\n border-radius: 50%;\r\n flex-shrink: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 10px;\r\n }\r\n\r\n .badge-excellent { background: #238636; }\r\n .badge-good { background: #1f6feb; }\r\n .badge-acceptable{ background: #9e6a03; }\r\n .badge-poor { background: #da3633; }\r\n\r\n .tag-name {\r\n font-family: monospace;\r\n font-size: 12px;\r\n color: #8b949e;\r\n flex-shrink: 0;\r\n }\r\n\r\n .attr-value {\r\n font-family: monospace;\r\n font-size: 12px;\r\n color: #c9d1d9;\r\n flex: 1;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n .selector-preview {\r\n font-family: monospace;\r\n font-size: 11px;\r\n color: #58a6ff;\r\n flex-shrink: 0;\r\n max-width: 180px;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n .poor-warning {\r\n font-size: 10px;\r\n color: #f85149;\r\n margin-left: auto;\r\n }\r\n\r\n .footer {\r\n padding: 8px 14px 10px;\r\n border-top: 1px solid #21262d;\r\n display: flex;\r\n gap: 16px;\r\n font-size: 11px;\r\n color: #484f58;\r\n }\r\n\r\n .hint kbd {\r\n background: #21262d;\r\n border: 1px solid #30363d;\r\n border-radius: 3px;\r\n padding: 1px 5px;\r\n font-size: 10px;\r\n color: #8b949e;\r\n }\r\n`;\r\n","export function escHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\nexport function escAttr(s: string): string {\n return s.replace(/\"/g, '"').replace(/</g, '<');\n}\n","import type { PickerRow, SelectorQuality } from '../../utils/selector-quality.utils';\r\nimport { escHtml } from '../../utils/html.utils';\r\n\r\nconst QUALITY_EMOJI: Record<SelectorQuality, string> = {\r\n excellent: '🟢',\r\n good: '🔵',\r\n acceptable: '🟡',\r\n poor: '🔴',\r\n};\r\n\r\nconst QUALITY_CLASS: Record<SelectorQuality, string> = {\r\n excellent: 'badge-excellent',\r\n good: 'badge-good',\r\n acceptable: 'badge-acceptable',\r\n poor: 'badge-poor',\r\n};\r\n\r\nexport function renderPickerRows(\r\n rows: PickerRow[],\r\n selectedIndex: number,\r\n t: (key: string) => string,\r\n): string {\r\n return rows.map((row, i) => {\r\n const isSelected = i === selectedIndex;\r\n const isPoor = row.quality === 'poor';\r\n\r\n return `\r\n <div class=\"row${isSelected ? ' selected' : ''}\" data-idx=\"${i}\" role=\"option\" aria-selected=\"${isSelected}\">\r\n <span class=\"quality-badge ${QUALITY_CLASS[row.quality]}\" title=\"${escHtml(t(`SELECTOR_PICKER.QUALITY_${row.quality.toUpperCase()}`))}\">\r\n ${QUALITY_EMOJI[row.quality]}\r\n </span>\r\n <span class=\"tag-name\"><${escHtml(row.tag)}></span>\r\n ${row.attr ? `<span class=\"attr-value\">${escHtml(row.attr)}</span>` : '<span class=\"attr-value\"></span>'}\r\n <span class=\"selector-preview\">${escHtml(row.selector)}</span>\r\n ${isPoor ? `<span class=\"poor-warning\" title=\"${escHtml(t('SELECTOR_PICKER.QUALITY_POOR'))}\">⚠</span>` : ''}\r\n </div>`;\r\n }).join('');\r\n}\r\n\r\nexport function renderPicker(\r\n rows: PickerRow[],\r\n selectedIndex: number,\r\n t: (key: string) => string,\r\n): string {\r\n return `\r\n <div class=\"overlay\" role=\"listbox\">\r\n <div class=\"header\">${escHtml(t('SELECTOR_PICKER.TITLE'))}</div>\r\n <div class=\"list\">\r\n ${renderPickerRows(rows, selectedIndex, t)}\r\n </div>\r\n <div class=\"footer\">\r\n <span class=\"hint\"><kbd>↑↓</kbd> ${escHtml(t('SELECTOR_PICKER.PREVIEW_LABEL'))}</span>\r\n <span class=\"hint\"><kbd>Enter</kbd> ${escHtml(t('SELECTOR_PICKER.CONFIRM_HINT'))}</span>\r\n <span class=\"hint\"><kbd>Esc</kbd> ${escHtml(t('SELECTOR_PICKER.CANCEL_HINT'))}</span>\r\n </div>\r\n </div>`;\r\n}\r\n","import type { RecordingService } from '../../services/recording.service';\r\nimport type { TranslationService } from '../../services/translation.service';\r\nimport { describePickerRow, type PickerRow } from '../../utils/selector-quality.utils';\r\nimport { SELECTOR_PICKER_STYLES } from './selector-picker.styles';\r\nimport { renderPicker } from './selector-picker.template';\r\n\r\nconst OWN_DATA_CY = 'lib-e2e-cypress-for-dummys';\r\nconst MAX_ANCESTORS = 10;\r\n\r\nexport class SelectorPickerElement extends HTMLElement {\r\n targetElement: HTMLElement | null = null;\r\n recording!: RecordingService;\r\n translation!: TranslationService;\r\n\r\n private shadow: ShadowRoot;\r\n private ancestors: HTMLElement[] = [];\r\n private rows: PickerRow[] = [];\r\n private selectedIndex = 0;\r\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\r\n private unsubRecording: (() => void) | null = null;\r\n private unsubPause: (() => void) | null = null;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\r\n this.ancestors = this.buildAncestors();\r\n this.rows = this.ancestors.map(describePickerRow);\r\n this.selectedIndex = this.findBestIndex();\r\n this.render();\r\n this.attachKeyListener();\r\n this.attachRowClickListeners();\r\n this.subscribeToRecordingChanges();\r\n }\r\n\r\n disconnectedCallback(): void {\r\n this.detachKeyListener();\r\n this.unsubRecording?.();\r\n this.unsubPause?.();\r\n }\r\n\r\n private t(key: string): string {\r\n return this.translation?.translate(key) ?? key;\r\n }\r\n\r\n // ── Ancestor chain ──────────────────────────────────────────────────────────\r\n\r\n private buildAncestors(): HTMLElement[] {\r\n const chain: HTMLElement[] = [];\r\n let current: HTMLElement | null = this.targetElement;\r\n\r\n while (current && current.tagName.toLowerCase() !== 'html' && chain.length < MAX_ANCESTORS) {\r\n if (current.getAttribute('data-cy') === OWN_DATA_CY) {\r\n current = current.parentElement;\r\n continue;\r\n }\r\n chain.push(current);\r\n current = current.parentElement;\r\n }\r\n\r\n return chain;\r\n }\r\n\r\n private findBestIndex(): number {\r\n for (let i = 0; i < this.rows.length; i++) {\r\n const q = this.rows[i].quality;\r\n if (q === 'excellent' || q === 'good' || q === 'acceptable') return i;\r\n }\r\n return 0;\r\n }\r\n\r\n // ── Rendering ───────────────────────────────────────────────────────────────\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${SELECTOR_PICKER_STYLES}</style>${renderPicker(\r\n this.rows,\r\n this.selectedIndex,\r\n this.t.bind(this),\r\n )}`;\r\n }\r\n\r\n // ── Keyboard ────────────────────────────────────────────────────────────────\r\n\r\n private attachKeyListener(): void {\r\n this.keyHandler = (e: KeyboardEvent) => {\r\n if (e.key === 'ArrowDown') {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n this.selectedIndex = (this.selectedIndex + 1) % this.ancestors.length;\r\n this.render();\r\n this.attachRowClickListeners();\r\n } else if (e.key === 'ArrowUp') {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n this.selectedIndex = (this.selectedIndex - 1 + this.ancestors.length) % this.ancestors.length;\r\n this.render();\r\n this.attachRowClickListeners();\r\n } else if (e.key === 'Enter') {\r\n e.stopPropagation();\r\n this.confirm(this.selectedIndex);\r\n } else if (e.key === 'Escape') {\r\n e.stopPropagation();\r\n this.cancel();\r\n }\r\n };\r\n window.addEventListener('keydown', this.keyHandler, { capture: true });\r\n }\r\n\r\n private detachKeyListener(): void {\r\n if (this.keyHandler) {\r\n window.removeEventListener('keydown', this.keyHandler, { capture: true });\r\n this.keyHandler = null;\r\n }\r\n }\r\n\r\n // ── Row click listeners ─────────────────────────────────────────────────────\r\n\r\n private attachRowClickListeners(): void {\r\n this.shadow.querySelectorAll('[data-idx]').forEach((row) => {\r\n (row as HTMLElement).addEventListener('click', () => {\r\n const idx = parseInt((row as HTMLElement).dataset['idx'] ?? '0', 10);\r\n this.confirm(idx);\r\n });\r\n });\r\n }\r\n\r\n // ── Recording auto-close ────────────────────────────────────────────────────\r\n\r\n private subscribeToRecordingChanges(): void {\r\n this.unsubRecording = this.recording.onRecordingChange((isRecording) => {\r\n if (!isRecording) this.closeSilently();\r\n });\r\n this.unsubPause = this.recording.onPauseChange((isPaused) => {\r\n if (isPaused) this.closeSilently();\r\n });\r\n }\r\n\r\n // ── Actions ─────────────────────────────────────────────────────────────────\r\n\r\n private confirm(index: number): void {\r\n const row = this.rows[index];\r\n if (!row) return;\r\n const command = `cy.get('${row.selector}').click()`;\r\n this.recording.appendCommand(command);\r\n this.dispatchEvent(new CustomEvent('selectorchosen', { detail: command, bubbles: true, composed: true }));\r\n this.closeSilently();\r\n }\r\n\r\n private cancel(): void {\r\n this.dispatchEvent(new CustomEvent('pickercancelled', { bubbles: true, composed: true }));\r\n this.closeSilently();\r\n }\r\n\r\n private closeSilently(): void {\r\n this.detachKeyListener();\r\n this.unsubRecording?.();\r\n this.unsubPause?.();\r\n this.unsubRecording = null;\r\n this.unsubPause = null;\r\n this.remove();\r\n }\r\n}\r\n\r\nif (!customElements.get('selector-picker')) {\r\n customElements.define('selector-picker', SelectorPickerElement);\r\n}\r\n","// Public API — populated as migration phases are completed\r\n// Keep in sync with package.json \"version\" (asserted in specs/public-api.spec.ts).\r\nexport const VERSION = '0.8.0';\r\n\r\n// Phase 1 — Models\r\nexport * from './models/lang.model';\r\nexport * from './models/input-types.model';\r\nexport * from './models/db-schema.model';\r\nexport * from './models/active-session.model';\r\nexport * from './models/issue-tracker.model';\r\n\r\n// Phase 2 — TranslationService\r\nexport * from './services/translation.service';\r\n\r\n// Phase 3 — Transformation Services\r\nexport * from './services/transformation.service';\r\nexport * from './services/advanced-test.transformation.service';\r\n\r\n// Phase 4 — RecordingService\r\nexport * from './utils/subject';\r\nexport * from './services/recording.service';\r\n\r\n// Phase 5 — PersistenceService\r\nexport * from './services/persistence.service';\r\n\r\n// Phase 6 — HttpMonitor\r\nexport * from './services/http-monitor';\r\n\r\n// Phase 7 — UI Utilities\r\nexport * from './utils/styles.utils';\r\nexport * from './utils/modal.utils';\r\nexport * from './utils/toast.utils';\r\nexport * from './utils/export-selection.utils';\r\nexport * from './utils/host.utils';\r\nexport * from './utils/widget-position.utils';\r\nexport * from './utils/assertion.utils';\r\nexport * from './utils/ticket.utils';\r\nexport * from './utils/cypress-completions';\r\nexport * from './utils/code-editor';\r\n\r\n// Phase 8 — Web Components\r\nexport * from './components/selector-picker/selector-picker';\r\nexport * from './components/test-previsualizer/test-previsualizer';\r\nexport * from './components/save-test/save-test';\r\nexport * from './components/test-editor/test-editor';\r\nexport * from './components/configuration/configuration';\r\nexport * from './components/advanced-test-editor/advanced-test-editor';\r\nexport * from './components/file-preview/file-preview';\r\nexport * from './components/help-panel/help-panel';\r\nexport * from './components/lib-e2e-recorder/lib-e2e-recorder';\r\n","export type Lang = 'es' | 'en' | 'fr' | 'it' | 'de';\r\n\r\nexport const SUPPORTED_LANGS: Lang[] = ['es', 'en', 'fr', 'it', 'de'];\r\n\r\nexport function isLang(value: string): value is Lang {\r\n return SUPPORTED_LANGS.includes(value as Lang);\r\n}\r\n\r\n/** BCP-47 locale used for date/number formatting per UI language. */\r\nexport const LOCALE_BY_LANG: Record<Lang, string> = {\r\n es: 'es-ES',\r\n en: 'en-GB',\r\n fr: 'fr-FR',\r\n it: 'it-IT',\r\n de: 'de-DE',\r\n};\r\n\r\n/** Returns the formatting locale for a UI language (falls back to es-ES). */\r\nexport function localeForLang(lang: string): string {\r\n return isLang(lang) ? LOCALE_BY_LANG[lang] : 'es-ES';\r\n}\r\n","export const INPUT_TYPES = [\r\n 'text',\r\n 'password',\r\n 'email',\r\n 'search',\r\n 'tel',\r\n 'url',\r\n 'number',\r\n 'textarea',\r\n] as const;\r\n\r\nexport type InputType = (typeof INPUT_TYPES)[number];\r\n","export interface DBStoreIndex {\r\n name: string;\r\n keyPath: string;\r\n unique: boolean;\r\n}\r\n\r\nexport interface DBStore {\r\n name: string;\r\n keyPath: string;\r\n autoIncrement: boolean;\r\n indexes: DBStoreIndex[];\r\n}\r\n\r\nexport interface DBSchema {\r\n name: string;\r\n version: number;\r\n stores: DBStore[];\r\n}\r\n\r\nexport const DB_SCHEMA: DBSchema = {\r\n name: 'E2ECypressDB',\r\n version: 11,\r\n stores: [\r\n {\r\n name: 'tests',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'name', keyPath: 'name', unique: false },\r\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\r\n ],\r\n },\r\n {\r\n name: 'commands',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'command', keyPath: 'command', unique: false },\r\n { name: 'testId', keyPath: 'testId', unique: false },\r\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\r\n ],\r\n },\r\n {\r\n name: 'interceptors',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'interceptor', keyPath: 'interceptor', unique: false },\r\n { name: 'testId', keyPath: 'testId', unique: false },\r\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\r\n ],\r\n },\r\n {\r\n name: 'configuration',\r\n keyPath: 'id',\r\n autoIncrement: true,\r\n indexes: [\r\n { name: 'language', keyPath: 'language', unique: false },\r\n { name: 'extendedHttpCommands', keyPath: 'extendedHttpCommands', unique: false },\r\n { name: 'allowReadWriteFiles', keyPath: 'allowReadWriteFiles', unique: false },\r\n ],\r\n },\r\n {\r\n // Single-record store (fixed key id=1) holding the live, in-progress\r\n // recording session so it survives a micro-frontend crossing or reload.\r\n // See docs/specs/006-cross-app-recording-continuity.md.\r\n name: 'activeSession',\r\n keyPath: 'id',\r\n autoIncrement: false,\r\n indexes: [],\r\n },\r\n ],\r\n};\r\n\r\nexport const DB_STORE_NAMES = DB_SCHEMA.stores.map(s => s.name) as [\r\n 'tests',\r\n 'commands',\r\n 'interceptors',\r\n 'configuration',\r\n 'activeSession',\r\n];\r\n","import type { SelectorStrategy } from '../services/recording.service';\r\n\r\n/**\r\n * A live, in-progress recording session, persisted so it can survive a\r\n * micro-frontend crossing (single-spa app swap) or an accidental same-origin\r\n * reload. Only an actively-recording session is ever stored/resumed.\r\n *\r\n * The full payload lives in IndexedDB; a lightweight breadcrumb (sessionId +\r\n * isRecording + updatedAt) is mirrored to localStorage for synchronous detection.\r\n *\r\n * See docs/specs/006-cross-app-recording-continuity.md.\r\n */\r\nexport interface ActiveSessionState {\r\n /** Stable id for the session, generated when recording starts. */\r\n sessionId: string;\r\n isRecording: boolean;\r\n isPaused: boolean;\r\n commands: string[];\r\n interceptors: string[];\r\n selectorStrategy: SelectorStrategy;\r\n /** Epoch ms when the session started recording. */\r\n startedAt: number;\r\n /** Epoch ms of the last mutation — acts as the recency heartbeat. */\r\n updatedAt: number;\r\n}\r\n\r\n/** localStorage key for the synchronous \"is a session active?\" breadcrumb. */\r\nexport const ACTIVE_SESSION_BREADCRUMB_KEY = 'e2e-active-session';\r\n\r\n/** Configuration key (in the `configuration` store) for the resume recency TTL. */\r\nexport const RESUME_TTL_CONFIG_KEY = 'resumeRecencyTtlMinutes';\r\n\r\n/** Default minutes within which an active session resumes silently. */\r\nexport const DEFAULT_RESUME_TTL_MINUTES = 30;\r\n","/**\n * Issue-tracker presets for the *link-only* ticket reference (spec 014).\n *\n * These are static, data-driven descriptors — there is NO API call, no auth and\n * no synchronisation. A provider only knows how to turn a ticket id plus a few\n * user-supplied fields into a deep link. Adding a new tracker is a single entry\n * in {@link ISSUE_TRACKER_PROVIDERS}; no new code paths are required.\n */\n\n/** A single user-configured field a provider needs to build its links. */\nexport interface IssueTrackerField {\n /** Token used in {@link IssueTrackerProvider.urlTemplate}, e.g. `org`. */\n key: string;\n /** i18n key for the field's label in the configuration panel. */\n labelKey: string;\n /** i18n key for the field's input placeholder. */\n placeholderKey: string;\n}\n\n/** A link-only issue-tracker descriptor. */\nexport interface IssueTrackerProvider {\n /** Stable id persisted in configuration, e.g. `jira`. */\n id: string;\n /** Display name — a proper noun (Jira, GitHub…), not translated. */\n labelKey: string;\n /**\n * URL template with `{id}` plus one token per field. For `custom` the template\n * itself comes from a field (`{template}`), so a single substitution path serves\n * every provider.\n */\n urlTemplate: string;\n /** Structured fields the user fills in Settings for this provider. */\n fields: IssueTrackerField[];\n /** Regex source used for a soft (non-blocking) id-format warning. */\n idPattern: string;\n /** i18n key for the ticket-id input placeholder in the save dialog. */\n idPlaceholderKey: string;\n}\n\nexport const ISSUE_TRACKER_PROVIDERS: IssueTrackerProvider[] = [\n {\n id: 'jira',\n labelKey: 'CONFIG.ISSUE_TRACKER_PROVIDER_JIRA',\n urlTemplate: '{baseUrl}/browse/{id}',\n fields: [\n { key: 'baseUrl', labelKey: 'CONFIG.ISSUE_TRACKER_FIELD_BASEURL', placeholderKey: 'CONFIG.ISSUE_TRACKER_PH_JIRA_BASEURL' },\n ],\n idPattern: '^[A-Za-z][A-Za-z0-9_]+-\\\\d+$',\n idPlaceholderKey: 'SAVE_TEST.TICKET_PH_JIRA',\n },\n {\n id: 'azure-devops',\n labelKey: 'CONFIG.ISSUE_TRACKER_PROVIDER_AZURE',\n urlTemplate: 'https://dev.azure.com/{org}/{project}/_workitems/edit/{id}',\n fields: [\n { key: 'org', labelKey: 'CONFIG.ISSUE_TRACKER_FIELD_ORG', placeholderKey: 'CONFIG.ISSUE_TRACKER_PH_AZURE_ORG' },\n { key: 'project', labelKey: 'CONFIG.ISSUE_TRACKER_FIELD_PROJECT', placeholderKey: 'CONFIG.ISSUE_TRACKER_PH_AZURE_PROJECT' },\n ],\n idPattern: '^\\\\d+$',\n idPlaceholderKey: 'SAVE_TEST.TICKET_PH_AZURE',\n },\n {\n id: 'github',\n labelKey: 'CONFIG.ISSUE_TRACKER_PROVIDER_GITHUB',\n urlTemplate: 'https://github.com/{owner}/{repo}/issues/{id}',\n fields: [\n { key: 'owner', labelKey: 'CONFIG.ISSUE_TRACKER_FIELD_OWNER', placeholderKey: 'CONFIG.ISSUE_TRACKER_PH_GITHUB_OWNER' },\n { key: 'repo', labelKey: 'CONFIG.ISSUE_TRACKER_FIELD_REPO', placeholderKey: 'CONFIG.ISSUE_TRACKER_PH_GITHUB_REPO' },\n ],\n idPattern: '^\\\\d+$',\n idPlaceholderKey: 'SAVE_TEST.TICKET_PH_GITHUB',\n },\n {\n id: 'trello',\n labelKey: 'CONFIG.ISSUE_TRACKER_PROVIDER_TRELLO',\n urlTemplate: 'https://trello.com/c/{id}',\n fields: [],\n idPattern: '^[A-Za-z0-9]+$',\n idPlaceholderKey: 'SAVE_TEST.TICKET_PH_TRELLO',\n },\n {\n id: 'custom',\n labelKey: 'CONFIG.ISSUE_TRACKER_PROVIDER_CUSTOM',\n urlTemplate: '{template}',\n fields: [\n { key: 'template', labelKey: 'CONFIG.ISSUE_TRACKER_FIELD_TEMPLATE', placeholderKey: 'CONFIG.ISSUE_TRACKER_PH_CUSTOM_TEMPLATE' },\n ],\n idPattern: '.*',\n idPlaceholderKey: 'SAVE_TEST.TICKET_PH_CUSTOM',\n },\n];\n\n/** Feature is inert until configured: default to a custom, empty template. */\nexport const DEFAULT_ISSUE_TRACKER_PROVIDER_ID = 'custom';\n\n/** Looks up a provider by id, or `undefined` when unknown. */\nexport function findIssueTrackerProvider(id: string): IssueTrackerProvider | undefined {\n return ISSUE_TRACKER_PROVIDERS.find((p) => p.id === id);\n}\n","export class Subject<T> {\r\n private _value: T;\r\n private listeners = new Set<(v: T) => void>();\r\n\r\n constructor(initialValue: T) {\r\n this._value = initialValue;\r\n }\r\n\r\n next(value: T): void {\r\n this._value = value;\r\n this.listeners.forEach((l) => l(value));\r\n }\r\n\r\n getValue(): T {\r\n return this._value;\r\n }\r\n\r\n subscribe(fn: (v: T) => void): () => void {\r\n this.listeners.add(fn);\r\n return () => this.listeners.delete(fn);\r\n }\r\n}\r\n","export const I18N_ES = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Configuración',\r\n SHOW_ADVANCED_EDITOR: 'Editor avanzado',\r\n DIALOG_SAVED_TESTS: 'Pruebas guardadas',\r\n DIALOG_COMMANDS: 'Previsualizador de comandos Cypress',\r\n DIALOG_SAVE: '¿Guardar la grabación?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Descripción de la prueba',\r\n CANCEL: 'Cancelar',\r\n ASK: '¿Guardar el test grabado?',\r\n YES_CONTINUE: 'Sí, continuar',\r\n NO_DISCARD: 'No, descartar',\r\n DESC_PLACEHOLDER: 'Ej: Login correcto con credenciales válidas',\r\n TAGS_LABEL: 'Etiquetas (opcional, para filtrar después):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regresión…',\r\n ADD_TAG: '+ Añadir',\r\n NO_TAGS: 'Sin etiquetas',\r\n SAVE_BTN: '💾 Guardar',\r\n SAVE_AND_EDIT: '📝 Guardar y editar',\r\n REMOVE_TAG_TITLE: 'Quitar',\r\n NOTES_LABEL: 'Descripción / Notas (opcional):',\r\n NOTES_PLACEHOLDER: 'Qué valida este test, condiciones previas, etc.',\r\n TICKET_LABEL: 'Ticket (opcional):',\r\n TICKET_PH_JIRA: 'ej. PROJ-123',\r\n TICKET_PH_AZURE: 'ej. 1234',\r\n TICKET_PH_GITHUB: 'ej. 42',\r\n TICKET_PH_TRELLO: 'ej. aBc123',\r\n TICKET_PH_CUSTOM: 'id del ticket',\r\n TICKET_INVALID: 'El id del ticket no coincide con el formato esperado del gestor seleccionado.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Sin etiquetas',\r\n SELECTED_SINGULAR: 'seleccionado',\r\n SELECTED_PLURAL: 'seleccionados',\r\n DESCRIBE_PLACEHOLDER: 'Nombre del describe (opcional)',\r\n COPY_DESCRIBE: '🗂 Copiar describe()',\r\n MULTI_SELECT: '🗂 Multi-select',\r\n CANCEL_SELECT: '✕ Cancelar',\r\n COPY_CMDS_BTN: '📋 Copiar comandos',\r\n COPY_ICPS_BTN: '📋 Copiar interceptores',\r\n DEFAULT_DESCRIBE: 'Suite de tests',\r\n NO_TESTS: 'No hay tests guardados',\r\n DELETE_TITLE: 'Eliminar',\r\n GROUP_BY_TICKET: '🎫 Agrupar por ticket',\r\n NO_TICKET_GROUP: 'Sin ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Idioma',\r\n LANG_FIELD: 'Interfaz',\r\n HTTP_SECTION: '⚡ HTTP Avanzado',\r\n HTTP_TITLE: 'Validaciones de body',\r\n HTTP_SUB: 'GET → response · POST/PUT → request',\r\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\r\n FIXTURE_TITLE: 'Grabar respuestas como fixtures',\r\n FIXTURE_SUB: 'Las GET se guardan en cypress/fixtures y se stubean con cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Estrategia de selector',\r\n SELECTOR_LABEL: 'Atributo preferido para cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (por defecto)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#elemento)',\r\n SELECTOR_HINT: 'El grabador buscará este atributo primero. Si no existe, intentará los demás.',\r\n FOLDER_SECTION: '📁 Carpeta Cypress',\r\n FOLDER_CONNECTED: 'conectado —',\r\n FOLDER_NOT_SET: 'sin configurar',\r\n FOLDER_CHANGE_BTN: '📁 Cambiar carpeta',\r\n FOLDER_SELECT_BTN: '📁 Seleccionar carpeta',\r\n FOLDER_REVOKE_BTN: '✕ Quitar acceso',\r\n DATA_SECTION: '💾 Datos',\r\n DATA_DESC: 'Exporta todos tus tests a JSON o importa una copia de seguridad.',\r\n EXPORT_BTN: '⬆️ Exportar tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Exportar tests',\r\n EXPORT_MODE_ALL: 'Todo',\r\n EXPORT_MODE_MANUAL: 'Selección manual',\r\n EXPORT_MODE_TAGS: 'Por tags',\r\n EXPORT_ALL_DESC: 'Se exportarán todos los tests guardados.',\r\n EXPORT_COUNT: 'A exportar:',\r\n EXPORT_CONFIRM: '⬆️ Exportar',\r\n EXPORT_CANCEL: 'Cancelar',\r\n EXPORT_EMPTY: 'No hay tests para exportar.',\r\n EXPORT_NO_TAGS: 'No hay tags disponibles.',\r\n EXPORT_TAGS_HINT: 'Selecciona uno o más tags para ver qué pruebas se exportarán.',\r\n EXPORT_RESULT_LABEL: 'Pruebas que se exportarán:',\r\n IMPORT_BTN: '⬇️ Importar tests',\r\n FOLDER_UPDATED_TOAST: '✓ Carpeta de Cypress actualizada',\r\n FOLDER_ERROR_TOAST: 'Error al acceder a la carpeta',\r\n IMPORT_SUCCESS: 'Datos importados correctamente.',\r\n IMPORT_ERROR: 'Error al importar.',\r\n JSON_INVALID: 'El archivo no es un JSON válido.',\r\n JSON_BAD_FORMAT: 'El archivo no tiene el formato esperado.',\r\n SMART_SELECTOR_SECTION: '🔍 Selector inteligente',\r\n SMART_SELECTOR_TITLE: 'Selector inteligente',\r\n SMART_SELECTOR_SUB: 'Muestra un picker al hacer click en elementos sin selector válido.',\r\n START_HIDDEN_SECTION: '👁 Visibilidad del widget',\r\n START_HIDDEN_TITLE: 'Iniciar oculto',\r\n START_HIDDEN_SUB: 'El widget arranca invisible. Usa Ctrl+Shift+E para mostrarlo u ocultarlo.',\r\n RESUME_TTL_SECTION: '⏱ Continuidad de grabación',\r\n RESUME_TTL_LABEL: 'Reanudar sin preguntar (minutos)',\r\n RESUME_TTL_HINT: 'Si recargas o cambias de proyecto, una grabación activa se reanuda sin preguntar dentro de este margen. Pasado ese tiempo, te preguntará si continuar o descartar.',\r\n WIDGET_POSITION_SECTION: '🧲 Posición del widget',\r\n WIDGET_POSITION_HINT: 'Arrastra el botón de grabar para moverlo donde no estorbe. Se recuerda su posición.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Restablecer posición',\r\n WIDGET_POSITION_RESET_DONE: '✓ Posición restablecida',\r\n ISSUE_TRACKER_SECTION: '🎫 Gestor de incidencias',\r\n ISSUE_TRACKER_LABEL: 'Gestor (solo enlace, sin sincronización)',\r\n ISSUE_TRACKER_DISCLAIMER: 'Solo genera enlaces — nunca se conecta ni sincroniza con la plataforma.',\r\n ISSUE_TRACKER_PROVIDER_JIRA: 'Jira',\r\n ISSUE_TRACKER_PROVIDER_AZURE: 'Azure DevOps',\r\n ISSUE_TRACKER_PROVIDER_GITHUB: 'GitHub',\r\n ISSUE_TRACKER_PROVIDER_TRELLO: 'Trello',\r\n ISSUE_TRACKER_PROVIDER_CUSTOM: 'Personalizado',\r\n ISSUE_TRACKER_FIELD_BASEURL: 'URL base',\r\n ISSUE_TRACKER_FIELD_ORG: 'Organización',\r\n ISSUE_TRACKER_FIELD_PROJECT: 'Proyecto',\r\n ISSUE_TRACKER_FIELD_OWNER: 'Propietario',\r\n ISSUE_TRACKER_FIELD_REPO: 'Repositorio',\r\n ISSUE_TRACKER_FIELD_TEMPLATE: 'Plantilla de URL (debe contener {id})',\r\n ISSUE_TRACKER_PH_JIRA_BASEURL: 'https://tu-org.atlassian.net',\r\n ISSUE_TRACKER_PH_AZURE_ORG: 'organización',\r\n ISSUE_TRACKER_PH_AZURE_PROJECT: 'proyecto',\r\n ISSUE_TRACKER_PH_GITHUB_OWNER: 'propietario',\r\n ISSUE_TRACKER_PH_GITHUB_REPO: 'repositorio',\r\n ISSUE_TRACKER_PH_CUSTOM_TEMPLATE: 'https://tracker.example.com/{id}',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Selecciona un elemento del DOM',\r\n PREVIEW_LABEL: 'navegar',\r\n CONFIRM_HINT: 'confirmar',\r\n CANCEL_HINT: 'cancelar',\r\n QUALITY_EXCELLENT: 'Excelente — tiene atributo de prueba (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Bueno — tiene un id válido',\r\n QUALITY_ACCEPTABLE: 'Aceptable — solo tiene clases CSS',\r\n QUALITY_POOR: 'No recomendado — solo tag o estilo inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptores',\r\n COPY_CMDS_BTN: '📋 Copiar comandos',\r\n SHOW_INTERCEPTORS: '▼ Ver interceptores',\r\n HIDE_INTERCEPTORS: '▲ Ocultar interceptores',\r\n SECTION_COMMANDS: 'Comandos',\r\n NO_CMDS_YET: 'Sin comandos aún',\r\n NO_ICP_SHORT: 'Sin interceptores',\r\n COPY_ICP_BTN: '📋 Copiar interceptores',\r\n UP_TITLE: 'Subir',\r\n DOWN_TITLE: 'Bajar',\r\n DEL_TITLE: 'Eliminar',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Reactivar acceso',\r\n PERMISSION_EXPIRED: '🔑 El permiso ha caducado',\r\n PERMISSION_EXPIRED_HINT: 'Haz clic para reactivar el acceso a tu carpeta de Cypress.',\r\n NO_ACCESS: '🔒 Sin acceso a archivos locales',\r\n NO_ACCESS_HINT: 'Configura el acceso en ⚙️ Config.',\r\n NO_FILES: 'Sin archivos',\r\n SELECT_FILE: '← Selecciona un archivo del árbol',\r\n IT_LABEL: '🧪 it() a insertar:',\r\n COPY_IT_BTN: '📋 Copiar it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptores:',\r\n COPY_ICP_BTN: '📋 Copiar interceptores',\r\n INSERT_BTN: '💾 Insertar en archivo',\r\n EDIT_MANUAL_BTN: '✏️ Editar manualmente',\r\n CLOSE_BTN: '✕ Cerrar',\r\n NEW_FILE_BTN: '+ Nuevo archivo',\r\n NEW_FOLDER_BTN: '+ Nueva carpeta',\r\n REFRESH_BTN: '↻ Actualizar',\r\n NEW_FILE_PLACEHOLDER: 'nombre-del-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nombre-de-carpeta',\r\n NEW_FILE_CONFIRM: 'Crear',\r\n NEW_FILE_CANCEL: 'Cancelar',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Sin archivo',\r\n COPY_TITLE: 'Copiar contenido del editor',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copiar',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'Sin cambios respecto al original',\r\n NO_CHANGES_SHORT: 'Sin cambios',\r\n LAUNCH_BTN: '▶ Lanzar test',\r\n LAUNCH_LOCAL_ONLY: 'Muévelo a local para poder probar',\r\n LAUNCH_RUNNING: '⏳ Ejecutando…',\r\n LAUNCH_PASSED: '✓ Prueba superada',\r\n LAUNCH_FAILED: '✗ Prueba fallida',\r\n LAUNCH_NO_RUNNER: 'No se detectó el runner local (¿lo has arrancado?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Guardar',\r\n CLOSE_BTN: '✕ Cerrar',\r\n BACK_TO_EDITOR: '← Volver al editor',\r\n INSERT_BTN: '🪄 Insertar bloques',\r\n INSERT_TITLE: 'Insertar it() y beforeEach() en el contenido del editor',\r\n INSERT_DONE: 'Bloques insertados en el editor',\r\n INSERT_ERROR: 'No se encontró un bloque describe() válido en el archivo',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Acceso a ficheros',\r\n FS_LATER_BTN: 'Ahora no',\r\n FS_SELECT_BTN: '📁 Seleccionar carpeta',\r\n FS_SUCCESS_TOAST: '✓ Carpeta de Cypress configurada',\r\n FS_ERROR_TOAST: 'Error al acceder a la carpeta',\r\n FS_INTRO_HTML: 'El <strong style=\"color:#e6edf3\">editor avanzado</strong> puede insertar tus tests directamente en los archivos <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Selecciona la carpeta que contiene la subcarpeta <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. La extensión espera esta estructura:',\r\n FS_TREE_PICK_HINT: '← selecciona esta carpeta',\r\n FS_TREE_READ_HINT: '← la extensión leerá aquí',\r\n FS_PERMISSION_NOTE: 'El permiso se guarda en el navegador y no se vuelve a solicitar.',\r\n ASSERTION_SECTION: '➕ Añadir aserción',\r\n ASSERT_SELECTOR_PH: 'selector, ej: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valor esperado',\r\n ASSERT_ADD_BTN: '➕ Añadir',\r\n FILE_EDITOR_TITLE: '✏️ Editor de archivo',\r\n FILE_SAVED_TOAST: '✓ Archivo guardado',\r\n FILE_SAVE_ERROR_TOAST: 'Error al guardar el archivo',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures escritos en cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'No se pudieron escribir los fixtures (configura la carpeta Cypress)',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Ficheros',\r\n BTN_COMMANDS: 'Comandos',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pausar (Ctrl+P)',\r\n RESUME_TITLE: 'Reanudar (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSA',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Detener (Ctrl+R)',\r\n START_TITLE: 'Grabar (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Grabación en curso',\r\n SESSION_RESUME_TEXT: 'Hay una grabación activa sin terminar.',\r\n SESSION_RESUME_COUNT: 'comandos capturados',\r\n SESSION_CONTINUE_BTN: 'Continuar grabando',\r\n SESSION_DISCARD_BTN: 'Descartar',\r\n BTN_HELP: 'Ayuda',\r\n },\r\n HELP: {\r\n TITLE: '❓ Ayuda — Guía rápida',\r\n INTRO: 'Todo lo que puede hacer el grabador.',\r\n SEC_RECORDING: '⏺ Grabar',\r\n RECORDING_1: 'Pulsa ⏺ (o Ctrl+R) para empezar; ⏹ para parar y guardar.',\r\n RECORDING_2: 'Pausa / reanuda con ⏸ (o Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Atajos de teclado',\r\n SC_RECORD: 'Ctrl+R — Grabar / detener',\r\n SC_PAUSE: 'Ctrl+P — Pausar / reanudar',\r\n SC_TESTS: 'Ctrl+1 — Panel de tests guardados',\r\n SC_COMMANDS: 'Ctrl+2 — Panel de comandos',\r\n SC_CONFIG: 'Ctrl+3 — Configuración',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostrar / ocultar el widget',\r\n SC_HELP: 'Ctrl+Shift+H — Esta ayuda',\r\n SEC_CAPTURED: '🎯 Qué se graba',\r\n CAP_CLICK: 'Click → .click()',\r\n CAP_DBLCLICK: 'Doble-click → .dblclick()',\r\n CAP_RIGHTCLICK: 'Click derecho → .rightclick()',\r\n CAP_TYPE: 'Escribir en un campo → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Cambio de ruta (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Aserciones',\r\n ASSERT_1: 'Alt+click sobre un elemento para verificarlo sin ejecutar su acción (texto, valor, checked o visible).',\r\n ASSERT_2: 'O usa el constructor de aserciones en el panel de Comandos.',\r\n SEC_PANELS: '🗂 Paneles',\r\n PANEL_TESTS: '📋 Tests — guardados: filtrar por tag, copiar, combinar, exportar.',\r\n PANEL_COMMANDS: '⌨️ Comandos — de la grabación actual: reordenar, borrar, añadir aserciones.',\r\n PANEL_CONFIG: '⚙️ Config — idioma, selector, HTTP, carpeta Cypress, datos, visibilidad, posición.',\r\n PANEL_FILES: '📁 Ficheros — inserta tests en tus .cy.ts y lanza el runner.',\r\n SEC_SELECTOR: '🔎 Selectores',\r\n SELECTOR_1: 'Elige el atributo preferido (data-cy, data-testid, aria-label, id) en Config.',\r\n SELECTOR_2: 'Si un click no tiene selector fiable, aparece un picker para elegir el mejor ancestro.',\r\n SEC_DATA: '💾 Datos',\r\n DATA_1: 'Exporta tests a JSON (todo / selección / por tags).',\r\n DATA_2: 'Importa un JSON: se fusiona con lo existente (no se borra nada).',\r\n SEC_ADVANCED: '🚀 Avanzado',\r\n ADV_INVISIBLE: 'Modo invisible: start-hidden + Ctrl+Shift+E para grabar en producción sin molestar.',\r\n ADV_RUNNER: 'Runner local: npx lib-e2e-cypress-runner para lanzar un spec headless desde el editor.',\r\n ADV_CROSSAPP: 'Cross-app: la grabación sobrevive al cambiar de micro-frontend (mismo origen).',\r\n ADV_DRAG: 'Arrastra el botón ⏺ para mover el widget; recuerda su posición.',\r\n CLOSE: 'Cerrar',\r\n TAB_REFERENCE: 'Referencia rápida',\r\n TAB_GUIDE: 'Guía de uso',\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n G_NC_6: 'Generación de login programático (en el roadmap).',\r\n },\r\n};\r\n","export const I18N_EN = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Settings',\r\n SHOW_ADVANCED_EDITOR: 'Advanced editor',\r\n DIALOG_SAVED_TESTS: 'Saved tests',\r\n DIALOG_COMMANDS: 'Cypress commands previewer',\r\n DIALOG_SAVE: 'Save recording?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Test description',\r\n CANCEL: 'Cancel',\r\n ASK: 'Save the recorded test?',\r\n YES_CONTINUE: 'Yes, continue',\r\n NO_DISCARD: 'No, discard',\r\n DESC_PLACEHOLDER: 'E.g.: Successful login with valid credentials',\r\n TAGS_LABEL: 'Tags (optional, for later filtering):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\r\n ADD_TAG: '+ Add',\r\n NO_TAGS: 'No tags',\r\n SAVE_BTN: '💾 Save',\r\n SAVE_AND_EDIT: '📝 Save and edit',\r\n REMOVE_TAG_TITLE: 'Remove',\r\n NOTES_LABEL: 'Description / Notes (optional):',\r\n NOTES_PLACEHOLDER: 'What this test validates, preconditions, etc.',\r\n TICKET_LABEL: 'Ticket (optional):',\r\n TICKET_PH_JIRA: 'e.g. PROJ-123',\r\n TICKET_PH_AZURE: 'e.g. 1234',\r\n TICKET_PH_GITHUB: 'e.g. 42',\r\n TICKET_PH_TRELLO: 'e.g. aBc123',\r\n TICKET_PH_CUSTOM: 'ticket id',\r\n TICKET_INVALID: 'The ticket id does not match the expected format for the selected tracker.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'No tags',\r\n SELECTED_SINGULAR: 'selected',\r\n SELECTED_PLURAL: 'selected',\r\n DESCRIBE_PLACEHOLDER: 'describe name (optional)',\r\n COPY_DESCRIBE: '🗂 Copy describe()',\r\n MULTI_SELECT: '🗂 Multi-select',\r\n CANCEL_SELECT: '✕ Cancel',\r\n COPY_CMDS_BTN: '📋 Copy commands',\r\n COPY_ICPS_BTN: '📋 Copy interceptors',\r\n DEFAULT_DESCRIBE: 'Test suite',\r\n NO_TESTS: 'No saved tests',\r\n DELETE_TITLE: 'Delete',\r\n GROUP_BY_TICKET: '🎫 Group by ticket',\r\n NO_TICKET_GROUP: 'No ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Language',\r\n LANG_FIELD: 'Interface',\r\n HTTP_SECTION: '⚡ Advanced HTTP',\r\n HTTP_TITLE: 'Body validations',\r\n HTTP_SUB: 'GET → response · POST/PUT → request',\r\n FIXTURE_SECTION: '🧪 HTTP Fixtures',\r\n FIXTURE_TITLE: 'Record responses as fixtures',\r\n FIXTURE_SUB: 'GET responses are saved to cypress/fixtures and stubbed via cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Selector strategy',\r\n SELECTOR_LABEL: 'Preferred attribute for cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (default)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#element)',\r\n SELECTOR_HINT: 'The recorder will look for this attribute first. If not found, it will try the others.',\r\n FOLDER_SECTION: '📁 Cypress Folder',\r\n FOLDER_CONNECTED: 'connected —',\r\n FOLDER_NOT_SET: 'not configured',\r\n FOLDER_CHANGE_BTN: '📁 Change folder',\r\n FOLDER_SELECT_BTN: '📁 Select folder',\r\n FOLDER_REVOKE_BTN: '✕ Revoke access',\r\n DATA_SECTION: '💾 Data',\r\n DATA_DESC: 'Export all your tests to JSON or import a backup.',\r\n EXPORT_BTN: '⬆️ Export tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Export tests',\r\n EXPORT_MODE_ALL: 'All',\r\n EXPORT_MODE_MANUAL: 'Manual selection',\r\n EXPORT_MODE_TAGS: 'By tags',\r\n EXPORT_ALL_DESC: 'All saved tests will be exported.',\r\n EXPORT_COUNT: 'To export:',\r\n EXPORT_CONFIRM: '⬆️ Export',\r\n EXPORT_CANCEL: 'Cancel',\r\n EXPORT_EMPTY: 'No tests to export.',\r\n EXPORT_NO_TAGS: 'No tags available.',\r\n EXPORT_TAGS_HINT: 'Select one or more tags to preview which tests will be exported.',\r\n EXPORT_RESULT_LABEL: 'Tests that will be exported:',\r\n IMPORT_BTN: '⬇️ Import tests',\r\n FOLDER_UPDATED_TOAST: '✓ Cypress folder updated',\r\n FOLDER_ERROR_TOAST: 'Error accessing the folder',\r\n IMPORT_SUCCESS: 'Data imported successfully.',\r\n IMPORT_ERROR: 'Error importing.',\r\n JSON_INVALID: 'The file is not valid JSON.',\r\n JSON_BAD_FORMAT: 'The file does not have the expected format.',\r\n SMART_SELECTOR_SECTION: '🔍 Smart selector',\r\n SMART_SELECTOR_TITLE: 'Smart selector',\r\n SMART_SELECTOR_SUB: 'Shows a picker when clicking elements with no valid selector.',\r\n START_HIDDEN_SECTION: '👁 Widget visibility',\r\n START_HIDDEN_TITLE: 'Start hidden',\r\n START_HIDDEN_SUB: 'The widget starts invisible. Use Ctrl+Shift+E to show or hide it.',\r\n RESUME_TTL_SECTION: '⏱ Recording continuity',\r\n RESUME_TTL_LABEL: 'Resume without asking (minutes)',\r\n RESUME_TTL_HINT: 'If you reload or switch projects, an active recording resumes without asking within this window. After that, you will be asked to continue or discard.',\r\n WIDGET_POSITION_SECTION: '🧲 Widget position',\r\n WIDGET_POSITION_HINT: 'Drag the record button to move it out of the way. Its position is remembered.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Reset position',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position reset',\r\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\r\n ISSUE_TRACKER_LABEL: 'Tracker (link only, no sync)',\r\n ISSUE_TRACKER_DISCLAIMER: 'Builds links only — it never connects to or syncs with the platform.',\r\n ISSUE_TRACKER_PROVIDER_JIRA: 'Jira',\r\n ISSUE_TRACKER_PROVIDER_AZURE: 'Azure DevOps',\r\n ISSUE_TRACKER_PROVIDER_GITHUB: 'GitHub',\r\n ISSUE_TRACKER_PROVIDER_TRELLO: 'Trello',\r\n ISSUE_TRACKER_PROVIDER_CUSTOM: 'Custom',\r\n ISSUE_TRACKER_FIELD_BASEURL: 'Base URL',\r\n ISSUE_TRACKER_FIELD_ORG: 'Organization',\r\n ISSUE_TRACKER_FIELD_PROJECT: 'Project',\r\n ISSUE_TRACKER_FIELD_OWNER: 'Owner',\r\n ISSUE_TRACKER_FIELD_REPO: 'Repository',\r\n ISSUE_TRACKER_FIELD_TEMPLATE: 'URL template (must contain {id})',\r\n ISSUE_TRACKER_PH_JIRA_BASEURL: 'https://your-org.atlassian.net',\r\n ISSUE_TRACKER_PH_AZURE_ORG: 'organization',\r\n ISSUE_TRACKER_PH_AZURE_PROJECT: 'project',\r\n ISSUE_TRACKER_PH_GITHUB_OWNER: 'owner',\r\n ISSUE_TRACKER_PH_GITHUB_REPO: 'repository',\r\n ISSUE_TRACKER_PH_CUSTOM_TEMPLATE: 'https://tracker.example.com/{id}',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Select a DOM element',\r\n PREVIEW_LABEL: 'navigate',\r\n CONFIRM_HINT: 'confirm',\r\n CANCEL_HINT: 'cancel',\r\n QUALITY_EXCELLENT: 'Excellent — has a testing attribute (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Good — has a valid id',\r\n QUALITY_ACCEPTABLE: 'Acceptable — CSS classes only',\r\n QUALITY_POOR: 'Not recommended — tag name or inline style only',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptors',\r\n COPY_CMDS_BTN: '📋 Copy commands',\r\n SHOW_INTERCEPTORS: '▼ Show interceptors',\r\n HIDE_INTERCEPTORS: '▲ Hide interceptors',\r\n SECTION_COMMANDS: 'Commands',\r\n NO_CMDS_YET: 'No commands yet',\r\n NO_ICP_SHORT: 'No interceptors',\r\n COPY_ICP_BTN: '📋 Copy interceptors',\r\n UP_TITLE: 'Move up',\r\n DOWN_TITLE: 'Move down',\r\n DEL_TITLE: 'Delete',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Reactivate access',\r\n PERMISSION_EXPIRED: '🔑 Permission expired',\r\n PERMISSION_EXPIRED_HINT: 'Click to reactivate access to your Cypress folder.',\r\n NO_ACCESS: '🔒 No access to local files',\r\n NO_ACCESS_HINT: 'Configure access in ⚙️ Config.',\r\n NO_FILES: 'No files',\r\n SELECT_FILE: '← Select a file from the tree',\r\n IT_LABEL: '🧪 it() to insert:',\r\n COPY_IT_BTN: '📋 Copy it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptors:',\r\n COPY_ICP_BTN: '📋 Copy interceptors',\r\n INSERT_BTN: '💾 Insert into file',\r\n EDIT_MANUAL_BTN: '✏️ Edit manually',\r\n CLOSE_BTN: '✕ Close',\r\n NEW_FILE_BTN: '+ New file',\r\n NEW_FOLDER_BTN: '+ New folder',\r\n REFRESH_BTN: '↻ Refresh',\r\n NEW_FILE_PLACEHOLDER: 'test-name',\r\n NEW_FOLDER_PLACEHOLDER: 'folder-name',\r\n NEW_FILE_CONFIRM: 'Create',\r\n NEW_FILE_CANCEL: 'Cancel',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'No file',\r\n COPY_TITLE: 'Copy editor content',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copy',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'No changes from original',\r\n NO_CHANGES_SHORT: 'No changes',\r\n LAUNCH_BTN: '▶ Run test',\r\n LAUNCH_LOCAL_ONLY: 'Move it to localhost to run tests',\r\n LAUNCH_RUNNING: '⏳ Running…',\r\n LAUNCH_PASSED: '✓ Test passed',\r\n LAUNCH_FAILED: '✗ Test failed',\r\n LAUNCH_NO_RUNNER: 'No local runner detected (did you start it?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Save',\r\n CLOSE_BTN: '✕ Close',\r\n BACK_TO_EDITOR: '← Back to editor',\r\n INSERT_BTN: '🪄 Insert blocks',\r\n INSERT_TITLE: 'Insert it() and beforeEach() into the editor content',\r\n INSERT_DONE: 'Blocks inserted into the editor',\r\n INSERT_ERROR: 'No valid describe() block found in the file',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 File access',\r\n FS_LATER_BTN: 'Not now',\r\n FS_SELECT_BTN: '📁 Select folder',\r\n FS_SUCCESS_TOAST: '✓ Cypress folder configured',\r\n FS_ERROR_TOAST: 'Error accessing the folder',\r\n FS_INTRO_HTML: 'The <strong style=\"color:#e6edf3\">advanced editor</strong> can insert your tests directly into the Cypress <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> files.',\r\n FS_STRUCTURE_HINT_HTML: 'Select the folder that contains the <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> subfolder. The extension expects this structure:',\r\n FS_TREE_PICK_HINT: '← select this folder',\r\n FS_TREE_READ_HINT: '← the extension will read here',\r\n FS_PERMISSION_NOTE: 'The permission is stored in the browser and will not be requested again.',\r\n ASSERTION_SECTION: '➕ Add assertion',\r\n ASSERT_SELECTOR_PH: 'selector, e.g.: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'expected value',\r\n ASSERT_ADD_BTN: '➕ Add',\r\n FILE_EDITOR_TITLE: '✏️ File editor',\r\n FILE_SAVED_TOAST: '✓ File saved',\r\n FILE_SAVE_ERROR_TOAST: 'Error saving the file',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures written to cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'Could not write fixtures (configure the Cypress folder)',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Files',\r\n BTN_COMMANDS: 'Commands',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pause (Ctrl+P)',\r\n RESUME_TITLE: 'Resume (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSED',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Stop (Ctrl+R)',\r\n START_TITLE: 'Record (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Recording in progress',\r\n SESSION_RESUME_TEXT: 'There is an unfinished active recording.',\r\n SESSION_RESUME_COUNT: 'commands captured',\r\n SESSION_CONTINUE_BTN: 'Keep recording',\r\n SESSION_DISCARD_BTN: 'Discard',\r\n BTN_HELP: 'Help',\r\n },\r\n HELP: {\r\n TITLE: '❓ Help — Quick guide',\r\n INTRO: 'Everything the recorder can do.',\r\n SEC_RECORDING: '⏺ Recording',\r\n RECORDING_1: 'Press ⏺ (or Ctrl+R) to start; ⏹ to stop and save.',\r\n RECORDING_2: 'Pause / resume with ⏸ (or Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Keyboard shortcuts',\r\n SC_RECORD: 'Ctrl+R — Record / stop',\r\n SC_PAUSE: 'Ctrl+P — Pause / resume',\r\n SC_TESTS: 'Ctrl+1 — Saved tests panel',\r\n SC_COMMANDS: 'Ctrl+2 — Commands panel',\r\n SC_CONFIG: 'Ctrl+3 — Settings',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Show / hide the widget',\r\n SC_HELP: 'Ctrl+Shift+H — This help',\r\n SEC_CAPTURED: '🎯 What gets recorded',\r\n CAP_CLICK: 'Click → .click()',\r\n CAP_DBLCLICK: 'Double-click → .dblclick()',\r\n CAP_RIGHTCLICK: 'Right-click → .rightclick()',\r\n CAP_TYPE: 'Type into a field → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Route change (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Assertions',\r\n ASSERT_1: 'Alt+click an element to verify it without running its action (text, value, checked or visible).',\r\n ASSERT_2: 'Or use the assertion builder in the Commands panel.',\r\n SEC_PANELS: '🗂 Panels',\r\n PANEL_TESTS: '📋 Tests — saved tests: filter by tag, copy, combine, export.',\r\n PANEL_COMMANDS: '⌨️ Commands — current recording: reorder, delete, add assertions.',\r\n PANEL_CONFIG: '⚙️ Config — language, selector, HTTP, Cypress folder, data, visibility, position.',\r\n PANEL_FILES: '📁 Files — insert tests into your .cy.ts and launch the runner.',\r\n SEC_SELECTOR: '🔎 Selectors',\r\n SELECTOR_1: 'Choose the preferred attribute (data-cy, data-testid, aria-label, id) in Config.',\r\n SELECTOR_2: 'If a click has no reliable selector, a picker appears to choose the best ancestor.',\r\n SEC_DATA: '💾 Data',\r\n DATA_1: 'Export tests to JSON (all / selection / by tags).',\r\n DATA_2: 'Import a JSON: it merges into your data (nothing is wiped).',\r\n SEC_ADVANCED: '🚀 Advanced',\r\n ADV_INVISIBLE: 'Invisible mode: start-hidden + Ctrl+Shift+E to record in production unobtrusively.',\r\n ADV_RUNNER: 'Local runner: npx lib-e2e-cypress-runner to run a spec headless from the editor.',\r\n ADV_CROSSAPP: 'Cross-app: the recording survives switching micro-frontend (same origin).',\r\n ADV_DRAG: 'Drag the ⏺ button to move the widget; its position is remembered.',\r\n CLOSE: 'Close',\r\n TAB_REFERENCE: 'Quick reference',\r\n TAB_GUIDE: 'Usage guide',\r\n GUIDE_INTRO: 'How to get the most out of the recorder, and what it does / doesn\\'t cover.',\r\n G_SEC_WORKFLOW: '🧭 Workflow',\r\n G_WF_1: '1. Press ⏺ (or Ctrl+R) to start recording.',\r\n G_WF_2: '2. Use your app like a user: clicks, forms, navigation. Each action becomes a Cypress command.',\r\n G_WF_3: '3. Add checks with Alt+click on whatever you want to verify.',\r\n G_WF_4: '4. Press ⏹ to stop; give it a name and tags, and save it.',\r\n G_WF_5: '5. In 📁 Files, insert the test into a .cy.ts or run it with the local runner.',\r\n G_SEC_COVERED: '✅ What it covers',\r\n G_COV_1: 'Clicks, double-click, right-click, text inputs, checkbox/radio, select and Enter/Escape keys.',\r\n G_COV_2: 'SPA navigation (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'fetch/XHR calls (GET/POST/PUT) → cy.intercept + cy.wait, with optional body validation.',\r\n G_COV_4: 'Reliable selector (data-cy/testid/aria/id) and a picker when none is obvious.',\r\n G_COV_5: 'Automatic assertions (Alt+click) and the manual builder.',\r\n G_COV_6: 'Continuity when switching micro-frontend (same origin), invisible mode and i18n.',\r\n G_SEC_NOTCOVERED: '🚫 What it does NOT cover (yet)',\r\n G_NC_1: 'Different origins / subdomains (same origin only).',\r\n G_NC_2: 'File upload (selectFile), drag & drop, and hover.',\r\n G_NC_3: 'The Tab key (Cypress can\\'t .type() it).',\r\n G_NC_4: 'DELETE requests (intentionally ignored).',\r\n G_NC_5: 'Third-party iframes and Shadow DOM may not be captured.',\r\n G_NC_6: 'Programmatic login generation (on the roadmap).',\r\n },\r\n};\r\n","export const I18N_FR = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Paramètres',\r\n SHOW_ADVANCED_EDITOR: 'Éditeur avancé',\r\n DIALOG_SAVED_TESTS: 'Tests enregistrés',\r\n DIALOG_COMMANDS: 'Aperçu des commandes Cypress',\r\n DIALOG_SAVE: \"Enregistrer l'enregistrement ?\",\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Description du test',\r\n CANCEL: 'Annuler',\r\n ASK: 'Enregistrer le test ?',\r\n YES_CONTINUE: 'Oui, continuer',\r\n NO_DISCARD: 'Non, ignorer',\r\n DESC_PLACEHOLDER: 'Ex : Connexion réussie avec identifiants valides',\r\n TAGS_LABEL: 'Étiquettes (optionnel, pour filtrer ensuite) :',\r\n TAGS_PLACEHOLDER: 'smoke, login, régression…',\r\n ADD_TAG: '+ Ajouter',\r\n NO_TAGS: 'Sans étiquettes',\r\n SAVE_BTN: '💾 Enregistrer',\r\n SAVE_AND_EDIT: '📝 Enregistrer et éditer',\r\n REMOVE_TAG_TITLE: 'Retirer',\r\n NOTES_LABEL: 'Description / Notes (optionnel) :',\r\n NOTES_PLACEHOLDER: 'Ce que ce test valide, conditions préalables, etc.',\r\n TICKET_LABEL: 'Ticket (optionnel) :',\r\n TICKET_PH_JIRA: 'p. ex. PROJ-123',\r\n TICKET_PH_AZURE: 'p. ex. 1234',\r\n TICKET_PH_GITHUB: 'p. ex. 42',\r\n TICKET_PH_TRELLO: 'p. ex. aBc123',\r\n TICKET_PH_CUSTOM: 'id du ticket',\r\n TICKET_INVALID: \"L'id du ticket ne correspond pas au format attendu par le gestionnaire sélectionné.\",\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Sans étiquettes',\r\n SELECTED_SINGULAR: 'sélectionné',\r\n SELECTED_PLURAL: 'sélectionnés',\r\n DESCRIBE_PLACEHOLDER: 'Nom du describe (optionnel)',\r\n COPY_DESCRIBE: '🗂 Copier describe()',\r\n MULTI_SELECT: '🗂 Multi-sélection',\r\n CANCEL_SELECT: '✕ Annuler',\r\n COPY_CMDS_BTN: '📋 Copier les commandes',\r\n COPY_ICPS_BTN: '📋 Copier les intercepteurs',\r\n DEFAULT_DESCRIBE: 'Suite de tests',\r\n NO_TESTS: 'Aucun test enregistré',\r\n DELETE_TITLE: 'Supprimer',\r\n GROUP_BY_TICKET: '🎫 Grouper par ticket',\r\n NO_TICKET_GROUP: 'Sans ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Langue',\r\n LANG_FIELD: 'Interface',\r\n HTTP_SECTION: '⚡ HTTP Avancé',\r\n HTTP_TITLE: 'Validations du corps',\r\n HTTP_SUB: 'GET → réponse · POST/PUT → requête',\r\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\r\n FIXTURE_TITLE: 'Enregistrer les réponses comme fixtures',\r\n FIXTURE_SUB: 'Les GET sont enregistrées dans cypress/fixtures et stubées via cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Stratégie de sélecteur',\r\n SELECTOR_LABEL: 'Attribut préféré pour cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (par défaut)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#élément)',\r\n SELECTOR_HINT: \"L'enregistreur cherchera d'abord cet attribut. Si absent, il essaiera les autres.\",\r\n FOLDER_SECTION: '📁 Dossier Cypress',\r\n FOLDER_CONNECTED: 'connecté —',\r\n FOLDER_NOT_SET: 'non configuré',\r\n FOLDER_CHANGE_BTN: '📁 Changer de dossier',\r\n FOLDER_SELECT_BTN: '📁 Sélectionner un dossier',\r\n FOLDER_REVOKE_BTN: \"✕ Révoquer l'accès\",\r\n DATA_SECTION: '💾 Données',\r\n DATA_DESC: 'Exportez tous vos tests en JSON ou importez une sauvegarde.',\r\n EXPORT_BTN: '⬆️ Exporter les tests',\r\n EXPORT_DIALOG_TITLE: '⬆️ Exporter les tests',\r\n EXPORT_MODE_ALL: 'Tout',\r\n EXPORT_MODE_MANUAL: 'Sélection manuelle',\r\n EXPORT_MODE_TAGS: 'Par tags',\r\n EXPORT_ALL_DESC: 'Tous les tests enregistrés seront exportés.',\r\n EXPORT_COUNT: 'À exporter :',\r\n EXPORT_CONFIRM: '⬆️ Exporter',\r\n EXPORT_CANCEL: 'Annuler',\r\n EXPORT_EMPTY: 'Aucun test à exporter.',\r\n EXPORT_NO_TAGS: 'Aucun tag disponible.',\r\n EXPORT_TAGS_HINT: 'Sélectionnez un ou plusieurs tags pour voir les tests qui seront exportés.',\r\n EXPORT_RESULT_LABEL: 'Tests qui seront exportés :',\r\n IMPORT_BTN: '⬇️ Importer les tests',\r\n FOLDER_UPDATED_TOAST: '✓ Dossier Cypress mis à jour',\r\n FOLDER_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\r\n IMPORT_SUCCESS: 'Données importées avec succès.',\r\n IMPORT_ERROR: \"Erreur lors de l'importation.\",\r\n JSON_INVALID: \"Le fichier n'est pas un JSON valide.\",\r\n JSON_BAD_FORMAT: \"Le fichier n'a pas le format attendu.\",\r\n SMART_SELECTOR_SECTION: '🔍 Sélecteur intelligent',\r\n SMART_SELECTOR_TITLE: 'Sélecteur intelligent',\r\n SMART_SELECTOR_SUB: 'Affiche un sélecteur lors du clic sur des éléments sans sélecteur valide.',\r\n START_HIDDEN_SECTION: '👁 Visibilité du widget',\r\n START_HIDDEN_TITLE: 'Démarrer masqué',\r\n START_HIDDEN_SUB: 'Le widget démarre invisible. Utilisez Ctrl+Shift+E pour l\\'afficher ou le masquer.',\r\n RESUME_TTL_SECTION: '⏱ Continuité d\\'enregistrement',\r\n RESUME_TTL_LABEL: 'Reprendre sans demander (minutes)',\r\n RESUME_TTL_HINT: 'Si vous rechargez ou changez de projet, un enregistrement actif reprend sans demander dans ce délai. Au-delà, il vous demandera de continuer ou d\\'ignorer.',\r\n WIDGET_POSITION_SECTION: '🧲 Position du widget',\r\n WIDGET_POSITION_HINT: 'Fais glisser le bouton d\\'enregistrement pour le déplacer. Sa position est mémorisée.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Réinitialiser la position',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position réinitialisée',\r\n ISSUE_TRACKER_SECTION: '🎫 Gestionnaire de tickets',\r\n ISSUE_TRACKER_LABEL: 'Gestionnaire (lien uniquement, sans synchronisation)',\r\n ISSUE_TRACKER_DISCLAIMER: 'Génère uniquement des liens — ne se connecte ni ne se synchronise jamais avec la plateforme.',\r\n ISSUE_TRACKER_PROVIDER_JIRA: 'Jira',\r\n ISSUE_TRACKER_PROVIDER_AZURE: 'Azure DevOps',\r\n ISSUE_TRACKER_PROVIDER_GITHUB: 'GitHub',\r\n ISSUE_TRACKER_PROVIDER_TRELLO: 'Trello',\r\n ISSUE_TRACKER_PROVIDER_CUSTOM: 'Personnalisé',\r\n ISSUE_TRACKER_FIELD_BASEURL: 'URL de base',\r\n ISSUE_TRACKER_FIELD_ORG: 'Organisation',\r\n ISSUE_TRACKER_FIELD_PROJECT: 'Projet',\r\n ISSUE_TRACKER_FIELD_OWNER: 'Propriétaire',\r\n ISSUE_TRACKER_FIELD_REPO: 'Dépôt',\r\n ISSUE_TRACKER_FIELD_TEMPLATE: \"Modèle d'URL (doit contenir {id})\",\r\n ISSUE_TRACKER_PH_JIRA_BASEURL: 'https://votre-org.atlassian.net',\r\n ISSUE_TRACKER_PH_AZURE_ORG: 'organisation',\r\n ISSUE_TRACKER_PH_AZURE_PROJECT: 'projet',\r\n ISSUE_TRACKER_PH_GITHUB_OWNER: 'propriétaire',\r\n ISSUE_TRACKER_PH_GITHUB_REPO: 'dépôt',\r\n ISSUE_TRACKER_PH_CUSTOM_TEMPLATE: 'https://tracker.example.com/{id}',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Sélectionnez un élément du DOM',\r\n PREVIEW_LABEL: 'naviguer',\r\n CONFIRM_HINT: 'confirmer',\r\n CANCEL_HINT: 'annuler',\r\n QUALITY_EXCELLENT: 'Excellent — attribut de test présent (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Bon — id valide',\r\n QUALITY_ACCEPTABLE: 'Acceptable — classes CSS uniquement',\r\n QUALITY_POOR: 'Déconseillé — seulement le nom de balise ou style inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Intercepteurs',\r\n COPY_CMDS_BTN: '📋 Copier les commandes',\r\n SHOW_INTERCEPTORS: '▼ Voir les intercepteurs',\r\n HIDE_INTERCEPTORS: '▲ Masquer les intercepteurs',\r\n SECTION_COMMANDS: 'Commandes',\r\n NO_CMDS_YET: 'Aucune commande encore',\r\n NO_ICP_SHORT: 'Aucun intercepteur',\r\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\r\n UP_TITLE: 'Monter',\r\n DOWN_TITLE: 'Descendre',\r\n DEL_TITLE: 'Supprimer',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: \"🔓 Réactiver l'accès\",\r\n PERMISSION_EXPIRED: '🔑 Autorisation expirée',\r\n PERMISSION_EXPIRED_HINT: \"Cliquez pour réactiver l'accès à votre dossier Cypress.\",\r\n NO_ACCESS: '🔒 Pas d\\'accès aux fichiers locaux',\r\n NO_ACCESS_HINT: \"Configurez l'accès dans ⚙️ Config.\",\r\n NO_FILES: 'Aucun fichier',\r\n SELECT_FILE: \"← Sélectionnez un fichier dans l'arborescence\",\r\n IT_LABEL: '🧪 it() à insérer :',\r\n COPY_IT_BTN: '📋 Copier it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() intercepteurs :',\r\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\r\n INSERT_BTN: '💾 Insérer dans le fichier',\r\n EDIT_MANUAL_BTN: '✏️ Éditer manuellement',\r\n CLOSE_BTN: '✕ Fermer',\r\n NEW_FILE_BTN: '+ Nouveau fichier',\r\n NEW_FOLDER_BTN: '+ Nouveau dossier',\r\n REFRESH_BTN: '↻ Actualiser',\r\n NEW_FILE_PLACEHOLDER: 'nom-du-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nom-du-dossier',\r\n NEW_FILE_CONFIRM: 'Créer',\r\n NEW_FILE_CANCEL: 'Annuler',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Sans fichier',\r\n COPY_TITLE: \"Copier le contenu de l'éditeur\",\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copier',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: \"Aucun changement par rapport à l'original\",\r\n NO_CHANGES_SHORT: 'Aucun changement',\r\n LAUNCH_BTN: '▶ Lancer le test',\r\n LAUNCH_LOCAL_ONLY: 'Passe en local pour pouvoir tester',\r\n LAUNCH_RUNNING: '⏳ Exécution…',\r\n LAUNCH_PASSED: '✓ Test réussi',\r\n LAUNCH_FAILED: '✗ Test échoué',\r\n LAUNCH_NO_RUNNER: \"Aucun runner local détecté (l'avez-vous démarré ?)\",\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Enregistrer',\r\n CLOSE_BTN: '✕ Fermer',\r\n BACK_TO_EDITOR: \"← Retour à l'éditeur\",\r\n INSERT_BTN: '🪄 Insérer les blocs',\r\n INSERT_TITLE: \"Insérer it() et beforeEach() dans le contenu de l'éditeur\",\r\n INSERT_DONE: \"Blocs insérés dans l'éditeur\",\r\n INSERT_ERROR: 'Aucun bloc describe() valide trouvé dans le fichier',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Accès aux fichiers',\r\n FS_LATER_BTN: 'Pas maintenant',\r\n FS_SELECT_BTN: '📁 Sélectionner un dossier',\r\n FS_SUCCESS_TOAST: '✓ Dossier Cypress configuré',\r\n FS_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\r\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">éditeur avancé</strong> peut insérer vos tests directement dans les fichiers <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Sélectionnez le dossier qui contient le sous-dossier <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'extension attend cette structure :',\r\n FS_TREE_PICK_HINT: '← sélectionnez ce dossier',\r\n FS_TREE_READ_HINT: '← l\\'extension lira ici',\r\n FS_PERMISSION_NOTE: 'L\\'autorisation est enregistrée dans le navigateur et ne sera plus demandée.',\r\n ASSERTION_SECTION: '➕ Ajouter une assertion',\r\n ASSERT_SELECTOR_PH: 'sélecteur, ex : [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valeur attendue',\r\n ASSERT_ADD_BTN: '➕ Ajouter',\r\n FILE_EDITOR_TITLE: '✏️ Éditeur de fichier',\r\n FILE_SAVED_TOAST: '✓ Fichier enregistré',\r\n FILE_SAVE_ERROR_TOAST: \"Erreur lors de l'enregistrement\",\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures écrites dans cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'Impossible d\\'écrire les fixtures (configure le dossier Cypress)',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Fichiers',\r\n BTN_COMMANDS: 'Commandes',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pause (Ctrl+P)',\r\n RESUME_TITLE: 'Reprendre (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSE',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Arrêter (Ctrl+R)',\r\n START_TITLE: 'Enregistrer (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Enregistrement en cours',\r\n SESSION_RESUME_TEXT: 'Un enregistrement actif est inachevé.',\r\n SESSION_RESUME_COUNT: 'commandes capturées',\r\n SESSION_CONTINUE_BTN: 'Continuer l\\'enregistrement',\r\n SESSION_DISCARD_BTN: 'Ignorer',\r\n BTN_HELP: 'Aide',\r\n },\r\n HELP: {\r\n TITLE: '❓ Aide — Guide rapide',\r\n INTRO: 'Tout ce que l\\'enregistreur sait faire.',\r\n SEC_RECORDING: '⏺ Enregistrer',\r\n RECORDING_1: 'Appuie sur ⏺ (ou Ctrl+R) pour commencer ; ⏹ pour arrêter et enregistrer.',\r\n RECORDING_2: 'Pause / reprise avec ⏸ (ou Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Raccourcis clavier',\r\n SC_RECORD: 'Ctrl+R — Enregistrer / arrêter',\r\n SC_PAUSE: 'Ctrl+P — Pause / reprise',\r\n SC_TESTS: 'Ctrl+1 — Panneau des tests enregistrés',\r\n SC_COMMANDS: 'Ctrl+2 — Panneau des commandes',\r\n SC_CONFIG: 'Ctrl+3 — Paramètres',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Afficher / masquer le widget',\r\n SC_HELP: 'Ctrl+Shift+H — Cette aide',\r\n SEC_CAPTURED: '🎯 Ce qui est enregistré',\r\n CAP_CLICK: 'Clic → .click()',\r\n CAP_DBLCLICK: 'Double-clic → .dblclick()',\r\n CAP_RIGHTCLICK: 'Clic droit → .rightclick()',\r\n CAP_TYPE: 'Saisie dans un champ → .clear().type(...)',\r\n CAP_CHECK: 'Case à cocher / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Entrée / Échap → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Changement de route (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Assertions',\r\n ASSERT_1: 'Alt+clic sur un élément pour le vérifier sans exécuter son action (texte, valeur, coché ou visible).',\r\n ASSERT_2: 'Ou utilise le constructeur d\\'assertions dans le panneau Commandes.',\r\n SEC_PANELS: '🗂 Panneaux',\r\n PANEL_TESTS: '📋 Tests — enregistrés : filtrer par tag, copier, combiner, exporter.',\r\n PANEL_COMMANDS: '⌨️ Commandes — enregistrement en cours : réordonner, supprimer, ajouter des assertions.',\r\n PANEL_CONFIG: '⚙️ Config — langue, sélecteur, HTTP, dossier Cypress, données, visibilité, position.',\r\n PANEL_FILES: '📁 Fichiers — insère des tests dans tes .cy.ts et lance le runner.',\r\n SEC_SELECTOR: '🔎 Sélecteurs',\r\n SELECTOR_1: 'Choisis l\\'attribut préféré (data-cy, data-testid, aria-label, id) dans Config.',\r\n SELECTOR_2: 'Si un clic n\\'a pas de sélecteur fiable, un sélecteur apparaît pour choisir le meilleur ancêtre.',\r\n SEC_DATA: '💾 Données',\r\n DATA_1: 'Exporte les tests en JSON (tout / sélection / par tags).',\r\n DATA_2: 'Importe un JSON : il fusionne avec tes données (rien n\\'est effacé).',\r\n SEC_ADVANCED: '🚀 Avancé',\r\n ADV_INVISIBLE: 'Mode invisible : start-hidden + Ctrl+Shift+E pour enregistrer en production discrètement.',\r\n ADV_RUNNER: 'Runner local : npx lib-e2e-cypress-runner pour lancer un spec headless depuis l\\'éditeur.',\r\n ADV_CROSSAPP: 'Cross-app : l\\'enregistrement survit au changement de micro-frontend (même origine).',\r\n ADV_DRAG: 'Fais glisser le bouton ⏺ pour déplacer le widget ; sa position est mémorisée.',\r\n CLOSE: 'Fermer',\r\n TAB_REFERENCE: 'Référence rapide',\r\n TAB_GUIDE: 'Guide d\\'utilisation',\r\n // TODO: translate (fr) — usage guide body kept in Spanish for now.\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n G_NC_6: 'Generación de login programático (en el roadmap).',\r\n },\r\n};\r\n","export const I18N_IT = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Impostazioni',\r\n SHOW_ADVANCED_EDITOR: 'Editor avanzato',\r\n DIALOG_SAVED_TESTS: 'Test salvati',\r\n DIALOG_COMMANDS: 'Anteprima comandi Cypress',\r\n DIALOG_SAVE: 'Salvare la registrazione?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Descrizione del test',\r\n CANCEL: 'Annulla',\r\n ASK: 'Salvare il test registrato?',\r\n YES_CONTINUE: 'Sì, continua',\r\n NO_DISCARD: 'No, annulla',\r\n DESC_PLACEHOLDER: 'Es: Login riuscito con credenziali valide',\r\n TAGS_LABEL: 'Etichette (opzionale, per filtrare dopo):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regressione…',\r\n ADD_TAG: '+ Aggiungi',\r\n NO_TAGS: 'Nessuna etichetta',\r\n SAVE_BTN: '💾 Salva',\r\n SAVE_AND_EDIT: '📝 Salva e modifica',\r\n REMOVE_TAG_TITLE: 'Rimuovi',\r\n NOTES_LABEL: 'Descrizione / Note (opzionale):',\r\n NOTES_PLACEHOLDER: 'Cosa valida questo test, condizioni preliminari, ecc.',\r\n TICKET_LABEL: 'Ticket (opzionale):',\r\n TICKET_PH_JIRA: 'es. PROJ-123',\r\n TICKET_PH_AZURE: 'es. 1234',\r\n TICKET_PH_GITHUB: 'es. 42',\r\n TICKET_PH_TRELLO: 'es. aBc123',\r\n TICKET_PH_CUSTOM: 'id del ticket',\r\n TICKET_INVALID: \"L'id del ticket non corrisponde al formato previsto dal gestore selezionato.\",\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Nessuna etichetta',\r\n SELECTED_SINGULAR: 'selezionato',\r\n SELECTED_PLURAL: 'selezionati',\r\n DESCRIBE_PLACEHOLDER: 'Nome del describe (opzionale)',\r\n COPY_DESCRIBE: '🗂 Copia describe()',\r\n MULTI_SELECT: '🗂 Multi-selezione',\r\n CANCEL_SELECT: '✕ Annulla',\r\n COPY_CMDS_BTN: '📋 Copia comandi',\r\n COPY_ICPS_BTN: '📋 Copia interceptor',\r\n DEFAULT_DESCRIBE: 'Suite di test',\r\n NO_TESTS: 'Nessun test salvato',\r\n DELETE_TITLE: 'Elimina',\r\n GROUP_BY_TICKET: '🎫 Raggruppa per ticket',\r\n NO_TICKET_GROUP: 'Senza ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Lingua',\r\n LANG_FIELD: 'Interfaccia',\r\n HTTP_SECTION: '⚡ HTTP Avanzato',\r\n HTTP_TITLE: 'Validazioni del body',\r\n HTTP_SUB: 'GET → risposta · POST/PUT → richiesta',\r\n FIXTURE_SECTION: '🧪 Fixture HTTP',\r\n FIXTURE_TITLE: 'Registra le risposte come fixture',\r\n FIXTURE_SUB: 'Le GET vengono salvate in cypress/fixtures e stubbate con cy.intercept({ fixture }).',\r\n SELECTOR_SECTION: '🎯 Strategia selettore',\r\n SELECTOR_LABEL: 'Attributo preferito per cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (predefinito)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#elemento)',\r\n SELECTOR_HINT: 'Il registratore cercherà prima questo attributo. Se assente, proverà gli altri.',\r\n FOLDER_SECTION: '📁 Cartella Cypress',\r\n FOLDER_CONNECTED: 'connesso —',\r\n FOLDER_NOT_SET: 'non configurato',\r\n FOLDER_CHANGE_BTN: '📁 Cambia cartella',\r\n FOLDER_SELECT_BTN: '📁 Seleziona cartella',\r\n FOLDER_REVOKE_BTN: '✕ Revoca accesso',\r\n DATA_SECTION: '💾 Dati',\r\n DATA_DESC: 'Esporta tutti i tuoi test in JSON o importa un backup.',\r\n EXPORT_BTN: '⬆️ Esporta test',\r\n EXPORT_DIALOG_TITLE: '⬆️ Esporta test',\r\n EXPORT_MODE_ALL: 'Tutto',\r\n EXPORT_MODE_MANUAL: 'Selezione manuale',\r\n EXPORT_MODE_TAGS: 'Per tag',\r\n EXPORT_ALL_DESC: 'Verranno esportati tutti i test salvati.',\r\n EXPORT_COUNT: 'Da esportare:',\r\n EXPORT_CONFIRM: '⬆️ Esporta',\r\n EXPORT_CANCEL: 'Annulla',\r\n EXPORT_EMPTY: 'Nessun test da esportare.',\r\n EXPORT_NO_TAGS: 'Nessun tag disponibile.',\r\n EXPORT_TAGS_HINT: 'Seleziona uno o più tag per vedere quali test verranno esportati.',\r\n EXPORT_RESULT_LABEL: 'Test che verranno esportati:',\r\n IMPORT_BTN: '⬇️ Importa test',\r\n FOLDER_UPDATED_TOAST: '✓ Cartella Cypress aggiornata',\r\n FOLDER_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\r\n IMPORT_SUCCESS: 'Dati importati correttamente.',\r\n IMPORT_ERROR: \"Errore durante l'importazione.\",\r\n JSON_INVALID: 'Il file non è un JSON valido.',\r\n JSON_BAD_FORMAT: 'Il file non ha il formato previsto.',\r\n SMART_SELECTOR_SECTION: '🔍 Selettore intelligente',\r\n SMART_SELECTOR_TITLE: 'Selettore intelligente',\r\n SMART_SELECTOR_SUB: 'Mostra un selettore quando si fa clic su elementi senza selettore valido.',\r\n START_HIDDEN_SECTION: '👁 Visibilità del widget',\r\n START_HIDDEN_TITLE: 'Avvia nascosto',\r\n START_HIDDEN_SUB: 'Il widget si avvia invisibile. Usa Ctrl+Shift+E per mostrarlo o nasconderlo.',\r\n RESUME_TTL_SECTION: '⏱ Continuità di registrazione',\r\n RESUME_TTL_LABEL: 'Riprendi senza chiedere (minuti)',\r\n RESUME_TTL_HINT: 'Se ricarichi o cambi progetto, una registrazione attiva riprende senza chiedere entro questo intervallo. Trascorso, ti chiederà se continuare o annullare.',\r\n WIDGET_POSITION_SECTION: '🧲 Posizione del widget',\r\n WIDGET_POSITION_HINT: 'Trascina il pulsante di registrazione per spostarlo. La posizione viene ricordata.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Reimposta posizione',\r\n WIDGET_POSITION_RESET_DONE: '✓ Posizione reimpostata',\r\n ISSUE_TRACKER_SECTION: '🎫 Gestore ticket',\r\n ISSUE_TRACKER_LABEL: 'Gestore (solo link, senza sincronizzazione)',\r\n ISSUE_TRACKER_DISCLAIMER: 'Genera solo link — non si connette né si sincronizza mai con la piattaforma.',\r\n ISSUE_TRACKER_PROVIDER_JIRA: 'Jira',\r\n ISSUE_TRACKER_PROVIDER_AZURE: 'Azure DevOps',\r\n ISSUE_TRACKER_PROVIDER_GITHUB: 'GitHub',\r\n ISSUE_TRACKER_PROVIDER_TRELLO: 'Trello',\r\n ISSUE_TRACKER_PROVIDER_CUSTOM: 'Personalizzato',\r\n ISSUE_TRACKER_FIELD_BASEURL: 'URL di base',\r\n ISSUE_TRACKER_FIELD_ORG: 'Organizzazione',\r\n ISSUE_TRACKER_FIELD_PROJECT: 'Progetto',\r\n ISSUE_TRACKER_FIELD_OWNER: 'Proprietario',\r\n ISSUE_TRACKER_FIELD_REPO: 'Repository',\r\n ISSUE_TRACKER_FIELD_TEMPLATE: 'Modello di URL (deve contenere {id})',\r\n ISSUE_TRACKER_PH_JIRA_BASEURL: 'https://tua-org.atlassian.net',\r\n ISSUE_TRACKER_PH_AZURE_ORG: 'organizzazione',\r\n ISSUE_TRACKER_PH_AZURE_PROJECT: 'progetto',\r\n ISSUE_TRACKER_PH_GITHUB_OWNER: 'proprietario',\r\n ISSUE_TRACKER_PH_GITHUB_REPO: 'repository',\r\n ISSUE_TRACKER_PH_CUSTOM_TEMPLATE: 'https://tracker.example.com/{id}',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'Seleziona un elemento DOM',\r\n PREVIEW_LABEL: 'navigare',\r\n CONFIRM_HINT: 'confermare',\r\n CANCEL_HINT: 'annullare',\r\n QUALITY_EXCELLENT: 'Eccellente — attributo di test presente (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Buono — id valido',\r\n QUALITY_ACCEPTABLE: 'Accettabile — solo classi CSS',\r\n QUALITY_POOR: 'Sconsigliato — solo tag o stile inline',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptor',\r\n COPY_CMDS_BTN: '📋 Copia comandi',\r\n SHOW_INTERCEPTORS: '▼ Vedi interceptor',\r\n HIDE_INTERCEPTORS: '▲ Nascondi interceptor',\r\n SECTION_COMMANDS: 'Comandi',\r\n NO_CMDS_YET: 'Ancora nessun comando',\r\n NO_ICP_SHORT: 'Nessun interceptor',\r\n COPY_ICP_BTN: '📋 Copia interceptor',\r\n UP_TITLE: 'Su',\r\n DOWN_TITLE: 'Giù',\r\n DEL_TITLE: 'Elimina',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Riattiva accesso',\r\n PERMISSION_EXPIRED: '🔑 Autorizzazione scaduta',\r\n PERMISSION_EXPIRED_HINT: \"Clicca per riattivare l'accesso alla cartella Cypress.\",\r\n NO_ACCESS: '🔒 Nessun accesso ai file locali',\r\n NO_ACCESS_HINT: \"Configura l'accesso in ⚙️ Config.\",\r\n NO_FILES: 'Nessun file',\r\n SELECT_FILE: \"← Seleziona un file dall'albero\",\r\n IT_LABEL: '🧪 it() da inserire:',\r\n COPY_IT_BTN: '📋 Copia it()',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptor:',\r\n COPY_ICP_BTN: '📋 Copia interceptor',\r\n INSERT_BTN: '💾 Inserisci nel file',\r\n EDIT_MANUAL_BTN: '✏️ Modifica manualmente',\r\n CLOSE_BTN: '✕ Chiudi',\r\n NEW_FILE_BTN: '+ Nuovo file',\r\n NEW_FOLDER_BTN: '+ Nuova cartella',\r\n REFRESH_BTN: '↻ Aggiorna',\r\n NEW_FILE_PLACEHOLDER: 'nome-del-test',\r\n NEW_FOLDER_PLACEHOLDER: 'nome-cartella',\r\n NEW_FILE_CONFIRM: 'Crea',\r\n NEW_FILE_CANCEL: 'Annulla',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Nessun file',\r\n COPY_TITLE: \"Copia il contenuto dell'editor\",\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Copia',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: \"Nessuna modifica rispetto all'originale\",\r\n NO_CHANGES_SHORT: 'Nessuna modifica',\r\n LAUNCH_BTN: '▶ Esegui test',\r\n LAUNCH_LOCAL_ONLY: 'Spostati in locale per poter testare',\r\n LAUNCH_RUNNING: '⏳ Esecuzione…',\r\n LAUNCH_PASSED: '✓ Test superato',\r\n LAUNCH_FAILED: '✗ Test fallito',\r\n LAUNCH_NO_RUNNER: \"Nessun runner locale rilevato (l'hai avviato?)\",\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Salva',\r\n CLOSE_BTN: '✕ Chiudi',\r\n BACK_TO_EDITOR: \"← Torna all'editor\",\r\n INSERT_BTN: '🪄 Inserisci blocchi',\r\n INSERT_TITLE: \"Inserisci it() e beforeEach() nel contenuto dell'editor\",\r\n INSERT_DONE: \"Blocchi inseriti nell'editor\",\r\n INSERT_ERROR: 'Nessun blocco describe() valido trovato nel file',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Accesso ai file',\r\n FS_LATER_BTN: 'Non ora',\r\n FS_SELECT_BTN: '📁 Seleziona cartella',\r\n FS_SUCCESS_TOAST: '✓ Cartella Cypress configurata',\r\n FS_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\r\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">editor avanzato</strong> può inserire i tuoi test direttamente nei file <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> di Cypress.',\r\n FS_STRUCTURE_HINT_HTML: 'Seleziona la cartella che contiene la sottocartella <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'estensione si aspetta questa struttura:',\r\n FS_TREE_PICK_HINT: '← seleziona questa cartella',\r\n FS_TREE_READ_HINT: '← l\\'estensione leggerà qui',\r\n FS_PERMISSION_NOTE: 'Il permesso viene salvato nel browser e non sarà richiesto di nuovo.',\r\n ASSERTION_SECTION: '➕ Aggiungi asserzione',\r\n ASSERT_SELECTOR_PH: 'selettore, es: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'valore atteso',\r\n ASSERT_ADD_BTN: '➕ Aggiungi',\r\n FILE_EDITOR_TITLE: '✏️ Editor di file',\r\n FILE_SAVED_TOAST: '✓ File salvato',\r\n FILE_SAVE_ERROR_TOAST: 'Errore durante il salvataggio',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixture scritte in cypress/fixtures',\r\n FIXTURES_NO_FOLDER_TOAST: 'Impossibile scrivere le fixture (configura la cartella Cypress)',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'File',\r\n BTN_COMMANDS: 'Comandi',\r\n BTN_TESTS: 'Test',\r\n PAUSE_TITLE: 'Pausa (Ctrl+P)',\r\n RESUME_TITLE: 'Riprendi (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSA',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Ferma (Ctrl+R)',\r\n START_TITLE: 'Registra (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Registrazione in corso',\r\n SESSION_RESUME_TEXT: 'C\\'è una registrazione attiva non terminata.',\r\n SESSION_RESUME_COUNT: 'comandi catturati',\r\n SESSION_CONTINUE_BTN: 'Continua a registrare',\r\n SESSION_DISCARD_BTN: 'Annulla',\r\n BTN_HELP: 'Aiuto',\r\n },\r\n HELP: {\r\n TITLE: '❓ Aiuto — Guida rapida',\r\n INTRO: 'Tutto ciò che il registratore sa fare.',\r\n SEC_RECORDING: '⏺ Registrare',\r\n RECORDING_1: 'Premi ⏺ (o Ctrl+R) per iniziare; ⏹ per fermare e salvare.',\r\n RECORDING_2: 'Pausa / ripresa con ⏸ (o Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Scorciatoie da tastiera',\r\n SC_RECORD: 'Ctrl+R — Registra / ferma',\r\n SC_PAUSE: 'Ctrl+P — Pausa / ripresa',\r\n SC_TESTS: 'Ctrl+1 — Pannello test salvati',\r\n SC_COMMANDS: 'Ctrl+2 — Pannello comandi',\r\n SC_CONFIG: 'Ctrl+3 — Impostazioni',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostra / nascondi il widget',\r\n SC_HELP: 'Ctrl+Shift+H — Questo aiuto',\r\n SEC_CAPTURED: '🎯 Cosa viene registrato',\r\n CAP_CLICK: 'Click → .click()',\r\n CAP_DBLCLICK: 'Doppio click → .dblclick()',\r\n CAP_RIGHTCLICK: 'Click destro → .rightclick()',\r\n CAP_TYPE: 'Digitare in un campo → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Invio / Esc → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Cambio di rotta (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Asserzioni',\r\n ASSERT_1: 'Alt+click su un elemento per verificarlo senza eseguire la sua azione (testo, valore, checked o visibile).',\r\n ASSERT_2: 'Oppure usa il costruttore di asserzioni nel pannello Comandi.',\r\n SEC_PANELS: '🗂 Pannelli',\r\n PANEL_TESTS: '📋 Test — salvati: filtra per tag, copia, combina, esporta.',\r\n PANEL_COMMANDS: '⌨️ Comandi — registrazione corrente: riordina, elimina, aggiungi asserzioni.',\r\n PANEL_CONFIG: '⚙️ Config — lingua, selettore, HTTP, cartella Cypress, dati, visibilità, posizione.',\r\n PANEL_FILES: '📁 File — inserisci test nei tuoi .cy.ts e avvia il runner.',\r\n SEC_SELECTOR: '🔎 Selettori',\r\n SELECTOR_1: 'Scegli l\\'attributo preferito (data-cy, data-testid, aria-label, id) in Config.',\r\n SELECTOR_2: 'Se un click non ha un selettore affidabile, appare un picker per scegliere l\\'antenato migliore.',\r\n SEC_DATA: '💾 Dati',\r\n DATA_1: 'Esporta i test in JSON (tutto / selezione / per tag).',\r\n DATA_2: 'Importa un JSON: si fonde con i tuoi dati (non si cancella nulla).',\r\n SEC_ADVANCED: '🚀 Avanzato',\r\n ADV_INVISIBLE: 'Modalità invisibile: start-hidden + Ctrl+Shift+E per registrare in produzione senza disturbare.',\r\n ADV_RUNNER: 'Runner locale: npx lib-e2e-cypress-runner per eseguire uno spec headless dall\\'editor.',\r\n ADV_CROSSAPP: 'Cross-app: la registrazione sopravvive al cambio di micro-frontend (stessa origine).',\r\n ADV_DRAG: 'Trascina il pulsante ⏺ per spostare il widget; la posizione viene ricordata.',\r\n CLOSE: 'Chiudi',\r\n TAB_REFERENCE: 'Riferimento rapido',\r\n TAB_GUIDE: 'Guida all\\'uso',\r\n // TODO: translate (it) — usage guide body kept in Spanish for now.\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n G_NC_6: 'Generación de login programático (en el roadmap).',\r\n },\r\n};\r\n","export const I18N_DE = {\r\n MAIN_FRAME: {\r\n SETTINGS: 'Einstellungen',\r\n SHOW_ADVANCED_EDITOR: 'Erweiterter Editor',\r\n DIALOG_SAVED_TESTS: 'Gespeicherte Tests',\r\n DIALOG_COMMANDS: 'Cypress-Befehle Vorschau',\r\n DIALOG_SAVE: 'Aufzeichnung speichern?',\r\n },\r\n SAVE_TEST: {\r\n DESC_LABEL: 'Testbeschreibung',\r\n CANCEL: 'Abbrechen',\r\n ASK: 'Aufgezeichneten Test speichern?',\r\n YES_CONTINUE: 'Ja, weiter',\r\n NO_DISCARD: 'Nein, verwerfen',\r\n DESC_PLACEHOLDER: 'Z. B.: Erfolgreiche Anmeldung mit gültigen Zugangsdaten',\r\n TAGS_LABEL: 'Tags (optional, zum späteren Filtern):',\r\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\r\n ADD_TAG: '+ Hinzufügen',\r\n NO_TAGS: 'Keine Tags',\r\n SAVE_BTN: '💾 Speichern',\r\n SAVE_AND_EDIT: '📝 Speichern und bearbeiten',\r\n REMOVE_TAG_TITLE: 'Entfernen',\r\n NOTES_LABEL: 'Beschreibung / Notizen (optional):',\r\n NOTES_PLACEHOLDER: 'Was dieser Test validiert, Voraussetzungen usw.',\r\n TICKET_LABEL: 'Ticket (optional):',\r\n TICKET_PH_JIRA: 'z. B. PROJ-123',\r\n TICKET_PH_AZURE: 'z. B. 1234',\r\n TICKET_PH_GITHUB: 'z. B. 42',\r\n TICKET_PH_TRELLO: 'z. B. aBc123',\r\n TICKET_PH_CUSTOM: 'Ticket-ID',\r\n TICKET_INVALID: 'Die Ticket-ID entspricht nicht dem erwarteten Format des ausgewählten Trackers.',\r\n },\r\n TEST_EDITOR: {\r\n NO_TAGS: 'Keine Tags',\r\n SELECTED_SINGULAR: 'ausgewählt',\r\n SELECTED_PLURAL: 'ausgewählt',\r\n DESCRIBE_PLACEHOLDER: 'describe-Name (optional)',\r\n COPY_DESCRIBE: '🗂 describe() kopieren',\r\n MULTI_SELECT: '🗂 Mehrfachauswahl',\r\n CANCEL_SELECT: '✕ Abbrechen',\r\n COPY_CMDS_BTN: '📋 Befehle kopieren',\r\n COPY_ICPS_BTN: '📋 Interceptors kopieren',\r\n DEFAULT_DESCRIBE: 'Test-Suite',\r\n NO_TESTS: 'Keine gespeicherten Tests',\r\n DELETE_TITLE: 'Löschen',\r\n GROUP_BY_TICKET: '🎫 Nach Ticket gruppieren',\r\n NO_TICKET_GROUP: 'Kein Ticket',\r\n },\r\n CONFIG: {\r\n LANG_SECTION: '🌐 Sprache',\r\n LANG_FIELD: 'Oberfläche',\r\n HTTP_SECTION: '⚡ Erweitertes HTTP',\r\n HTTP_TITLE: 'Body-Validierungen',\r\n HTTP_SUB: 'GET → Antwort · POST/PUT → Anfrage',\r\n FIXTURE_SECTION: '🧪 HTTP-Fixtures',\r\n FIXTURE_TITLE: 'Antworten als Fixtures aufzeichnen',\r\n FIXTURE_SUB: 'GET-Antworten werden in cypress/fixtures gespeichert und mit cy.intercept({ fixture }) gestubbt.',\r\n SELECTOR_SECTION: '🎯 Selector-Strategie',\r\n SELECTOR_LABEL: 'Bevorzugtes Attribut für cy.get()',\r\n SELECTOR_OPT_DATACY: 'data-cy (Standard)',\r\n SELECTOR_OPT_TESTID: 'data-testid',\r\n SELECTOR_OPT_ARIA: 'aria-label',\r\n SELECTOR_OPT_ID: 'id (#element)',\r\n SELECTOR_HINT: 'Der Recorder sucht zuerst nach diesem Attribut. Falls nicht gefunden, versucht er die anderen.',\r\n FOLDER_SECTION: '📁 Cypress-Ordner',\r\n FOLDER_CONNECTED: 'verbunden —',\r\n FOLDER_NOT_SET: 'nicht konfiguriert',\r\n FOLDER_CHANGE_BTN: '📁 Ordner wechseln',\r\n FOLDER_SELECT_BTN: '📁 Ordner auswählen',\r\n FOLDER_REVOKE_BTN: '✕ Zugriff widerrufen',\r\n DATA_SECTION: '💾 Daten',\r\n DATA_DESC: 'Exportieren Sie alle Tests als JSON oder importieren Sie ein Backup.',\r\n EXPORT_BTN: '⬆️ Tests exportieren',\r\n EXPORT_DIALOG_TITLE: '⬆️ Tests exportieren',\r\n EXPORT_MODE_ALL: 'Alle',\r\n EXPORT_MODE_MANUAL: 'Manuelle Auswahl',\r\n EXPORT_MODE_TAGS: 'Nach Tags',\r\n EXPORT_ALL_DESC: 'Alle gespeicherten Tests werden exportiert.',\r\n EXPORT_COUNT: 'Zu exportieren:',\r\n EXPORT_CONFIRM: '⬆️ Exportieren',\r\n EXPORT_CANCEL: 'Abbrechen',\r\n EXPORT_EMPTY: 'Keine Tests zum Exportieren.',\r\n EXPORT_NO_TAGS: 'Keine Tags verfügbar.',\r\n EXPORT_TAGS_HINT: 'Wähle ein oder mehrere Tags, um zu sehen, welche Tests exportiert werden.',\r\n EXPORT_RESULT_LABEL: 'Diese Tests werden exportiert:',\r\n IMPORT_BTN: '⬇️ Tests importieren',\r\n FOLDER_UPDATED_TOAST: '✓ Cypress-Ordner aktualisiert',\r\n FOLDER_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\r\n IMPORT_SUCCESS: 'Daten erfolgreich importiert.',\r\n IMPORT_ERROR: 'Fehler beim Importieren.',\r\n JSON_INVALID: 'Die Datei ist kein gültiges JSON.',\r\n JSON_BAD_FORMAT: 'Die Datei hat nicht das erwartete Format.',\r\n SMART_SELECTOR_SECTION: '🔍 Intelligenter Selektor',\r\n SMART_SELECTOR_TITLE: 'Intelligenter Selektor',\r\n SMART_SELECTOR_SUB: 'Zeigt ein Auswahlfeld, wenn auf Elemente ohne gültigen Selektor geklickt wird.',\r\n START_HIDDEN_SECTION: '👁 Widget-Sichtbarkeit',\r\n START_HIDDEN_TITLE: 'Versteckt starten',\r\n START_HIDDEN_SUB: 'Das Widget startet unsichtbar. Verwenden Sie Ctrl+Shift+E zum Ein-/Ausblenden.',\r\n RESUME_TTL_SECTION: '⏱ Aufzeichnungskontinuität',\r\n RESUME_TTL_LABEL: 'Ohne Nachfrage fortsetzen (Minuten)',\r\n RESUME_TTL_HINT: 'Wenn Sie neu laden oder das Projekt wechseln, wird eine aktive Aufzeichnung innerhalb dieses Zeitfensters ohne Nachfrage fortgesetzt. Danach werden Sie gefragt, ob fortsetzen oder verwerfen.',\r\n WIDGET_POSITION_SECTION: '🧲 Widget-Position',\r\n WIDGET_POSITION_HINT: 'Ziehe den Aufnahme-Button, um ihn aus dem Weg zu schieben. Die Position wird gespeichert.',\r\n WIDGET_POSITION_RESET_BTN: '↺ Position zurücksetzen',\r\n WIDGET_POSITION_RESET_DONE: '✓ Position zurückgesetzt',\r\n ISSUE_TRACKER_SECTION: '🎫 Issue-Tracker',\r\n ISSUE_TRACKER_LABEL: 'Tracker (nur Link, keine Synchronisierung)',\r\n ISSUE_TRACKER_DISCLAIMER: 'Erstellt nur Links — verbindet oder synchronisiert sich nie mit der Plattform.',\r\n ISSUE_TRACKER_PROVIDER_JIRA: 'Jira',\r\n ISSUE_TRACKER_PROVIDER_AZURE: 'Azure DevOps',\r\n ISSUE_TRACKER_PROVIDER_GITHUB: 'GitHub',\r\n ISSUE_TRACKER_PROVIDER_TRELLO: 'Trello',\r\n ISSUE_TRACKER_PROVIDER_CUSTOM: 'Benutzerdefiniert',\r\n ISSUE_TRACKER_FIELD_BASEURL: 'Basis-URL',\r\n ISSUE_TRACKER_FIELD_ORG: 'Organisation',\r\n ISSUE_TRACKER_FIELD_PROJECT: 'Projekt',\r\n ISSUE_TRACKER_FIELD_OWNER: 'Eigentümer',\r\n ISSUE_TRACKER_FIELD_REPO: 'Repository',\r\n ISSUE_TRACKER_FIELD_TEMPLATE: 'URL-Vorlage (muss {id} enthalten)',\r\n ISSUE_TRACKER_PH_JIRA_BASEURL: 'https://ihre-org.atlassian.net',\r\n ISSUE_TRACKER_PH_AZURE_ORG: 'Organisation',\r\n ISSUE_TRACKER_PH_AZURE_PROJECT: 'Projekt',\r\n ISSUE_TRACKER_PH_GITHUB_OWNER: 'Eigentümer',\r\n ISSUE_TRACKER_PH_GITHUB_REPO: 'Repository',\r\n ISSUE_TRACKER_PH_CUSTOM_TEMPLATE: 'https://tracker.example.com/{id}',\r\n },\r\n SELECTOR_PICKER: {\r\n TITLE: 'DOM-Element auswählen',\r\n PREVIEW_LABEL: 'navigieren',\r\n CONFIRM_HINT: 'bestätigen',\r\n CANCEL_HINT: 'abbrechen',\r\n QUALITY_EXCELLENT: 'Ausgezeichnet — Test-Attribut vorhanden (data-cy / data-testid / aria-label)',\r\n QUALITY_GOOD: 'Gut — gültige ID',\r\n QUALITY_ACCEPTABLE: 'Akzeptabel — nur CSS-Klassen',\r\n QUALITY_POOR: 'Nicht empfohlen — nur Tag oder Inline-Style',\r\n },\r\n TEST_PREVISUALIZER: {\r\n INTERCEPTORS: 'Interceptors',\r\n COPY_CMDS_BTN: '📋 Befehle kopieren',\r\n SHOW_INTERCEPTORS: '▼ Interceptors anzeigen',\r\n HIDE_INTERCEPTORS: '▲ Interceptors ausblenden',\r\n SECTION_COMMANDS: 'Befehle',\r\n NO_CMDS_YET: 'Noch keine Befehle',\r\n NO_ICP_SHORT: 'Keine Interceptors',\r\n COPY_ICP_BTN: '📋 Interceptors kopieren',\r\n UP_TITLE: 'Nach oben',\r\n DOWN_TITLE: 'Nach unten',\r\n DEL_TITLE: 'Löschen',\r\n },\r\n ADVANCED_EDITOR: {\r\n REAUTH_BTN: '🔓 Zugriff reaktivieren',\r\n PERMISSION_EXPIRED: '🔑 Berechtigung abgelaufen',\r\n PERMISSION_EXPIRED_HINT: 'Klicken Sie, um den Zugriff auf Ihren Cypress-Ordner zu reaktivieren.',\r\n NO_ACCESS: '🔒 Kein Zugriff auf lokale Dateien',\r\n NO_ACCESS_HINT: 'Konfigurieren Sie den Zugriff unter ⚙️ Config.',\r\n NO_FILES: 'Keine Dateien',\r\n SELECT_FILE: '← Wählen Sie eine Datei aus dem Baum',\r\n IT_LABEL: '🧪 it() zum Einfügen:',\r\n COPY_IT_BTN: '📋 it() kopieren',\r\n BEFORE_EACH_LABEL: '🔀 beforeEach() Interceptors:',\r\n COPY_ICP_BTN: '📋 Interceptors kopieren',\r\n INSERT_BTN: '💾 In Datei einfügen',\r\n EDIT_MANUAL_BTN: '✏️ Manuell bearbeiten',\r\n CLOSE_BTN: '✕ Schließen',\r\n NEW_FILE_BTN: '+ Neue Datei',\r\n NEW_FOLDER_BTN: '+ Neuer Ordner',\r\n REFRESH_BTN: '↻ Aktualisieren',\r\n NEW_FILE_PLACEHOLDER: 'test-name',\r\n NEW_FOLDER_PLACEHOLDER: 'ordnername',\r\n NEW_FILE_CONFIRM: 'Erstellen',\r\n NEW_FILE_CANCEL: 'Abbrechen',\r\n },\r\n FILE_PREVIEW: {\r\n NO_FILE: 'Keine Datei',\r\n COPY_TITLE: 'Editor-Inhalt kopieren',\r\n BLOCK_IT: '🧪 it()',\r\n COPY_BTN: '📋 Kopieren',\r\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\r\n NO_CHANGES: 'Keine Änderungen gegenüber dem Original',\r\n NO_CHANGES_SHORT: 'Keine Änderungen',\r\n LAUNCH_BTN: '▶ Test starten',\r\n LAUNCH_LOCAL_ONLY: 'Wechsle zu localhost, um Tests auszuführen',\r\n LAUNCH_RUNNING: '⏳ Läuft…',\r\n LAUNCH_PASSED: '✓ Test bestanden',\r\n LAUNCH_FAILED: '✗ Test fehlgeschlagen',\r\n LAUNCH_NO_RUNNER: 'Kein lokaler Runner erkannt (gestartet?)',\r\n DIFF_BTN: '📊 Diff',\r\n SAVE_BTN: '💾 Speichern',\r\n CLOSE_BTN: '✕ Schließen',\r\n BACK_TO_EDITOR: '← Zurück zum Editor',\r\n INSERT_BTN: '🪄 Blöcke einfügen',\r\n INSERT_TITLE: 'it() und beforeEach() in den Editor-Inhalt einfügen',\r\n INSERT_DONE: 'Blöcke in den Editor eingefügt',\r\n INSERT_ERROR: 'Kein gültiger describe()-Block in der Datei gefunden',\r\n },\r\n RECORDER: {\r\n FS_TITLE: '📁 Dateizugriff',\r\n FS_LATER_BTN: 'Nicht jetzt',\r\n FS_SELECT_BTN: '📁 Ordner auswählen',\r\n FS_SUCCESS_TOAST: '✓ Cypress-Ordner konfiguriert',\r\n FS_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\r\n FS_INTRO_HTML: 'Der <strong style=\"color:#e6edf3\">erweiterte Editor</strong> kann Ihre Tests direkt in die Cypress-Dateien <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> einfügen.',\r\n FS_STRUCTURE_HINT_HTML: 'Wählen Sie den Ordner, der den Unterordner <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> enthält. Die Erweiterung erwartet diese Struktur:',\r\n FS_TREE_PICK_HINT: '← diesen Ordner auswählen',\r\n FS_TREE_READ_HINT: '← die Erweiterung liest hier',\r\n FS_PERMISSION_NOTE: 'Die Berechtigung wird im Browser gespeichert und nicht erneut angefordert.',\r\n ASSERTION_SECTION: '➕ Assertion hinzufügen',\r\n ASSERT_SELECTOR_PH: 'Selektor, z. B.: [data-cy=\"btn\"]',\r\n ASSERT_VALUE_PH: 'erwarteter Wert',\r\n ASSERT_ADD_BTN: '➕ Hinzufügen',\r\n FILE_EDITOR_TITLE: '✏️ Datei-Editor',\r\n FILE_SAVED_TOAST: '✓ Datei gespeichert',\r\n FILE_SAVE_ERROR_TOAST: 'Fehler beim Speichern',\r\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures in cypress/fixtures geschrieben',\r\n FIXTURES_NO_FOLDER_TOAST: 'Fixtures konnten nicht geschrieben werden (Cypress-Ordner konfigurieren)',\r\n BTN_CONFIG: 'Config',\r\n BTN_FILES: 'Dateien',\r\n BTN_COMMANDS: 'Befehle',\r\n BTN_TESTS: 'Tests',\r\n PAUSE_TITLE: 'Pausieren (Ctrl+P)',\r\n RESUME_TITLE: 'Fortsetzen (Ctrl+P)',\r\n BADGE_PAUSED: '⏸ PAUSE',\r\n BADGE_REC: '● REC',\r\n STOP_TITLE: 'Stopp (Ctrl+R)',\r\n START_TITLE: 'Aufzeichnen (Ctrl+R)',\r\n SESSION_RESUME_TITLE: '⏺ Aufzeichnung läuft',\r\n SESSION_RESUME_TEXT: 'Es gibt eine nicht abgeschlossene aktive Aufzeichnung.',\r\n SESSION_RESUME_COUNT: 'erfasste Befehle',\r\n SESSION_CONTINUE_BTN: 'Weiter aufzeichnen',\r\n SESSION_DISCARD_BTN: 'Verwerfen',\r\n BTN_HELP: 'Hilfe',\r\n },\r\n HELP: {\r\n TITLE: '❓ Hilfe — Kurzanleitung',\r\n INTRO: 'Alles, was der Recorder kann.',\r\n SEC_RECORDING: '⏺ Aufzeichnen',\r\n RECORDING_1: 'Drücke ⏺ (oder Ctrl+R) zum Starten; ⏹ zum Stoppen und Speichern.',\r\n RECORDING_2: 'Pause / Fortsetzen mit ⏸ (oder Ctrl+P).',\r\n SEC_SHORTCUTS: '⌨️ Tastenkürzel',\r\n SC_RECORD: 'Ctrl+R — Aufzeichnen / stoppen',\r\n SC_PAUSE: 'Ctrl+P — Pausieren / fortsetzen',\r\n SC_TESTS: 'Ctrl+1 — Panel gespeicherte Tests',\r\n SC_COMMANDS: 'Ctrl+2 — Befehle-Panel',\r\n SC_CONFIG: 'Ctrl+3 — Einstellungen',\r\n SC_VISIBILITY: 'Ctrl+Shift+E — Widget ein-/ausblenden',\r\n SC_HELP: 'Ctrl+Shift+H — Diese Hilfe',\r\n SEC_CAPTURED: '🎯 Was aufgezeichnet wird',\r\n CAP_CLICK: 'Klick → .click()',\r\n CAP_DBLCLICK: 'Doppelklick → .dblclick()',\r\n CAP_RIGHTCLICK: 'Rechtsklick → .rightclick()',\r\n CAP_TYPE: 'In ein Feld tippen → .clear().type(...)',\r\n CAP_CHECK: 'Checkbox / Radio → .check() / .uncheck()',\r\n CAP_SELECT: '<select> → .select(...)',\r\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\r\n CAP_ROUTE: 'Routenwechsel (SPA) → cy.url().should(...)',\r\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\r\n SEC_ASSERT: '✅ Assertions',\r\n ASSERT_1: 'Alt+Klick auf ein Element, um es zu prüfen, ohne seine Aktion auszulösen (Text, Wert, checked oder sichtbar).',\r\n ASSERT_2: 'Oder nutze den Assertion-Builder im Befehle-Panel.',\r\n SEC_PANELS: '🗂 Panels',\r\n PANEL_TESTS: '📋 Tests — gespeichert: nach Tag filtern, kopieren, kombinieren, exportieren.',\r\n PANEL_COMMANDS: '⌨️ Befehle — aktuelle Aufzeichnung: umsortieren, löschen, Assertions hinzufügen.',\r\n PANEL_CONFIG: '⚙️ Config — Sprache, Selektor, HTTP, Cypress-Ordner, Daten, Sichtbarkeit, Position.',\r\n PANEL_FILES: '📁 Dateien — Tests in deine .cy.ts einfügen und den Runner starten.',\r\n SEC_SELECTOR: '🔎 Selektoren',\r\n SELECTOR_1: 'Wähle das bevorzugte Attribut (data-cy, data-testid, aria-label, id) unter Config.',\r\n SELECTOR_2: 'Hat ein Klick keinen zuverlässigen Selektor, erscheint ein Picker zur Wahl des besten Vorfahren.',\r\n SEC_DATA: '💾 Daten',\r\n DATA_1: 'Tests als JSON exportieren (alle / Auswahl / nach Tags).',\r\n DATA_2: 'JSON importieren: wird zu deinen Daten hinzugefügt (nichts wird gelöscht).',\r\n SEC_ADVANCED: '🚀 Erweitert',\r\n ADV_INVISIBLE: 'Unsichtbarer Modus: start-hidden + Ctrl+Shift+E, um in Produktion unauffällig aufzuzeichnen.',\r\n ADV_RUNNER: 'Lokaler Runner: npx lib-e2e-cypress-runner, um einen Spec headless aus dem Editor zu starten.',\r\n ADV_CROSSAPP: 'Cross-App: die Aufzeichnung übersteht den Wechsel des Micro-Frontends (gleicher Origin).',\r\n ADV_DRAG: 'Ziehe den ⏺-Button, um das Widget zu verschieben; die Position wird gemerkt.',\r\n CLOSE: 'Schließen',\r\n TAB_REFERENCE: 'Kurzreferenz',\r\n TAB_GUIDE: 'Nutzungsleitfaden',\r\n // TODO: translate (de) — usage guide body kept in Spanish for now.\r\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\r\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\r\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\r\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\r\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\r\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\r\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\r\n G_SEC_COVERED: '✅ Qué cubre',\r\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\r\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\r\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\r\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\r\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\r\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\r\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\r\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\r\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\r\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\r\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\r\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\r\n G_NC_6: 'Generación de login programático (en el roadmap).',\r\n },\r\n};\r\n","import { type Lang, isLang } from '../models/lang.model';\r\nimport { Subject } from '../utils/subject';\r\nimport { I18N_ES } from '../i18n/es';\r\nimport { I18N_EN } from '../i18n/en';\r\nimport { I18N_FR } from '../i18n/fr';\r\nimport { I18N_IT } from '../i18n/it';\r\nimport { I18N_DE } from '../i18n/de';\r\n\r\ntype Translations = typeof I18N_ES;\r\n\r\nexport class TranslationService {\r\n private readonly lang$: Subject<Lang>;\r\n\r\n private readonly translations: Record<Lang, Translations> = {\r\n es: I18N_ES,\r\n en: I18N_EN,\r\n fr: I18N_FR,\r\n it: I18N_IT,\r\n de: I18N_DE,\r\n };\r\n\r\n constructor() {\r\n this.lang$ = new Subject<Lang>(this.detectLang());\r\n }\r\n\r\n setLang(lang: Lang): void {\r\n this.lang$.next(lang);\r\n }\r\n\r\n getLang(): Lang {\r\n return this.lang$.getValue();\r\n }\r\n\r\n /** Subscribe to language changes; returns an unsubscribe function. */\r\n onLangChange(fn: (lang: Lang) => void): () => void {\r\n return this.lang$.subscribe(fn);\r\n }\r\n\r\n translate(key: string): string {\r\n const keys = key.split('.');\r\n let value: unknown = this.translations[this.lang$.getValue()];\r\n for (const k of keys) {\r\n value = (value as Record<string, unknown>)?.[k];\r\n if (value === undefined) return key;\r\n }\r\n return value as string;\r\n }\r\n\r\n detectLang(): Lang {\r\n const browserLang = navigator.language.split('-')[0];\r\n return isLang(browserLang) ? browserLang : 'es';\r\n }\r\n}\r\n\r\nexport const translationService = new TranslationService();\r\n","function gcd(a: number, b: number): number {\n while (b) { const t = b; b = a % b; a = t; }\n return a;\n}\n\n/**\n * Escapes backslashes and single quotes so a value can be safely embedded inside\n * a single-quoted JavaScript string literal — e.g. an `it('…')` / `describe('…')`\n * name. Without this, a test named `User's login` produces broken generated JS.\n */\nexport function escapeSingleQuotes(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n/**\n * Normalizes indentation in a code block and prefixes every line with baseIndent.\n *\n * Algorithm:\n * 1. Strip trailing whitespace from each line.\n * 2. Find the minimum leading-whitespace count of non-empty lines (dedent).\n * 3. Compute the indent step as the GCD of all non-zero relative indent values,\n * so the original indent unit (4-space, 8-space, etc.) maps to 2-space levels.\n * 4. Re-emit each line as: baseIndent + ' '.repeat(level) + trimmedContent.\n *\n * This handles multi-line interceptor/command blocks that were stored with\n * inconsistent or file-origin indentation.\n */\nexport function normalizeBlock(code: string, baseIndent: string): string {\n const lines = code.split('\\n').map(l => l.trimEnd());\n const nonEmpty = lines.filter(l => l.trim().length > 0);\n if (!nonEmpty.length) return '';\n\n const indents = nonEmpty.map(l => l.length - l.trimStart().length);\n const minIndent = Math.min(...indents);\n const relIndents = [...new Set(indents.map(n => n - minIndent).filter(n => n > 0))];\n const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;\n\n return lines\n .map(l => {\n if (!l.trim()) return '';\n const level = Math.round((l.length - l.trimStart().length - minIndent) / step);\n return baseIndent + ' '.repeat(level) + l.trimStart();\n })\n .join('\\n');\n}\n","import { type Lang, isLang } from '../models/lang.model';\r\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\r\n\r\nexport class TransformationService {\r\n toLang(lang: string): Lang {\r\n return isLang(lang) ? lang : 'en';\r\n }\r\n\r\n generateItDescription(description: string, commands: string[]): string {\r\n const commandsBlock = commands.map((cmd) => normalizeBlock(cmd, ' ')).join('\\n');\r\n return `it('${escapeSingleQuotes(description)}', () => {\\n${commandsBlock}\\n});`;\r\n }\r\n}\r\n\r\nexport const transformationService = new TransformationService();\r\n","export interface DirectoryNode {\r\n name: string;\r\n kind: 'directory';\r\n children: (DirectoryNode | FileNode)[];\r\n}\r\n\r\nexport interface FileNode {\r\n name: string;\r\n kind: 'file';\r\n}\r\n\r\nexport class AdvancedTestTransformationService {\r\n insertBeforeEach(content: string, interceptors: string, alertFn?: (msg: string) => void): string {\r\n const match = content.match(/(describe\\s*\\(.*?{)/s);\r\n if (!match) {\r\n alertFn?.('ADVANCED_EDITOR.NO_DESCRIBE');\r\n return '';\r\n }\r\n const insertPos = (match.index ?? 0) + match[0].length;\r\n const beforeEachBlock = `\\n beforeEach(() => {\\n${interceptors} })\\n`;\r\n return content.slice(0, insertPos) + beforeEachBlock + content.slice(insertPos);\r\n }\r\n\r\n insertItBlock(content: string, itBlock: string, alertFn?: (msg: string) => void): string {\r\n const idx = content.lastIndexOf('})');\r\n if (idx === -1) {\r\n alertFn?.('ADVANCED_EDITOR.NO_END');\r\n return '';\r\n }\r\n return content.slice(0, idx) + '\\n' + itBlock + '\\n' + content.slice(idx);\r\n }\r\n\r\n buildBlockComment(notes: string): string {\r\n if (!notes.trim()) return '';\r\n const lines = notes.split('\\n').map(l => ` * ${l}`).join('\\n');\r\n return `/**\\n${lines}\\n */`;\r\n }\r\n\r\n isFile(file: unknown): boolean {\r\n return !!file && (file as FileNode).kind === 'file';\r\n }\r\n\r\n async scanDirectory(dirHandle: FileSystemDirectoryHandle): Promise<DirectoryNode> {\r\n const result: DirectoryNode = { name: dirHandle.name, kind: 'directory', children: [] };\r\n for await (const entry of dirHandle.values()) {\r\n if (entry.kind === 'directory') {\r\n result.children.push(await this.scanDirectory(entry as FileSystemDirectoryHandle));\r\n } else {\r\n result.children.push({ name: entry.name, kind: 'file' });\r\n }\r\n }\r\n return result;\r\n }\r\n}\r\n\r\nexport const advancedTestTransformationService = new AdvancedTestTransformationService();\r\n","import { INPUT_TYPES } from '../models/input-types.model';\r\nimport type { ActiveSessionState } from '../models/active-session.model';\r\nimport { Subject } from '../utils/subject';\r\nimport { FORBIDDEN_ID_PREFIXES } from '../utils/selector-quality.utils';\r\nimport { inferAssertionCommand } from '../utils/assertion.utils';\r\n\r\nconst OWN_SELECTOR = '[data-cy=\"lib-e2e-cypress-for-dummys\"]';\r\n\r\nexport type SelectorStrategy = 'data-cy' | 'data-testid' | 'aria-label' | 'id';\r\n\r\n/** Generates a stable, collision-resistant session id (browser + jsdom safe). */\r\nfunction createSessionId(): string {\r\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n return crypto.randomUUID();\r\n }\r\n return `sess-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;\r\n}\r\n\r\nexport class RecordingService {\r\n private readonly commands$ = new Subject<string[]>([]);\r\n private readonly interceptors$ = new Subject<string[]>([]);\r\n private readonly isRecording$ = new Subject<boolean>(false);\r\n private readonly isPaused$ = new Subject<boolean>(false);\r\n private readonly selectorNotFound$ = new Subject<{ target: HTMLElement; action: 'click' } | null>(null);\r\n private readonly inputDebounceTimers = new Map<HTMLElement, ReturnType<typeof setTimeout>>();\r\n private readonly fixtures = new Map<string, string>();\r\n private readonly abort = new AbortController();\r\n\r\n selectorStrategy: SelectorStrategy = 'data-cy';\r\n\r\n /** Stable id of the current live session (null when none has started). */\r\n sessionId: string | null = null;\r\n private startedAt = 0;\r\n\r\n // Stored originals for history patching cleanup\r\n private readonly origPushState = history.pushState.bind(history);\r\n private readonly origReplaceState = history.replaceState.bind(history);\r\n\r\n constructor() {\r\n this.listenToAssertClicks();\r\n this.listenToClicks();\r\n this.listenToDoubleClicks();\r\n this.listenToContextMenu();\r\n this.listenToInput();\r\n this.listenToSelect();\r\n this.listenToKeys();\r\n this.listenToRouteChanges();\r\n }\r\n\r\n // ── Public API ────────────────────────────────────────────────────────────\r\n\r\n startRecording(): void {\r\n this.sessionId = createSessionId();\r\n this.startedAt = Date.now();\r\n this.isPaused$.next(false);\r\n this.isRecording$.next(true);\r\n this.addCommand(`cy.viewport(1900, 1200)`);\r\n this.addCommand(`cy.visit('${window.location.pathname}')`);\r\n this.addCommand(`cy.get('[data-cy=\"lib-e2e-cypress-for-dummys\"]').invoke('hide');`);\r\n }\r\n\r\n /**\r\n * Rehydrates a previously persisted session WITHOUT running the startRecording\r\n * bootstrap (no viewport/visit/hide). Used to continue a recording across a\r\n * micro-frontend crossing or a same-origin reload.\r\n * See docs/specs/006-cross-app-recording-continuity.md.\r\n */\r\n restoreSession(state: ActiveSessionState): void {\r\n this.sessionId = state.sessionId;\r\n this.startedAt = state.startedAt;\r\n this.selectorStrategy = state.selectorStrategy;\r\n this.commands$.next([...state.commands]);\r\n this.interceptors$.next([...state.interceptors]);\r\n this.isPaused$.next(state.isPaused);\r\n // isRecording last so subscribers observe a fully-populated buffer.\r\n this.isRecording$.next(state.isRecording);\r\n }\r\n\r\n /** Full snapshot of the live session for persistence. */\r\n getSessionSnapshot(): ActiveSessionState {\r\n return {\r\n sessionId: this.sessionId ?? createSessionId(),\r\n isRecording: this.isRecording$.getValue(),\r\n isPaused: this.isPaused$.getValue(),\r\n commands: this.commands$.getValue(),\r\n interceptors: this.interceptors$.getValue(),\r\n selectorStrategy: this.selectorStrategy,\r\n startedAt: this.startedAt,\r\n updatedAt: Date.now(),\r\n };\r\n }\r\n\r\n stopRecording(): void {\r\n this.isPaused$.next(false);\r\n this.isRecording$.next(false);\r\n }\r\n\r\n toggleRecording(): void {\r\n if (this.isRecording$.getValue()) {\r\n this.stopRecording();\r\n } else {\r\n this.startRecording();\r\n }\r\n }\r\n\r\n pauseRecording(): void {\r\n if (!this.isRecording$.getValue()) return;\r\n this.isPaused$.next(true);\r\n }\r\n\r\n resumeRecording(): void {\r\n this.isPaused$.next(false);\r\n }\r\n\r\n togglePause(): void {\r\n if (this.isPaused$.getValue()) {\r\n this.resumeRecording();\r\n } else {\r\n this.pauseRecording();\r\n }\r\n }\r\n\r\n addCommand(cmd: string): void {\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n this.commands$.next([...this.commands$.getValue(), cmd]);\r\n }\r\n\r\n /** Appends a command regardless of recording/paused state (e.g. assertions added manually). */\r\n appendCommand(cmd: string): void {\r\n this.commands$.next([...this.commands$.getValue(), cmd]);\r\n }\r\n\r\n removeCommand(index: number): void {\r\n const cmds = this.commands$.getValue();\r\n if (index < 0 || index >= cmds.length) return;\r\n this.commands$.next([...cmds.slice(0, index), ...cmds.slice(index + 1)]);\r\n }\r\n\r\n moveCommand(from: number, to: number): void {\r\n const cmds = [...this.commands$.getValue()];\r\n if (from < 0 || to < 0 || from >= cmds.length || to >= cmds.length || from === to) return;\r\n const [item] = cmds.splice(from, 1);\r\n cmds.splice(to, 0, item);\r\n this.commands$.next(cmds);\r\n }\r\n\r\n removeInterceptor(index: number): void {\r\n const ints = this.interceptors$.getValue();\r\n if (index < 0 || index >= ints.length) return;\r\n this.interceptors$.next([...ints.slice(0, index), ...ints.slice(index + 1)]);\r\n }\r\n\r\n registerInterceptor(method: string, url: string, alias: string, fixtureFile?: string): void {\r\n // Only capture interceptors while actively recording — otherwise HTTP calls\r\n // the host app fires before recording starts (the monitor is installed on\r\n // mount) would leak orphan cy.intercept lines into the saved test.\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n const wildcard = this.urlToWildcard(url, method);\r\n const command = fixtureFile\r\n ? `cy.intercept('${method}', '${wildcard}', { fixture: '${fixtureFile}' }).as('${alias}')`\r\n : `cy.intercept('${method}', '${wildcard}').as('${alias}')`;\r\n const current = this.interceptors$.getValue();\r\n if (!current.includes(command)) {\r\n this.interceptors$.next([...current, command]);\r\n }\r\n }\r\n\r\n /** Registers a captured response as a Cypress fixture (name → JSON content). */\r\n registerFixture(name: string, content: string): void {\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n this.fixtures.set(name, content);\r\n }\r\n\r\n getFixturesSnapshot(): Array<{ name: string; content: string }> {\r\n return [...this.fixtures.entries()].map(([name, content]) => ({ name, content }));\r\n }\r\n\r\n clearCommands(): void {\r\n this.commands$.next([]);\r\n this.interceptors$.next([]);\r\n this.fixtures.clear();\r\n }\r\n\r\n clearInterceptors(): void {\r\n this.interceptors$.next([]);\r\n }\r\n\r\n getCommandsSnapshot(): string[] { return this.commands$.getValue(); }\r\n getInterceptorsSnapshot(): string[] { return this.interceptors$.getValue(); }\r\n getPausedSnapshot(): boolean { return this.isPaused$.getValue(); }\r\n\r\n onCommandsChange(fn: (cmds: string[]) => void): () => void {\r\n return this.commands$.subscribe(fn);\r\n }\r\n\r\n onInterceptorsChange(fn: (ints: string[]) => void): () => void {\r\n return this.interceptors$.subscribe(fn);\r\n }\r\n\r\n onRecordingChange(fn: (isRecording: boolean) => void): () => void {\r\n return this.isRecording$.subscribe(fn);\r\n }\r\n\r\n onPauseChange(fn: (isPaused: boolean) => void): () => void {\r\n return this.isPaused$.subscribe(fn);\r\n }\r\n\r\n /**\r\n * Fires a full session snapshot whenever any persisted field changes\r\n * (commands, interceptors, recording or paused state). Drives the debounced\r\n * persistence of the live session. Returns a combined unsubscribe.\r\n */\r\n onSessionChange(fn: (state: ActiveSessionState) => void): () => void {\r\n const emit = (): void => fn(this.getSessionSnapshot());\r\n const unsubs = [\r\n this.commands$.subscribe(emit),\r\n this.interceptors$.subscribe(emit),\r\n this.isRecording$.subscribe(emit),\r\n this.isPaused$.subscribe(emit),\r\n ];\r\n return () => unsubs.forEach((u) => u());\r\n }\r\n\r\n onSelectorNotFound(fn: (target: HTMLElement, action: 'click') => void): () => void {\r\n return this.selectorNotFound$.subscribe((v) => {\r\n if (v) fn(v.target, v.action);\r\n });\r\n }\r\n\r\n destroy(): void {\r\n this.abort.abort();\r\n history.pushState = this.origPushState;\r\n history.replaceState = this.origReplaceState;\r\n this.inputDebounceTimers.forEach((t) => clearTimeout(t));\r\n this.inputDebounceTimers.clear();\r\n }\r\n\r\n // ── DOM listeners ─────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Alt+click captures an ASSERTION for the element instead of a click, and\r\n * suppresses the element's real action. Runs in the capture phase so it fires\r\n * before the app's handlers and before the bubble-phase click listener below\r\n * (stopImmediatePropagation prevents a duplicate `.click()`). See spec 009.\r\n */\r\n private listenToAssertClicks(): void {\r\n document.addEventListener(\r\n 'click',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n if (!(e as MouseEvent).altKey) return;\r\n const target = e.target as HTMLElement;\r\n if (!target || this.isOwnElement(target)) return;\r\n const tag = target.tagName?.toLowerCase();\r\n if (tag === 'body' || tag === 'html') return;\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) return; // no reliable selector → leave it as a normal Alt+click\r\n const selector = this.getReliableSelector(container);\r\n if (!selector || this.isOwnSelector(selector)) return;\r\n // Assert-only: don't let the click perform its action or record a click.\r\n e.preventDefault();\r\n e.stopImmediatePropagation();\r\n const emit = (): void => this.addCommand(inferAssertionCommand(container, selector));\r\n // A checkbox/radio toggles its `checked` during the click's activation;\r\n // since we cancelled the action it is restored afterwards, so read the true\r\n // state on the next microtask rather than the transient toggled value.\r\n const type = (container.getAttribute('type') ?? '').toLowerCase();\r\n if (container.tagName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio')) {\r\n queueMicrotask(emit);\r\n } else {\r\n emit();\r\n }\r\n },\r\n { capture: true, signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToClicks(): void {\r\n document.addEventListener(\r\n 'click',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue()) return;\r\n const target = e.target as HTMLElement;\r\n if (!target || this.isOwnElement(target)) return;\r\n const tag = target.tagName?.toLowerCase();\r\n if (tag === 'body' || tag === 'html') return;\r\n this.handleClickEvent(target);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n /** Centralised selector resolution for the pointer/key listeners (spec 010). */\r\n private resolveSelectorFor(target: HTMLElement | null): string | null {\r\n if (!target || this.isOwnElement(target)) return null;\r\n const tag = target.tagName?.toLowerCase();\r\n if (tag === 'body' || tag === 'html') return null;\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) return null;\r\n const selector = this.getReliableSelector(container);\r\n if (!selector || this.isOwnSelector(selector)) return null;\r\n return selector;\r\n }\r\n\r\n private listenToDoubleClicks(): void {\r\n document.addEventListener(\r\n 'dblclick',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n if ((e as MouseEvent).altKey) return;\r\n const selector = this.resolveSelectorFor(e.target as HTMLElement);\r\n if (!selector) return;\r\n // Collapse the up-to-2 single clicks the browser fired before the dblclick.\r\n const clickCmd = `cy.get('${selector}').click()`;\r\n let cmds = this.commands$.getValue();\r\n let removed = 0;\r\n while (removed < 2 && cmds.length > 0 && cmds[cmds.length - 1] === clickCmd) {\r\n cmds = cmds.slice(0, -1);\r\n removed++;\r\n }\r\n if (removed > 0) this.commands$.next(cmds);\r\n this.addCommand(`cy.get('${selector}').dblclick()`);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToContextMenu(): void {\r\n document.addEventListener(\r\n 'contextmenu',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n const selector = this.resolveSelectorFor(e.target as HTMLElement);\r\n if (!selector) return;\r\n this.addCommand(`cy.get('${selector}').rightclick()`);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n /** Enter → type('{enter}'), Escape → type('{esc}'), only inside a field. */\r\n private listenToKeys(): void {\r\n document.addEventListener(\r\n 'keydown',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\r\n const key = (e as KeyboardEvent).key;\r\n if (key !== 'Enter' && key !== 'Escape') return;\r\n const target = e.target as HTMLElement;\r\n const tag = target?.tagName?.toLowerCase();\r\n if (tag !== 'input' && tag !== 'textarea' && tag !== 'select') return;\r\n const selector = this.resolveSelectorFor(target);\r\n if (!selector) return;\r\n // Record the field's pending value before the key press.\r\n this.flushInputDebounce(target);\r\n const token = key === 'Enter' ? '{enter}' : '{esc}';\r\n this.addCommand(`cy.get('${selector}').type('${token}')`);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToInput(): void {\r\n document.addEventListener(\r\n 'input',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue()) return;\r\n const target = e.target as HTMLInputElement | HTMLTextAreaElement;\r\n if (!target || this.isOwnElement(target)) return;\r\n this.handleInputEvent(target);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToSelect(): void {\r\n document.addEventListener(\r\n 'change',\r\n (e: Event) => {\r\n if (!this.isRecording$.getValue()) return;\r\n const target = e.target as HTMLSelectElement;\r\n if (!target || this.isOwnElement(target)) return;\r\n if (target.tagName.toLowerCase() === 'select') {\r\n this.handleSelectEvent(target);\r\n }\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n private listenToRouteChanges(): void {\r\n let lastUrl = window.location.pathname + window.location.search + window.location.hash;\r\n\r\n const addUrlCommand = (newUrl: string): void => {\r\n if (!this.isRecording$.getValue()) return;\r\n if (newUrl === lastUrl) return;\r\n this.addCommand(`cy.url().should('include', '${newUrl}')`);\r\n lastUrl = newUrl;\r\n };\r\n\r\n const wrapMethod = (type: 'pushState' | 'replaceState'): void => {\r\n const orig = history[type].bind(history);\r\n history[type] = (data: unknown, unused: string, url?: string | URL | null) => {\r\n const result = orig(data, unused, url);\r\n let newUrl = window.location.pathname + window.location.search + window.location.hash;\r\n if (typeof url === 'string' && url.length > 0) {\r\n const a = document.createElement('a');\r\n a.href = url;\r\n newUrl = a.pathname + a.search + a.hash;\r\n } else if (url instanceof URL) {\r\n newUrl = url.pathname + url.search + url.hash;\r\n }\r\n addUrlCommand(newUrl);\r\n return result;\r\n };\r\n };\r\n\r\n wrapMethod('pushState');\r\n wrapMethod('replaceState');\r\n\r\n window.addEventListener(\r\n 'popstate',\r\n () => {\r\n const newUrl = window.location.pathname + window.location.search + window.location.hash;\r\n addUrlCommand(newUrl);\r\n },\r\n { signal: this.abort.signal }\r\n );\r\n }\r\n\r\n // ── Click helpers ─────────────────────────────────────────────────────────\r\n\r\n private handleClickEvent(target: HTMLElement): void {\r\n // Bubble up from non-interactive span/div inside button or mat-option\r\n if (!this.isInteractiveElement(target)) {\r\n const tag = target.tagName.toLowerCase();\r\n if (\r\n (tag === 'span' || tag === 'div') &&\r\n target.parentElement &&\r\n (target.parentElement.tagName.toLowerCase() === 'button' ||\r\n target.parentElement.tagName.toLowerCase() === 'mat-option') &&\r\n (target.parentElement.hasAttribute('data-cy') || target.parentElement.hasAttribute('id'))\r\n ) {\r\n target = target.parentElement;\r\n }\r\n const matSelect = target.closest('mat-select');\r\n if (matSelect) {\r\n const sel = this.getReliableSelector(matSelect as HTMLElement);\r\n if (sel) {\r\n this.addCommand(`cy.get('${sel}').click()`);\r\n } else {\r\n this.selectorNotFound$.next({ target: matSelect as HTMLElement, action: 'click' });\r\n }\r\n return;\r\n }\r\n }\r\n\r\n const tag = target.tagName.toLowerCase();\r\n if (tag === 'input' || tag === 'textarea' || tag === 'select') {\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) { this.selectorNotFound$.next({ target, action: 'click' }); return; }\r\n // Checkbox/radio → check()/uncheck(); other input clicks stay a no-op (the\r\n // value is captured via the `input` event). Runs in the bubble phase, so\r\n // `checked` already reflects the post-click state (spec 010).\r\n if (tag === 'input') {\r\n const input = target as HTMLInputElement;\r\n const type = (input.getAttribute('type') ?? '').toLowerCase();\r\n if (type === 'checkbox' || type === 'radio') {\r\n const selector = this.getReliableSelector(container);\r\n if (selector && !this.isOwnSelector(selector)) {\r\n const action = type === 'radio' || input.checked ? 'check' : 'uncheck';\r\n this.addCommand(`cy.get('${selector}').${action}()`);\r\n }\r\n }\r\n }\r\n return;\r\n }\r\n\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) {\r\n this.selectorNotFound$.next({ target, action: 'click' });\r\n return;\r\n }\r\n\r\n const selector = this.getReliableSelector(container);\r\n if (selector === OWN_SELECTOR) return;\r\n\r\n if (tag === 'mat-option') {\r\n this.handleMatOptionClick(target, selector);\r\n return;\r\n }\r\n\r\n this.addGenericCommand({\r\n selector,\r\n action: (s) => `cy.get('${s}').click()`,\r\n });\r\n }\r\n\r\n private handleMatOptionClick(target: HTMLElement, selector: string | null): void {\r\n const matSelect = target.closest('mat-select');\r\n let dataCy: string | null = null;\r\n if (matSelect) dataCy = matSelect.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\r\n if (!dataCy) dataCy = target.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\r\n if (dataCy) {\r\n this.addCommand(`cy.get('[data-cy=\"${dataCy}\"]').click()`);\r\n return;\r\n }\r\n if (selector) {\r\n this.addCommand(`cy.get('${selector}').eq(0).click()`);\r\n } else {\r\n this.selectorNotFound$.next({ target, action: 'click' });\r\n }\r\n }\r\n\r\n // ── Input helpers ─────────────────────────────────────────────────────────\r\n\r\n private handleInputEvent(target: HTMLInputElement | HTMLTextAreaElement): void {\r\n const tag = target.tagName.toLowerCase();\r\n const isText = tag === 'textarea' || (tag === 'input' && (INPUT_TYPES as readonly string[]).includes(target.type));\r\n if (!isText) return;\r\n\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) return;\r\n\r\n if (this.inputDebounceTimers.has(target)) {\r\n clearTimeout(this.inputDebounceTimers.get(target));\r\n }\r\n this.inputDebounceTimers.set(\r\n target,\r\n setTimeout(() => {\r\n this.inputDebounceTimers.delete(target);\r\n this.recordInputValue(target);\r\n }, 1000)\r\n );\r\n }\r\n\r\n /** Records a text field's current value as a `clear().type()` command. */\r\n private recordInputValue(target: HTMLInputElement | HTMLTextAreaElement): void {\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) return;\r\n const selector = this.getReliableSelector(container);\r\n const value = target.value.replace(/'/g, \"\\\\'\");\r\n this.addGenericCommand({\r\n selector,\r\n action: (s) => `cy.get('${s}').clear().type('${value}')`,\r\n });\r\n }\r\n\r\n /** Flushes any pending debounced value for an element, recording it now. */\r\n private flushInputDebounce(target: HTMLElement): void {\r\n const timer = this.inputDebounceTimers.get(target);\r\n if (timer === undefined) return;\r\n clearTimeout(timer);\r\n this.inputDebounceTimers.delete(target);\r\n this.recordInputValue(target as HTMLInputElement | HTMLTextAreaElement);\r\n }\r\n\r\n // ── Select helpers ────────────────────────────────────────────────────────\r\n\r\n private handleSelectEvent(target: HTMLSelectElement): void {\r\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\r\n if (!container) return;\r\n const selector = this.getReliableSelector(container);\r\n const value = target.value.replace(/'/g, \"\\\\'\");\r\n this.addGenericCommand({\r\n selector,\r\n action: (s) => `cy.get('${s}').select('${value}')`,\r\n });\r\n }\r\n\r\n // ── Shared helpers ────────────────────────────────────────────────────────\r\n\r\n private addGenericCommand(opts: {\r\n selector: string | null;\r\n action: (s: string) => string;\r\n }): void {\r\n if (!opts.selector || this.isOwnSelector(opts.selector)) return;\r\n this.addCommand(opts.action(opts.selector));\r\n }\r\n\r\n private getReliableSelector(el: HTMLElement): string | null {\r\n const strategy = this.selectorStrategy;\r\n const dataCy = el.getAttribute('data-cy');\r\n const dataTestid = el.getAttribute('data-testid');\r\n const ariaLabel = el.getAttribute('aria-label');\r\n const dataDotCy = el.getAttribute('data.cy');\r\n\r\n const rawId = el.id;\r\n const validId = rawId &&\r\n rawId.length < 25 &&\r\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\r\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\r\n !/^\\d+$/.test(rawId) ? rawId : null;\r\n\r\n switch (strategy) {\r\n case 'data-testid':\r\n if (dataTestid) return `[data-testid=\"${dataTestid}\"]`;\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n return validId ? `#${validId}` : null;\r\n case 'aria-label':\r\n if (ariaLabel) return `[aria-label=\"${ariaLabel}\"]`;\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n return validId ? `#${validId}` : null;\r\n case 'id':\r\n if (validId) return `#${validId}`;\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n return dataTestid ? `[data-testid=\"${dataTestid}\"]` : null;\r\n default: // 'data-cy'\r\n if (dataCy) return `[data-cy=\"${dataCy}\"]`;\r\n if (dataDotCy) return `[data.cy=\"${dataDotCy}\"]`;\r\n return validId ? `#${validId}` : null;\r\n }\r\n }\r\n\r\n private isInteractiveElement(target: EventTarget | null): boolean {\r\n if (!(target instanceof HTMLElement)) return false;\r\n const tag = target.tagName.toLowerCase();\r\n return ['select', 'option', 'input', 'textarea', 'button'].includes(tag);\r\n }\r\n\r\n private isOwnSelector(selector: string | null): boolean {\r\n return selector === OWN_SELECTOR;\r\n }\r\n\r\n private isOwnElement(target: HTMLElement): boolean {\r\n return !!target.closest('[data-cy=\"lib-e2e-cypress-for-dummys\"]');\r\n }\r\n\r\n private urlToWildcard(url: string, method: string): string {\r\n const u = new URL(url, 'http://localhost');\r\n if (method.toUpperCase() === 'GET' && u.search) {\r\n return `**${u.pathname}/**`;\r\n }\r\n return `**${u.pathname}`;\r\n }\r\n}\r\n","import { escapeSingleQuotes } from './code-format.utils';\r\n\r\n/** Longest visible-text snippet turned into a `contain.text` assertion. */\r\nconst MAX_TEXT_LENGTH = 60;\r\n\r\n/**\r\n * Infers a sensible Cypress assertion for an element, given the selector already\r\n * resolved for it (spec 009 — Alt+click assertion capture):\r\n *\r\n * - checkbox / radio → should('be.checked' | 'not.be.checked')\r\n * - input/textarea/select → should('have.value', '<value>') (or be.visible if empty)\r\n * - short visible text → should('contain.text', '<text>')\r\n * - otherwise → should('be.visible')\r\n *\r\n * All embedded values/text are single-quote escaped so the generated command is\r\n * always valid JS.\r\n */\r\nexport function inferAssertionCommand(el: HTMLElement, selector: string): string {\r\n const should = (body: string): string => `cy.get('${selector}').should(${body})`;\r\n const tag = el.tagName.toLowerCase();\r\n\r\n if (tag === 'input') {\r\n const input = el as HTMLInputElement;\r\n const type = (input.getAttribute('type') ?? 'text').toLowerCase();\r\n if (type === 'checkbox' || type === 'radio') {\r\n return should(`'${input.checked ? 'be.checked' : 'not.be.checked'}'`);\r\n }\r\n return input.value\r\n ? should(`'have.value', '${escapeSingleQuotes(input.value)}'`)\r\n : should(`'be.visible'`);\r\n }\r\n\r\n if (tag === 'textarea' || tag === 'select') {\r\n const value = (el as HTMLTextAreaElement | HTMLSelectElement).value;\r\n return value\r\n ? should(`'have.value', '${escapeSingleQuotes(value)}'`)\r\n : should(`'be.visible'`);\r\n }\r\n\r\n const text = (el.textContent ?? '').replace(/\\s+/g, ' ').trim();\r\n if (text && text.length <= MAX_TEXT_LENGTH) {\r\n return should(`'contain.text', '${escapeSingleQuotes(text)}'`);\r\n }\r\n return should(`'be.visible'`);\r\n}\r\n","import { openDB, type IDBPDatabase } from 'idb';\r\nimport { DB_SCHEMA } from '../models/db-schema.model';\r\nimport type { ActiveSessionState } from '../models/active-session.model';\r\nimport { DEFAULT_ISSUE_TRACKER_PROVIDER_ID } from '../models/issue-tracker.model';\r\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\r\nimport { buildTicketComment, resolveTicketUrl } from '../utils/ticket.utils';\r\n\r\n/** Fixed primary key for the single active-session record. */\r\nconst ACTIVE_SESSION_ID = 1;\r\n\r\ninterface TestRecord { id: number; name: string; createdAt: number; tags?: string[]; notes?: string; ticketId?: string; }\r\ninterface CommandRecord { id: number; command: string; testId: number; createdAt: number; }\r\ninterface InterceptorRecord { id: number; interceptor: string; testId: number; createdAt: number; }\r\ninterface ConfigRecord { id: number; [key: string]: unknown; }\r\n\r\nexport interface TestWithDetails extends TestRecord {\r\n commands: string[];\r\n interceptors: string[];\r\n}\r\n\r\nexport interface TestDetail extends TestWithDetails {\r\n cypressCommands: string[];\r\n itBlock: string;\r\n interceptorsBlock: string;\r\n}\r\n\r\nexport class PersistenceService {\r\n private _db: Promise<IDBPDatabase> | null = null;\r\n\r\n // dbName is overridable so tests can use unique names for isolation.\r\n constructor(private readonly dbName: string = DB_SCHEMA.name) {}\r\n\r\n private getDB(): Promise<IDBPDatabase> {\r\n if (!this._db) {\r\n this._db = openDB(this.dbName, DB_SCHEMA.version, {\r\n upgrade(database) {\r\n for (const store of DB_SCHEMA.stores) {\r\n if (!database.objectStoreNames.contains(store.name)) {\r\n const os = database.createObjectStore(store.name, {\r\n keyPath: store.keyPath,\r\n autoIncrement: store.autoIncrement,\r\n });\r\n for (const index of store.indexes) {\r\n os.createIndex(index.name, index.keyPath, { unique: index.unique });\r\n }\r\n }\r\n }\r\n },\r\n });\r\n }\r\n return this._db;\r\n }\r\n\r\n // ── Tests ─────────────────────────────────────────────────────────────────\r\n\r\n async insertTest(name: string, commands: string[] = [], interceptors: string[] = [], tags: string[] = [], notes?: string, ticketId?: string): Promise<number> {\r\n const db = await this.getDB();\r\n const record: Omit<TestRecord, 'id'> = { name, createdAt: Date.now(), ...(tags.length ? { tags } : {}), ...(notes ? { notes } : {}), ...(ticketId ? { ticketId } : {}) };\r\n const id = await db.add('tests', record) as number;\r\n if (commands.length) await this.insertCommands(commands, id);\r\n if (interceptors.length) await this.insertInterceptors(interceptors, id);\r\n return id;\r\n }\r\n\r\n async getAllTests(): Promise<TestWithDetails[]> {\r\n const db = await this.getDB();\r\n const tests = await db.getAll('tests') as TestRecord[];\r\n return Promise.all(\r\n tests.map(async (test) => ({\r\n ...test,\r\n commands: await this.getCommandStrings(test.id),\r\n interceptors: await this.getInterceptorStrings(test.id),\r\n }))\r\n );\r\n }\r\n\r\n async getTestById(testId: number): Promise<TestDetail | null> {\r\n const db = await this.getDB();\r\n const record = await db.get('tests', testId) as TestRecord | undefined;\r\n if (!record) return null;\r\n\r\n const commands = await this.getCommandStrings(testId);\r\n const interceptors = await this.getInterceptorStrings(testId);\r\n const ticketComment = await this.ticketCommentFor(record);\r\n const itBody = `it('${escapeSingleQuotes(record.name)}', () => {\\n${commands.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\r\n const itBlock = ticketComment ? `${ticketComment}\\n${itBody}` : itBody;\r\n const interceptorsBlock = interceptors.length\r\n ? ' // Auto-generated Cypress interceptors\\n' +\r\n interceptors.map(i => normalizeBlock(i, ' ')).join('\\n') + '\\n'\r\n : '';\r\n\r\n return { ...record, commands, interceptors, cypressCommands: commands, itBlock, interceptorsBlock };\r\n }\r\n\r\n /**\r\n * Builds the traceability comment for a test record (spec 014), reading the\r\n * configured issue-tracker provider/params so the link — when resolvable — is\r\n * embedded. Returns `null` when the record has no ticket id.\r\n */\r\n private async ticketCommentFor(record: TestRecord): Promise<string | null> {\r\n if (!record.ticketId) return null;\r\n const config = await this.getGeneralConfig();\r\n const providerId = (config?.['issueTrackerProviderId'] as string) ?? DEFAULT_ISSUE_TRACKER_PROVIDER_ID;\r\n const params = (config?.['issueTrackerParams'] as Record<string, Record<string, string>>) ?? {};\r\n const url = resolveTicketUrl(providerId, params, record.ticketId);\r\n return buildTicketComment(record.ticketId, url);\r\n }\r\n\r\n async deleteTest(id: number): Promise<void> {\r\n const db = await this.getDB();\r\n await db.delete('tests', id);\r\n await this.deleteCommandsByTestId(id);\r\n await this.deleteInterceptorsByTestId(id);\r\n }\r\n\r\n // ── Commands ──────────────────────────────────────────────────────────────\r\n\r\n async insertCommands(commands: string[], testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n await Promise.all(\r\n commands.map((command) => db.add('commands', { command, testId, createdAt: Date.now() }))\r\n );\r\n }\r\n\r\n async getCommandsByTestId(testId: number): Promise<CommandRecord[]> {\r\n const db = await this.getDB();\r\n return db.getAllFromIndex('commands', 'testId', testId) as Promise<CommandRecord[]>;\r\n }\r\n\r\n private async getCommandStrings(testId: number): Promise<string[]> {\r\n return (await this.getCommandsByTestId(testId)).map((r) => r.command).filter(Boolean);\r\n }\r\n\r\n private async deleteCommandsByTestId(testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n const rows = await this.getCommandsByTestId(testId);\r\n const tx = db.transaction('commands', 'readwrite');\r\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\r\n await tx.done;\r\n }\r\n\r\n // ── Interceptors ──────────────────────────────────────────────────────────\r\n\r\n async insertInterceptors(interceptors: string[], testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n await Promise.all(\r\n interceptors.map((interceptor) => db.add('interceptors', { interceptor, testId, createdAt: Date.now() }))\r\n );\r\n }\r\n\r\n async getInterceptorsByTestId(testId: number): Promise<InterceptorRecord[]> {\r\n const db = await this.getDB();\r\n return db.getAllFromIndex('interceptors', 'testId', testId) as Promise<InterceptorRecord[]>;\r\n }\r\n\r\n private async getInterceptorStrings(testId: number): Promise<string[]> {\r\n return (await this.getInterceptorsByTestId(testId)).map((r) => r.interceptor).filter(Boolean);\r\n }\r\n\r\n async deleteInterceptorsByTestId(testId: number): Promise<void> {\r\n const db = await this.getDB();\r\n const rows = await this.getInterceptorsByTestId(testId);\r\n const tx = db.transaction('interceptors', 'readwrite');\r\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\r\n await tx.done;\r\n }\r\n\r\n // ── Configuration ─────────────────────────────────────────────────────────\r\n\r\n async setConfig(config: Record<string, unknown>): Promise<void> {\r\n const db = await this.getDB();\r\n const records = await db.getAll('configuration') as ConfigRecord[];\r\n const current = records[0] ?? {};\r\n const merged = { ...current, ...config };\r\n if ((current as ConfigRecord).id) {\r\n await db.put('configuration', merged);\r\n } else {\r\n await db.add('configuration', merged);\r\n }\r\n }\r\n\r\n async setConfigKey(key: string, value: unknown): Promise<void> {\r\n return this.setConfig({ [key]: value });\r\n }\r\n\r\n async getConfig(key: string): Promise<Record<string, unknown> | null> {\r\n const db = await this.getDB();\r\n const records = await db.getAll('configuration') as ConfigRecord[];\r\n if (!records.length) return null;\r\n const config = records[0];\r\n return Object.prototype.hasOwnProperty.call(config, key) ? { [key]: config[key] } : null;\r\n }\r\n\r\n async getGeneralConfig(): Promise<ConfigRecord | null> {\r\n const db = await this.getDB();\r\n const records = await db.getAll('configuration') as ConfigRecord[];\r\n return records[0] ?? null;\r\n }\r\n\r\n // ── Active recording session ──────────────────────────────────────────────\r\n\r\n /** Upserts the live recording session (single record, fixed key). */\r\n async saveActiveSession(state: ActiveSessionState): Promise<void> {\r\n const db = await this.getDB();\r\n await db.put('activeSession', { ...state, id: ACTIVE_SESSION_ID });\r\n }\r\n\r\n /** Returns the persisted live session, or null when none is stored. */\r\n async getActiveSession(): Promise<ActiveSessionState | null> {\r\n const db = await this.getDB();\r\n const record = await db.get('activeSession', ACTIVE_SESSION_ID) as (ActiveSessionState & { id: number }) | undefined;\r\n if (!record) return null;\r\n const { id: _id, ...state } = record;\r\n return state as ActiveSessionState;\r\n }\r\n\r\n /** Removes the live session record. Safe to call when none exists. */\r\n async clearActiveSession(): Promise<void> {\r\n const db = await this.getDB();\r\n await db.delete('activeSession', ACTIVE_SESSION_ID);\r\n }\r\n\r\n // ── Bulk operations ───────────────────────────────────────────────────────\r\n\r\n async clearAllData(): Promise<void> {\r\n const db = await this.getDB();\r\n await Promise.all([\r\n db.clear('tests'),\r\n db.clear('commands'),\r\n db.clear('interceptors'),\r\n ]);\r\n }\r\n\r\n async ingestFileData(tests: Record<string, unknown>[], interceptors: Record<string, unknown>[]): Promise<void> {\r\n if (Array.isArray(tests)) {\r\n const db = await this.getDB();\r\n for (const test of tests) {\r\n // Split the nested commands/interceptors back into their own stores,\r\n // keyed by the freshly-assigned testId — otherwise they would be stored\r\n // as stray fields and silently lost on read (getAllTests reads them by\r\n // testId from the commands/interceptors stores).\r\n const { id: _id, commands, interceptors: testInterceptors, ...record } = test;\r\n const newId = await db.add('tests', record) as number;\r\n const cmds = Array.isArray(commands) ? commands as string[] : [];\r\n const icps = Array.isArray(testInterceptors) ? testInterceptors as string[] : [];\r\n if (cmds.length) await this.insertCommands(cmds, newId);\r\n if (icps.length) await this.insertInterceptors(icps, newId);\r\n }\r\n }\r\n // Back-compat: legacy files may carry top-level interceptors with their own testId.\r\n await this.bulkInsertWithoutId('interceptors', interceptors);\r\n }\r\n\r\n async requestDirectoryPermissions(): Promise<void> {\r\n if (!('showDirectoryPicker' in window)) {\r\n throw new Error('File System Access API not supported');\r\n }\r\n const dirHandle = await window.showDirectoryPicker();\r\n await this.setConfigKey('cypressDirectoryHandle', dirHandle);\r\n await this.setConfigKey('allowReadWriteFiles', 'true');\r\n }\r\n\r\n /**\r\n * Writes captured fixtures into `cypress/fixtures/` using the configured Cypress\r\n * folder handle (spec 012). Returns the number written. Throws if no folder is\r\n * configured or write permission is denied.\r\n */\r\n async writeFixtures(fixtures: Array<{ name: string; content: string }>): Promise<number> {\r\n if (!fixtures.length) return 0;\r\n const config = await this.getGeneralConfig();\r\n const dirHandle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\r\n if (!dirHandle) throw new Error('No Cypress folder configured');\r\n\r\n const perm = dirHandle as unknown as FileSystemHandleWithPermission;\r\n let state = await perm.queryPermission({ mode: 'readwrite' });\r\n if (state !== 'granted') state = await perm.requestPermission({ mode: 'readwrite' });\r\n if (state !== 'granted') throw new Error('Write permission denied');\r\n\r\n const fixturesDir = await dirHandle.getDirectoryHandle('fixtures', { create: true });\r\n let written = 0;\r\n for (const fx of fixtures) {\r\n const fileHandle = await fixturesDir.getFileHandle(fx.name, { create: true });\r\n const writable = await fileHandle.createWritable();\r\n await writable.write(fx.content);\r\n await writable.close();\r\n written++;\r\n }\r\n return written;\r\n }\r\n\r\n private async bulkInsertWithoutId(store: string, items: Record<string, unknown>[]): Promise<void> {\r\n if (!Array.isArray(items)) return;\r\n const db = await this.getDB();\r\n for (const item of items) {\r\n const { id: _id, ...rest } = item;\r\n await db.add(store, rest);\r\n }\r\n }\r\n}\r\n\r\nexport const persistenceService = new PersistenceService();\r\n","import { findIssueTrackerProvider, type IssueTrackerProvider } from '../models/issue-tracker.model';\n\n/**\n * Ticket-reference helpers for the link-only issue-tracker feature (spec 014).\n *\n * Pure functions: no DOM, no network. `buildTicketUrl` never trusts its inputs —\n * it only returns a URL when the result parses to a safe `http(s)` link, which is\n * what guards a user-supplied custom template from `javascript:`/`data:` injection.\n */\n\n/**\n * Resolves a provider template into a deep link for `id`.\n *\n * Substitutes each `{fieldKey}` (custom's `{template}` first, so a template that\n * itself contains `{id}` is handled by the same path) and then `{id}` (URL-encoded).\n * Returns `null` when a required field is missing, a token is left unresolved, or\n * the result is not a valid `http:`/`https:` URL.\n */\nexport function buildTicketUrl(\n provider: IssueTrackerProvider,\n params: Record<string, string>,\n id: string,\n): string | null {\n const ticketId = (id ?? '').trim();\n if (!provider || !ticketId) return null;\n\n let url = provider.urlTemplate;\n for (const field of provider.fields) {\n const value = (params?.[field.key] ?? '').trim().replace(/\\/+$/, '');\n if (!value) return null; // required field not filled → cannot build a link\n url = url.split(`{${field.key}}`).join(value);\n }\n\n url = url.split('{id}').join(encodeURIComponent(ticketId));\n if (url.includes('{') || url.includes('}')) return null; // unresolved token\n\n return toSafeHttpUrl(url);\n}\n\n/**\n * Convenience wrapper for the configuration shape: looks up the provider by id and\n * picks its field values out of the per-provider `allParams` map before delegating\n * to {@link buildTicketUrl}. Returns `null` for an unknown provider, an empty id, or\n * any input that would not resolve to a safe `http(s)` link.\n */\nexport function resolveTicketUrl(\n providerId: string,\n allParams: Record<string, Record<string, string>>,\n ticketId?: string,\n): string | null {\n const id = (ticketId ?? '').trim();\n if (!id) return null;\n const provider = findIssueTrackerProvider(providerId);\n if (!provider) return null;\n return buildTicketUrl(provider, allParams?.[providerId] ?? {}, id);\n}\n\n/** Returns the normalized href only for `http:`/`https:` URLs, otherwise `null`. */\nfunction toSafeHttpUrl(candidate: string): string | null {\n try {\n const parsed = new URL(candidate);\n return parsed.protocol === 'http:' || parsed.protocol === 'https:' ? parsed.href : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Builds the traceability comment emitted above the generated `it()` block:\n * `// {id} — {url}` when a link is available, otherwise `// {id}`.\n */\nexport function buildTicketComment(id: string, url: string | null): string {\n const ticketId = (id ?? '').trim();\n return url ? `// ${ticketId} — ${url}` : `// ${ticketId}`;\n}\n","import { type RecordingService } from './recording.service';\r\n\r\nconst INTERCEPTED_METHODS = ['GET', 'POST', 'PUT'] as const;\r\ntype InterceptedMethod = (typeof INTERCEPTED_METHODS)[number];\r\n\r\nexport function generateAlias(method: string, url: string): string {\r\n try {\r\n const u = new URL(url, 'http://localhost');\r\n const path = u.pathname\r\n .replace(/[^a-zA-Z0-9]/g, '-')\r\n .replace(/-+/g, '-')\r\n .replace(/(^-)|(-$)/g, '');\r\n return `${method.toLowerCase()}-${path}`;\r\n } catch {\r\n return `${method.toLowerCase()}-intercepted-request`;\r\n }\r\n}\r\n\r\nfunction buildValidations(base: string, obj: Record<string, unknown>): string {\r\n return Object.keys(obj)\r\n .filter((key) => key !== 'id' && key !== 'uid')\r\n .map((key) => `expect(${base}.${key}).to.equal(${JSON.stringify(obj[key])});`)\r\n .join('\\n');\r\n}\r\n\r\nfunction buildCyWaitCommand(\r\n method: string,\r\n alias: string,\r\n extendedHttp: boolean,\r\n requestBody: Record<string, unknown> | null,\r\n responseBody: Record<string, unknown> | null\r\n): string {\r\n if (extendedHttp && method === 'GET' && responseBody) {\r\n const validations = buildValidations('interception.response.body', responseBody);\r\n return `cy.wait('@${alias}').then((interception) => {\\n if (interception.response) {\\n${validations}\\n }\\n})`;\r\n }\r\n if (extendedHttp && (method === 'POST' || method === 'PUT') && requestBody) {\r\n const validations = buildValidations('interception.request.body', requestBody);\r\n return `cy.wait('@${alias}').then((interception) => {\\n${validations}\\n})`;\r\n }\r\n return `cy.wait('@${alias}').then((interception) => { })`;\r\n}\r\n\r\nfunction parseJsonObject(text: string): Record<string, unknown> | null {\r\n try {\r\n const parsed = JSON.parse(text);\r\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\r\n return parsed as Record<string, unknown>;\r\n }\r\n } catch {\r\n // Non-JSON or array — fall through\r\n }\r\n return null;\r\n}\r\n\r\n/** Returns pretty-printed JSON (objects OR arrays) for a fixture, or null. */\r\nfunction prettyJsonOrNull(text: string): string | null {\r\n try {\r\n const parsed = JSON.parse(text);\r\n if (parsed && typeof parsed === 'object') return JSON.stringify(parsed, null, 2);\r\n } catch {\r\n // not JSON\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseRequestBody(init?: RequestInit): Record<string, unknown> | null {\r\n const body = init?.body;\r\n if (typeof body === 'string') return parseJsonObject(body);\r\n return null;\r\n}\r\n\r\nfunction resolveUrl(input: RequestInfo | URL): string {\r\n if (typeof input === 'string') return input;\r\n if (input instanceof URL) return input.href;\r\n return input.url;\r\n}\r\n\r\nfunction resolveMethod(input: RequestInfo | URL, init?: RequestInit): string {\r\n if (init?.method) return init.method.toUpperCase();\r\n if (input instanceof Request) return input.method.toUpperCase();\r\n return 'GET';\r\n}\r\n\r\nexport class HttpMonitor {\r\n private originalFetch: typeof window.fetch | null = null;\r\n private originalXHR: typeof XMLHttpRequest | null = null;\r\n\r\n constructor(private readonly recording: RecordingService) {}\r\n\r\n install(): void {\r\n this.installFetch();\r\n this.installXhr();\r\n }\r\n\r\n uninstall(): void {\r\n this.uninstallFetch();\r\n this.uninstallXhr();\r\n }\r\n\r\n isExtendedHttpEnabled(): boolean {\r\n return localStorage.getItem('extendedHttpCommands') === 'true';\r\n }\r\n\r\n isFixtureModeEnabled(): boolean {\r\n return localStorage.getItem('fixtureMode') === 'true';\r\n }\r\n\r\n private installFetch(): void {\r\n if (this.originalFetch) return;\r\n const originalFetch = window.fetch;\r\n this.originalFetch = originalFetch;\r\n\r\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\r\n const response = await originalFetch(input, init);\r\n try {\r\n await this.handleFetchInterception(input, init, response.clone());\r\n } catch {\r\n // Never let monitoring errors break the actual request\r\n }\r\n return response;\r\n };\r\n }\r\n\r\n private uninstallFetch(): void {\r\n if (!this.originalFetch) return;\r\n window.fetch = this.originalFetch;\r\n this.originalFetch = null;\r\n }\r\n\r\n private installXhr(): void {\r\n if (this.originalXHR) return;\r\n this.originalXHR = window.XMLHttpRequest;\r\n const OrigXHR = this.originalXHR;\r\n const handleXhrInterception = this.handleXhrInterception.bind(this);\r\n\r\n window.XMLHttpRequest = class extends OrigXHR {\r\n private _xhrMethod = 'GET';\r\n private _xhrUrl = '';\r\n private _xhrRequestBody: Record<string, unknown> | null = null;\r\n\r\n override open(\r\n method: string,\r\n url: string | URL,\r\n async = true,\r\n user?: string | null,\r\n password?: string | null\r\n ): void {\r\n this._xhrMethod = method.toUpperCase();\r\n this._xhrUrl = url instanceof URL ? url.href : url;\r\n super.open(method, url as string, async, user, password);\r\n }\r\n\r\n override send(body?: Document | XMLHttpRequestBodyInit | null): void {\r\n if (typeof body === 'string') {\r\n this._xhrRequestBody = parseJsonObject(body);\r\n }\r\n this.addEventListener('load', () => {\r\n try {\r\n handleXhrInterception(\r\n this._xhrMethod,\r\n this._xhrUrl,\r\n this._xhrRequestBody,\r\n this.responseText\r\n );\r\n } catch {\r\n // Never let monitoring errors surface\r\n }\r\n });\r\n super.send(body);\r\n }\r\n } as unknown as typeof XMLHttpRequest;\r\n }\r\n\r\n private uninstallXhr(): void {\r\n if (!this.originalXHR) return;\r\n window.XMLHttpRequest = this.originalXHR;\r\n this.originalXHR = null;\r\n }\r\n\r\n private async handleFetchInterception(\r\n input: RequestInfo | URL,\r\n init: RequestInit | undefined,\r\n responseClone: Response\r\n ): Promise<void> {\r\n const method = resolveMethod(input, init);\r\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method)) return;\r\n\r\n const url = resolveUrl(input);\r\n const alias = generateAlias(method, url);\r\n\r\n // Fixture (stub) mode: a GET with a JSON body becomes a fixture + stub.\r\n if (this.isFixtureModeEnabled() && method === 'GET') {\r\n const pretty = prettyJsonOrNull(await responseClone.text());\r\n const fixtureFile = `${alias}.json`;\r\n if (pretty !== null) this.recording.registerFixture(fixtureFile, pretty);\r\n this.recording.registerInterceptor(method, url, alias, pretty !== null ? fixtureFile : undefined);\r\n this.recording.addCommand(`cy.wait('@${alias}').then((interception) => { })`);\r\n return; // body already consumed; can't re-read for validations\r\n }\r\n\r\n this.recording.registerInterceptor(method, url, alias);\r\n\r\n const extendedHttp = this.isExtendedHttpEnabled();\r\n const requestBody = extendedHttp ? parseRequestBody(init) : null;\r\n let responseBody: Record<string, unknown> | null = null;\r\n if (extendedHttp) {\r\n try {\r\n responseBody = parseJsonObject(await responseClone.text());\r\n } catch {\r\n // Unreadable body — continue without validations\r\n }\r\n }\r\n\r\n const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);\r\n this.recording.addCommand(cmd);\r\n }\r\n\r\n private handleXhrInterception(\r\n method: string,\r\n url: string,\r\n requestBody: Record<string, unknown> | null,\r\n responseText: string\r\n ): void {\r\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method as InterceptedMethod)) return;\r\n\r\n const alias = generateAlias(method, url);\r\n\r\n // Fixture (stub) mode: a GET with a JSON body becomes a fixture + stub.\r\n if (this.isFixtureModeEnabled() && method === 'GET') {\r\n const pretty = prettyJsonOrNull(responseText);\r\n const fixtureFile = `${alias}.json`;\r\n if (pretty !== null) this.recording.registerFixture(fixtureFile, pretty);\r\n this.recording.registerInterceptor(method, url, alias, pretty !== null ? fixtureFile : undefined);\r\n this.recording.addCommand(`cy.wait('@${alias}').then((interception) => { })`);\r\n return;\r\n }\r\n\r\n this.recording.registerInterceptor(method, url, alias);\r\n\r\n const extendedHttp = this.isExtendedHttpEnabled();\r\n const responseBody = extendedHttp ? parseJsonObject(responseText) : null;\r\n\r\n const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);\r\n this.recording.addCommand(cmd);\r\n }\r\n}\r\n\r\n","export const SCROLLBAR_STYLES = `\r\n.swal2-popup::-webkit-scrollbar,\r\n.swal2-html-container::-webkit-scrollbar,\r\n.swal2-content::-webkit-scrollbar,\r\n.swal2-container::-webkit-scrollbar {\r\n width: 5px;\r\n height: 5px;\r\n background: transparent;\r\n}\r\n.swal2-popup::-webkit-scrollbar-thumb,\r\n.swal2-html-container::-webkit-scrollbar-thumb,\r\n.swal2-content::-webkit-scrollbar-thumb,\r\n.swal2-container::-webkit-scrollbar-thumb {\r\n background: #30363d;\r\n border-radius: 3px;\r\n}\r\n.swal2-popup::-webkit-scrollbar-thumb:hover,\r\n.swal2-html-container::-webkit-scrollbar-thumb:hover,\r\n.swal2-content::-webkit-scrollbar-thumb:hover {\r\n background: #484f58;\r\n}\r\n.swal2-popup::-webkit-scrollbar-track,\r\n.swal2-html-container::-webkit-scrollbar-track,\r\n.swal2-content::-webkit-scrollbar-track,\r\n.swal2-container::-webkit-scrollbar-track {\r\n background: transparent;\r\n}\r\n.swal2-popup, .swal2-html-container, .swal2-content, .swal2-container {\r\n scrollbar-width: thin;\r\n scrollbar-color: #30363d transparent;\r\n}\r\n`;\r\n\r\nexport const LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES = `\r\n.swal2-container, .swal2-popup {\r\n z-index: 99999 !important;\r\n}\r\n.swal2-container {\r\n padding: 0 !important;\r\n align-items: center !important;\r\n justify-content: center !important;\r\n}\r\n.swal2-popup {\r\n background: #161b22 !important;\r\n color: #e6edf3 !important;\r\n border-radius: 12px !important;\r\n box-shadow: 0 24px 64px rgba(0,0,0,0.72), 0 0 0 1px #30363d !important;\r\n border: none !important;\r\n padding: 0 !important;\r\n min-width: 400px;\r\n max-width: 90vw;\r\n min-height: 200px;\r\n max-height: 90vh;\r\n}\r\n/* Override SweetAlert2 v11's display:grid on .swal2-popup.swal2-modal */\r\n.swal2-popup.swal2-modal {\r\n display: flex !important;\r\n flex-direction: column !important;\r\n align-items: stretch !important;\r\n overflow: hidden !important;\r\n}\r\n.swal2-header {\r\n flex-shrink: 0 !important;\r\n flex-grow: 0 !important;\r\n overflow: hidden !important;\r\n}\r\n.swal2-title {\r\n color: #e6edf3 !important;\r\n font-weight: 600 !important;\r\n font-size: 14px !important;\r\n background: #161b22;\r\n padding: 14px 48px 13px 18px !important;\r\n margin: 0 !important;\r\n border-bottom: 1px solid #21262d;\r\n text-align: left !important;\r\n letter-spacing: 0.1px;\r\n white-space: nowrap !important;\r\n overflow: hidden !important;\r\n text-overflow: ellipsis !important;\r\n}\r\n.swal2-close {\r\n position: absolute !important;\r\n top: 10px !important;\r\n right: 12px !important;\r\n color: #8b949e !important;\r\n font-size: 1.1rem !important;\r\n z-index: 1 !important;\r\n border-radius: 6px !important;\r\n width: 28px !important;\r\n height: 28px !important;\r\n line-height: 28px !important;\r\n transition: background 0.15s, color 0.15s !important;\r\n}\r\n.swal2-close:hover {\r\n background: #21262d !important;\r\n color: #e6edf3 !important;\r\n}\r\n/* In SweetAlert2 v11, .swal2-html-container is a direct child of .swal2-popup */\r\n.swal2-html-container {\r\n flex: 1 !important;\r\n min-height: 0 !important;\r\n background: #161b22;\r\n padding: 0 !important;\r\n margin: 0 !important;\r\n width: 100%;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n align-items: stretch;\r\n box-sizing: border-box;\r\n overflow: hidden !important;\r\n /* Left-align modal body text/code (SweetAlert defaults it to centre, which\r\n inherits into the panels — including their shadow DOM). Titles/buttons keep\r\n their own alignment. */\r\n text-align: left !important;\r\n}\r\n/* The single wrapper div we inject inside each modal fills the container */\r\n.swal2-html-container > div {\r\n flex: 1 !important;\r\n min-height: 0 !important;\r\n display: flex !important;\r\n flex-direction: column !important;\r\n overflow: hidden !important;\r\n}\r\n.swal2-actions, .swal2-footer {\r\n flex-shrink: 0 !important;\r\n flex-grow: 0 !important;\r\n}\r\n`;\r\n\r\nexport function injectStyles(css: string, id: string): void {\r\n if (document.getElementById(id)) return;\r\n const style = document.createElement('style');\r\n style.id = id;\r\n style.innerHTML = css;\r\n document.head.appendChild(style);\r\n}\r\n","export function makeModalResizable(\r\n modal: HTMLElement,\r\n options?: { minWidth?: number; minHeight?: number }\r\n): () => void {\r\n if (!modal || modal.querySelector('.modal-resizer')) return () => { /* no-op */ };\r\n\r\n const rect = modal.getBoundingClientRect();\r\n modal.style.position = 'fixed';\r\n modal.style.top = `${rect.top}px`;\r\n modal.style.left = `${rect.left}px`;\r\n modal.style.width = `${rect.width}px`;\r\n modal.style.margin = '0';\r\n modal.style.resize = 'both';\r\n modal.style.overflow = 'hidden';\r\n modal.style.minWidth = (options?.minWidth ?? 320) + 'px';\r\n modal.style.minHeight = (options?.minHeight ?? 180) + 'px';\r\n\r\n const resizer = document.createElement('div');\r\n resizer.className = 'modal-resizer';\r\n resizer.style.position = 'absolute';\r\n resizer.style.width = '16px';\r\n resizer.style.height = '16px';\r\n resizer.style.right = '2px';\r\n resizer.style.bottom = '2px';\r\n resizer.style.cursor = 'nwse-resize';\r\n resizer.style.background = 'rgba(0,0,0,0.1)';\r\n resizer.style.zIndex = '10';\r\n modal.appendChild(resizer);\r\n\r\n let isResizing = false;\r\n let lastX = 0;\r\n let lastY = 0;\r\n\r\n const mouseMove = (e: MouseEvent): void => {\r\n if (!isResizing) return;\r\n const dx = e.clientX - lastX;\r\n const dy = e.clientY - lastY;\r\n lastX = e.clientX;\r\n lastY = e.clientY;\r\n const rect = modal.getBoundingClientRect();\r\n modal.style.width = rect.width + dx + 'px';\r\n modal.style.height = rect.height + dy + 'px';\r\n };\r\n\r\n const mouseUp = (): void => {\r\n isResizing = false;\r\n document.body.style.userSelect = '';\r\n };\r\n\r\n resizer.addEventListener('mousedown', (e) => {\r\n e.preventDefault();\r\n isResizing = true;\r\n lastX = e.clientX;\r\n lastY = e.clientY;\r\n document.body.style.userSelect = 'none';\r\n });\r\n\r\n window.addEventListener('mousemove', mouseMove);\r\n window.addEventListener('mouseup', mouseUp);\r\n\r\n return () => {\r\n window.removeEventListener('mousemove', mouseMove);\r\n window.removeEventListener('mouseup', mouseUp);\r\n if (resizer.parentNode) resizer.parentNode.removeChild(resizer);\r\n };\r\n}\r\n\r\nfunction applyDraggable(swal: HTMLElement, dragArea: HTMLElement): void {\r\n let isDragging = false;\r\n let offsetX = 0;\r\n let offsetY = 0;\r\n\r\n dragArea.style.cursor = 'move';\r\n dragArea.onmousedown = (e: MouseEvent) => {\r\n isDragging = true;\r\n const rect = swal.getBoundingClientRect();\r\n offsetX = e.clientX - rect.left;\r\n offsetY = e.clientY - rect.top;\r\n document.onmousemove = (ev: MouseEvent) => {\r\n if (isDragging) {\r\n swal.style.position = 'fixed';\r\n swal.style.margin = '0';\r\n swal.style.left = `${ev.clientX - offsetX}px`;\r\n swal.style.top = `${ev.clientY - offsetY}px`;\r\n }\r\n };\r\n document.onmouseup = () => {\r\n isDragging = false;\r\n document.onmousemove = null;\r\n document.onmouseup = null;\r\n };\r\n };\r\n}\r\n\r\nfunction resolveDragArea(swal: HTMLElement): HTMLElement | null {\r\n return (swal.querySelector('.swal2-header') as HTMLElement | null)\r\n ?? (swal.querySelector('.swal2-title') as HTMLElement | null);\r\n}\r\n\r\nexport function makeSwalDraggable(): void {\r\n const popups = document.querySelectorAll('.swal2-popup');\r\n if (!popups.length) return;\r\n const swal = popups[popups.length - 1] as HTMLElement;\r\n const dragArea = resolveDragArea(swal);\r\n if (!dragArea) return;\r\n applyDraggable(swal, dragArea);\r\n}\r\n\r\nexport function makeSwalDraggableByContentId(contentId: string): void {\r\n const content = document.getElementById(contentId);\r\n if (!content) {\r\n makeSwalDraggable();\r\n return;\r\n }\r\n const swal = (content.closest('.swal2-popup') as HTMLElement | null)\r\n ?? (document.querySelector('.swal2-popup') as HTMLElement | null);\r\n if (!swal) return;\r\n const dragArea = resolveDragArea(swal);\r\n if (!dragArea) return;\r\n applyDraggable(swal, dragArea);\r\n}\r\n\r\nexport function setSwal2DataCyAttribute(dataCy = 'lib-e2e-cypress-for-dummys'): void {\r\n document.querySelector('.swal2-container')?.setAttribute('data-cy', dataCy);\r\n document.querySelector('.swal2-html-container')?.setAttribute('data-cy', dataCy);\r\n document.querySelector('.swal2-title')?.setAttribute('data-cy', dataCy);\r\n}\r\n","export function showToast(message: string, isSuccess = true): void {\r\n const toast = document.createElement('div');\r\n toast.textContent = message;\r\n toast.style.position = 'fixed';\r\n toast.style.top = '30px';\r\n toast.style.right = '30px';\r\n toast.style.padding = '16px 24px';\r\n toast.style.background = isSuccess ? '#4caf50' : '#f44336';\r\n toast.style.color = '#fff';\r\n toast.style.borderRadius = '8px';\r\n toast.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)';\r\n toast.style.zIndex = '9999';\r\n toast.style.fontSize = '1rem';\r\n toast.style.fontWeight = 'bold';\r\n toast.style.pointerEvents = 'none';\r\n document.body.appendChild(toast);\r\n setTimeout(() => toast.remove(), 3000);\r\n}\r\n","import type { TestWithDetails } from '../services/persistence.service';\n\n/** How the user chose which tests to export. */\nexport type ExportMode = 'all' | 'manual' | 'tags';\n\nexport interface ExportSelectionOptions {\n /** Test ids to include in `manual` mode. */\n ids?: Iterable<number>;\n /** Tags to match in `tags` mode. */\n tags?: Iterable<string>;\n}\n\n/**\n * Returns the subset of tests to export for a given selection mode.\n *\n * - `all` → every test (a shallow copy).\n * - `manual` → tests whose id is in `opts.ids`. Empty/absent ids → none.\n * - `tags` → tests carrying at least one of `opts.tags` (OR semantics).\n * Empty/absent tags → none.\n *\n * Pure: never mutates its inputs.\n */\nexport function selectTestsForExport(\n tests: TestWithDetails[],\n mode: ExportMode,\n opts: ExportSelectionOptions = {},\n): TestWithDetails[] {\n if (mode === 'all') return [...tests];\n\n if (mode === 'manual') {\n const ids = new Set(opts.ids ?? []);\n return tests.filter((t) => ids.has(t.id));\n }\n\n // 'tags' — include a test if it carries ANY of the selected tags (OR).\n const tags = new Set(opts.tags ?? []);\n if (tags.size === 0) return [];\n return tests.filter((t) => (t.tags ?? []).some((tag) => tags.has(tag)));\n}\n","/**\n * True when a hostname refers to the local machine — used to gate dev-only\n * features (e.g. launching a Cypress run via the local runner) so they are\n * offered only when the app is served locally, not from a deployed environment.\n *\n * Treats as local: localhost, *.localhost, 127.0.0.1, ::1, 0.0.0.0, and the\n * empty hostname (e.g. file:// URLs). Case-insensitive.\n */\nexport function isLocalHost(hostname: string): boolean {\n if (!hostname) return true;\n const h = hostname.toLowerCase();\n return (\n h === 'localhost' ||\n h.endsWith('.localhost') ||\n h === '127.0.0.1' ||\n h === '::1' ||\n h === '0.0.0.0'\n );\n}\n","/**\r\n * Geometry helpers for the draggable recording widget (spec 007).\r\n * Pure functions — no DOM — so the drag/clamp/expansion logic is unit-testable\r\n * without real layout (jsdom returns 0-sized rects).\r\n */\r\n\r\nexport type ExpandDirection = 'up-left' | 'up-right' | 'down-left' | 'down-right';\r\n\r\nexport interface Point {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/** Toggle radius (44/2) + small gap, so the toggle never touches the edge. */\r\nexport const TOGGLE_MARGIN = 30;\r\n\r\n/** Pixels the pointer must travel before a press becomes a drag (vs a click). */\r\nexport const DRAG_THRESHOLD = 5;\r\n\r\n/** Distance, in px, from the bottom-right edges of the original (default) anchor. */\r\nconst DEFAULT_EDGE_OFFSET = 46;\r\n\r\n/**\r\n * Toggle-centre offset inside the 190×190 widget box, per expansion direction.\r\n * The toggle sits at the box corner nearest the screen edge so the arc always\r\n * expands toward the viewport interior (and stays inside the box / on screen).\r\n */\r\nexport function boxOffsetForDirection(dir: ExpandDirection): Point {\r\n return {\r\n x: dir.endsWith('left') ? 144 : 46,\r\n y: dir.startsWith('up') ? 144 : 46,\r\n };\r\n}\r\n\r\n/** Clamps the toggle-centre so the toggle button stays fully on screen. */\r\nexport function clampTogglePosition(\r\n x: number,\r\n y: number,\r\n vw: number,\r\n vh: number,\r\n margin: number = TOGGLE_MARGIN,\r\n): Point {\r\n const maxX = Math.max(margin, vw - margin);\r\n const maxY = Math.max(margin, vh - margin);\r\n return {\r\n x: Math.min(Math.max(x, margin), maxX),\r\n y: Math.min(Math.max(y, margin), maxY),\r\n };\r\n}\r\n\r\n/**\r\n * Chooses the radial expansion direction so the menu opens toward the centre of\r\n * the viewport (top half → expand down; left half → expand right).\r\n */\r\nexport function resolveExpandDirection(x: number, y: number, vw: number, vh: number): ExpandDirection {\r\n const vertical = y < vh / 2 ? 'down' : 'up';\r\n const horizontal = x < vw / 2 ? 'right' : 'left';\r\n return `${vertical}-${horizontal}` as ExpandDirection;\r\n}\r\n\r\n/** Default toggle-centre (bottom-right corner), matching the original CSS anchor. */\r\nexport function defaultTogglePosition(vw: number, vh: number): Point {\r\n return { x: vw - DEFAULT_EDGE_OFFSET, y: vh - DEFAULT_EDGE_OFFSET };\r\n}\r\n\r\n/** Box top-left for a given (clamped) toggle-centre and direction. */\r\nexport function boxTopLeftFor(toggleCentre: Point, dir: ExpandDirection): Point {\r\n const off = boxOffsetForDirection(dir);\r\n return { x: toggleCentre.x - off.x, y: toggleCentre.y - off.y };\r\n}\r\n","/**\n * Hand-authored Cypress autocomplete data (spec 013). Pure — no CodeMirror — so\n * it is unit-testable; `code-editor.ts` wraps it into a CodeMirror CompletionSource.\n */\n\n/** Methods offered after typing `cy.` */\nexport const CY_METHODS: string[] = [\n 'visit', 'get', 'contains', 'intercept', 'wait', 'request', 'url', 'location',\n 'viewport', 'fixture', 'wrap', 'reload', 'go', 'window', 'document', 'session',\n 'clearCookies', 'clearLocalStorage', 'screenshot', 'log',\n];\n\n/** Methods offered after a chained `.` (e.g. `cy.get('x').`). */\nexport const CHAIN_METHODS: string[] = [\n 'click', 'dblclick', 'rightclick', 'type', 'clear', 'select', 'check', 'uncheck',\n 'should', 'and', 'find', 'first', 'last', 'eq', 'then', 'its', 'invoke', 'as',\n 'trigger', 'focus', 'blur', 'scrollIntoView', 'within', 'parent', 'children',\n 'siblings', 'contains', 'each', 'filter', 'wait',\n];\n\n/** Top-level identifiers offered at the start of a statement. */\nexport const TOP_LEVEL: string[] = [\n 'cy', 'describe', 'it', 'context', 'beforeEach', 'afterEach', 'before', 'after', 'Cypress',\n];\n\n/** All completion labels (used for the pure filter and tests). */\nexport const CYPRESS_COMPLETIONS: string[] = [\n ...TOP_LEVEL,\n ...CY_METHODS.map((m) => `cy.${m}`),\n ...CHAIN_METHODS,\n];\n\n/** Case-insensitive substring filter over a label list. */\nexport function filterCompletions(list: string[], prefix: string): string[] {\n const p = prefix.toLowerCase();\n if (!p) return [...list];\n return list.filter((label) => label.toLowerCase().includes(p));\n}\n\n/** Convenience filter over the full completion set. */\nexport function filterCypressCompletions(prefix: string): string[] {\n return filterCompletions(CYPRESS_COMPLETIONS, prefix);\n}\n","import type { CompletionContext, CompletionResult, Completion } from '@codemirror/autocomplete';\nimport { CY_METHODS, CHAIN_METHODS, TOP_LEVEL, filterCompletions } from './cypress-completions';\n\n/**\n * Lazy CodeMirror 6 factory for the code editor (spec 013). CodeMirror is loaded\n * on demand (its own chunk) via dynamic import, so it never bloats the initial\n * bundle. Browser-only; not exercised in jsdom (see the file-preview fallback).\n */\n\nexport interface CodeEditorHandle {\n getValue(): string;\n setValue(value: string): void;\n focus(): void;\n destroy(): void;\n}\n\nexport interface CreateCodeEditorOptions {\n parent: HTMLElement;\n root?: Document | ShadowRoot;\n doc: string;\n onChange?: (value: string) => void;\n}\n\nfunction toOptions(labels: string[], type: string): Completion[] {\n return labels.map((label) => ({ label, type }));\n}\n\n/** CodeMirror completion source backed by the hand-authored Cypress command lists. */\nfunction cypressCompletionSource(context: CompletionContext): CompletionResult | null {\n const cyMatch = context.matchBefore(/cy\\.\\w*$/);\n if (cyMatch) {\n return { from: cyMatch.from + 3, options: toOptions(filterCompletions(CY_METHODS, cyMatch.text.slice(3)), 'method') };\n }\n const chainMatch = context.matchBefore(/\\.\\w*$/);\n if (chainMatch) {\n return { from: chainMatch.from + 1, options: toOptions(filterCompletions(CHAIN_METHODS, chainMatch.text.slice(1)), 'method') };\n }\n const word = context.matchBefore(/\\w*/);\n if (!word || (word.from === word.to && !context.explicit)) return null;\n return { from: word.from, options: toOptions(filterCompletions(TOP_LEVEL, word.text), 'keyword') };\n}\n\nexport async function createCodeEditor(opts: CreateCodeEditorOptions): Promise<CodeEditorHandle> {\n const [view, state, language, langJs, autocomplete, commands, highlight] = await Promise.all([\n import('@codemirror/view'),\n import('@codemirror/state'),\n import('@codemirror/language'),\n import('@codemirror/lang-javascript'),\n import('@codemirror/autocomplete'),\n import('@codemirror/commands'),\n import('@lezer/highlight'),\n ]);\n\n const { EditorView, keymap, lineNumbers, highlightActiveLine, drawSelection } = view;\n const { EditorState } = state;\n const { syntaxHighlighting, HighlightStyle, indentOnInput, bracketMatching } = language;\n const { javascript } = langJs;\n const { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } = autocomplete;\n const { history, defaultKeymap, historyKeymap, indentWithTab } = commands;\n const { tags } = highlight;\n\n const darkHighlight = HighlightStyle.define([\n { tag: tags.keyword, color: '#ff7b72' },\n { tag: tags.string, color: '#a5d6ff' },\n { tag: [tags.function(tags.variableName), tags.function(tags.propertyName)], color: '#d2a8ff' },\n { tag: tags.number, color: '#79c0ff' },\n { tag: [tags.bool, tags.null], color: '#79c0ff' },\n { tag: tags.comment, color: '#8b949e', fontStyle: 'italic' },\n { tag: [tags.propertyName, tags.attributeName], color: '#7ee787' },\n { tag: [tags.typeName, tags.className], color: '#ffa657' },\n { tag: tags.operator, color: '#ff7b72' },\n { tag: [tags.brace, tags.bracket, tags.punctuation], color: '#c9d1d9' },\n ]);\n\n const theme = EditorView.theme(\n {\n '&': { color: '#c9d1d9', backgroundColor: '#0d1117', height: '100%', fontSize: '13px' },\n '.cm-scroller': { fontFamily: \"'Cascadia Code','Fira Code',Consolas,monospace\", overflow: 'auto' },\n '.cm-gutters': { backgroundColor: '#0d1117', color: '#484f58', border: 'none' },\n '.cm-activeLine': { backgroundColor: 'rgba(110,118,129,0.10)' },\n '.cm-activeLineGutter': { backgroundColor: 'transparent' },\n '&.cm-focused': { outline: 'none' },\n '.cm-tooltip': { background: '#161b22', border: '1px solid #30363d', color: '#c9d1d9', borderRadius: '6px' },\n '.cm-tooltip-autocomplete ul li[aria-selected]': { background: '#1f6feb', color: '#fff' },\n },\n { dark: true },\n );\n\n const editorView = new EditorView({\n parent: opts.parent,\n ...(opts.root ? { root: opts.root } : {}),\n state: EditorState.create({\n doc: opts.doc,\n extensions: [\n lineNumbers(),\n highlightActiveLine(),\n drawSelection(),\n history(),\n indentOnInput(),\n bracketMatching(),\n closeBrackets(),\n javascript({ typescript: true }),\n syntaxHighlighting(darkHighlight),\n autocompletion({ override: [cypressCompletionSource] }),\n keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...completionKeymap, indentWithTab]),\n theme,\n EditorView.updateListener.of((update) => {\n if (update.docChanged && opts.onChange) opts.onChange(update.state.doc.toString());\n }),\n ],\n }),\n });\n\n return {\n getValue: () => editorView.state.doc.toString(),\n setValue: (value: string) =>\n editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: value } }),\n focus: () => editorView.focus(),\n destroy: () => editorView.destroy(),\n };\n}\n","export const TEST_PREVISUALIZER_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; gap: 6px; padding: 10px 12px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d;\n }\n button {\n padding: 5px 12px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s; letter-spacing: 0.1px;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button.active { background: #2f81f7; color: #fff; }\n .section { padding: 10px 12px; flex-shrink: 0; }\n .section.section-cmds { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .section-title {\n font-size: 10px; font-weight: 600; color: #484f58; text-transform: uppercase;\n letter-spacing: 0.8px; margin-bottom: 7px; flex-shrink: 0;\n }\n .list {\n overflow-y: auto; background: #0d1117;\n border-radius: 8px; padding: 6px 8px;\n border: 1px solid #21262d;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .section-cmds .list { flex: 1; min-height: 0; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .item {\n display: flex; align-items: flex-start; gap: 6px;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n color: #c9d1d9; padding: 4px 8px; border-radius: 4px;\n word-break: break-all; line-height: 1.65;\n border-left: 2px solid transparent;\n transition: background 0.1s, border-color 0.1s;\n }\n .item:hover { background: #161b22; border-left-color: #2f81f7; }\n .cmd-text { flex: 1; }\n .item-actions {\n display: flex; gap: 3px; flex-shrink: 0;\n opacity: 0; transition: opacity 0.15s;\n }\n .item:hover .item-actions { opacity: 1; }\n .btn-step {\n width: 20px; height: 20px; border: none; border-radius: 3px; cursor: pointer;\n font-size: 12px; background: transparent; color: #484f58;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; justify-content: center;\n padding: 0; line-height: 1;\n }\n .btn-step:hover { background: #30363d; color: #e6edf3; }\n .btn-step-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n .empty { color: #484f58; font-size: 12px; padding: 20px 8px; text-align: center; }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport function renderTestPrevisualizer(\n commands: string[],\n interceptors: string[],\n showInterceptors: boolean,\n editable: boolean,\n t: (key: string) => string,\n): string {\n const editControls = (idx: number, total: number) => editable ? `\n <span class=\"item-actions\">\n <button class=\"btn-step\" data-move-up=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.UP_TITLE')}\" ${idx === 0 ? 'disabled style=\"opacity:.3\"' : ''}>↑</button>\n <button class=\"btn-step\" data-move-dn=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DOWN_TITLE')}\" ${idx === total - 1 ? 'disabled style=\"opacity:.3\"' : ''}>↓</button>\n <button class=\"btn-step btn-step-del\" data-del=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button>\n </span>` : '';\n\n const cmdItems = commands.length\n ? commands.map((c, i) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(c)}</span>\n ${editControls(i, commands.length)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_CMDS_YET')}</div>`;\n\n const icpEditControls = (idx: number) => editable\n ? `<span class=\"item-actions\"><button class=\"btn-step btn-step-del\" data-del-icp=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button></span>`\n : '';\n\n const icpSection = showInterceptors\n ? `<div class=\"section\" data-section=\"interceptors\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.INTERCEPTORS')}</div>\n <div class=\"list\">\n ${\n interceptors.length\n ? interceptors.map((ic, idx) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(ic)}</span>\n ${icpEditControls(idx)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_ICP_SHORT')}</div>`\n }\n </div>\n <button style=\"margin-top:6px\" data-action=\"copy-icp\">${t('TEST_PREVISUALIZER.COPY_ICP_BTN')}</button>\n </div>`\n : '';\n\n return `\n <div class=\"toolbar\">\n <button data-action=\"copy\">${t('TEST_PREVISUALIZER.COPY_CMDS_BTN')}</button>\n <button data-action=\"toggle-icp\" class=\"${showInterceptors ? 'active' : ''}\">\n ${showInterceptors ? t('TEST_PREVISUALIZER.HIDE_INTERCEPTORS') : t('TEST_PREVISUALIZER.SHOW_INTERCEPTORS')} (${interceptors.length})\n </button>\n </div>\n <div class=\"section section-cmds\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.SECTION_COMMANDS')} (${commands.length})</div>\n <div class=\"list\" data-ref=\"cmds\">${cmdItems}</div>\n </div>\n ${icpSection}`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\r\nimport { TEST_PREVISUALIZER_STYLES } from './test-previsualizer.styles';\r\nimport { renderTestPrevisualizer } from './test-previsualizer.template';\r\n\r\nexport class TestPrevisualizerElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private _commands: string[] = [];\r\n private _interceptors: string[] = [];\r\n private _showInterceptors = false;\r\n editable = false;\r\n translation: TranslationService = translationService;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n this.render();\r\n }\r\n\r\n get commands(): string[] {\r\n return this._commands;\r\n }\r\n set commands(v: string[]) {\r\n this._commands = v;\r\n this.render();\r\n }\r\n\r\n get interceptors(): string[] {\r\n return this._interceptors;\r\n }\r\n set interceptors(v: string[]) {\r\n this._interceptors = v;\r\n this.render();\r\n }\r\n\r\n get showInterceptors(): boolean {\r\n return this._showInterceptors;\r\n }\r\n\r\n toggleInterceptors(): void {\r\n this._showInterceptors = !this._showInterceptors;\r\n this.render();\r\n }\r\n\r\n copyToClipboard(): void {\r\n const text = this._commands.join('\\n');\r\n if (!text) return;\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n copyInterceptorsToClipboard(): void {\r\n const text = this._interceptors.join('\\n');\r\n if (!text) return;\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private dispatchDelete(index: number): void {\r\n this.dispatchEvent(new CustomEvent('deletecommand', { detail: index, bubbles: true, composed: true }));\r\n }\r\n\r\n private dispatchMove(from: number, to: number): void {\r\n this.dispatchEvent(new CustomEvent('movecommand', { detail: { from, to }, bubbles: true, composed: true }));\r\n }\r\n\r\n private dispatchDeleteInterceptor(index: number): void {\r\n this.dispatchEvent(new CustomEvent('deleteinterceptor', { detail: index, bubbles: true, composed: true }));\r\n }\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${TEST_PREVISUALIZER_STYLES}</style>${renderTestPrevisualizer(\r\n this._commands,\r\n this._interceptors,\r\n this._showInterceptors,\r\n this.editable,\r\n this.t.bind(this),\r\n )}`;\r\n\r\n const cmdsEl = this.shadow.querySelector<HTMLElement>('[data-ref=\"cmds\"]');\r\n if (cmdsEl) cmdsEl.scrollTop = cmdsEl.scrollHeight;\r\n\r\n this.shadow.querySelector('[data-action=\"copy\"]')?.addEventListener('click', () => this.copyToClipboard());\r\n this.shadow.querySelector('[data-action=\"toggle-icp\"]')?.addEventListener('click', () => this.toggleInterceptors());\r\n this.shadow.querySelector('[data-action=\"copy-icp\"]')?.addEventListener('click', () => this.copyInterceptorsToClipboard());\r\n\r\n if (this.editable) {\r\n this.shadow.querySelectorAll('[data-del]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.dispatchDelete(Number((btn as HTMLElement).dataset['del']));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-move-up]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n const idx = Number((btn as HTMLElement).dataset['moveUp']);\r\n this.dispatchMove(idx, idx - 1);\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-move-dn]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n const idx = Number((btn as HTMLElement).dataset['moveDn']);\r\n this.dispatchMove(idx, idx + 1);\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-del-icp]').forEach((btn) => {\r\n btn.addEventListener('click', (e) => {\r\n e.stopPropagation();\r\n this.dispatchDeleteInterceptor(Number((btn as HTMLElement).dataset['delIcp']));\r\n });\r\n });\r\n }\r\n }\r\n}\r\n\r\nif (!customElements.get('test-previsualizer')) {\r\n customElements.define('test-previsualizer', TestPrevisualizerElement);\r\n}\r\n","export const SAVE_TEST_STYLES = `\r\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\r\n * { box-sizing: border-box; }\r\n .container { padding: 24px 28px; text-align: left; }\r\n .btn-row { text-align: center; }\r\n p { margin: 0 0 20px; font-size: 14px; color: #8b949e; line-height: 1.5; }\r\n .btn-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }\r\n button {\r\n padding: 7px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\r\n font-size: 12px; font-weight: 500; transition: filter 0.15s, transform 0.1s;\r\n letter-spacing: 0.1px;\r\n }\r\n button:hover { filter: brightness(1.1); }\r\n button:active { transform: scale(0.97); }\r\n .btn-primary { background: #2f81f7; color: #fff; }\r\n .btn-success { background: #3fb950; color: #fff; }\r\n .btn-danger { background: transparent; color: #f85149; border: 1px solid rgba(248,81,73,0.5); }\r\n .btn-danger:hover { background: rgba(248,81,73,0.08); filter: none; }\r\n input[type=\"text\"] {\r\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\r\n border-radius: 8px; background: #0d1117; color: #e6edf3;\r\n font-size: 14px; outline: none; margin-bottom: 4px;\r\n transition: border-color 0.15s, box-shadow 0.15s;\r\n }\r\n input[type=\"text\"]:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\r\n input[type=\"text\"]::placeholder { color: #484f58; }\r\n textarea {\r\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\r\n border-radius: 8px; background: #0d1117; color: #e6edf3;\r\n font-size: 14px; outline: none; margin-bottom: 4px;\r\n font-family: inherit; resize: vertical; line-height: 1.5;\r\n transition: border-color 0.15s, box-shadow 0.15s;\r\n }\r\n textarea:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\r\n textarea::placeholder { color: #484f58; }\r\n .tag-label {\r\n font-size: 11px; color: #484f58; text-align: left; margin-bottom: 5px; display: block;\r\n }\r\n .tag-input-row { display: flex; gap: 6px; margin-bottom: 8px; }\r\n .tag-input-row input[type=\"text\"] {\r\n font-size: 12px; padding: 6px 10px; margin: 0;\r\n }\r\n .btn-tag-add {\r\n padding: 6px 12px; font-size: 12px; background: #21262d; color: #8b949e;\r\n border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\r\n transition: background 0.15s, color 0.12s; white-space: nowrap; flex-shrink: 0;\r\n }\r\n .btn-tag-add:hover { background: #30363d; color: #e6edf3; filter: none; }\r\n .chips { display: flex; flex-wrap: wrap; gap: 5px; min-height: 24px; text-align: left; }\r\n .chip {\r\n display: inline-flex; align-items: center; gap: 5px;\r\n background: rgba(47,129,247,0.15); color: #2f81f7;\r\n border: 1px solid rgba(47,129,247,0.3); border-radius: 20px;\r\n padding: 2px 10px 2px 10px; font-size: 11px; font-weight: 500;\r\n }\r\n .chip-del {\r\n cursor: pointer; color: #8b949e; font-size: 12px; line-height: 1;\r\n transition: color 0.12s; padding: 0; background: none; border: none;\r\n }\r\n .chip-del:hover { color: #f85149; filter: none; }\r\n`;\r\n","import { escHtml, escAttr } from '../../utils/html.utils';\n\nexport function renderSaveTestAsk(t: (key: string) => string): string {\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.ASK')}</p>\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-yes\">${t('SAVE_TEST.YES_CONTINUE')}</button>\n <button class=\"btn-danger\" id=\"btn-no\">${t('SAVE_TEST.NO_DISCARD')}</button>\n </div>\n </div>`;\n}\n\n/** View data for the optional ticket-reference field (spec 014). */\nexport interface SaveTestTicketView {\n /** The raw value the user is editing. */\n id: string;\n /** i18n key for the provider-aware placeholder. */\n placeholderKey: string;\n /** Whether the id fails the provider's soft format check (non-blocking). */\n invalid: boolean;\n}\n\nexport function renderSaveTestDesc(description: string, notes: string, tags: string[], ticket: SaveTestTicketView, t: (key: string) => string): string {\n const chipsHtml = tags.map((tag) =>\n `<span class=\"chip\">${escHtml(tag)}<button class=\"chip-del\" data-tag=\"${escAttr(tag)}\" title=\"${t('SAVE_TEST.REMOVE_TAG_TITLE')}\">✕</button></span>`\n ).join('');\n\n const ticketWarning = ticket.invalid\n ? `<div class=\"ticket-warning\" style=\"color:#d29922;font-size:11px;margin-top:2px\">${t('SAVE_TEST.TICKET_INVALID')}</div>`\n : '';\n\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.DESC_LABEL')} (<code>it()</code>):</p>\n <input id=\"desc-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.DESC_PLACEHOLDER')}\"\n value=\"${escAttr(description)}\" autocomplete=\"off\" />\n <span class=\"tag-label\">${t('SAVE_TEST.NOTES_LABEL')}</span>\n <textarea id=\"notes-input\" rows=\"3\" placeholder=\"${escAttr(t('SAVE_TEST.NOTES_PLACEHOLDER'))}\">${escHtml(notes)}</textarea>\n <span class=\"tag-label\">${t('SAVE_TEST.TICKET_LABEL')}</span>\n <input id=\"ticket-input\" type=\"text\" placeholder=\"${escAttr(t(ticket.placeholderKey))}\"\n value=\"${escAttr(ticket.id)}\" autocomplete=\"off\" />\n ${ticketWarning}\n <span class=\"tag-label\">${t('SAVE_TEST.TAGS_LABEL')}</span>\n <div class=\"tag-input-row\">\n <input id=\"tag-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.TAGS_PLACEHOLDER')}\" autocomplete=\"off\" />\n <button class=\"btn-tag-add\" id=\"btn-add-tag\">${t('SAVE_TEST.ADD_TAG')}</button>\n </div>\n <div class=\"chips\" id=\"chips-container\">${chipsHtml || `<span style=\"color:#484f58;font-size:11px\">${t('SAVE_TEST.NO_TAGS')}</span>`}</div>\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-confirm\">${t('SAVE_TEST.SAVE_BTN')}</button>\n <button class=\"btn-success\" id=\"btn-export\">${t('SAVE_TEST.SAVE_AND_EDIT')}</button>\n <button class=\"btn-danger\" id=\"btn-cancel\">${t('SAVE_TEST.CANCEL')}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { DEFAULT_ISSUE_TRACKER_PROVIDER_ID, findIssueTrackerProvider, ISSUE_TRACKER_PROVIDERS } from '../../models/issue-tracker.model';\nimport { SAVE_TEST_STYLES } from './save-test.styles';\nimport { renderSaveTestAsk, renderSaveTestDesc, type SaveTestTicketView } from './save-test.template';\n\nexport class SaveTestElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _step: 'ask' | 'desc' = 'ask';\n description = '';\n notes = '';\n tags: string[] = [];\n ticketId = '';\n /** Set by the host from config so the ticket placeholder/validation is provider-aware. */\n issueTrackerProviderId = DEFAULT_ISSUE_TRACKER_PROVIDER_ID;\n translation: TranslationService = translationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void { this.render(); }\n\n get step(): 'ask' | 'desc' { return this._step; }\n\n askSave(): void { this._step = 'desc'; this.render(); }\n\n confirmSave(): void { this.dispatch('savetest', { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() || null }); }\n\n confirmSaveAndExport(): void { this.dispatch('saveandexport', { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() || null }); }\n\n cancel(): void { this.dispatch('savetest', { description: null, notes: '', tags: [], ticketId: null }); }\n\n restartComponent(): void { this._step = 'ask'; this.description = ''; this.notes = ''; this.tags = []; this.ticketId = ''; this.render(); }\n\n addTag(tag: string): void {\n const t = tag.trim().replace(/[,;]/g, '');\n if (t && !this.tags.includes(t)) {\n this.tags = [...this.tags, t];\n this.render();\n }\n }\n\n removeTag(tag: string): void {\n this.tags = this.tags.filter((t) => t !== tag);\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n /** Builds the ticket field view: provider-aware placeholder + soft (non-blocking) format check. */\n private ticketView(): SaveTestTicketView {\n const provider = findIssueTrackerProvider(this.issueTrackerProviderId) ?? ISSUE_TRACKER_PROVIDERS[0];\n const trimmed = this.ticketId.trim();\n let invalid = false;\n if (trimmed) {\n try { invalid = !new RegExp(provider.idPattern).test(trimmed); } catch { invalid = false; }\n }\n return { id: this.ticketId, placeholderKey: provider.idPlaceholderKey, invalid };\n }\n\n private dispatch(type: string, detail: { description: string | null; notes: string; tags: string[]; ticketId: string | null }): void {\n this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));\n }\n\n private render(): void {\n if (this._step === 'ask') {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestAsk(this.t.bind(this))}`;\n this.shadow.getElementById('btn-yes')?.addEventListener('click', () => this.askSave());\n this.shadow.getElementById('btn-no')?.addEventListener('click', () => this.cancel());\n } else {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.ticketView(), this.t.bind(this))}`;\n\n const descInput = this.shadow.getElementById('desc-input') as HTMLInputElement;\n const notesInput = this.shadow.getElementById('notes-input') as HTMLTextAreaElement;\n const ticketInput = this.shadow.getElementById('ticket-input') as HTMLInputElement;\n const tagInput = this.shadow.getElementById('tag-input') as HTMLInputElement;\n\n descInput.addEventListener('input', () => { this.description = descInput.value; });\n notesInput.addEventListener('input', () => { this.notes = notesInput.value; });\n // Keep ticketId live on every keystroke (for save), re-render on blur to refresh the warning.\n ticketInput.addEventListener('input', () => { this.ticketId = ticketInput.value; });\n ticketInput.addEventListener('change', () => { this.ticketId = ticketInput.value; this.render(); });\n\n const tryAddTag = () => {\n this.addTag(tagInput.value);\n tagInput.value = '';\n };\n this.shadow.getElementById('btn-add-tag')?.addEventListener('click', tryAddTag);\n tagInput.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ',') { e.preventDefault(); tryAddTag(); }\n });\n\n this.shadow.querySelectorAll<HTMLButtonElement>('.chip-del').forEach((btn) => {\n btn.addEventListener('click', () => this.removeTag(btn.dataset['tag'] ?? ''));\n });\n\n this.shadow.getElementById('btn-confirm')?.addEventListener('click', () => this.confirmSave());\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.confirmSaveAndExport());\n this.shadow.getElementById('btn-cancel')?.addEventListener('click', () => this.cancel());\n setTimeout(() => descInput.focus(), 60);\n }\n }\n}\n\nif (!customElements.get('save-test')) {\n customElements.define('save-test', SaveTestElement);\n}\n","export const TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; align-items: center; gap: 6px; padding: 8px 10px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d; flex-wrap: wrap;\n }\n .tag-filter { display: flex; gap: 5px; flex-wrap: wrap; flex: 1; }\n .tag-chip {\n padding: 2px 10px; border-radius: 20px; cursor: pointer; font-size: 11px; font-weight: 500;\n border: 1px solid #30363d; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s, border-color 0.12s;\n }\n .tag-chip:hover { background: #30363d; color: #e6edf3; }\n .tag-chip.active { background: rgba(47,129,247,0.2); color: #2f81f7; border-color: rgba(47,129,247,0.4); }\n .btn-select {\n padding: 4px 12px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-select:hover { background: #30363d; color: #e6edf3; }\n .btn-select.active { background: rgba(47,129,247,0.15); color: #2f81f7; border-color: rgba(47,129,247,0.3); }\n .describe-bar {\n display: flex; align-items: center; gap: 8px; padding: 8px 10px;\n background: rgba(47,129,247,0.06); border-bottom: 1px solid rgba(47,129,247,0.2);\n flex-wrap: wrap;\n }\n .describe-bar input {\n flex: 1; min-width: 150px; padding: 5px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px; color: #e6edf3;\n font-size: 12px; outline: none;\n }\n .describe-bar input:focus { border-color: #2f81f7; }\n .btn-gen-describe {\n padding: 5px 14px; border: 1px solid #2f81f7; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: rgba(47,129,247,0.15); color: #2f81f7;\n transition: background 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-gen-describe:hover { background: rgba(47,129,247,0.25); }\n .selected-count { font-size: 11px; color: #8b949e; }\n .describe-bar { flex-shrink: 0; }\n .list { padding: 8px; flex: 1; min-height: 0; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .empty { color: #484f58; text-align: center; padding: 32px; font-size: 13px; }\n .row {\n background: #0d1117; border-radius: 8px; margin-bottom: 6px;\n overflow: hidden; border: 1px solid #21262d;\n transition: border-color 0.15s;\n }\n .row:hover { border-color: #30363d; }\n .row.selected-row { border-color: rgba(47,129,247,0.5); }\n .row-header {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px; cursor: pointer; user-select: none;\n }\n .row-header:hover { background: rgba(48,54,61,0.3); }\n .test-name { flex: 1; font-size: 13px; font-weight: 500; color: #e6edf3; }\n .test-date { font-size: 10.5px; color: #484f58; margin-right: 4px; }\n .test-tags { display: flex; gap: 4px; margin-right: 4px; }\n .test-tag {\n padding: 1px 7px; border-radius: 20px; font-size: 10px;\n background: rgba(47,129,247,0.1); color: #8b949e; border: 1px solid rgba(47,129,247,0.2);\n }\n .btn-icon {\n padding: 3px 8px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n .btn-icon:hover { background: #30363d; color: #e6edf3; }\n .btn-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n input[type=\"checkbox\"] {\n width: 14px; height: 14px; accent-color: #2f81f7; cursor: pointer; flex-shrink: 0;\n }\n .row-body {\n background: #0d1117; padding: 10px 14px;\n border-top: 1px solid #21262d;\n }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .code-preview {\n margin: 0; padding: 10px 12px; background: #161b22;\n border-radius: 6px; border: 1px solid #21262d;\n font-size: 11px; color: #c9d1d9; line-height: 1.7;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n overflow-x: auto; white-space: pre;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .code-preview::-webkit-scrollbar { height: 4px; }\n .code-preview::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .code-preview-icp { margin-top: 8px; }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport { normalizeBlock, escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { buildTicketComment } from '../../utils/ticket.utils';\nimport type { TestWithDetails } from '../../services/persistence.service';\n\nexport interface TestEditorState {\n tags: string[];\n visible: TestWithDetails[];\n selectedVisible: TestWithDetails[];\n activeTag: string | null;\n selectMode: boolean;\n selectedIds: Set<number>;\n describeName: string;\n expandedIndex: number | null;\n interceptorsByTest: Record<number, string[]>;\n groupByTicket: boolean;\n /** Resolved ticket URL per test id (null when it cannot build a safe http(s) link). */\n ticketUrlByTest: Record<number, string | null>;\n locale: string;\n}\n\nexport function renderTestEditor(state: TestEditorState, t: (key: string) => string): string {\n const { tags, visible, selectedVisible, activeTag, selectMode, selectedIds, describeName, expandedIndex, interceptorsByTest, groupByTicket, ticketUrlByTest, locale } = state;\n\n const tagFilterHtml = tags.length\n ? `<div class=\"tag-filter\">\n ${tags.map((tag) => `<button class=\"tag-chip${activeTag === tag ? ' active' : ''}\" data-filter-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}\n </div>`\n : `<div class=\"tag-filter\" style=\"color:#484f58;font-size:11px\">${t('TEST_EDITOR.NO_TAGS')}</div>`;\n\n const describeBarHtml = selectMode && selectedVisible.length > 0\n ? `<div class=\"describe-bar\">\n <span class=\"selected-count\">${selectedVisible.length} ${selectedVisible.length !== 1 ? t('TEST_EDITOR.SELECTED_PLURAL') : t('TEST_EDITOR.SELECTED_SINGULAR')}</span>\n <input id=\"describe-name\" type=\"text\" placeholder=\"${t('TEST_EDITOR.DESCRIBE_PLACEHOLDER')}\" value=\"${escAttr(describeName)}\" />\n <button class=\"btn-gen-describe\" id=\"btn-gen-describe\">${t('TEST_EDITOR.COPY_DESCRIBE')}</button>\n </div>`\n : '';\n\n // `i` is always the index into `visible` so the component's expand/copy/delete\n // handlers keep working unchanged — grouping only changes display order, not indices.\n const renderRow = (test: TestWithDetails, i: number): string => {\n const expanded = expandedIndex === i;\n const date = new Date(test.createdAt).toLocaleString(locale, { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });\n const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];\n const tagsHtml = (test.tags ?? []).length\n ? `<span class=\"test-tags\">${(test.tags ?? []).map((tag) => `<span class=\"test-tag\">${escHtml(tag)}</span>`).join('')}</span>`\n : '';\n const ticketId = (test.ticketId ?? '').trim();\n const ticketUrl = ticketUrlByTest[test.id] ?? null;\n const ticketHtml = !ticketId\n ? ''\n : ticketUrl\n ? `<a class=\"test-ticket\" data-ticket-link href=\"${escAttr(ticketUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color:#58a6ff;font-size:11px;text-decoration:none\">🎫 ${escHtml(ticketId)}</a>`\n : `<span class=\"test-ticket\" style=\"color:#8b949e;font-size:11px\">🎫 ${escHtml(ticketId)}</span>`;\n const checkbox = selectMode\n ? `<input type=\"checkbox\" ${selectedIds.has(test.id) ? 'checked' : ''} data-select=\"${test.id}\" />`\n : '';\n const hasIcps = (test.interceptors ?? []).length > 0;\n const ticketComment = ticketId ? `${buildTicketComment(ticketId, ticketUrl)}\\n` : '';\n const itBlockCode = `${ticketComment}it('${escapeSingleQuotes(test.name)}', () => {\\n${(test.commands ?? []).map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\n const icpBlockCode = icps.length ? `beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n${icps.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});` : '';\n const notesHtml = (expanded && test.notes)\n ? `<p class=\"test-notes\">${escHtml(test.notes)}</p>`\n : '';\n const body = expanded ? `\n <div class=\"row-body\">\n ${notesHtml}\n <pre class=\"code-preview\">${syntaxHighlight(itBlockCode)}</pre>\n ${icpBlockCode ? `<pre class=\"code-preview code-preview-icp\">${syntaxHighlight(icpBlockCode)}</pre>` : ''}\n </div>` : '';\n return `\n <div class=\"row${selectedIds.has(test.id) ? ' selected-row' : ''}\">\n <div class=\"row-header\" data-action=\"expand\" data-idx=\"${i}\">\n ${checkbox}\n <span class=\"test-name\">${escHtml(test.name)}</span>\n ${tagsHtml}\n ${ticketHtml}\n <span class=\"test-date\">${date}</span>\n <button class=\"btn-icon\" data-action=\"copy-cmds\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_CMDS_BTN')}\">${t('TEST_EDITOR.COPY_CMDS_BTN')}</button>\n ${hasIcps ? `<button class=\"btn-icon\" data-action=\"copy-icps\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_ICPS_BTN')}\">${t('TEST_EDITOR.COPY_ICPS_BTN')}</button>` : ''}\n <button class=\"btn-icon btn-del\" data-action=\"delete\" data-id=\"${test.id}\" title=\"${t('TEST_EDITOR.DELETE_TITLE')}\">🗑</button>\n </div>\n ${body}\n </div>`;\n };\n\n const indexed = visible.map((test, i) => ({ test, i }));\n\n const groupedRows = (): string => {\n const groups = new Map<string, Array<{ test: TestWithDetails; i: number }>>();\n for (const item of indexed) {\n const key = (item.test.ticketId ?? '').trim();\n const bucket = groups.get(key);\n if (bucket) bucket.push(item); else groups.set(key, [item]);\n }\n // Ticket groups sorted by id; the \"no ticket\" bucket ('') is always last.\n const keys = [...groups.keys()].sort((a, b) => (a === '' ? 1 : b === '' ? -1 : a.localeCompare(b)));\n return keys.map((key) => {\n const items = groups.get(key) ?? [];\n const label = key || t('TEST_EDITOR.NO_TICKET_GROUP');\n const url = key ? (ticketUrlByTest[items[0].test.id] ?? null) : null;\n const header = url\n ? `<a data-ticket-link href=\"${escAttr(url)}\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color:#58a6ff;text-decoration:none\">🎫 ${escHtml(label)}</a>`\n : `🎫 ${escHtml(label)}`;\n return `<div class=\"ticket-group\">\n <div class=\"ticket-group-hd\" style=\"padding:6px 10px;color:#8b949e;font-size:12px;font-weight:600;border-top:1px solid #21262d\">${header}</div>\n ${items.map(({ test, i }) => renderRow(test, i)).join('')}\n </div>`;\n }).join('');\n };\n\n const listBody = !visible.length\n ? `<div class=\"empty\">${t('TEST_EDITOR.NO_TESTS')}</div>`\n : groupByTicket ? groupedRows() : indexed.map(({ test, i }) => renderRow(test, i)).join('');\n\n return `\n <div class=\"toolbar\">\n ${tagFilterHtml}\n <button class=\"btn-select${groupByTicket ? ' active' : ''}\" id=\"btn-group-ticket\">${t('TEST_EDITOR.GROUP_BY_TICKET')}</button>\n <button class=\"btn-select${selectMode ? ' active' : ''}\" id=\"btn-select-mode\">\n ${selectMode ? t('TEST_EDITOR.CANCEL_SELECT') : t('TEST_EDITOR.MULTI_SELECT')}\n </button>\n </div>\n ${describeBarHtml}\n <div class=\"list\">\n ${listBody}\n </div>`;\n}\n","import { escHtml } from './html.utils';\n\nconst KEYWORDS = new Set([\n 'describe', 'it', 'xit', 'fit', 'xdescribe', 'fdescribe',\n 'beforeEach', 'afterEach', 'before', 'after', 'context',\n 'const', 'let', 'var', 'function', 'return', 'if', 'else',\n 'import', 'export', 'from', 'new', 'this', 'null', 'undefined',\n 'true', 'false', 'async', 'await', 'of', 'in', 'typeof', 'void',\n]);\n\nconst BUILTINS = new Set(['cy', 'expect', 'assert', 'Cypress', 'chai']);\n\nexport function syntaxHighlight(code: string): string {\n return code.split('\\n').map(highlightLine).join('\\n');\n}\n\nfunction highlightLine(line: string): string {\n let result = '';\n let i = 0;\n const len = line.length;\n\n while (i < len) {\n // Single-line comment\n if (line[i] === '/' && i + 1 < len && line[i + 1] === '/') {\n result += `<span class=\"sh-cmt\">${escHtml(line.slice(i))}</span>`;\n return result;\n }\n // String literal (single, double, or template)\n const q = line[i];\n if (q === \"'\" || q === '\"' || q === '`') {\n let j = i + 1;\n while (j < len) {\n if (line[j] === '\\\\') { j += 2; continue; }\n if (line[j] === q) { j++; break; }\n j++;\n }\n result += `<span class=\"sh-str\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Number (not preceded by identifier character)\n if (/[0-9]/.test(line[i]) && (i === 0 || !/[a-zA-Z_$]/.test(line[i - 1]))) {\n let j = i;\n while (j < len && /[0-9.]/.test(line[j])) j++;\n result += `<span class=\"sh-num\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Identifier, keyword, or builtin\n if (/[a-zA-Z_$]/.test(line[i])) {\n let j = i;\n while (j < len && /[a-zA-Z0-9_$]/.test(line[j])) j++;\n const word = line.slice(i, j);\n if (KEYWORDS.has(word)) {\n result += `<span class=\"sh-kw\">${escHtml(word)}</span>`;\n } else if (BUILTINS.has(word)) {\n result += `<span class=\"sh-bi\">${escHtml(word)}</span>`;\n } else {\n result += escHtml(word);\n }\n i = j;\n continue;\n }\n result += escHtml(line[i]);\n i++;\n }\n return result;\n}\n","import { PersistenceService } from '../../services/persistence.service';\r\nimport type { TestWithDetails } from '../../services/persistence.service';\r\nimport { translationService, type TranslationService } from '../../services/translation.service';\r\nimport { localeForLang } from '../../models/lang.model';\r\nimport { DEFAULT_ISSUE_TRACKER_PROVIDER_ID } from '../../models/issue-tracker.model';\r\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\r\nimport { resolveTicketUrl } from '../../utils/ticket.utils';\r\nimport { TEST_EDITOR_STYLES } from './test-editor.styles';\r\nimport { renderTestEditor } from './test-editor.template';\r\n\r\nexport class TestEditorElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n persistence!: PersistenceService;\r\n translation: TranslationService = translationService;\r\n tests: TestWithDetails[] = [];\r\n expandedIndex: number | null = null;\r\n interceptorsByTest: Record<number, string[]> = {};\r\n activeTag: string | null = null;\r\n selectMode = false;\r\n selectedIds: Set<number> = new Set();\r\n describeName = '';\r\n groupByTicket = false;\r\n issueTrackerProviderId = DEFAULT_ISSUE_TRACKER_PROVIDER_ID;\r\n issueTrackerParams: Record<string, Record<string, string>> = {};\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n this.loadTests();\r\n }\r\n\r\n async loadTests(): Promise<void> {\r\n const [tests, config] = await Promise.all([\r\n this.persistence.getAllTests(),\r\n this.persistence.getGeneralConfig(),\r\n ]);\r\n this.tests = tests;\r\n this.issueTrackerProviderId = (config?.['issueTrackerProviderId'] as string) ?? DEFAULT_ISSUE_TRACKER_PROVIDER_ID;\r\n this.issueTrackerParams = (config?.['issueTrackerParams'] as Record<string, Record<string, string>>) ?? {};\r\n this.render();\r\n }\r\n\r\n toggleGroupByTicket(): void {\r\n this.groupByTicket = !this.groupByTicket;\r\n this.render();\r\n }\r\n\r\n async deleteTest(id: number): Promise<void> {\r\n await this.persistence.deleteTest(id);\r\n this.selectedIds.delete(id);\r\n await this.loadTests();\r\n }\r\n\r\n toggleExpand(index: number): void {\r\n this.expandedIndex = this.expandedIndex === index ? null : index;\r\n if (this.expandedIndex !== null) {\r\n const test = this.tests[this.expandedIndex];\r\n if (test?.id && !this.interceptorsByTest[test.id]) {\r\n this.interceptorsByTest[test.id] = Array.isArray(test.interceptors) ? test.interceptors : [];\r\n }\r\n }\r\n this.render();\r\n }\r\n\r\n hasInterceptors(testId: number): boolean {\r\n return Array.isArray(this.interceptorsByTest[testId]) && this.interceptorsByTest[testId].length > 0;\r\n }\r\n\r\n toggleSelectMode(): void {\r\n this.selectMode = !this.selectMode;\r\n if (!this.selectMode) this.selectedIds.clear();\r\n this.render();\r\n }\r\n\r\n toggleSelectTest(id: number): void {\r\n if (this.selectedIds.has(id)) this.selectedIds.delete(id);\r\n else this.selectedIds.add(id);\r\n this.render();\r\n }\r\n\r\n generateDescribe(): void {\r\n const selected = this.tests.filter((t) => this.selectedIds.has(t.id));\r\n if (!selected.length) return;\r\n\r\n const name = this.describeName.trim() || this.t('TEST_EDITOR.DEFAULT_DESCRIBE');\r\n\r\n const allInterceptors = [...new Set(\r\n selected.flatMap((t) => this.interceptorsByTest[t.id] ?? t.interceptors ?? [])\r\n )];\r\n\r\n const beforeEach = allInterceptors.length\r\n ? ` beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n ${allInterceptors.join('\\n ')}\\n });\\n\\n`\r\n : '';\r\n\r\n const itBlocks = selected\r\n .map((t) => {\r\n const cmds = (t.commands ?? []).map((c) => ` ${c}`).join('\\n');\r\n return ` it('${escapeSingleQuotes(t.name ?? '')}', () => {\\n${cmds}\\n });`;\r\n })\r\n .join('\\n\\n');\r\n\r\n const block = `describe('${escapeSingleQuotes(name)}', () => {\\n${beforeEach}${itBlocks}\\n});`;\r\n navigator.clipboard?.writeText(block);\r\n }\r\n\r\n copyToClipboard(text: string): void {\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n get allTags(): string[] {\r\n const tagSet = new Set<string>();\r\n this.tests.forEach((t) => (t.tags ?? []).forEach((tag) => tagSet.add(tag)));\r\n return [...tagSet].sort();\r\n }\r\n\r\n get visibleTests(): TestWithDetails[] {\r\n const tag = this.activeTag;\r\n if (!tag) return this.tests;\r\n return this.tests.filter((t) => (t.tags ?? []).includes(tag));\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private render(): void {\r\n const tags = this.allTags;\r\n const visible = this.visibleTests;\r\n const selectedVisible = visible.filter((t) => this.selectedIds.has(t.id));\r\n\r\n const ticketUrlByTest: Record<number, string | null> = {};\r\n for (const test of visible) {\r\n if (test.ticketId) {\r\n ticketUrlByTest[test.id] = resolveTicketUrl(this.issueTrackerProviderId, this.issueTrackerParams, test.ticketId);\r\n }\r\n }\r\n\r\n this.shadow.innerHTML = `<style>${TEST_EDITOR_STYLES}</style>${renderTestEditor({\r\n tags,\r\n visible,\r\n selectedVisible,\r\n activeTag: this.activeTag,\r\n selectMode: this.selectMode,\r\n selectedIds: this.selectedIds,\r\n describeName: this.describeName,\r\n expandedIndex: this.expandedIndex,\r\n interceptorsByTest: this.interceptorsByTest,\r\n groupByTicket: this.groupByTicket,\r\n ticketUrlByTest,\r\n locale: localeForLang(this.translation.getLang()),\r\n }, this.t.bind(this))}`;\r\n\r\n this.shadow.getElementById('btn-select-mode')?.addEventListener('click', () => this.toggleSelectMode());\r\n this.shadow.getElementById('btn-group-ticket')?.addEventListener('click', () => this.toggleGroupByTicket());\r\n // Let the ticket link open in a new tab without also toggling the row's expand.\r\n this.shadow.querySelectorAll('[data-ticket-link]').forEach((el) =>\r\n el.addEventListener('click', (ev) => ev.stopPropagation()),\r\n );\r\n\r\n this.shadow.querySelectorAll('[data-filter-tag]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n const tag = (el as HTMLElement).dataset['filterTag'] ?? '';\r\n if (!tag) return;\r\n this.activeTag = this.activeTag === tag ? null : tag;\r\n this.render();\r\n });\r\n });\r\n\r\n const descInput = this.shadow.getElementById('describe-name') as HTMLInputElement | null;\r\n if (descInput) {\r\n descInput.addEventListener('input', () => { this.describeName = descInput.value; });\r\n }\r\n this.shadow.getElementById('btn-gen-describe')?.addEventListener('click', () => {\r\n this.describeName = descInput?.value ?? this.describeName;\r\n this.generateDescribe();\r\n });\r\n\r\n this.shadow.querySelectorAll('[data-select]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n this.toggleSelectTest(Number((el as HTMLElement).dataset['select']));\r\n });\r\n });\r\n\r\n this.shadow.querySelectorAll('[data-action=\"expand\"]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n if (this.selectMode) {\r\n const row = visible[Number((el as HTMLElement).dataset['idx'])];\r\n if (row) this.toggleSelectTest(row.id);\r\n } else {\r\n this.toggleExpand(Number((el as HTMLElement).dataset['idx']));\r\n }\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-action=\"delete\"]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n this.deleteTest(Number((el as HTMLElement).dataset['id']));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-action=\"copy-cmds\"]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n const idx = Number((el as HTMLElement).dataset['idx']);\r\n this.copyToClipboard((visible[idx]?.commands ?? []).join('\\n'));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-action=\"copy-icps\"]').forEach((el) => {\r\n el.addEventListener('click', (ev) => {\r\n ev.stopPropagation();\r\n const idx = Number((el as HTMLElement).dataset['idx']);\r\n const t = visible[idx];\r\n this.copyToClipboard((this.interceptorsByTest[t?.id] ?? t?.interceptors ?? []).join('\\n'));\r\n });\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('test-editor')) {\r\n customElements.define('test-editor', TestEditorElement);\r\n}\r\n","export const CONFIGURATION_STYLES = `\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n\n /* ── Grid container ───────────────────────────────────── */\n /* The SweetAlert2 host clips overflow (overflow:hidden), so the grid owns its\n own scroll — otherwise the last cards fall below the fold with no scrollbar. */\n .cfg-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n padding: 14px;\n max-height: 72vh;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: #30363d transparent;\n }\n .cfg-grid::-webkit-scrollbar { width: 8px; }\n .cfg-grid::-webkit-scrollbar-thumb { background: #30363d; border-radius: 4px; }\n .cfg-grid::-webkit-scrollbar-thumb:hover { background: #484f58; }\n .cfg-grid::-webkit-scrollbar-track { background: transparent; }\n\n /* ── Cards ────────────────────────────────────────────── */\n .card {\n background: #161b22;\n border: 1px solid #21262d;\n border-radius: 10px;\n padding: 14px 16px;\n transition: border-color 0.15s;\n }\n .card:hover { border-color: #30363d; }\n .card-wide { grid-column: 1 / -1; }\n\n /* ── Card header ──────────────────────────────────────── */\n .card-hd {\n display: flex; align-items: center; gap: 7px;\n font-size: 10px; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.8px; color: #484f58; margin-bottom: 12px;\n }\n .card-hd-icon { font-size: 13px; }\n\n /* ── Language ─────────────────────────────────────────── */\n .field-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\n .field-label { font-size: 12px; color: #8b949e; }\n select {\n background: #0d1117; color: #e6edf3; border: 1px solid #30363d;\n border-radius: 6px; padding: 6px 10px; font-size: 12px; outline: none;\n cursor: pointer; transition: border-color 0.15s; flex-shrink: 0;\n }\n select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n /* ── HTTP toggle ──────────────────────────────────────── */\n .check-row {\n display: flex; align-items: flex-start; gap: 10px;\n cursor: pointer; user-select: none;\n }\n input[type=\"checkbox\"] { width: 15px; height: 15px; margin-top: 2px; cursor: pointer; accent-color: #2f81f7; flex-shrink: 0; }\n .check-title { font-size: 12px; color: #c9d1d9; margin-bottom: 3px; }\n .check-sub { font-size: 10px; color: #484f58; line-height: 1.5; }\n\n /* ── Cypress folder ───────────────────────────────────── */\n .fs-layout { display: flex; gap: 12px; align-items: flex-start; }\n .fs-tree {\n flex-shrink: 0;\n margin: 0; padding: 8px 10px;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n font-size: 10px; color: #c9d1d9; line-height: 1.8;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n }\n .fs-right { display: flex; flex-direction: column; gap: 10px; flex: 1; }\n .fs-status {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: #8b949e;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n padding: 8px 10px;\n }\n .fs-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }\n .fs-dot.on { background: #3fb950; box-shadow: 0 0 6px rgba(63,185,80,.5); }\n .fs-dot.off { background: #484f58; }\n .fs-folder { color: #e6edf3; font-family: 'Cascadia Code','Fira Code','Consolas',monospace; font-size: 11px; }\n\n /* ── Buttons ──────────────────────────────────────────── */\n .btn-row { display: flex; gap: 8px; flex-wrap: wrap; }\n button {\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n button:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-import {\n display: inline-block;\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n .btn-import:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-danger { border-color: rgba(248,81,73,.4); color: #f85149; background: transparent; }\n .btn-danger:hover { background: rgba(248,81,73,.08); border-color: #f85149; color: #f85149; }\n .file-input { display: none; }\n\n /* ── Data section desc ────────────────────────────────── */\n .data-desc { font-size: 11px; color: #484f58; margin-bottom: 10px; line-height: 1.5; }\n\n /* ── Export overlay (modal) ───────────────────────────── */\n .export-overlay {\n position: fixed; inset: 0; z-index: 100000;\n background: rgba(1,4,9,0.7);\n display: flex; align-items: center; justify-content: center; padding: 20px;\n }\n .export-modal {\n width: 640px; max-width: 100%; max-height: 86vh;\n display: flex; flex-direction: column;\n background: #161b22; border: 1px solid #30363d; border-radius: 12px;\n box-shadow: 0 12px 40px rgba(0,0,0,0.5); overflow: hidden;\n }\n .export-hd {\n padding: 14px 18px; font-size: 13px; font-weight: 700;\n border-bottom: 1px solid #21262d; color: #e6edf3;\n }\n .export-modes { display: flex; gap: 6px; padding: 12px 18px 0; }\n .export-mode {\n flex: 1; padding: 7px 10px; font-size: 11px; border-radius: 6px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-mode:hover { background: #21262d; color: #e6edf3; }\n .export-mode.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-body {\n padding: 14px 18px; overflow-y: auto; flex: 1; min-height: 160px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .export-tag-hint { font-size: 12px; color: #484f58; margin-top: 12px; }\n .export-result-label {\n font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px;\n font-weight: 600; margin: 14px 0 6px;\n }\n .export-row-static { cursor: default; }\n .export-row-static:hover { background: transparent; }\n .export-all-desc { font-size: 12px; color: #8b949e; }\n .export-empty { font-size: 12px; color: #484f58; text-align: center; padding: 20px; }\n .export-list { display: flex; flex-direction: column; gap: 4px; }\n .export-row {\n display: flex; align-items: center; gap: 8px;\n padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 12px; color: #c9d1d9;\n }\n .export-row:hover { background: #0d1117; }\n .export-row-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .export-row-tag {\n font-size: 9px; color: #8b949e; background: #0d1117;\n border: 1px solid #30363d; border-radius: 10px; padding: 1px 7px; flex-shrink: 0;\n }\n .export-tags { display: flex; flex-wrap: wrap; gap: 6px; }\n .export-tag {\n padding: 4px 10px; font-size: 11px; border-radius: 12px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-tag:hover { background: #21262d; color: #e6edf3; }\n .export-tag.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-ft {\n display: flex; align-items: center; justify-content: space-between; gap: 10px;\n padding: 12px 18px; border-top: 1px solid #21262d;\n }\n .export-count { font-size: 11px; color: #8b949e; }\n .export-count b { color: #e6edf3; }\n .export-ft-actions { display: flex; gap: 8px; }\n .btn-export-confirm { background: #238636; border-color: #238636; color: #fff; }\n .btn-export-confirm:hover:not(:disabled) { background: #2ea043; border-color: #2ea043; }\n .btn-export-confirm:disabled { opacity: 0.45; cursor: not-allowed; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\r\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\r\nimport type { TestWithDetails } from '../../services/persistence.service';\r\nimport { ISSUE_TRACKER_PROVIDERS, findIssueTrackerProvider } from '../../models/issue-tracker.model';\r\n\r\nexport const LANGS = [\r\n { value: 'es', label: 'Español' },\r\n { value: 'en', label: 'English' },\r\n { value: 'fr', label: 'Français' },\r\n { value: 'it', label: 'Italiano' },\r\n { value: 'de', label: 'Deutsch' },\r\n];\r\n\r\nexport interface ConfigurationState {\r\n selectedLanguage: string;\r\n advancedHttpConfig: boolean;\r\n fixtureMode: boolean;\r\n selectorStrategy: string;\r\n filesystemGranted: boolean;\r\n cypressFolderName: string | null;\r\n smartSelectorEnabled: boolean;\r\n startHidden: boolean;\r\n resumeTtlMinutes: number;\r\n issueTrackerProviderId: string;\r\n issueTrackerParams: Record<string, Record<string, string>>;\r\n isExporting: boolean;\r\n exportMode: ExportMode;\r\n exportTests: TestWithDetails[];\r\n exportSelectedIds: Set<number>;\r\n exportSelectedTags: Set<string>;\r\n}\r\n\r\nexport function renderExportOverlay(state: ConfigurationState, t: (key: string) => string): string {\r\n const { isExporting, exportMode, exportTests, exportSelectedIds, exportSelectedTags } = state;\r\n if (!isExporting) return '';\r\n\r\n const count = selectTestsForExport(exportTests, exportMode, {\r\n ids: exportSelectedIds,\r\n tags: exportSelectedTags,\r\n }).length;\r\n\r\n const modeBtn = (mode: ExportMode, key: string) =>\r\n `<button class=\"export-mode ${exportMode === mode ? 'active' : ''}\" data-export-mode=\"${mode}\">${t(key)}</button>`;\r\n\r\n let body: string;\r\n if (exportTests.length === 0) {\r\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_EMPTY')}</div>`;\r\n } else if (exportMode === 'all') {\r\n body = `<div class=\"export-all-desc\">${t('CONFIG.EXPORT_ALL_DESC')}</div>`;\r\n } else if (exportMode === 'manual') {\r\n body = `<div class=\"export-list\">${exportTests.map((test) => `\r\n <label class=\"export-row\">\r\n <input type=\"checkbox\" data-export-test=\"${test.id}\" ${exportSelectedIds.has(test.id) ? 'checked' : ''} />\r\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\r\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\r\n </label>`).join('')}</div>`;\r\n } else {\r\n const allTags = [...new Set(exportTests.flatMap((test) => test.tags ?? []))].sort();\r\n if (!allTags.length) {\r\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_NO_TAGS')}</div>`;\r\n } else {\r\n const chips = `<div class=\"export-tags\">${allTags.map((tag) =>\r\n `<button class=\"export-tag ${exportSelectedTags.has(tag) ? 'active' : ''}\" data-export-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}</div>`;\r\n // Preview the tests that the selected tags resolve to, so QA sees exactly\r\n // what will be exported.\r\n const matched = selectTestsForExport(exportTests, 'tags', { tags: exportSelectedTags });\r\n const preview = exportSelectedTags.size === 0\r\n ? `<div class=\"export-tag-hint\">${t('CONFIG.EXPORT_TAGS_HINT')}</div>`\r\n : `<div class=\"export-result-label\">${t('CONFIG.EXPORT_RESULT_LABEL')}</div>\r\n <div class=\"export-list\">${matched.map((test) => `\r\n <div class=\"export-row export-row-static\">\r\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\r\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\r\n </div>`).join('')}</div>`;\r\n body = chips + preview;\r\n }\r\n }\r\n\r\n return `\r\n <div class=\"export-overlay\" id=\"export-overlay\">\r\n <div class=\"export-modal\">\r\n <div class=\"export-hd\">${t('CONFIG.EXPORT_DIALOG_TITLE')}</div>\r\n ${exportTests.length ? `<div class=\"export-modes\">\r\n ${modeBtn('all', 'CONFIG.EXPORT_MODE_ALL')}\r\n ${modeBtn('manual', 'CONFIG.EXPORT_MODE_MANUAL')}\r\n ${modeBtn('tags', 'CONFIG.EXPORT_MODE_TAGS')}\r\n </div>` : ''}\r\n <div class=\"export-body\">${body}</div>\r\n <div class=\"export-ft\">\r\n <span class=\"export-count\">${t('CONFIG.EXPORT_COUNT')} <b>${count}</b></span>\r\n <span class=\"export-ft-actions\">\r\n <button id=\"btn-export-confirm\" class=\"btn-export-confirm\" ${count === 0 ? 'disabled' : ''}>${t('CONFIG.EXPORT_CONFIRM')}</button>\r\n <button id=\"btn-export-cancel\">${t('CONFIG.EXPORT_CANCEL')}</button>\r\n </span>\r\n </div>\r\n </div>\r\n </div>`;\r\n}\r\n\r\nconst TRACKER_INPUT_STYLE =\r\n 'flex:1;min-width:180px;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none';\r\n\r\n/** Issue-tracker card: link-only, no sync (spec 014). */\r\nexport function renderIssueTrackerCard(state: ConfigurationState, t: (key: string) => string): string {\r\n const { issueTrackerProviderId, issueTrackerParams } = state;\r\n const provider = findIssueTrackerProvider(issueTrackerProviderId) ?? ISSUE_TRACKER_PROVIDERS[0];\r\n const values = issueTrackerParams[provider.id] ?? {};\r\n\r\n const options = ISSUE_TRACKER_PROVIDERS.map(\r\n (p) => `<option value=\"${escAttr(p.id)}\" ${provider.id === p.id ? 'selected' : ''}>${escHtml(t(p.labelKey))}</option>`,\r\n ).join('');\r\n\r\n const fields = provider.fields.map((f) => `\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${escHtml(t(f.labelKey))}</span>\r\n <input type=\"text\" data-tracker-field=\"${escAttr(f.key)}\" value=\"${escAttr(values[f.key] ?? '')}\"\r\n placeholder=\"${escAttr(t(f.placeholderKey))}\" style=\"${TRACKER_INPUT_STYLE}\" />\r\n </div>`).join('');\r\n\r\n return `\r\n <div class=\"card card-wide\">\r\n <div class=\"card-hd\">${t('CONFIG.ISSUE_TRACKER_SECTION')}</div>\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${t('CONFIG.ISSUE_TRACKER_LABEL')}</span>\r\n <select id=\"issue-tracker-provider\">${options}</select>\r\n </div>\r\n ${fields}\r\n <div class=\"check-sub issue-tracker-disclaimer\" style=\"margin-top:8px\">${t('CONFIG.ISSUE_TRACKER_DISCLAIMER')}</div>\r\n </div>`;\r\n}\r\n\r\nexport function renderConfiguration(state: ConfigurationState, t: (key: string) => string): string {\r\n const { selectedLanguage, advancedHttpConfig, fixtureMode, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes } = state;\r\n\r\n const langOptions = LANGS.map(\r\n (l) => `<option value=\"${l.value}\" ${selectedLanguage === l.value ? 'selected' : ''}>${l.label}</option>`,\r\n ).join('');\r\n\r\n return `\r\n <div class=\"cfg-grid\">\r\n\r\n <!-- Language -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.LANG_SECTION')}</div>\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${t('CONFIG.LANG_FIELD')}</span>\r\n <select id=\"lang-select\">${langOptions}</select>\r\n </div>\r\n </div>\r\n\r\n <!-- HTTP Advanced -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.HTTP_SECTION')}</div>\r\n <label class=\"check-row\">\r\n <input type=\"checkbox\" id=\"http-toggle\" ${advancedHttpConfig ? 'checked' : ''} />\r\n <div>\r\n <div class=\"check-title\">${t('CONFIG.HTTP_TITLE')}</div>\r\n <div class=\"check-sub\">${t('CONFIG.HTTP_SUB')}</div>\r\n </div>\r\n </label>\r\n </div>\r\n\r\n <!-- HTTP Fixtures -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.FIXTURE_SECTION')}</div>\r\n <label class=\"check-row\">\r\n <input type=\"checkbox\" id=\"fixture-toggle\" ${fixtureMode ? 'checked' : ''} />\r\n <div>\r\n <div class=\"check-title\">${t('CONFIG.FIXTURE_TITLE')}</div>\r\n <div class=\"check-sub\">${t('CONFIG.FIXTURE_SUB')}</div>\r\n </div>\r\n </label>\r\n </div>\r\n\r\n <!-- Smart Selector -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.SMART_SELECTOR_SECTION')}</div>\r\n <label class=\"check-row\">\r\n <input type=\"checkbox\" id=\"smart-selector-toggle\" ${smartSelectorEnabled ? 'checked' : ''} />\r\n <div>\r\n <div class=\"check-title\">${t('CONFIG.SMART_SELECTOR_TITLE')}</div>\r\n <div class=\"check-sub\">${t('CONFIG.SMART_SELECTOR_SUB')}</div>\r\n </div>\r\n </label>\r\n </div>\r\n\r\n <!-- Start Hidden -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.START_HIDDEN_SECTION')}</div>\r\n <label class=\"check-row\">\r\n <input type=\"checkbox\" id=\"start-hidden-toggle\" ${startHidden ? 'checked' : ''} />\r\n <div>\r\n <div class=\"check-title\">${t('CONFIG.START_HIDDEN_TITLE')}</div>\r\n <div class=\"check-sub\">${t('CONFIG.START_HIDDEN_SUB')}</div>\r\n </div>\r\n </label>\r\n </div>\r\n\r\n <!-- Widget position (draggable widget) -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.WIDGET_POSITION_SECTION')}</div>\r\n <div class=\"check-sub\" style=\"margin-bottom:10px\">${t('CONFIG.WIDGET_POSITION_HINT')}</div>\r\n <div class=\"btn-row\">\r\n <button id=\"btn-reset-position\">${t('CONFIG.WIDGET_POSITION_RESET_BTN')}</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Recording continuity (cross-app resume TTL) -->\r\n <div class=\"card\">\r\n <div class=\"card-hd\">${t('CONFIG.RESUME_TTL_SECTION')}</div>\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${t('CONFIG.RESUME_TTL_LABEL')}</span>\r\n <input type=\"number\" id=\"resume-ttl-input\" min=\"1\" step=\"1\" value=\"${resumeTtlMinutes}\"\r\n style=\"width:80px;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none\" />\r\n </div>\r\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.RESUME_TTL_HINT')}</div>\r\n </div>\r\n\r\n <!-- Selector Strategy -->\r\n <div class=\"card card-wide\">\r\n <div class=\"card-hd\">${t('CONFIG.SELECTOR_SECTION')}</div>\r\n <div class=\"field-row\">\r\n <span class=\"field-label\">${t('CONFIG.SELECTOR_LABEL')}</span>\r\n <select id=\"selector-strategy\">\r\n <option value=\"data-cy\" ${selectorStrategy === 'data-cy' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_DATACY')}</option>\r\n <option value=\"data-testid\" ${selectorStrategy === 'data-testid' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_TESTID')}</option>\r\n <option value=\"aria-label\" ${selectorStrategy === 'aria-label' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ARIA')}</option>\r\n <option value=\"id\" ${selectorStrategy === 'id' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ID')}</option>\r\n </select>\r\n </div>\r\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.SELECTOR_HINT')}</div>\r\n </div>\r\n\r\n <!-- Cypress Folder -->\r\n <div class=\"card card-wide\">\r\n <div class=\"card-hd\">${t('CONFIG.FOLDER_SECTION')}</div>\r\n <div class=\"fs-layout\">\r\n <pre class=\"fs-tree\">cypress/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_PICK_HINT')}</span>\r\n└── e2e/\r\n └── *.cy.ts</pre>\r\n <div class=\"fs-right\">\r\n <div class=\"fs-status\">\r\n <span class=\"fs-dot ${filesystemGranted ? 'on' : 'off'}\"></span>\r\n ${filesystemGranted && cypressFolderName\r\n ? `<span>${t('CONFIG.FOLDER_CONNECTED')}</span> <span class=\"fs-folder\">📁 ${escHtml(cypressFolderName)}</span>`\r\n : `<span>${t('CONFIG.FOLDER_NOT_SET')}</span>`}\r\n </div>\r\n <div class=\"btn-row\">\r\n <button id=\"btn-change-folder\">\r\n ${filesystemGranted ? t('CONFIG.FOLDER_CHANGE_BTN') : t('CONFIG.FOLDER_SELECT_BTN')}\r\n </button>\r\n ${filesystemGranted\r\n ? `<button id=\"btn-revoke\" class=\"btn-danger\">${t('CONFIG.FOLDER_REVOKE_BTN')}</button>`\r\n : ''}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Issue tracker (spec 014) -->\r\n ${renderIssueTrackerCard(state, t)}\r\n\r\n <!-- Data -->\r\n <div class=\"card card-wide\">\r\n <div class=\"card-hd\">${t('CONFIG.DATA_SECTION')}</div>\r\n <p class=\"data-desc\">${t('CONFIG.DATA_DESC')}</p>\r\n <div class=\"btn-row\">\r\n <button id=\"btn-export\">${t('CONFIG.EXPORT_BTN')}</button>\r\n <label style=\"cursor:pointer;margin:0\">\r\n <span class=\"btn-import\">${t('CONFIG.IMPORT_BTN')}</span>\r\n <input type=\"file\" class=\"file-input\" id=\"file-input\" accept=\".json\" />\r\n </label>\r\n </div>\r\n </div>\r\n\r\n </div>${renderExportOverlay(state, t)}`;\r\n}\r\n","import { PersistenceService } from '../../services/persistence.service';\r\nimport type { TestWithDetails } from '../../services/persistence.service';\r\nimport { TranslationService } from '../../services/translation.service';\r\nimport type { Lang } from '../../models/lang.model';\r\nimport type { SelectorStrategy } from '../../services/recording.service';\r\nimport { RESUME_TTL_CONFIG_KEY, DEFAULT_RESUME_TTL_MINUTES } from '../../models/active-session.model';\r\nimport { DEFAULT_ISSUE_TRACKER_PROVIDER_ID } from '../../models/issue-tracker.model';\r\nimport { showToast } from '../../utils/toast.utils';\r\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\r\nimport { CONFIGURATION_STYLES } from './configuration.styles';\r\nimport { renderConfiguration } from './configuration.template';\r\n\r\nexport class ConfigurationElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n persistence!: PersistenceService;\r\n translation!: TranslationService;\r\n selectedLanguage = 'es';\r\n advancedHttpConfig = false;\r\n fixtureMode = false;\r\n selectorStrategy: SelectorStrategy = 'data-cy';\r\n smartSelectorEnabled = true;\r\n startHidden = false;\r\n resumeTtlMinutes = DEFAULT_RESUME_TTL_MINUTES;\r\n issueTrackerProviderId = DEFAULT_ISSUE_TRACKER_PROVIDER_ID;\r\n issueTrackerParams: Record<string, Record<string, string>> = {};\r\n isExporting = false;\r\n exportMode: ExportMode = 'all';\r\n exportTests: TestWithDetails[] = [];\r\n exportSelectedIds: Set<number> = new Set();\r\n exportSelectedTags: Set<string> = new Set();\r\n private filesystemGranted = false;\r\n private cypressFolderName: string | null = null;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\r\n this.fixtureMode = localStorage.getItem('fixtureMode') === 'true';\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n if (!this.translation) this.translation = new TranslationService();\r\n this.loadConfig();\r\n this.render();\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private async loadConfig(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n if (config?.['language']) {\r\n this.selectedLanguage = config['language'] as string;\r\n this.translation.setLang(this.selectedLanguage as Lang);\r\n }\r\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\r\n this.fixtureMode = localStorage.getItem('fixtureMode') === 'true';\r\n this.selectorStrategy = (config?.['selectorStrategy'] as SelectorStrategy) ?? 'data-cy';\r\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\r\n this.startHidden = config?.['startHidden'] === 'true';\r\n // Only override when the key exists — otherwise an async load could clobber a\r\n // value just set via onResumeTtlChange (same pattern as `language`).\r\n const ttlRaw = config?.[RESUME_TTL_CONFIG_KEY];\r\n if (ttlRaw !== undefined && ttlRaw !== null) {\r\n const ttl = Number(ttlRaw);\r\n this.resumeTtlMinutes = Number.isFinite(ttl) && ttl > 0 ? ttl : DEFAULT_RESUME_TTL_MINUTES;\r\n }\r\n this.filesystemGranted = config?.['allowReadWriteFiles'] === 'true';\r\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\r\n this.cypressFolderName = handle?.name ?? null;\r\n // Only override when the key exists — a late async load must not clobber a value\r\n // just set via onIssueTracker*Change (same guard as `language` / resume TTL).\r\n if (config?.['issueTrackerProviderId'] !== undefined) {\r\n this.issueTrackerProviderId = config['issueTrackerProviderId'] as string;\r\n }\r\n if (config?.['issueTrackerParams'] !== undefined) {\r\n this.issueTrackerParams = config['issueTrackerParams'] as Record<string, Record<string, string>>;\r\n }\r\n this.render();\r\n }\r\n\r\n async onLanguageChange(lang: string): Promise<void> {\r\n this.selectedLanguage = lang;\r\n this.translation.setLang(lang as Lang);\r\n await this.persistence.setConfig({ language: lang });\r\n this.render();\r\n }\r\n\r\n onAdvancedHttpConfigChange(checked: boolean): void {\r\n this.advancedHttpConfig = checked;\r\n localStorage.setItem('extendedHttpCommands', checked ? 'true' : 'false');\r\n this.persistence.setConfig({ extendedHttpCommands: checked ? 'true' : 'false' });\r\n this.render();\r\n }\r\n\r\n onFixtureModeChange(checked: boolean): void {\r\n this.fixtureMode = checked;\r\n localStorage.setItem('fixtureMode', checked ? 'true' : 'false');\r\n this.persistence.setConfig({ fixtureMode: checked ? 'true' : 'false' });\r\n this.render();\r\n }\r\n\r\n async onStartHiddenChange(checked: boolean): Promise<void> {\r\n this.startHidden = checked;\r\n await this.persistence.setConfig({ startHidden: checked ? 'true' : 'false' });\r\n this.dispatchEvent(new CustomEvent('starthiddenchange', { detail: checked, bubbles: true, composed: true }));\r\n this.render();\r\n }\r\n\r\n async onResumeTtlChange(minutes: number): Promise<void> {\r\n const safe = Number.isFinite(minutes) && minutes > 0 ? Math.round(minutes) : DEFAULT_RESUME_TTL_MINUTES;\r\n this.resumeTtlMinutes = safe;\r\n await this.persistence.setConfig({ [RESUME_TTL_CONFIG_KEY]: safe });\r\n this.render();\r\n }\r\n\r\n /** Selects the issue-tracker provider (link-only, no sync — spec 014). */\r\n async onIssueTrackerProviderChange(id: string): Promise<void> {\r\n this.issueTrackerProviderId = id;\r\n await this.persistence.setConfig({ issueTrackerProviderId: id });\r\n this.render();\r\n }\r\n\r\n /** Stores a provider field value, scoped to the active provider so switching keeps values. */\r\n async onIssueTrackerParamChange(fieldKey: string, value: string): Promise<void> {\r\n const providerId = this.issueTrackerProviderId;\r\n const current = { ...(this.issueTrackerParams[providerId] ?? {}) };\r\n current[fieldKey] = value;\r\n this.issueTrackerParams = { ...this.issueTrackerParams, [providerId]: current };\r\n await this.persistence.setConfig({ issueTrackerParams: this.issueTrackerParams });\r\n }\r\n\r\n onResetWidgetPosition(): void {\r\n this.dispatchEvent(new CustomEvent('resetwidgetposition', { bubbles: true, composed: true }));\r\n showToast(this.t('CONFIG.WIDGET_POSITION_RESET_DONE'));\r\n }\r\n\r\n async onSmartSelectorChange(enabled: boolean): Promise<void> {\r\n this.smartSelectorEnabled = enabled;\r\n await this.persistence.setConfig({ smartSelectorEnabled: enabled ? 'true' : 'false' });\r\n this.dispatchEvent(new CustomEvent('smartselectorchange', { detail: enabled, bubbles: true, composed: true }));\r\n this.render();\r\n }\r\n\r\n async onSelectorStrategyChange(strategy: SelectorStrategy): Promise<void> {\r\n this.selectorStrategy = strategy;\r\n await this.persistence.setConfig({ selectorStrategy: strategy });\r\n this.dispatchEvent(new CustomEvent('selectorstrategychange', { detail: strategy, bubbles: true, composed: true }));\r\n this.render();\r\n }\r\n\r\n async changeFolder(): Promise<void> {\r\n try {\r\n await this.persistence.requestDirectoryPermissions();\r\n await this.loadConfig();\r\n showToast(this.t('CONFIG.FOLDER_UPDATED_TOAST'));\r\n } catch (e: unknown) {\r\n if ((e as DOMException)?.name !== 'AbortError') {\r\n showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\r\n }\r\n }\r\n }\r\n\r\n async revokeAccess(): Promise<void> {\r\n await this.persistence.setConfig({ allowReadWriteFiles: 'false', cypressDirectoryHandle: null });\r\n this.filesystemGranted = false;\r\n this.cypressFolderName = null;\r\n this.render();\r\n }\r\n\r\n private downloadTests(tests: TestWithDetails[]): void {\r\n const blob = new Blob([JSON.stringify({ tests, interceptors: [] }, null, 2)], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = 'e2e-cypress-export.json';\r\n a.click();\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n /** Downloads every saved test (used by the \"Todo\" mode and as a direct API). */\r\n async exportAllData(): Promise<void> {\r\n const tests = await this.persistence.getAllTests();\r\n this.downloadTests(tests);\r\n }\r\n\r\n /** Opens the export selection dialog, loading the current tests. */\r\n async openExportDialog(): Promise<void> {\r\n this.exportTests = await this.persistence.getAllTests();\r\n this.exportMode = 'all';\r\n this.exportSelectedIds = new Set();\r\n this.exportSelectedTags = new Set();\r\n this.isExporting = true;\r\n this.render();\r\n }\r\n\r\n cancelExport(): void {\r\n this.isExporting = false;\r\n this.exportSelectedIds.clear();\r\n this.exportSelectedTags.clear();\r\n this.render();\r\n }\r\n\r\n setExportMode(mode: ExportMode): void {\r\n this.exportMode = mode;\r\n this.render();\r\n }\r\n\r\n toggleExportTest(id: number): void {\r\n if (this.exportSelectedIds.has(id)) this.exportSelectedIds.delete(id);\r\n else this.exportSelectedIds.add(id);\r\n this.render();\r\n }\r\n\r\n toggleExportTag(tag: string): void {\r\n if (this.exportSelectedTags.has(tag)) this.exportSelectedTags.delete(tag);\r\n else this.exportSelectedTags.add(tag);\r\n this.render();\r\n }\r\n\r\n /** Downloads the tests resolved by the current mode + selection. No-op if empty. */\r\n confirmExport(): void {\r\n const subset = selectTestsForExport(this.exportTests, this.exportMode, {\r\n ids: this.exportSelectedIds,\r\n tags: this.exportSelectedTags,\r\n });\r\n if (!subset.length) return;\r\n this.downloadTests(subset);\r\n this.isExporting = false;\r\n this.exportSelectedIds.clear();\r\n this.exportSelectedTags.clear();\r\n this.render();\r\n }\r\n\r\n async importAllData(file: File): Promise<void> {\r\n const text = await file.text();\r\n let data: { tests: Record<string, unknown>[]; interceptors: Record<string, unknown>[] };\r\n try {\r\n data = JSON.parse(text);\r\n } catch {\r\n throw new Error(this.t('CONFIG.JSON_INVALID'));\r\n }\r\n if (!data || !Array.isArray(data.tests) || !Array.isArray(data.interceptors)) {\r\n throw new Error(this.t('CONFIG.JSON_BAD_FORMAT'));\r\n }\r\n // Merge: append the imported tests to whatever is already stored — never wipe\r\n // existing data (see docs/specs/004-merge-on-import.md).\r\n await this.persistence.ingestFileData(data.tests, data.interceptors);\r\n }\r\n\r\n private render(): void {\r\n this.shadow.innerHTML = `<style>${CONFIGURATION_STYLES}</style>${renderConfiguration({\r\n selectedLanguage: this.selectedLanguage,\r\n advancedHttpConfig: this.advancedHttpConfig,\r\n fixtureMode: this.fixtureMode,\r\n selectorStrategy: this.selectorStrategy,\r\n filesystemGranted: this.filesystemGranted,\r\n cypressFolderName: this.cypressFolderName,\r\n smartSelectorEnabled: this.smartSelectorEnabled,\r\n startHidden: this.startHidden,\r\n resumeTtlMinutes: this.resumeTtlMinutes,\r\n issueTrackerProviderId: this.issueTrackerProviderId,\r\n issueTrackerParams: this.issueTrackerParams,\r\n isExporting: this.isExporting,\r\n exportMode: this.exportMode,\r\n exportTests: this.exportTests,\r\n exportSelectedIds: this.exportSelectedIds,\r\n exportSelectedTags: this.exportSelectedTags,\r\n }, this.t.bind(this))}`;\r\n ;(this.shadow.getElementById('lang-select') as HTMLSelectElement).addEventListener('change', (e) =>\r\n this.onLanguageChange((e.target as HTMLSelectElement).value),\r\n )\r\n ;(this.shadow.getElementById('http-toggle') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onAdvancedHttpConfigChange((e.target as HTMLInputElement).checked),\r\n )\r\n ;(this.shadow.getElementById('fixture-toggle') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onFixtureModeChange((e.target as HTMLInputElement).checked),\r\n )\r\n ;(this.shadow.getElementById('smart-selector-toggle') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onSmartSelectorChange((e.target as HTMLInputElement).checked),\r\n )\r\n ;(this.shadow.getElementById('start-hidden-toggle') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onStartHiddenChange((e.target as HTMLInputElement).checked),\r\n )\r\n ;(this.shadow.getElementById('resume-ttl-input') as HTMLInputElement).addEventListener('change', (e) =>\r\n this.onResumeTtlChange(Number((e.target as HTMLInputElement).value)),\r\n )\r\n ;this.shadow.getElementById('btn-reset-position')?.addEventListener('click', () => this.onResetWidgetPosition())\r\n ;(this.shadow.getElementById('selector-strategy') as HTMLSelectElement).addEventListener('change', (e) =>\r\n this.onSelectorStrategyChange((e.target as HTMLSelectElement).value as SelectorStrategy),\r\n );\r\n\r\n this.shadow.getElementById('issue-tracker-provider')?.addEventListener('change', (e) =>\r\n this.onIssueTrackerProviderChange((e.target as HTMLSelectElement).value),\r\n );\r\n this.shadow.querySelectorAll('[data-tracker-field]').forEach((el) =>\r\n el.addEventListener('change', () =>\r\n this.onIssueTrackerParamChange((el as HTMLElement).dataset['trackerField'] ?? '', (el as HTMLInputElement).value),\r\n ),\r\n );\r\n\r\n this.shadow.getElementById('btn-change-folder')?.addEventListener('click', () => this.changeFolder());\r\n this.shadow.getElementById('btn-revoke')?.addEventListener('click', () => this.revokeAccess());\r\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.openExportDialog());\r\n\r\n this.shadow.getElementById('btn-export-confirm')?.addEventListener('click', () => this.confirmExport());\r\n this.shadow.getElementById('btn-export-cancel')?.addEventListener('click', () => this.cancelExport());\r\n this.shadow.querySelectorAll('[data-export-mode]').forEach((el) =>\r\n el.addEventListener('click', () => this.setExportMode((el as HTMLElement).dataset['exportMode'] as ExportMode)),\r\n );\r\n this.shadow.querySelectorAll('[data-export-test]').forEach((el) =>\r\n el.addEventListener('change', () => this.toggleExportTest(Number((el as HTMLElement).dataset['exportTest']))),\r\n );\r\n this.shadow.querySelectorAll('[data-export-tag]').forEach((el) =>\r\n el.addEventListener('click', () => this.toggleExportTag((el as HTMLElement).dataset['exportTag'] ?? '')),\r\n )\r\n ;(this.shadow.getElementById('file-input') as HTMLInputElement).addEventListener('change', async (e) => {\r\n const file = (e.target as HTMLInputElement).files?.[0];\r\n if (!file) return;\r\n try {\r\n await this.importAllData(file);\r\n alert(this.t('CONFIG.IMPORT_SUCCESS'));\r\n } catch (err: unknown) {\r\n alert((err as Error).message ?? this.t('CONFIG.IMPORT_ERROR'));\r\n }\r\n const target = e.target as HTMLInputElement | null;\r\n if (target) target.value = '';\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('e2e-configuration')) {\r\n customElements.define('e2e-configuration', ConfigurationElement);\r\n}\r\n","export const ADVANCED_TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .layout { display: flex; flex: 1; min-height: 0; }\n .sidebar {\n border-right: none; display: flex; flex-direction: column;\n background: #0d1117; flex-shrink: 0; min-width: 140px; max-width: 500px;\n }\n .tree-scroll {\n flex: 1; overflow-y: auto; padding: 6px 4px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .tree-scroll::-webkit-scrollbar { width: 4px; }\n .tree-scroll::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .resize-handle {\n width: 4px; background: #21262d; cursor: col-resize; flex-shrink: 0;\n transition: background 0.15s;\n }\n .resize-handle:hover, .resize-handle.dragging { background: #2f81f7; }\n .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #161b22; min-width: 0; }\n .no-perm {\n padding: 28px; color: #484f58; font-size: 13px; text-align: center;\n display: flex; flex-direction: column; align-items: center; gap: 12px; line-height: 1.6;\n }\n .tree-item {\n padding: 4px 6px; border-radius: 4px; cursor: pointer;\n font-size: 12px; color: #8b949e; white-space: nowrap;\n overflow: hidden; text-overflow: ellipsis;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; gap: 4px; user-select: none;\n }\n .tree-item:hover { background: #161b22; color: #c9d1d9; }\n .tree-item.selected { background: rgba(47,129,247,0.12); color: #2f81f7; }\n .tree-item.dir { color: #e3b341; font-weight: 600; }\n .tree-item.dir:hover { background: rgba(227,179,65,0.08); color: #f0c040; }\n .dir-arrow { font-size: 8px; color: #484f58; width: 10px; flex-shrink: 0; line-height: 1; }\n .tree-connector { display: block; width: 1px; background: #21262d; margin-left: 13px; height: 100%; }\n .content-area {\n flex: 1; padding: 12px 14px; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .content-area::-webkit-scrollbar { width: 4px; }\n .content-area::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .file-name { font-size: 11px; color: #484f58; margin-bottom: 8px; font-family: monospace; }\n pre {\n background: #0d1117; padding: 12px; border-radius: 8px;\n font-size: 11px; color: #c9d1d9; margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n line-height: 1.7; border: 1px solid #21262d;\n white-space: pre; overflow-x: auto; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n pre::-webkit-scrollbar { width: 4px; height: 4px; }\n pre::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .pre-block { font-size: 10.5px; }\n .pre-icp .sh-str { color: #85e89d; }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n .footer {\n padding: 10px 14px; border-top: 1px solid #21262d;\n display: flex; gap: 8px; justify-content: flex-end; background: #161b22;\n }\n button {\n padding: 6px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button:disabled { opacity: 0.35; cursor: default; }\n .btn-save { background: #2f81f7; border-color: #2f81f7; color: #fff; }\n .btn-save:hover { background: #1f6feb; border-color: #1f6feb; color: #fff; }\n .btn-save:disabled { background: #21262d; border-color: #30363d; color: #8b949e; }\n .placeholder { color: #484f58; font-size: 13px; padding: 28px; text-align: center; }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .block-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }\n .btn-copy {\n padding: 3px 10px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-copy:hover { background: #30363d; color: #e6edf3; }\n .sidebar-toolbar {\n display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 6px 4px;\n border-bottom: 1px solid #21262d; flex-shrink: 0; background: #0d1117;\n }\n .btn-toolbar {\n flex: 1 1 calc(50% - 2px); padding: 4px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #161b22; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; overflow: hidden;\n text-overflow: ellipsis;\n }\n .btn-toolbar.btn-full { flex: 1 1 100%; }\n .btn-toolbar:hover { background: #30363d; color: #e6edf3; }\n .btn-toolbar.btn-new { color: #3fb950; border-color: #238636; }\n .btn-toolbar.btn-new:hover { background: #238636; color: #fff; }\n .btn-toolbar.btn-new-folder { color: #d29922; border-color: #9e6a03; }\n .btn-toolbar.btn-new-folder:hover { background: #9e6a03; color: #fff; }\n .new-file-form {\n padding: 6px; border-bottom: 1px solid #21262d; display: flex; flex-direction: column; gap: 4px;\n }\n .new-file-form input {\n width: 100%; padding: 4px 7px; background: #0d1117; border: 1px solid #30363d;\n border-radius: 5px; color: #e6edf3; font-size: 11px; font-family: monospace;\n outline: none;\n }\n .new-file-form input:focus { border-color: #2f81f7; }\n .new-file-form .ext { font-size: 9px; color: #484f58; padding: 0 2px; }\n .new-file-actions { display: flex; gap: 4px; }\n .btn-confirm { flex: 1; padding: 3px 6px; border: 1px solid #238636; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #238636; color: #fff; transition: background 0.12s; }\n .btn-confirm:hover { background: #2ea043; }\n .btn-cancel-form { flex: 1; padding: 3px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e; transition: background 0.12s; }\n .btn-cancel-form:hover { background: #30363d; color: #e6edf3; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\n\nexport interface AdvancedEditorState {\n e2eTree: Array<DirectoryNode | FileNode>;\n selectedFile: unknown;\n selectedFileContent: string | null;\n testItBlock: string;\n interceptorsBlock: string;\n testNotes: string;\n saveButtonEnabled: boolean;\n isCreatingFile: boolean;\n isCreatingFolder: boolean;\n collapsedDirs: Set<string>;\n sidebarWidth: number;\n}\n\nexport function renderNoPermission(needsReauth: boolean, t: (key: string) => string): string {\n const reauthBtn = needsReauth\n ? `<button id=\"btn-reauth\"\n style=\"margin-top:14px;padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\n ${t('ADVANCED_EDITOR.REAUTH_BTN')}\n </button>`\n : '';\n\n return `\n <div class=\"no-perm\">\n <div>${needsReauth ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED') : t('ADVANCED_EDITOR.NO_ACCESS')}</div>\n <div style=\"font-size:11px\">${needsReauth\n ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED_HINT')\n : t('ADVANCED_EDITOR.NO_ACCESS_HINT')}</div>\n ${reauthBtn}\n </div>`;\n}\n\nexport function renderAdvancedEditor(state: AdvancedEditorState, t: (key: string) => string): string {\n const { e2eTree, selectedFile, selectedFileContent, testItBlock, interceptorsBlock, testNotes, saveButtonEnabled, isCreatingFile, isCreatingFolder, collapsedDirs, sidebarWidth } = state;\n\n const treeHtml = e2eTree.length\n ? renderTree(e2eTree, selectedFile, collapsedDirs)\n : `<div class=\"tree-item\" style=\"color:#6c7a99\">${t('ADVANCED_EDITOR.NO_FILES')}</div>`;\n\n const contentHtml = selectedFileContent\n ? `<div class=\"file-name\">📄 ${escHtml((selectedFile as { name?: string } | null)?.name ?? '')}</div>\n <pre class=\"pre-file\">${syntaxHighlight(selectedFileContent.slice(0, 6000))}${selectedFileContent.length > 6000 ? '\\n...' : ''}</pre>`\n : `<div class=\"placeholder\">${t('ADVANCED_EDITOR.SELECT_FILE')}</div>`;\n\n const notesHtml = (testItBlock && testNotes)\n ? `<p class=\"test-notes\">${escHtml(testNotes)}</p>`\n : '';\n\n const itHtml = testItBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.IT_LABEL')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_IT_BTN')}</button>\n </div>\n <pre class=\"pre-block\">${syntaxHighlight(testItBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const interceptorsHtml = interceptorsBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.BEFORE_EACH_LABEL')}</span>\n <button id=\"btn-copy-interceptors\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_ICP_BTN')}</button>\n </div>\n <pre class=\"pre-block pre-icp\">${syntaxHighlight(interceptorsBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const newFileForm = isCreatingFile\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-file\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FILE_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <span class=\"ext\">.cy.ts</span>\n <div class=\"new-file-actions\">\n <button id=\"btn-new-file-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-file-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const newFolderForm = isCreatingFolder\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-folder\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FOLDER_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <div class=\"new-file-actions\">\n <button id=\"btn-new-folder-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-folder-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const toolbar = `\n <div class=\"sidebar-toolbar\">\n <button id=\"btn-new-file\" class=\"btn-toolbar btn-new\">${t('ADVANCED_EDITOR.NEW_FILE_BTN')}</button>\n <button id=\"btn-new-folder\" class=\"btn-toolbar btn-new-folder\">${t('ADVANCED_EDITOR.NEW_FOLDER_BTN')}</button>\n <button id=\"btn-refresh\" class=\"btn-toolbar btn-full\">${t('ADVANCED_EDITOR.REFRESH_BTN')}</button>\n </div>`;\n\n return `\n <div class=\"layout\">\n <div class=\"sidebar\" style=\"width:${sidebarWidth}px\">\n ${toolbar}\n ${newFileForm}\n ${newFolderForm}\n <div class=\"tree-scroll\">${treeHtml}</div>\n </div>\n <div id=\"resize-handle\" class=\"resize-handle\"></div>\n <div class=\"main\">\n <div class=\"content-area\">${contentHtml}${notesHtml}${itHtml}${interceptorsHtml}</div>\n <div class=\"footer\">\n <button id=\"btn-save\" class=\"btn-save\"\n ${!saveButtonEnabled || !testItBlock ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.INSERT_BTN')}\n </button>\n <button id=\"btn-edit\" ${!saveButtonEnabled ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.EDIT_MANUAL_BTN')}\n </button>\n <button id=\"btn-close\">${t('ADVANCED_EDITOR.CLOSE_BTN')}</button>\n </div>\n </div>\n </div>`;\n}\n\nexport function renderTree(\n nodes: Array<DirectoryNode | FileNode>,\n selected: unknown,\n collapsedDirs: Set<string>,\n indent = 0,\n parentPath = '',\n): string {\n return nodes.map((n) => {\n const currentPath = parentPath ? `${parentPath}/${n.name}` : n.name;\n const isFile = n.kind === 'file';\n const pad = `padding-left:${6 + indent * 14}px`;\n\n if (!isFile) {\n const dir = n as DirectoryNode;\n const hasChildren = (dir.children?.length ?? 0) > 0;\n const isCollapsed = collapsedDirs.has(currentPath);\n const arrow = hasChildren ? (isCollapsed ? '▶' : '▼') : '·';\n const dirHtml = `<div class=\"tree-item dir\" style=\"${pad}\" data-dir-path=\"${escAttr(currentPath)}\">\n <span class=\"dir-arrow\">${arrow}</span>📁 ${escHtml(n.name)}\n </div>`;\n if (!hasChildren || isCollapsed) return dirHtml;\n return dirHtml + renderTree(dir.children, selected, collapsedDirs, indent + 1, currentPath);\n }\n\n const isSel = (selected as { name?: string } | null)?.name === n.name;\n const cls = `tree-item${isSel ? ' selected' : ''}`;\n const data = JSON.stringify({ kind: n.kind, name: n.name }).replace(/\"/g, '"');\n return `<div class=\"${cls}\" style=\"${pad}\" data-file=\"${data}\">📄 ${escHtml(n.name)}</div>`;\n }).join('');\n}\n\nexport async function findFileHandleRecursive(\n dir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemFileHandle | null> {\n for await (const entry of dir.values()) {\n if (entry.kind === 'file' && entry.name === name) return entry as FileSystemFileHandle;\n if (entry.kind === 'directory') {\n const found = await findFileHandleRecursive(entry as FileSystemDirectoryHandle, name);\n if (found) return found;\n }\n }\n return null;\n}\n","import { PersistenceService } from '../../services/persistence.service';\r\nimport { TranslationService } from '../../services/translation.service';\r\nimport { AdvancedTestTransformationService } from '../../services/advanced-test.transformation.service';\r\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\r\nimport { ADVANCED_TEST_EDITOR_STYLES } from './advanced-test-editor.styles';\r\nimport { renderNoPermission, renderAdvancedEditor, findFileHandleRecursive } from './advanced-test-editor.template';\r\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\r\n\r\nexport class AdvancedTestEditorElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private readonly transformationService = new AdvancedTestTransformationService();\r\n\r\n persistence!: PersistenceService;\r\n translation!: TranslationService;\r\n testId?: number;\r\n\r\n e2eTree: Array<DirectoryNode | FileNode> = [];\r\n selectedFile: unknown = null;\r\n saveButtonEnabled = false;\r\n selectedFileHandle: FileSystemFileHandle | null = null;\r\n selectedFileContent: string | null = null;\r\n testItBlock = '';\r\n interceptorsBlock = '';\r\n testNotes = '';\r\n isPreviewMode = false;\r\n previewFileName: string | null = null;\r\n previewFileContent: string | null = null;\r\n isCreatingFile = false;\r\n isCreatingFolder = false;\r\n collapsedDirs: Set<string> = new Set();\r\n sidebarWidth = 220;\r\n private hasPermission = false;\r\n private needsReauth = false;\r\n private _dirHandle: FileSystemDirectoryHandle | null = null;\r\n private _e2eHandle: FileSystemDirectoryHandle | null = null;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n if (!this.translation) this.translation = new TranslationService();\r\n this.init();\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n private async init(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n const allowed = config?.['allowReadWriteFiles'] === 'true';\r\n\r\n if (!allowed) {\r\n this.hasPermission = false;\r\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\r\n this.render();\r\n return;\r\n }\r\n\r\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | null;\r\n if (!handle) {\r\n this.hasPermission = false;\r\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\r\n this.render();\r\n return;\r\n }\r\n\r\n // queryPermission does NOT require a user gesture\r\n const perm = await (handle as unknown as FileSystemHandleWithPermission).queryPermission({ mode: 'readwrite' });\r\n this._dirHandle = handle;\r\n this.hasPermission = perm === 'granted';\r\n this.needsReauth = perm === 'prompt';\r\n\r\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\r\n if (this.hasPermission) await this.getFoldersData();\r\n this.render();\r\n }\r\n\r\n async getFoldersData(): Promise<void> {\r\n if (!this.hasPermission || !this._dirHandle) return;\r\n try {\r\n for await (const entry of this._dirHandle.values()) {\r\n if (entry.kind === 'directory' && entry.name === 'e2e') {\r\n this._e2eHandle = entry as FileSystemDirectoryHandle;\r\n const tree = await this.transformationService.scanDirectory(this._e2eHandle);\r\n this.e2eTree = tree.children ?? [];\r\n this.render();\r\n return;\r\n }\r\n }\r\n } catch { /* silently skip permission errors */ }\r\n }\r\n\r\n async createNewFile(rawName: string): Promise<void> {\r\n if (!this._e2eHandle) return;\r\n const name = rawName.trim().replace(/\\.cy\\.ts$/, '');\r\n if (!name) return;\r\n const fileName = `${name}.cy.ts`;\r\n const template = `describe('${escapeSingleQuotes(name)}', () => {\\n\\n it('should ', () => {\\n\\n });\\n\\n});\\n`;\r\n try {\r\n const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });\r\n const writable = await fileHandle.createWritable();\r\n await writable.write(template);\r\n await writable.close();\r\n } catch { /* silently ignore if file already exists or permission denied */ }\r\n this.isCreatingFile = false;\r\n await this.getFoldersData();\r\n }\r\n\r\n async createNewFolder(rawName: string): Promise<void> {\r\n if (!this._e2eHandle) return;\r\n const name = rawName.trim().replace(/[/\\\\]/g, '');\r\n if (!name) return;\r\n try {\r\n await this._e2eHandle.getDirectoryHandle(name, { create: true });\r\n } catch { /* silently ignore if folder already exists or permission denied */ }\r\n this.isCreatingFolder = false;\r\n await this.getFoldersData();\r\n }\r\n\r\n async refreshTree(): Promise<void> {\r\n await this.getFoldersData();\r\n }\r\n\r\n async saveCommandsToFile(): Promise<void> {\r\n if (!this.selectedFileHandle || !this.selectedFileContent || !this.testItBlock) return;\r\n let content = this.selectedFileContent;\r\n if (this.interceptorsBlock) {\r\n content = this.transformationService.insertBeforeEach(content, this.interceptorsBlock);\r\n }\r\n const comment = this.testNotes ? this.transformationService.buildBlockComment(this.testNotes) + '\\n' : '';\r\n content = this.transformationService.insertItBlock(content, comment + this.testItBlock);\r\n if (!content) return;\r\n const writable = await this.selectedFileHandle.createWritable();\r\n await writable.write(content);\r\n await writable.close();\r\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\r\n }\r\n\r\n async onFileClick(file: unknown): Promise<void> {\r\n if (!this.transformationService.isFile(file)) return;\r\n this.selectedFile = file;\r\n this.saveButtonEnabled = true;\r\n\r\n if (!this._dirHandle) return;\r\n const handle = await findFileHandleRecursive(this._dirHandle, (file as { name: string }).name);\r\n if (!handle) return;\r\n this.selectedFileHandle = handle;\r\n const fileObj = await handle.getFile();\r\n this.selectedFileContent = await fileObj.text();\r\n this.render();\r\n }\r\n\r\n markFileAsSelected(file: unknown): void {\r\n this.selectedFile = file;\r\n }\r\n\r\n async loadCypressCommandsForTest(testId: number): Promise<void> {\r\n const test = await this.persistence.getTestById(testId);\r\n if (test) {\r\n this.testItBlock = test.itBlock ?? '';\r\n this.interceptorsBlock = test.interceptorsBlock ?? '';\r\n this.testNotes = test.notes ?? '';\r\n } else {\r\n this.testItBlock = '';\r\n this.interceptorsBlock = '';\r\n this.testNotes = '';\r\n }\r\n this.render();\r\n }\r\n\r\n copyToClipboard(text: string): void {\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n openEditManually(): void {\r\n if (!this.selectedFileHandle || !this.selectedFileContent) return;\r\n this.dispatchEvent(new CustomEvent('openfileeditor', {\r\n detail: {\r\n handle: this.selectedFileHandle,\r\n content: this.selectedFileContent,\r\n fileName: (this.selectedFile as { name?: string } | null)?.name ?? '',\r\n testId: this.testId,\r\n itBlock: this.testItBlock,\r\n interceptorsBlock: this.interceptorsBlock,\r\n notes: this.testNotes,\r\n },\r\n bubbles: true,\r\n composed: true,\r\n }));\r\n }\r\n\r\n toggleDir(path: string): void {\r\n if (this.collapsedDirs.has(path)) {\r\n this.collapsedDirs.delete(path);\r\n } else {\r\n this.collapsedDirs.add(path);\r\n }\r\n this.render();\r\n }\r\n\r\n private setupResizeHandle(): void {\r\n const handle = this.shadow.getElementById('resize-handle');\r\n const sidebar = this.shadow.querySelector('.sidebar') as HTMLElement | null;\r\n if (!handle || !sidebar) return;\r\n\r\n let startX = 0;\r\n let startWidth = 0;\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n const delta = e.clientX - startX;\r\n const newWidth = Math.max(140, Math.min(500, startWidth + delta));\r\n this.sidebarWidth = newWidth;\r\n sidebar.style.width = `${newWidth}px`;\r\n };\r\n\r\n const onMouseUp = () => {\r\n document.removeEventListener('mousemove', onMouseMove);\r\n document.removeEventListener('mouseup', onMouseUp);\r\n document.body.style.cursor = '';\r\n document.body.style.userSelect = '';\r\n handle.classList.remove('dragging');\r\n };\r\n\r\n handle.addEventListener('mousedown', (e: MouseEvent) => {\r\n startX = e.clientX;\r\n startWidth = sidebar.offsetWidth;\r\n document.addEventListener('mousemove', onMouseMove);\r\n document.addEventListener('mouseup', onMouseUp);\r\n document.body.style.cursor = 'col-resize';\r\n document.body.style.userSelect = 'none';\r\n handle.classList.add('dragging');\r\n e.preventDefault();\r\n });\r\n }\r\n\r\n closePreview(): void {\r\n this.isPreviewMode = false;\r\n this.previewFileName = null;\r\n this.previewFileContent = null;\r\n if (this.testId !== undefined) {\r\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\r\n }\r\n this.render();\r\n }\r\n\r\n private render(): void {\r\n if (!this.hasPermission) {\r\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderNoPermission(this.needsReauth, this.t.bind(this))}`;\r\n\r\n this.shadow.getElementById('btn-reauth')?.addEventListener('click', async () => {\r\n if (!this._dirHandle) return;\r\n const perm = await (this._dirHandle as unknown as FileSystemHandleWithPermission).requestPermission({ mode: 'readwrite' });\r\n if (perm === 'granted') {\r\n this.hasPermission = true;\r\n this.needsReauth = false;\r\n await this.getFoldersData();\r\n this.render();\r\n }\r\n });\r\n return;\r\n }\r\n\r\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderAdvancedEditor({\r\n e2eTree: this.e2eTree,\r\n selectedFile: this.selectedFile,\r\n selectedFileContent: this.selectedFileContent,\r\n testItBlock: this.testItBlock,\r\n interceptorsBlock: this.interceptorsBlock,\r\n testNotes: this.testNotes,\r\n saveButtonEnabled: this.saveButtonEnabled,\r\n isCreatingFile: this.isCreatingFile,\r\n isCreatingFolder: this.isCreatingFolder,\r\n collapsedDirs: this.collapsedDirs,\r\n sidebarWidth: this.sidebarWidth,\r\n }, this.t.bind(this))}`;\r\n\r\n this.shadow.querySelectorAll('[data-file]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n const data = (el as HTMLElement).dataset['file'];\r\n if (data) this.onFileClick(JSON.parse(data));\r\n });\r\n });\r\n this.shadow.querySelectorAll('[data-dir-path]').forEach((el) => {\r\n el.addEventListener('click', () => {\r\n const path = (el as HTMLElement).dataset['dirPath'];\r\n if (path) this.toggleDir(path);\r\n });\r\n });\r\n this.setupResizeHandle();\r\n this.shadow.getElementById('btn-save')\r\n ?.addEventListener('click', () => this.saveCommandsToFile());\r\n this.shadow.getElementById('btn-edit')\r\n ?.addEventListener('click', () => this.openEditManually());\r\n this.shadow.getElementById('btn-copy-it')\r\n ?.addEventListener('click', () => this.copyToClipboard(this.testItBlock));\r\n this.shadow.getElementById('btn-copy-interceptors')\r\n ?.addEventListener('click', () => this.copyToClipboard(this.interceptorsBlock));\r\n this.shadow.getElementById('btn-close')\r\n ?.addEventListener('click', () => this.closePreview());\r\n this.shadow.getElementById('btn-new-file')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFile = !this.isCreatingFile;\r\n this.isCreatingFolder = false;\r\n this.render();\r\n if (this.isCreatingFile) this.shadow.getElementById('input-new-file')?.focus();\r\n });\r\n this.shadow.getElementById('btn-new-folder')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFolder = !this.isCreatingFolder;\r\n this.isCreatingFile = false;\r\n this.render();\r\n if (this.isCreatingFolder) this.shadow.getElementById('input-new-folder')?.focus();\r\n });\r\n this.shadow.getElementById('btn-refresh')\r\n ?.addEventListener('click', () => this.refreshTree());\r\n this.shadow.getElementById('btn-new-file-confirm')\r\n ?.addEventListener('click', () => {\r\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\r\n this.createNewFile(input?.value ?? '');\r\n });\r\n this.shadow.getElementById('btn-new-file-cancel')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFile = false;\r\n this.render();\r\n });\r\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\r\n input?.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') {\r\n this.createNewFile(input.value);\r\n } else if (e.key === 'Escape') {\r\n this.isCreatingFile = false;\r\n this.render();\r\n }\r\n });\r\n this.shadow.getElementById('btn-new-folder-confirm')\r\n ?.addEventListener('click', () => {\r\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\r\n this.createNewFolder(folderInput?.value ?? '');\r\n });\r\n this.shadow.getElementById('btn-new-folder-cancel')\r\n ?.addEventListener('click', () => {\r\n this.isCreatingFolder = false;\r\n this.render();\r\n });\r\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\r\n folderInput?.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') {\r\n this.createNewFolder(folderInput.value);\r\n } else if (e.key === 'Escape') {\r\n this.isCreatingFolder = false;\r\n this.render();\r\n }\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('advanced-test-editor')) {\r\n customElements.define('advanced-test-editor', AdvancedTestEditorElement);\r\n}\r\n","export const FILE_PREVIEW_STYLES = `\n :host { display: block; height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n .container { display: flex; flex-direction: column; height: 100%; }\n .header {\n display: flex; align-items: center; gap: 8px;\n padding: 8px 12px; border-bottom: 1px solid #21262d;\n background: #161b22;\n }\n .file-name { flex: 1; font-size: 12px; color: #8b949e;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; }\n .body { display: flex; flex: 1; overflow: hidden; min-height: 0; }\n /* Host for the CodeMirror editor (or the textarea fallback). */\n .editor-host { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }\n .editor-host .cm-editor { flex: 1; min-height: 0; }\n .editor {\n flex: 1; min-width: 0; padding: 14px;\n background: #0d1117; color: #c9d1d9; border: none; outline: none;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 12px;\n line-height: 1.7; resize: none;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .editor::-webkit-scrollbar { width: 5px; }\n .editor::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .blocks-panel {\n width: 260px; flex-shrink: 0; border-left: 1px solid #21262d;\n background: #0d1117; padding: 10px 12px; overflow-y: auto;\n display: flex; flex-direction: column; gap: 10px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .blocks-panel::-webkit-scrollbar { width: 4px; }\n .blocks-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .block-section { display: flex; flex-direction: column; gap: 4px; }\n .block-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }\n .block-label { font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600; }\n .btn-copy-sm {\n padding: 2px 8px; border: 1px solid #30363d; border-radius: 4px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap;\n }\n .btn-copy-sm:hover { background: #30363d; color: #e6edf3; }\n .block-pre {\n margin: 0; padding: 6px 8px; background: #161b22;\n border-radius: 5px; border: 1px solid #21262d;\n font-size: 10px; color: #c9d1d9; line-height: 1.6;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n max-height: 280px; overflow-y: auto; white-space: pre-wrap; word-break: break-all;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel {\n flex: 1; overflow-y: auto; background: #0d1117; border-left: 1px solid #21262d;\n padding: 8px 0; min-width: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n line-height: 1.6;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel::-webkit-scrollbar { width: 5px; }\n .diff-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .diff-line {\n display: flex; gap: 0; white-space: pre; padding: 0 12px;\n }\n .diff-line.added { background: rgba(63,185,80,0.12); color: #3fb950; }\n .diff-line.removed { background: rgba(248,81,73,0.1); color: #f85149; }\n .diff-line.same { color: #484f58; }\n .diff-sign { width: 14px; flex-shrink: 0; user-select: none; }\n .diff-empty { color: #484f58; font-size: 12px; padding: 20px; text-align: center; }\n .footer {\n display: flex; gap: 8px; padding: 8px 12px;\n border-top: 1px solid #21262d; justify-content: flex-end;\n background: #161b22;\n }\n button {\n padding: 6px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n .btn-save { background: #3fb950; border-color: #3fb950; color: #fff; }\n .btn-save:hover { background: #2ea043; border-color: #2ea043; }\n .btn-launch { background: transparent; border-color: #e3b341; color: #e3b341; }\n .btn-launch:hover { background: rgba(227,179,65,0.1); }\n .btn-launch:disabled { opacity: 0.45; cursor: not-allowed; }\n .btn-launch:disabled:hover { background: transparent; }\n .launch-hint { font-size: 10px; color: #8b6d3b; align-self: center; }\n .btn-insert { background: transparent; border-color: #a371f7; color: #a371f7; }\n .btn-insert:hover { background: rgba(163,113,247,0.12); color: #c8a8ff; }\n .btn-diff-active { background: rgba(47,129,247,0.15); border-color: rgba(47,129,247,0.4); color: #2f81f7; }\n\n /* ── Run result panel ─────────────────────────────────── */\n .run-result {\n border-top: 1px solid #21262d; padding: 8px 12px; background: #0d1117;\n max-height: 220px; overflow-y: auto; flex-shrink: 0;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .run-status { font-size: 12px; font-weight: 600; }\n .run-passed .run-status { color: #3fb950; }\n .run-failed .run-status { color: #f85149; }\n .run-running .run-status { color: #e3b341; }\n .run-error .run-status { color: #f85149; }\n .run-output {\n margin: 6px 0 0; padding: 8px 10px; background: #161b22; border: 1px solid #21262d;\n border-radius: 5px; font-size: 10px; color: #c9d1d9; line-height: 1.5;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto;\n }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport type DiffEntry = { type: 'same' | 'added' | 'removed'; line: string };\n\nexport function computeDiff(original: string, modified: string): DiffEntry[] {\n const MAX_LINES = 600;\n const a = original.split('\\n').slice(0, MAX_LINES);\n const b = modified.split('\\n').slice(0, MAX_LINES);\n const m = a.length, n = b.length;\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]);\n }\n }\n\n const result: DiffEntry[] = [];\n let i = m, j = n;\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {\n result.unshift({ type: 'same', line: a[i - 1] });\n i--; j--;\n } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {\n result.unshift({ type: 'added', line: b[j - 1] });\n j--;\n } else {\n result.unshift({ type: 'removed', line: a[i - 1] });\n i--;\n }\n }\n return result;\n}\n\nexport function buildDiffHtml(original: string, current: string, t: (key: string) => string): string {\n if (original === current) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES')}</div>`;\n\n const diff = computeDiff(original, current);\n if (!diff.length) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES_SHORT')}</div>`;\n\n const CONTEXT = 2;\n const compressed: DiffEntry[] = [];\n let sameRun = 0;\n for (let idx = 0; idx < diff.length; idx++) {\n if (diff[idx].type === 'same') {\n sameRun++;\n if (sameRun <= CONTEXT) compressed.push(diff[idx]);\n else if (idx + 1 < diff.length && diff[idx + 1].type !== 'same') {\n if (sameRun > CONTEXT * 2) compressed.push({ type: 'same', line: '…' });\n compressed.push(diff[idx]);\n }\n } else {\n sameRun = 0;\n compressed.push(diff[idx]);\n }\n }\n\n return compressed.map(({ type, line }) => {\n const sign = type === 'added' ? '+' : type === 'removed' ? '−' : ' ';\n return `<div class=\"diff-line ${type}\"><span class=\"diff-sign\">${sign}</span><span>${escHtml(line)}</span></div>`;\n }).join('');\n}\n\nexport type RunState = 'idle' | 'running' | 'passed' | 'failed' | 'error';\n\nexport interface FilePreviewState {\n fileName: string | null;\n showDiff: boolean;\n fileContent: string | null;\n originalContent: string | null;\n currentContent: string;\n itBlock: string;\n interceptorsBlock: string;\n closeLabel: string;\n isLocal: boolean;\n runState: RunState;\n runOutput: string;\n}\n\nconst RUN_STATUS_KEY: Record<Exclude<RunState, 'idle'>, string> = {\n running: 'FILE_PREVIEW.LAUNCH_RUNNING',\n passed: 'FILE_PREVIEW.LAUNCH_PASSED',\n failed: 'FILE_PREVIEW.LAUNCH_FAILED',\n error: 'FILE_PREVIEW.LAUNCH_NO_RUNNER',\n};\n\nexport function renderFilePreview(state: FilePreviewState, t: (key: string) => string): string {\n const { fileName, showDiff, fileContent, originalContent, currentContent, itBlock, interceptorsBlock, closeLabel, isLocal, runState, runOutput } = state;\n\n const blocksPanelHtml = (itBlock || interceptorsBlock) ? `\n <div class=\"blocks-panel\">\n ${itBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_IT')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\">${escHtml(itBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n ${interceptorsBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_BEFORE_EACH')}</span>\n <button id=\"btn-copy-icp\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\" style=\"color:#3fb950\">${escHtml(interceptorsBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n </div>` : '';\n\n const hasChanges = originalContent !== null && originalContent !== (fileContent ?? '');\n const hasBlocks = !!(itBlock || interceptorsBlock);\n\n const launchBtnHtml = isLocal\n ? `<button id=\"btn-launch\" class=\"btn-launch\" ${runState === 'running' ? 'disabled' : ''}>${runState === 'running' ? t('FILE_PREVIEW.LAUNCH_RUNNING') : t('FILE_PREVIEW.LAUNCH_BTN')}</button>`\n : `<button class=\"btn-launch\" disabled title=\"${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}\">${t('FILE_PREVIEW.LAUNCH_BTN')}</button>\n <span class=\"launch-hint\">${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}</span>`;\n\n const runResultHtml = runState !== 'idle'\n ? `<div class=\"run-result run-${runState}\">\n <span class=\"run-status\">${t(RUN_STATUS_KEY[runState])}</span>\n ${runOutput ? `<pre class=\"run-output\">${escHtml(runOutput.slice(0, 8000))}</pre>` : ''}\n </div>`\n : '';\n\n return `\n <div class=\"container\">\n <div class=\"header\">\n <span class=\"file-name\">📄 ${fileName ? escHtml(fileName) : t('FILE_PREVIEW.NO_FILE')}</span>\n <button id=\"btn-copy\" title=\"${t('FILE_PREVIEW.COPY_TITLE')}\">📋</button>\n </div>\n <div class=\"body\">\n ${showDiff\n ? `<div class=\"diff-panel\" id=\"diff-panel\">${buildDiffHtml(originalContent ?? '', currentContent, t)}</div>`\n : `<div class=\"editor-host\" id=\"editor-host\"><textarea class=\"editor\" id=\"editor\" spellcheck=\"false\">${escHtml(fileContent ?? '')}</textarea></div>`}\n ${blocksPanelHtml}\n </div>\n ${runResultHtml}\n <div class=\"footer\">\n ${launchBtnHtml}\n ${hasChanges ? `<button id=\"btn-diff\" class=\"${showDiff ? 'btn-diff-active' : ''}\">${t('FILE_PREVIEW.DIFF_BTN')}</button>` : ''}\n ${hasBlocks && !showDiff ? `<button id=\"btn-insert\" class=\"btn-insert\" title=\"${t('FILE_PREVIEW.INSERT_TITLE')}\">${t('FILE_PREVIEW.INSERT_BTN')}</button>` : ''}\n <button id=\"btn-save\" class=\"btn-save\">${t('FILE_PREVIEW.SAVE_BTN')}</button>\n <button id=\"btn-close\">${escHtml(closeLabel || t('FILE_PREVIEW.CLOSE_BTN'))}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\r\nimport { advancedTestTransformationService } from '../../services/advanced-test.transformation.service';\r\nimport { showToast } from '../../utils/toast.utils';\r\nimport { isLocalHost } from '../../utils/host.utils';\r\nimport { createCodeEditor, type CodeEditorHandle } from '../../utils/code-editor';\r\nimport { FILE_PREVIEW_STYLES } from './file-preview.styles';\r\nimport { renderFilePreview, type RunState } from './file-preview.template';\r\n\r\nexport class FilePreviewElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private textarea: HTMLTextAreaElement | null = null;\r\n private editor: CodeEditorHandle | null = null;\r\n\r\n fileName: string | null = null;\r\n closeLabel = '';\r\n translation: TranslationService = translationService;\r\n itBlock = '';\r\n interceptorsBlock = '';\r\n notes = '';\r\n commands: string[] = [];\r\n interceptors: string[] = [];\r\n /** Endpoint of the local Cypress runner. Configurable; defaults to the bundled runner's port. */\r\n runnerUrl = 'http://localhost:8123/run-test';\r\n /** Whether the app is served locally — gates the launch button. Overridable for tests. */\r\n isLocal = isLocalHost(window.location.hostname);\r\n private _fileContent: string | null = null;\r\n private _originalContent: string | null = null;\r\n private _showDiff = false;\r\n private _runState: RunState = 'idle';\r\n private _runOutput = '';\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.closeLabel) this.closeLabel = this.translation.translate('FILE_PREVIEW.CLOSE_BTN');\r\n this.render();\r\n }\r\n\r\n disconnectedCallback(): void {\r\n this.editor?.destroy();\r\n this.editor = null;\r\n }\r\n\r\n private t(key: string): string { return this.translation.translate(key); }\r\n\r\n /** Current editor content (CodeMirror if upgraded, else the textarea/fallback). */\r\n private currentValue(): string {\r\n return this.editor?.getValue() ?? this.textarea?.value ?? this._fileContent ?? '';\r\n }\r\n\r\n get fileContent(): string | null { return this._fileContent; }\r\n set fileContent(v: string | null) {\r\n if (this._originalContent === null) this._originalContent = v;\r\n this._fileContent = v;\r\n if (this.editor) this.editor.setValue(v ?? '');\r\n else if (this.textarea) this.textarea.value = v ?? '';\r\n else this.render();\r\n }\r\n\r\n saveFile(): void {\r\n const content = this.currentValue();\r\n this.dispatchEvent(new CustomEvent('save', { detail: content, bubbles: true, composed: true }));\r\n }\r\n\r\n onClose(): void {\r\n this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));\r\n }\r\n\r\n /**\r\n * Runs the current spec headless via the local runner and shows the result.\r\n * No-op off localhost. Never throws — connection failures surface as an\r\n * \"error\" state + toast instead of an unhandled rejection.\r\n */\r\n async launchTest(specPath?: string): Promise<void> {\r\n if (!this.isLocal) return;\r\n const path = specPath ?? this.fileName ?? '';\r\n if (!path) return;\r\n\r\n this._runState = 'running';\r\n this._runOutput = '';\r\n this.render();\r\n\r\n try {\r\n const response = await fetch(this.runnerUrl, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({ specPath: path }),\r\n });\r\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\r\n const result = await response.json() as { success?: boolean; output?: string };\r\n this._runOutput = result.output ?? '';\r\n this._runState = result.success ? 'passed' : 'failed';\r\n } catch {\r\n this._runState = 'error';\r\n this._runOutput = '';\r\n showToast(this.t('FILE_PREVIEW.LAUNCH_NO_RUNNER'), false);\r\n }\r\n this.render();\r\n }\r\n\r\n copyToClipboard(text: string): void {\r\n navigator.clipboard?.writeText(text);\r\n }\r\n\r\n toggleDiff(): void {\r\n this._showDiff = !this._showDiff;\r\n this.render();\r\n }\r\n\r\n /**\r\n * Merges the it() and beforeEach() blocks into the current editor content\r\n * using the same logic as the automatic \"Insert into file\" action, so the\r\n * user does not have to copy/paste manually. Leaves the content untouched\r\n * (and warns) when the file has no valid describe() block to insert into.\r\n */\r\n insertBlocks(): void {\r\n const base = this.currentValue();\r\n let content = base;\r\n if (this.interceptorsBlock) {\r\n const merged = advancedTestTransformationService.insertBeforeEach(content, this.interceptorsBlock);\r\n if (merged) content = merged;\r\n }\r\n if (this.itBlock) {\r\n const comment = this.notes ? advancedTestTransformationService.buildBlockComment(this.notes) + '\\n' : '';\r\n const merged = advancedTestTransformationService.insertItBlock(content, comment + this.itBlock);\r\n if (merged) content = merged;\r\n }\r\n if (content === base) {\r\n showToast(this.t('FILE_PREVIEW.INSERT_ERROR'), false);\r\n return;\r\n }\r\n this._fileContent = content;\r\n this.render();\r\n showToast(this.t('FILE_PREVIEW.INSERT_DONE'));\r\n }\r\n\r\n private render(): void {\r\n // Tear down any prior CodeMirror instance before replacing the DOM.\r\n this.editor?.destroy();\r\n this.editor = null;\r\n\r\n this.shadow.innerHTML = `<style>${FILE_PREVIEW_STYLES}</style>${renderFilePreview({\r\n fileName: this.fileName,\r\n showDiff: this._showDiff,\r\n fileContent: this._fileContent,\r\n originalContent: this._originalContent,\r\n currentContent: this._fileContent ?? '',\r\n itBlock: this.itBlock,\r\n interceptorsBlock: this.interceptorsBlock,\r\n closeLabel: this.closeLabel,\r\n isLocal: this.isLocal,\r\n runState: this._runState,\r\n runOutput: this._runOutput,\r\n }, this.t.bind(this))}`;\r\n\r\n this.textarea = this.shadow.getElementById('editor') as HTMLTextAreaElement | null;\r\n if (this.textarea) {\r\n const ta = this.textarea;\r\n this.textarea.addEventListener('input', () => {\r\n this._fileContent = ta.value;\r\n });\r\n // Upgrade the plain textarea to a CodeMirror editor (async, lazy). If\r\n // CodeMirror is unavailable the textarea stays as a graceful fallback.\r\n void this.upgradeEditor();\r\n }\r\n this.shadow.getElementById('btn-save')?.addEventListener('click', () => this.saveFile());\r\n this.shadow.getElementById('btn-close')?.addEventListener('click', () => this.onClose());\r\n this.shadow.getElementById('btn-launch')?.addEventListener('click', () => this.launchTest());\r\n this.shadow.getElementById('btn-copy')?.addEventListener('click', () => {\r\n this.copyToClipboard(this.currentValue());\r\n });\r\n this.shadow.getElementById('btn-diff')?.addEventListener('click', () => this.toggleDiff());\r\n this.shadow.getElementById('btn-insert')?.addEventListener('click', () => this.insertBlocks());\r\n this.shadow.getElementById('btn-copy-it')?.addEventListener('click', () => {\r\n this.copyToClipboard(this.itBlock);\r\n });\r\n this.shadow.getElementById('btn-copy-icp')?.addEventListener('click', () => {\r\n this.copyToClipboard(this.interceptorsBlock);\r\n });\r\n }\r\n\r\n /**\r\n * Lazily upgrades the textarea to a CodeMirror editor (syntax highlight +\r\n * Cypress autocomplete). On any failure the textarea is left in place, so the\r\n * editor degrades gracefully when CodeMirror can't load.\r\n */\r\n private async upgradeEditor(): Promise<void> {\r\n const host = this.shadow.getElementById('editor-host');\r\n const ta = this.textarea;\r\n if (!host || !ta) return;\r\n try {\r\n const handle = await createCodeEditor({\r\n parent: host,\r\n root: this.shadow,\r\n doc: this._fileContent ?? '',\r\n onChange: (value) => { this._fileContent = value; },\r\n });\r\n if (!host.isConnected) { handle.destroy(); return; }\r\n ta.remove();\r\n this.textarea = null;\r\n this.editor = handle;\r\n } catch {\r\n /* keep the textarea fallback */\r\n }\r\n }\r\n}\r\n\r\nif (!customElements.get('file-preview')) {\r\n customElements.define('file-preview', FilePreviewElement);\r\n}\r\n","export const HELP_PANEL_STYLES = `\r\n :host { display: block; }\r\n *, *::before, *::after { box-sizing: border-box; }\r\n\r\n .help-tabs {\r\n display: flex;\r\n gap: 4px;\r\n border-bottom: 1px solid #21262d;\r\n margin-bottom: 8px;\r\n }\r\n .help-tab {\r\n appearance: none;\r\n border: none;\r\n background: transparent;\r\n color: #8b949e;\r\n font-size: 12px;\r\n font-weight: 600;\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n border-bottom: 2px solid transparent;\r\n margin-bottom: -1px;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\r\n transition: color .12s, border-color .12s;\r\n }\r\n .help-tab:hover { color: #c9d1d9; }\r\n .help-tab.active { color: #e6edf3; border-bottom-color: #2f81f7; }\r\n\r\n .help-panel {\r\n max-height: 60vh;\r\n overflow-y: auto;\r\n padding: 4px 6px 8px;\r\n color: #c9d1d9;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\r\n font-size: 13px;\r\n line-height: 1.55;\r\n }\r\n\r\n .help-intro {\r\n margin: 0 0 12px;\r\n color: #8b949e;\r\n font-size: 12px;\r\n }\r\n\r\n .help-sec { margin: 0 0 14px; }\r\n\r\n .help-sec-hd {\r\n margin: 0 0 6px;\r\n font-size: 12px;\r\n font-weight: 700;\r\n color: #e6edf3;\r\n letter-spacing: .3px;\r\n border-bottom: 1px solid #21262d;\r\n padding-bottom: 4px;\r\n }\r\n\r\n .help-list {\r\n margin: 0;\r\n padding: 0;\r\n list-style: none;\r\n }\r\n\r\n .help-list li {\r\n padding: 3px 0 3px 14px;\r\n position: relative;\r\n color: #c9d1d9;\r\n }\r\n\r\n .help-list li::before {\r\n content: '·';\r\n position: absolute;\r\n left: 3px;\r\n color: #2f81f7;\r\n font-weight: 700;\r\n }\r\n`;\r\n","import { escHtml } from '../../utils/html.utils';\r\n\r\n/**\r\n * Pure render function for the in-app Help panel (spec 011). Two tabs — a quick\r\n * reference (cheat-sheet) and a verbose usage guide (workflow + coverage). All\r\n * text comes from the HELP.* i18n section and is escaped (values contain literal\r\n * `<select>` etc. that would otherwise be parsed as HTML).\r\n */\r\n\r\nexport type HelpTab = 'reference' | 'guide';\r\n\r\ninterface Section { title: string; items: string[] }\r\n\r\nconst REFERENCE_SECTIONS: Section[] = [\r\n { title: 'HELP.SEC_RECORDING', items: ['HELP.RECORDING_1', 'HELP.RECORDING_2'] },\r\n {\r\n title: 'HELP.SEC_SHORTCUTS',\r\n items: ['HELP.SC_RECORD', 'HELP.SC_PAUSE', 'HELP.SC_TESTS', 'HELP.SC_COMMANDS', 'HELP.SC_CONFIG', 'HELP.SC_VISIBILITY', 'HELP.SC_HELP'],\r\n },\r\n {\r\n title: 'HELP.SEC_CAPTURED',\r\n items: ['HELP.CAP_CLICK', 'HELP.CAP_DBLCLICK', 'HELP.CAP_RIGHTCLICK', 'HELP.CAP_TYPE', 'HELP.CAP_CHECK', 'HELP.CAP_SELECT', 'HELP.CAP_KEYS', 'HELP.CAP_ROUTE', 'HELP.CAP_HTTP'],\r\n },\r\n { title: 'HELP.SEC_ASSERT', items: ['HELP.ASSERT_1', 'HELP.ASSERT_2'] },\r\n { title: 'HELP.SEC_PANELS', items: ['HELP.PANEL_TESTS', 'HELP.PANEL_COMMANDS', 'HELP.PANEL_CONFIG', 'HELP.PANEL_FILES'] },\r\n { title: 'HELP.SEC_SELECTOR', items: ['HELP.SELECTOR_1', 'HELP.SELECTOR_2'] },\r\n { title: 'HELP.SEC_DATA', items: ['HELP.DATA_1', 'HELP.DATA_2'] },\r\n { title: 'HELP.SEC_ADVANCED', items: ['HELP.ADV_INVISIBLE', 'HELP.ADV_RUNNER', 'HELP.ADV_CROSSAPP', 'HELP.ADV_DRAG'] },\r\n];\r\n\r\nconst GUIDE_SECTIONS: Section[] = [\r\n { title: 'HELP.G_SEC_WORKFLOW', items: ['HELP.G_WF_1', 'HELP.G_WF_2', 'HELP.G_WF_3', 'HELP.G_WF_4', 'HELP.G_WF_5'] },\r\n { title: 'HELP.G_SEC_COVERED', items: ['HELP.G_COV_1', 'HELP.G_COV_2', 'HELP.G_COV_3', 'HELP.G_COV_4', 'HELP.G_COV_5', 'HELP.G_COV_6'] },\r\n { title: 'HELP.G_SEC_NOTCOVERED', items: ['HELP.G_NC_1', 'HELP.G_NC_2', 'HELP.G_NC_3', 'HELP.G_NC_4', 'HELP.G_NC_5', 'HELP.G_NC_6'] },\r\n];\r\n\r\nfunction sectionsHtml(sections: Section[], t: (key: string) => string): string {\r\n return sections\r\n .map(\r\n (s) => `\r\n <section class=\"help-sec\">\r\n <h3 class=\"help-sec-hd\">${escHtml(t(s.title))}</h3>\r\n <ul class=\"help-list\">${s.items.map((k) => `<li>${escHtml(t(k))}</li>`).join('')}</ul>\r\n </section>`,\r\n )\r\n .join('');\r\n}\r\n\r\nexport function renderHelpPanel(t: (key: string) => string, activeTab: HelpTab = 'reference'): string {\r\n const tab = (id: HelpTab, key: string): string =>\r\n `<button class=\"help-tab ${activeTab === id ? 'active' : ''}\" data-tab=\"${id}\">${escHtml(t(key))}</button>`;\r\n\r\n const body =\r\n activeTab === 'guide'\r\n ? `<p class=\"help-intro\">${escHtml(t('HELP.GUIDE_INTRO'))}</p>${sectionsHtml(GUIDE_SECTIONS, t)}`\r\n : `<p class=\"help-intro\">${escHtml(t('HELP.INTRO'))}</p>${sectionsHtml(REFERENCE_SECTIONS, t)}`;\r\n\r\n return `\r\n <div class=\"help-root\">\r\n <div class=\"help-tabs\" role=\"tablist\">\r\n ${tab('reference', 'HELP.TAB_REFERENCE')}\r\n ${tab('guide', 'HELP.TAB_GUIDE')}\r\n </div>\r\n <div class=\"help-panel\" data-tab-panel=\"${activeTab}\">${body}</div>\r\n </div>`;\r\n}\r\n","import { TranslationService } from '../../services/translation.service';\r\nimport { HELP_PANEL_STYLES } from './help-panel.styles';\r\nimport { renderHelpPanel, type HelpTab } from './help-panel.template';\r\n\r\n/**\r\n * `<help-panel>` — an in-app guide (spec 011). Two tabs: a quick reference\r\n * cheat-sheet and a verbose usage guide (workflow + coverage). Content is driven\r\n * by the HELP.* i18n keys.\r\n */\r\nexport class HelpPanelElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private activeTab: HelpTab = 'reference';\r\n translation!: TranslationService;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if (!this.translation) this.translation = new TranslationService();\r\n this.render();\r\n }\r\n\r\n private render(): void {\r\n this.shadow.innerHTML =\r\n `<style>${HELP_PANEL_STYLES}</style>${renderHelpPanel(this.translation.translate.bind(this.translation), this.activeTab)}`;\r\n this.shadow.querySelectorAll<HTMLElement>('[data-tab]').forEach((btn) => {\r\n btn.addEventListener('click', () => {\r\n this.activeTab = (btn.dataset['tab'] as HelpTab) ?? 'reference';\r\n this.render();\r\n });\r\n });\r\n }\r\n}\r\n\r\nif (!customElements.get('help-panel')) {\r\n customElements.define('help-panel', HelpPanelElement);\r\n}\r\n","import Swal from 'sweetalert2';\r\nimport { getRecorderStyles } from './lib-e2e-recorder.styles';\r\nimport { renderRecorderWidget } from './lib-e2e-recorder.template';\r\nimport { RecordingService, type SelectorStrategy } from '../../services/recording.service';\r\nimport { PersistenceService } from '../../services/persistence.service';\r\nimport { TranslationService } from '../../services/translation.service';\r\nimport { HttpMonitor } from '../../services/http-monitor';\r\nimport {\r\n injectStyles,\r\n LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,\r\n SCROLLBAR_STYLES,\r\n} from '../../utils/styles.utils';\r\nimport {\r\n makeModalResizable,\r\n makeSwalDraggable,\r\n setSwal2DataCyAttribute,\r\n} from '../../utils/modal.utils';\r\nimport type { Lang } from '../../models/lang.model';\r\nimport {\r\n type ActiveSessionState,\r\n ACTIVE_SESSION_BREADCRUMB_KEY,\r\n RESUME_TTL_CONFIG_KEY,\r\n DEFAULT_RESUME_TTL_MINUTES,\r\n} from '../../models/active-session.model';\r\nimport {\r\n type ExpandDirection,\r\n type Point,\r\n DRAG_THRESHOLD,\r\n clampTogglePosition,\r\n resolveExpandDirection,\r\n defaultTogglePosition,\r\n boxTopLeftFor,\r\n} from '../../utils/widget-position.utils';\r\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\r\nimport { showToast } from '../../utils/toast.utils';\r\n\r\n/**\r\n * Minimal property/event shapes for dynamically-created child custom elements.\r\n * Not extending HTMLElement avoids conflicts with the strict EventListener signature;\r\n * cast to Node/HTMLElement only for actual DOM insertion.\r\n */\r\ninterface PrevisualizerEl {\r\n translation: TranslationService; commands: string[]; interceptors: string[]; editable: boolean;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\r\n}\r\ninterface TestEditorEl { persistence: PersistenceService; translation: TranslationService }\r\ninterface SaveTestEl {\r\n translation: TranslationService;\r\n issueTrackerProviderId: string;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\r\n}\r\ninterface ConfigEl {\r\n persistence: PersistenceService; translation: TranslationService;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\r\n}\r\ninterface AdvancedEditorEl {\r\n persistence: PersistenceService; translation: TranslationService; testId?: number;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\r\n}\r\ninterface FilePreviewEl {\r\n translation: TranslationService; fileContent: string | null; fileName: string | null;\r\n closeLabel: string; itBlock: string; interceptorsBlock: string; notes: string;\r\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\r\n}\r\ninterface SelectorPickerEl {\r\n targetElement: HTMLElement; recording: RecordingService; translation: TranslationService;\r\n}\r\ninterface HelpPanelEl { translation: TranslationService }\r\n\r\nexport class LibE2eRecorderElement extends HTMLElement {\r\n private shadow: ShadowRoot;\r\n private _isDisabled = false;\r\n private keydownHandler!: (e: KeyboardEvent) => void;\r\n private recordingUnsub?: () => void;\r\n private commandsUnsub?: () => void;\r\n private interceptorsUnsub?: () => void;\r\n private pauseUnsub?: () => void;\r\n private selectorNotFoundUnsub?: () => void;\r\n private langUnsub?: () => void;\r\n private sessionUnsub?: () => void;\r\n private sessionSaveTimer?: ReturnType<typeof setTimeout>;\r\n private controlFirstTimeData = true;\r\n\r\n // ── draggable widget (spec 007) ──\r\n private togglePos: Point | null = null;\r\n private expandDir: ExpandDirection = 'up-left';\r\n private dragState?: { startX: number; startY: number; origX: number; origY: number; moved: boolean };\r\n private suppressNextToggleClick = false;\r\n private widgetPointerMove?: (e: MouseEvent) => void;\r\n private widgetPointerUp?: () => void;\r\n private widgetResize?: () => void;\r\n private _previsualizerRef: { commands: string[]; interceptors: string[] } | null = null;\r\n private httpMonitor?: HttpMonitor;\r\n private smartSelectorEnabled = true;\r\n private _needsRecordingRebuild = false;\r\n\r\n recording!: RecordingService;\r\n persistence!: PersistenceService;\r\n translation!: TranslationService;\r\n\r\n isVisible = false;\r\n isRecording = false;\r\n isPaused = false;\r\n cypressCommands: string[] = [];\r\n interceptors: string[] = [];\r\n\r\n isCommandsDialogOpen = false;\r\n isSavedTestsDialogOpen = false;\r\n isSaveTestDialogOpen = false;\r\n isSettingsDialogOpen = false;\r\n isAdvancedEditorDialogOpen = false;\r\n isHelpDialogOpen = false;\r\n\r\n constructor() {\r\n super();\r\n this.shadow = this.attachShadow({ mode: 'open' });\r\n }\r\n\r\n connectedCallback(): void {\r\n if ('Cypress' in window) {\r\n this._isDisabled = true;\r\n return;\r\n }\r\n if (!this.getAttribute('data-cy')) {\r\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\r\n }\r\n // Build a fresh recording service on first connect, or rebuild after a\r\n // disconnect destroyed the previous one (its listeners are dead). spec 008.\r\n if (!this.recording || this._needsRecordingRebuild) {\r\n this.recording = new RecordingService();\r\n this._needsRecordingRebuild = false;\r\n }\r\n if (!this.persistence) this.persistence = new PersistenceService();\r\n if (!this.translation) this.translation = new TranslationService();\r\n\r\n this.httpMonitor = new HttpMonitor(this.recording);\r\n this.httpMonitor.install();\r\n\r\n injectStyles(LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, 'lib-e2e-swal2-styles');\r\n injectStyles(SCROLLBAR_STYLES, 'lib-e2e-scrollbar-styles');\r\n\r\n this.initHttpConfig();\r\n this.initLanguage();\r\n this.initFilesystemAccess();\r\n this.initSelectorStrategy();\r\n this.initSubscriptions();\r\n this.render();\r\n this.initVisibility();\r\n this.initSessionContinuity();\r\n this.initWidgetPosition();\r\n\r\n this.keydownHandler = (e: KeyboardEvent) => this.handleKeyboardEvent(e);\r\n window.addEventListener('keydown', this.keydownHandler);\r\n\r\n // Draggable widget (spec 007): pointer move/up tracked at window level so the\r\n // drag keeps working even if the cursor leaves the toggle button.\r\n this.widgetPointerMove = (e: MouseEvent) => this.onWidgetPointerMove(e);\r\n this.widgetPointerUp = () => this.onWidgetPointerUp();\r\n this.widgetResize = () => this.applyWidgetPosition();\r\n window.addEventListener('pointermove', this.widgetPointerMove as EventListener);\r\n window.addEventListener('pointerup', this.widgetPointerUp);\r\n window.addEventListener('resize', this.widgetResize);\r\n }\r\n\r\n disconnectedCallback(): void {\r\n if (this._isDisabled) return;\r\n window.removeEventListener('keydown', this.keydownHandler);\r\n // Final flush: if a recording is in progress, persist it synchronously-ish\r\n // before tearing the service down, so an unmount (single-spa per-sub-project\r\n // placement) does not lose the last commands. The realm survives client-side\r\n // navigation, so this async write completes even after the element is gone.\r\n this.flushActiveSessionOnDisconnect();\r\n this.recordingUnsub?.();\r\n this.commandsUnsub?.();\r\n this.interceptorsUnsub?.();\r\n this.pauseUnsub?.();\r\n this.selectorNotFoundUnsub?.();\r\n this.langUnsub?.();\r\n this.sessionUnsub?.();\r\n if (this.widgetPointerMove) window.removeEventListener('pointermove', this.widgetPointerMove as EventListener);\r\n if (this.widgetPointerUp) window.removeEventListener('pointerup', this.widgetPointerUp);\r\n if (this.widgetResize) window.removeEventListener('resize', this.widgetResize);\r\n this.httpMonitor?.uninstall();\r\n this.recording.destroy();\r\n // The service's AbortController is now spent (DOM listeners are dead) and the\r\n // patched history methods are restored. Flag a rebuild so a reconnect of the\r\n // SAME element gets a FRESH service + monitor (the buffer is recovered from\r\n // IndexedDB by initSessionContinuity, spec 006). We do NOT null the reference\r\n // here — the Subjects stay functional, so any in-flight async (e.g. a deferred\r\n // save calling clearCommands) won't hit `undefined`.\r\n this._needsRecordingRebuild = true;\r\n }\r\n\r\n private async initHttpConfig(): Promise<void> {\r\n const config = await this.persistence.getConfig('extendedHttpCommands');\r\n if (config === null) {\r\n await this.persistence.setConfig({ extendedHttpCommands: 'true' });\r\n localStorage.setItem('extendedHttpCommands', 'true');\r\n } else {\r\n localStorage.setItem('extendedHttpCommands', (config['extendedHttpCommands'] as string) ?? 'true');\r\n }\r\n // Mirror the fixture-mode flag to localStorage so HttpMonitor can read it (spec 012).\r\n const fx = await this.persistence.getConfig('fixtureMode');\r\n localStorage.setItem('fixtureMode', (fx?.['fixtureMode'] as string) ?? 'false');\r\n }\r\n\r\n private async initLanguage(): Promise<void> {\r\n const config = await this.persistence.getConfig('language');\r\n const lang = config?.['language'] as Lang | undefined;\r\n this.translation.setLang(lang ?? this.translation.detectLang());\r\n }\r\n\r\n private initSubscriptions(): void {\r\n this.recordingUnsub = this.recording.onRecordingChange((val) => {\r\n this.isRecording = val;\r\n if (!val && !this.controlFirstTimeData) {\r\n this.saveRecordingHistory();\r\n // Stopping the recording ends the cross-app session: only an actively\r\n // recording session is ever persisted/resumed (spec 006, Q2).\r\n this.clearSessionPersistence();\r\n this.showSaveTestDialog();\r\n }\r\n this.controlFirstTimeData = false;\r\n this.render();\r\n });\r\n // Persist the live session incrementally so it survives a micro-frontend\r\n // crossing or a same-origin reload (spec 006).\r\n this.sessionUnsub = this.recording.onSessionChange((state) => this.persistActiveSession(state));\r\n this.commandsUnsub = this.recording.onCommandsChange((cmds) => {\r\n this.cypressCommands = cmds;\r\n if (this._previsualizerRef) this._previsualizerRef.commands = cmds;\r\n });\r\n this.interceptorsUnsub = this.recording.onInterceptorsChange((icps) => {\r\n this.interceptors = icps;\r\n if (this._previsualizerRef) this._previsualizerRef.interceptors = icps;\r\n });\r\n this.pauseUnsub = this.recording.onPauseChange((paused) => {\r\n this.isPaused = paused;\r\n this.render();\r\n });\r\n this.selectorNotFoundUnsub = this.recording.onSelectorNotFound((target) => {\r\n if (this.smartSelectorEnabled) this.showSelectorPicker(target);\r\n });\r\n // Re-render the widget chrome when the UI language changes so labels update live.\r\n this.langUnsub = this.translation.onLangChange(() => this.render());\r\n }\r\n\r\n private showSelectorPicker(target: HTMLElement): void {\r\n import('../../components/selector-picker/selector-picker').then(() => {\r\n const existing = document.querySelector('selector-picker');\r\n if (existing) existing.remove();\r\n\r\n const picker = document.createElement('selector-picker') as unknown as SelectorPickerEl;\r\n picker.targetElement = target;\r\n picker.recording = this.recording;\r\n picker.translation = this.translation;\r\n document.body.appendChild(picker as unknown as Node);\r\n });\r\n }\r\n\r\n private async initVisibility(): Promise<void> {\r\n if (this.hasAttribute('start-hidden')) {\r\n // Attribute overrides DB: presence → hidden, explicit \"false\" → visible\r\n this.isVisible = this.getAttribute('start-hidden') === 'false';\r\n this.style.display = this.isVisible ? '' : 'none';\r\n return;\r\n }\r\n const config = await this.persistence.getGeneralConfig();\r\n this.isVisible = config?.['startHidden'] !== 'true';\r\n this.style.display = this.isVisible ? '' : 'none';\r\n }\r\n\r\n private async initSelectorStrategy(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n const strategy = config?.['selectorStrategy'] as string | undefined;\r\n if (strategy) this.recording.selectorStrategy = strategy as SelectorStrategy;\r\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\r\n }\r\n\r\n // ── cross-app session continuity (spec 006) ───────────────────────────────\r\n\r\n /**\r\n * On mount, detect a persisted live recording session and either resume it\r\n * silently (recent) or prompt continue/discard (stale). No-op when there is\r\n * no actively-recording session.\r\n */\r\n private async initSessionContinuity(): Promise<void> {\r\n if (this._isDisabled) return;\r\n const session = await this.persistence.getActiveSession();\r\n if (!session || !session.isRecording) return;\r\n const ttlMin = await this.getResumeTtlMinutes();\r\n const ageMs = Date.now() - session.updatedAt;\r\n if (ageMs <= ttlMin * 60_000) {\r\n this.resumeSessionState(session);\r\n } else {\r\n this.promptResumeOrDiscard(session);\r\n }\r\n }\r\n\r\n private async getResumeTtlMinutes(): Promise<number> {\r\n const config = await this.persistence.getConfig(RESUME_TTL_CONFIG_KEY);\r\n const raw = config?.[RESUME_TTL_CONFIG_KEY];\r\n const n = typeof raw === 'number' ? raw : Number(raw);\r\n return Number.isFinite(n) && n > 0 ? n : DEFAULT_RESUME_TTL_MINUTES;\r\n }\r\n\r\n /** Rehydrates the recorder from a persisted session (no bootstrap re-emitted). */\r\n private resumeSessionState(session: ActiveSessionState): void {\r\n this.recording.restoreSession(session);\r\n this.cypressCommands = session.commands;\r\n this.interceptors = session.interceptors;\r\n this.controlFirstTimeData = false;\r\n this.render();\r\n }\r\n\r\n private async promptResumeOrDiscard(session: ActiveSessionState): Promise<void> {\r\n const t = this.translation.translate.bind(this.translation);\r\n const result = await Swal.fire({\r\n title: t('RECORDER.SESSION_RESUME_TITLE'),\r\n html:\r\n `<div style=\"padding:8px 4px;color:#8b949e;font-size:13px;line-height:1.6\">` +\r\n `<p>${t('RECORDER.SESSION_RESUME_TEXT')}</p>` +\r\n `<p style=\"margin-top:6px;color:#c9d1d9\"><b>${session.commands.length}</b> ${t('RECORDER.SESSION_RESUME_COUNT')}</p>` +\r\n `</div>`,\r\n showCancelButton: true,\r\n confirmButtonText: t('RECORDER.SESSION_CONTINUE_BTN'),\r\n cancelButtonText: t('RECORDER.SESSION_DISCARD_BTN'),\r\n color: '#e6edf3',\r\n });\r\n if (result && (result as { isConfirmed?: boolean }).isConfirmed) {\r\n this.resumeSessionState(session);\r\n } else {\r\n this.discardSession();\r\n }\r\n }\r\n\r\n /** Debounced persistence of the live session; clears it the moment recording stops. */\r\n private persistActiveSession(state: ActiveSessionState): void {\r\n if (this._isDisabled) return;\r\n if (!state.isRecording) {\r\n this.clearSessionPersistence();\r\n return;\r\n }\r\n this.writeSessionBreadcrumb(state);\r\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\r\n this.sessionSaveTimer = setTimeout(() => {\r\n const snap = this.recording.getSessionSnapshot();\r\n if (snap.isRecording) this.persistence.saveActiveSession(snap).catch(() => { /* storage errors are non-fatal */ });\r\n }, 300);\r\n }\r\n\r\n private writeSessionBreadcrumb(state: ActiveSessionState): void {\r\n try {\r\n localStorage.setItem(ACTIVE_SESSION_BREADCRUMB_KEY, JSON.stringify({\r\n sessionId: state.sessionId,\r\n isRecording: state.isRecording,\r\n updatedAt: state.updatedAt,\r\n }));\r\n } catch { /* ignore storage errors */ }\r\n }\r\n\r\n private flushActiveSessionOnDisconnect(): void {\r\n const snap = this.recording.getSessionSnapshot();\r\n if (!snap.isRecording) return;\r\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\r\n this.writeSessionBreadcrumb(snap);\r\n this.persistence.saveActiveSession(snap).catch(() => { /* non-fatal */ });\r\n }\r\n\r\n private clearSessionPersistence(): void {\r\n if (this.sessionSaveTimer) { clearTimeout(this.sessionSaveTimer); this.sessionSaveTimer = undefined; }\r\n try { localStorage.removeItem(ACTIVE_SESSION_BREADCRUMB_KEY); } catch { /* ignore */ }\r\n this.persistence.clearActiveSession().catch(() => { /* non-fatal */ });\r\n }\r\n\r\n /** True when a synchronous breadcrumb marks an active recording session. */\r\n hasActiveSession(): boolean {\r\n try {\r\n const raw = localStorage.getItem(ACTIVE_SESSION_BREADCRUMB_KEY);\r\n if (!raw) return false;\r\n return !!(JSON.parse(raw) as { isRecording?: boolean }).isRecording;\r\n } catch { return false; }\r\n }\r\n\r\n /** Programmatically resume the persisted session, if any. */\r\n resumeSession(): void {\r\n this.persistence.getActiveSession().then((s) => { if (s) this.resumeSessionState(s); });\r\n }\r\n\r\n /** Discard the persisted live session (breadcrumb + DB record). */\r\n discardSession(): void {\r\n this.clearSessionPersistence();\r\n }\r\n\r\n // ── draggable widget (spec 007) ────────────────────────────────────────────\r\n\r\n /** Loads a previously saved widget position and applies it. */\r\n private async initWidgetPosition(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n const pos = config?.['widgetPosition'] as Partial<Point> | null | undefined;\r\n if (pos && typeof pos.x === 'number' && typeof pos.y === 'number') {\r\n this.togglePos = { x: pos.x, y: pos.y };\r\n }\r\n this.applyWidgetPosition();\r\n }\r\n\r\n /** Positions the `.widget` box from the (clamped) toggle centre and orients the arc. */\r\n private applyWidgetPosition(): void {\r\n const widget = this.shadow.querySelector('.widget') as HTMLElement | null;\r\n if (!widget) return;\r\n const vw = window.innerWidth;\r\n const vh = window.innerHeight;\r\n const centre = this.togglePos ?? defaultTogglePosition(vw, vh);\r\n const clamped = clampTogglePosition(centre.x, centre.y, vw, vh);\r\n this.expandDir = resolveExpandDirection(clamped.x, clamped.y, vw, vh);\r\n const topLeft = boxTopLeftFor(clamped, this.expandDir);\r\n widget.style.left = `${topLeft.x}px`;\r\n widget.style.top = `${topLeft.y}px`;\r\n widget.style.right = 'auto';\r\n widget.style.bottom = 'auto';\r\n widget.setAttribute('data-expand', this.expandDir);\r\n }\r\n\r\n private beginWidgetDrag(e: MouseEvent): void {\r\n // Clear any stale suppression from a previous drag that ended off the toggle\r\n // (no click fired there), so this fresh press can't swallow a genuine click.\r\n this.suppressNextToggleClick = false;\r\n const origin = this.togglePos ?? defaultTogglePosition(window.innerWidth, window.innerHeight);\r\n this.dragState = { startX: e.clientX, startY: e.clientY, origX: origin.x, origY: origin.y, moved: false };\r\n }\r\n\r\n private onWidgetPointerMove(e: MouseEvent): void {\r\n if (!this.dragState) return;\r\n const dx = e.clientX - this.dragState.startX;\r\n const dy = e.clientY - this.dragState.startY;\r\n if (!this.dragState.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\r\n this.dragState.moved = true;\r\n this.togglePos = { x: this.dragState.origX + dx, y: this.dragState.origY + dy };\r\n this.applyWidgetPosition();\r\n }\r\n\r\n private onWidgetPointerUp(): void {\r\n if (!this.dragState) return;\r\n const moved = this.dragState.moved;\r\n this.dragState = undefined;\r\n if (!moved || !this.togglePos) return;\r\n // It was a drag, not a click: suppress the click that fires next and persist.\r\n this.suppressNextToggleClick = true;\r\n const clamped = clampTogglePosition(this.togglePos.x, this.togglePos.y, window.innerWidth, window.innerHeight);\r\n this.togglePos = clamped;\r\n this.persistence.setConfig({ widgetPosition: clamped }).catch(() => { /* non-fatal */ });\r\n }\r\n\r\n /** Resets the widget to its default corner and clears the saved position. */\r\n resetWidgetPosition(): void {\r\n this.togglePos = null;\r\n this.persistence.setConfig({ widgetPosition: null }).catch(() => { /* non-fatal */ });\r\n this.applyWidgetPosition();\r\n }\r\n\r\n toggle(): void {\r\n this.recording.toggleRecording();\r\n }\r\n\r\n togglePause(): void {\r\n this.recording.togglePause();\r\n }\r\n\r\n setLanguage(lang?: string): void {\r\n const resolved = lang ? (lang as Lang) : this.translation.detectLang();\r\n this.translation.setLang(resolved);\r\n }\r\n\r\n handleKeyboardEvent(event: KeyboardEvent): void {\r\n if (!event.ctrlKey) return;\r\n const key = event.key.toLowerCase();\r\n if (key === 'e' && event.shiftKey) { event.preventDefault(); this.toggleVisibility(); return; }\r\n if (!this.isVisible) return;\r\n if (key === 'r') { event.preventDefault(); this.toggle(); }\r\n else if (key === 'p') { event.preventDefault(); this.togglePause(); }\r\n else if (key === '1') { event.preventDefault(); this.showSavedTestsDialog(); }\r\n else if (key === '2') { event.preventDefault(); this.showCommandsDialog(); }\r\n else if (key === '3') { event.preventDefault(); this.showSettingsDialog(); }\r\n else if (key === 'h' && event.shiftKey) { event.preventDefault(); this.showHelpDialog(); }\r\n }\r\n\r\n toggleVisibility(): void {\r\n this.isVisible = !this.isVisible;\r\n this.style.display = this.isVisible ? '' : 'none';\r\n }\r\n\r\n // ── recording history (task 5) ────────────────────────────────────────────\r\n\r\n private saveRecordingHistory(): void {\r\n if (!this.cypressCommands.length) return;\r\n try {\r\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\r\n existing.unshift({ commands: this.cypressCommands, interceptors: this.interceptors, savedAt: Date.now() });\r\n if (existing.length > 5) existing.splice(5);\r\n localStorage.setItem('e2e-recording-history', JSON.stringify(existing));\r\n } catch { /* ignore storage errors */ }\r\n }\r\n\r\n recoverLastRecording(): void {\r\n try {\r\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\r\n if (!existing.length) return;\r\n const { commands, interceptors } = existing[0];\r\n commands.forEach((cmd: string) => this.recording.appendCommand(cmd));\r\n (interceptors as string[]).forEach((_icp: string) => { /* interceptors are not appendable the same way */ });\r\n } catch { /* ignore */ }\r\n }\r\n\r\n clearRecordingHistory(): void {\r\n localStorage.removeItem('e2e-recording-history');\r\n }\r\n\r\n getRecordingHistory(): Array<{ commands: string[]; interceptors: string[]; savedAt: number }> {\r\n try {\r\n return JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\r\n } catch { return []; }\r\n }\r\n\r\n // ── filesystem setup ─────────────────────────────────────────────────────\r\n\r\n private async initFilesystemAccess(): Promise<void> {\r\n const config = await this.persistence.getGeneralConfig();\r\n // Only show if the user has never made a choice (key doesn't exist yet)\r\n if (config && 'allowReadWriteFiles' in config) return;\r\n this.showFilesystemSetupDialog();\r\n }\r\n\r\n private showFilesystemSetupDialog(): void {\r\n Swal.fire({\r\n title: this.translation.translate('RECORDER.FS_TITLE'),\r\n html: '<div id=\"fs-setup-content\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('fs-setup-content');\r\n if (!container) return;\r\n container.innerHTML = `\r\n <div style=\"padding:16px 20px 20px;color:#8b949e;font-size:13px;line-height:1.7\">\r\n <p>${this.translation.translate('RECORDER.FS_INTRO_HTML')}</p>\r\n <p style=\"margin-top:10px;margin-bottom:6px;font-size:11px;color:#8b949e\">\r\n ${this.translation.translate('RECORDER.FS_STRUCTURE_HINT_HTML')}\r\n </p>\r\n <pre style=\"margin:0;padding:10px 14px;background:#0d1117;border:1px solid #21262d;\r\n border-radius:8px;font-size:11px;color:#c9d1d9;line-height:1.8;\r\n font-family:'Cascadia Code','Fira Code','Consolas',monospace\">\r\ncypress/ <span style=\"color:#484f58\">${this.translation.translate('RECORDER.FS_TREE_PICK_HINT')}</span>\r\n└── e2e/ <span style=\"color:#484f58\">${this.translation.translate('RECORDER.FS_TREE_READ_HINT')}</span>\r\n └── *.cy.ts</pre>\r\n <p style=\"margin-top:8px;font-size:11px;color:#484f58\">\r\n ${this.translation.translate('RECORDER.FS_PERMISSION_NOTE')}\r\n </p>\r\n <div style=\"display:flex;gap:8px;justify-content:flex-end;margin-top:20px\">\r\n <button id=\"fs-skip\"\r\n style=\"padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;\r\n font-size:12px;font-weight:500;background:transparent;color:#8b949e\">\r\n ${this.translation.translate('RECORDER.FS_LATER_BTN')}\r\n </button>\r\n <button id=\"fs-select\"\r\n style=\"padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\r\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\r\n ${this.translation.translate('RECORDER.FS_SELECT_BTN')}\r\n </button>\r\n </div>\r\n </div>`;\r\n\r\n document.getElementById('fs-skip')?.addEventListener('click', async () => {\r\n await this.persistence.setConfigKey('allowReadWriteFiles', 'false');\r\n Swal.close();\r\n });\r\n\r\n document.getElementById('fs-select')?.addEventListener('click', async () => {\r\n try {\r\n await this.persistence.requestDirectoryPermissions();\r\n Swal.close();\r\n showToast(this.translation.translate('RECORDER.FS_SUCCESS_TOAST'));\r\n } catch (e: unknown) {\r\n if ((e as DOMException)?.name !== 'AbortError') {\r\n showToast(this.translation.translate('RECORDER.FS_ERROR_TOAST'), false);\r\n }\r\n // AbortError = user cancelled the picker, leave dialog open\r\n }\r\n });\r\n },\r\n });\r\n }\r\n\r\n // ── dialogs ──────────────────────────────────────────────────────────────\r\n\r\n showCommandsDialog(): void {\r\n this.toggleModal('isCommandsDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.DIALOG_COMMANDS'),\r\n html: '<div id=\"commands-modal-content\" style=\"min-height:250px;padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n backdrop: false,\r\n width: 640,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n // Make the container click-through so the page underneath remains interactive\r\n const swalContainer = document.querySelector('.swal2-container') as HTMLElement | null;\r\n if (swalContainer) {\r\n swalContainer.style.pointerEvents = 'none';\r\n const popup = swalContainer.querySelector('.swal2-popup') as HTMLElement | null;\r\n if (popup) popup.style.pointerEvents = 'all';\r\n }\r\n const container = document.getElementById('commands-modal-content');\r\n if (!container) return;\r\n\r\n const child = document.createElement('test-previsualizer') as unknown as PrevisualizerEl;\r\n child.translation = this.translation;\r\n child.commands = this.cypressCommands;\r\n child.interceptors = this.interceptors;\r\n child.editable = true;\r\n container.appendChild(child as unknown as Node);\r\n this._previsualizerRef = child;\r\n\r\n child.addEventListener('deletecommand', (e: CustomEvent) => {\r\n this.recording.removeCommand(e.detail);\r\n });\r\n child.addEventListener('movecommand', (e: CustomEvent) => {\r\n this.recording.moveCommand(e.detail.from, e.detail.to);\r\n });\r\n child.addEventListener('deleteinterceptor', (e: CustomEvent) => {\r\n this.recording.removeInterceptor(e.detail);\r\n });\r\n\r\n // ── Assertion builder panel ──────────────────────────────────────\r\n const assertionHtml = `\r\n <div id=\"assertion-builder\"\r\n style=\"padding:10px 12px;border-top:1px solid #21262d;background:#0d1117\">\r\n <div style=\"font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px\">\r\n ${this.translation.translate('RECORDER.ASSERTION_SECTION')}\r\n </div>\r\n <div style=\"display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end\">\r\n <input id=\"assert-selector\" type=\"text\"\r\n placeholder=\"${this.translation.translate('RECORDER.ASSERT_SELECTOR_PH').replace(/\"/g, '"')}\"\r\n style=\"flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\r\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;\r\n font-family:'Cascadia Code','Fira Code',monospace\"/>\r\n <select id=\"assert-type\"\r\n style=\"padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;\r\n color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0\">\r\n <option value=\"be.visible\">be.visible</option>\r\n <option value=\"not.exist\">not.exist</option>\r\n <option value=\"be.disabled\">be.disabled</option>\r\n <option value=\"be.checked\">be.checked</option>\r\n <option value=\"contain.text\">contain.text</option>\r\n <option value=\"have.value\">have.value</option>\r\n <option value=\"have.length\">have.length</option>\r\n <option value=\"have.class\">have.class</option>\r\n <option value=\"have.attr\">have.attr</option>\r\n </select>\r\n <input id=\"assert-value\" type=\"text\" placeholder=\"${this.translation.translate('RECORDER.ASSERT_VALUE_PH')}\"\r\n style=\"flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\r\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none\"/>\r\n <button id=\"btn-add-assertion\"\r\n style=\"padding:5px 12px;border:none;border-radius:5px;cursor:pointer;\r\n font-size:11px;font-weight:500;background:#2f81f7;color:#fff;\r\n white-space:nowrap;flex-shrink:0\">\r\n ${this.translation.translate('RECORDER.ASSERT_ADD_BTN')}\r\n </button>\r\n </div>\r\n </div>`;\r\n container.insertAdjacentHTML('beforeend', assertionHtml);\r\n\r\n const NO_VALUE_ASSERTIONS = new Set(['be.visible', 'not.exist', 'be.disabled', 'be.checked']);\r\n document.getElementById('btn-add-assertion')?.addEventListener('click', () => {\r\n const sel = (document.getElementById('assert-selector') as HTMLInputElement).value.trim();\r\n const type = (document.getElementById('assert-type') as HTMLSelectElement).value;\r\n const val = (document.getElementById('assert-value') as HTMLInputElement).value.trim();\r\n if (!sel) return;\r\n const s = escapeSingleQuotes(sel);\r\n const v = escapeSingleQuotes(val);\r\n const cmd = NO_VALUE_ASSERTIONS.has(type) || !val\r\n ? `cy.get('${s}').should('${type}')`\r\n : `cy.get('${s}').should('${type}', '${v}')`;\r\n this.recording.appendCommand(cmd);\r\n (document.getElementById('assert-selector') as HTMLInputElement).value = '';\r\n (document.getElementById('assert-value') as HTMLInputElement).value = '';\r\n });\r\n },\r\n willClose: () => {\r\n this.isCommandsDialogOpen = false;\r\n this._previsualizerRef = null;\r\n },\r\n });\r\n this.resizePopup();\r\n });\r\n }\r\n\r\n showSavedTestsDialog(): void {\r\n this.toggleModal('isSavedTestsDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVED_TESTS'),\r\n html: '<div id=\"saved-tests-modal-content\" style=\"min-height:250px;padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n width: 680,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('saved-tests-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('test-editor') as unknown as TestEditorEl;\r\n child.persistence = this.persistence;\r\n child.translation = this.translation;\r\n container.appendChild(child as unknown as Node);\r\n },\r\n willClose: () => { this.isSavedTestsDialogOpen = false; },\r\n });\r\n this.resizePopup();\r\n });\r\n }\r\n\r\n showSaveTestDialog(): void {\r\n this.toggleModal('isSaveTestDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVE'),\r\n html: '<div id=\"save-test-modal-content\" style=\"padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('save-test-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('save-test') as unknown as SaveTestEl;\r\n child.translation = this.translation;\r\n // Provider is only needed once the user reaches the description step, so the\r\n // async config read completes well before it is read (spec 014).\r\n this.persistence.getGeneralConfig().then((config) => {\r\n const providerId = config?.['issueTrackerProviderId'] as string | undefined;\r\n if (providerId) child.issueTrackerProviderId = providerId;\r\n });\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('savetest', (e: CustomEvent) => {\r\n const { description, notes, tags, ticketId } = e.detail ?? {};\r\n this.onSaveTest(description ?? null, tags ?? [], notes ?? '', ticketId ?? null);\r\n Swal.close();\r\n });\r\n child.addEventListener('saveandexport', (e: CustomEvent) => {\r\n const { description, notes, tags, ticketId } = e.detail ?? {};\r\n this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? '', ticketId ?? null);\r\n Swal.close();\r\n });\r\n },\r\n willClose: () => { this.isSaveTestDialogOpen = false; },\r\n });\r\n });\r\n }\r\n\r\n showSettingsDialog(): void {\r\n this.toggleModal('isSettingsDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.SETTINGS'),\r\n html: '<div id=\"settings-modal-content\" style=\"padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n width: 520,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('settings-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('e2e-configuration') as unknown as ConfigEl;\r\n child.persistence = this.persistence;\r\n child.translation = this.translation;\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('smartselectorchange', (e: CustomEvent) => {\r\n this.smartSelectorEnabled = e.detail;\r\n });\r\n child.addEventListener('starthiddenchange', (e: CustomEvent) => {\r\n this.isVisible = !e.detail;\r\n this.style.display = this.isVisible ? '' : 'none';\r\n });\r\n child.addEventListener('resetwidgetposition', () => this.resetWidgetPosition());\r\n },\r\n willClose: () => { this.isSettingsDialogOpen = false; },\r\n });\r\n this.resizePopup();\r\n });\r\n }\r\n\r\n showHelpDialog(): void {\r\n this.toggleModal('isHelpDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('HELP.TITLE'),\r\n html: '<div id=\"help-modal-content\" style=\"padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n width: 560,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const container = document.getElementById('help-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('help-panel') as unknown as HelpPanelEl;\r\n child.translation = this.translation;\r\n container.appendChild(child as unknown as Node);\r\n },\r\n willClose: () => { this.isHelpDialogOpen = false; },\r\n });\r\n this.resizePopup();\r\n });\r\n }\r\n\r\n showAdvancedEditorDialog(testId?: number): void {\r\n this.toggleModal('isAdvancedEditorDialogOpen', () => {\r\n Swal.fire({\r\n title: this.translation.translate('MAIN_FRAME.SHOW_ADVANCED_EDITOR'),\r\n html: '<div id=\"advanced-editor-modal-content\" style=\"flex:1;min-height:0;display:flex;flex-direction:column;padding:0\"></div>',\r\n showCloseButton: true,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n width: 780,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n const popup = Swal.getPopup();\r\n if (popup) {\r\n popup.style.height = '600px';\r\n const htmlContainer = popup.querySelector('.swal2-html-container') as HTMLElement | null;\r\n if (htmlContainer) {\r\n htmlContainer.style.flex = '1';\r\n htmlContainer.style.minHeight = '0';\r\n htmlContainer.style.overflow = 'hidden';\r\n htmlContainer.style.padding = '0';\r\n htmlContainer.style.margin = '0';\r\n htmlContainer.style.display = 'flex';\r\n htmlContainer.style.flexDirection = 'column';\r\n }\r\n }\r\n const container = document.getElementById('advanced-editor-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('advanced-test-editor') as unknown as AdvancedEditorEl;\r\n child.persistence = this.persistence;\r\n child.translation = this.translation;\r\n if (testId !== undefined) child.testId = testId;\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('selectorstrategychange', (e: CustomEvent) => {\r\n this.recording.selectorStrategy = e.detail;\r\n });\r\n child.addEventListener('closemodal', () => Swal.close());\r\n child.addEventListener('openfileeditor', (e: CustomEvent) => {\r\n Swal.close();\r\n setTimeout(() => this.showFileEditorDialog(\r\n e.detail.handle, e.detail.content, e.detail.fileName, e.detail.testId,\r\n e.detail.itBlock, e.detail.interceptorsBlock, e.detail.notes,\r\n ), 150);\r\n });\r\n },\r\n willClose: () => { this.isAdvancedEditorDialogOpen = false; },\r\n });\r\n setTimeout(() => {\r\n const popup = Swal.getPopup();\r\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 0 });\r\n }, 0);\r\n });\r\n }\r\n\r\n private showFileEditorDialog(\r\n handle: FileSystemFileHandle,\r\n content: string,\r\n fileName: string,\r\n testId?: number,\r\n itBlock = '',\r\n interceptorsBlock = '',\r\n notes = '',\r\n ): void {\r\n Swal.fire({\r\n title: this.translation.translate('RECORDER.FILE_EDITOR_TITLE'),\r\n html: '<div id=\"file-editor-modal-content\" style=\"flex:1;min-height:0;display:flex;flex-direction:column;padding:0\"></div>',\r\n showCloseButton: false,\r\n showConfirmButton: false,\r\n allowOutsideClick: false,\r\n width: 1100,\r\n color: '#e6edf3',\r\n didOpen: () => {\r\n makeSwalDraggable();\r\n setSwal2DataCyAttribute();\r\n // Give the code editor a tall default height (otherwise the popup collapses\r\n // to its ~210px min-height and the user has to resize it every time).\r\n const popup = Swal.getPopup();\r\n if (popup) {\r\n popup.style.height = '640px';\r\n const htmlContainer = popup.querySelector('.swal2-html-container') as HTMLElement | null;\r\n if (htmlContainer) {\r\n htmlContainer.style.flex = '1';\r\n htmlContainer.style.minHeight = '0';\r\n htmlContainer.style.overflow = 'hidden';\r\n htmlContainer.style.padding = '0';\r\n htmlContainer.style.margin = '0';\r\n htmlContainer.style.display = 'flex';\r\n htmlContainer.style.flexDirection = 'column';\r\n }\r\n }\r\n const container = document.getElementById('file-editor-modal-content');\r\n if (!container) return;\r\n const child = document.createElement('file-preview') as unknown as FilePreviewEl;\r\n child.translation = this.translation;\r\n child.fileContent = content;\r\n child.fileName = fileName;\r\n child.closeLabel = this.translation.translate('FILE_PREVIEW.BACK_TO_EDITOR');\r\n child.itBlock = itBlock;\r\n child.interceptorsBlock = interceptorsBlock;\r\n child.notes = notes;\r\n container.appendChild(child as unknown as Node);\r\n child.addEventListener('close', () => {\r\n Swal.close();\r\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\r\n });\r\n child.addEventListener('save', async (e: CustomEvent) => {\r\n try {\r\n const writable = await handle.createWritable();\r\n await writable.write(e.detail);\r\n await writable.close();\r\n showToast(this.translation.translate('RECORDER.FILE_SAVED_TOAST'));\r\n } catch {\r\n showToast(this.translation.translate('RECORDER.FILE_SAVE_ERROR_TOAST'), false);\r\n }\r\n Swal.close();\r\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\r\n });\r\n },\r\n });\r\n this.resizePopup();\r\n }\r\n\r\n // ── save handlers ─────────────────────────────────────────────────────────\r\n\r\n private async onSaveTest(description: string | null, tags: string[] = [], notes = '', ticketId: string | null = null): Promise<void> {\r\n if (description) {\r\n const fixtures = this.recording.getFixturesSnapshot();\r\n await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes, ticketId ?? undefined);\r\n await this.writeFixturesIfAny(fixtures);\r\n this.recording.clearCommands();\r\n this.clearRecordingHistory();\r\n this.cypressCommands = [];\r\n this.interceptors = [];\r\n }\r\n }\r\n\r\n private async onSaveAndExportTest(description: string | null, tags: string[] = [], notes = '', ticketId: string | null = null): Promise<void> {\r\n if (description) {\r\n const fixtures = this.recording.getFixturesSnapshot();\r\n const id = await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes, ticketId ?? undefined);\r\n await this.writeFixturesIfAny(fixtures);\r\n this.recording.clearCommands();\r\n this.clearRecordingHistory();\r\n this.cypressCommands = [];\r\n this.interceptors = [];\r\n setTimeout(() => this.showAdvancedEditorDialog(id), 300);\r\n }\r\n }\r\n\r\n /** Writes captured fixtures to cypress/fixtures and toasts the outcome (spec 012). */\r\n private async writeFixturesIfAny(fixtures: Array<{ name: string; content: string }>): Promise<void> {\r\n if (!fixtures.length) return;\r\n try {\r\n const n = await this.persistence.writeFixtures(fixtures);\r\n showToast(`${this.translation.translate('RECORDER.FIXTURES_WRITTEN_TOAST')} (${n})`);\r\n } catch {\r\n showToast(this.translation.translate('RECORDER.FIXTURES_NO_FOLDER_TOAST'), false);\r\n }\r\n }\r\n\r\n // ── helpers ───────────────────────────────────────────────────────────────\r\n\r\n private toggleModal(flag: keyof this, openFn: () => void): void {\r\n if (this[flag]) {\r\n Swal.close();\r\n (this as Record<string, unknown>)[flag as string] = false;\r\n return;\r\n }\r\n (this as Record<string, unknown>)[flag as string] = true;\r\n openFn();\r\n }\r\n\r\n private resizePopup(): void {\r\n setTimeout(() => {\r\n const popup = Swal.getPopup();\r\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 200 });\r\n }, 0);\r\n }\r\n\r\n private render(): void {\r\n const rec = this.isRecording;\r\n const paused = this.isPaused;\r\n this.style.display = this.isVisible ? '' : 'none';\r\n this.shadow.innerHTML = `<style>${getRecorderStyles(rec, paused)}</style>${renderRecorderWidget(rec, paused, this.translation.translate.bind(this.translation))}`;\r\n const toggleBtn = this.shadow.querySelector('[data-action=\"toggle\"]');\r\n toggleBtn?.addEventListener('click', () => {\r\n // A drag ends with a click event we must swallow so it doesn't toggle recording.\r\n if (this.suppressNextToggleClick) { this.suppressNextToggleClick = false; return; }\r\n this.toggle();\r\n });\r\n toggleBtn?.addEventListener('pointerdown', (e) => this.beginWidgetDrag(e as MouseEvent));\r\n this.shadow.querySelector('[data-action=\"pause\"]')\r\n ?.addEventListener('click', () => this.togglePause());\r\n this.shadow.querySelector('[data-action=\"tests\"]')\r\n ?.addEventListener('click', () => this.showSavedTestsDialog());\r\n this.shadow.querySelector('[data-action=\"commands\"]')\r\n ?.addEventListener('click', () => this.showCommandsDialog());\r\n this.shadow.querySelector('[data-action=\"config\"]')\r\n ?.addEventListener('click', () => this.showSettingsDialog());\r\n this.shadow.querySelector('[data-action=\"browse\"]')\r\n ?.addEventListener('click', () => this.showAdvancedEditorDialog());\r\n this.shadow.querySelector('[data-action=\"help\"]')\r\n ?.addEventListener('click', () => this.showHelpDialog());\r\n // Re-apply the dragged position/orientation after every re-render.\r\n this.applyWidgetPosition();\r\n }\r\n}\r\n\r\nif (!customElements.get('lib-e2e-recorder')) {\r\n customElements.define('lib-e2e-recorder', LibE2eRecorderElement);\r\n}\r\n","import type { ExpandDirection } from '../../utils/widget-position.utils';\r\n\r\nconst DIRECTIONS: ExpandDirection[] = ['up-left', 'up-right', 'down-left', 'down-right'];\r\n\r\n/**\r\n * Per-direction anchors for the toggle/pause buttons and the action-menu popover.\r\n * The menu opens on the side of the FAB that faces the viewport interior, so it\r\n * stays on-screen wherever the (draggable) widget is dropped (spec 007 + 012).\r\n */\r\nfunction directionBlocks(): string {\r\n return DIRECTIONS.map((dir) => {\r\n const tv = dir.startsWith('up') ? 'bottom' : 'top'; // FAB vertical side\r\n const th = dir.endsWith('left') ? 'right' : 'left'; // FAB horizontal side\r\n const ov = tv === 'bottom' ? 'top' : 'bottom';\r\n const oh = th === 'right' ? 'left' : 'right';\r\n const sel = `.widget[data-expand=\"${dir}\"]`;\r\n return `\r\n ${sel} .btn-toggle { ${tv}: 24px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\r\n ${sel} .btn-pause { ${tv}: 78px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\r\n ${sel} .action-menu { ${tv}: 118px; ${th}: 8px; ${ov}: auto; ${oh}: auto; transform-origin: ${tv} ${th}; }\r\n `;\r\n }).join('\\n');\r\n}\r\n\r\nexport function getRecorderStyles(rec: boolean, paused: boolean): string {\r\n return `\r\n :host { all: initial; }\r\n *, *::before, *::after { box-sizing: border-box; }\r\n\r\n /*\r\n * Hit area. Position (left/top) is set from JS so the widget can be dragged;\r\n * data-expand orients the action-menu popover toward the viewport interior.\r\n * The menu is a DOM child, so hovering it keeps :host(.widget):hover alive even\r\n * though it visually overflows this box. Defaults to bottom-right.\r\n */\r\n .widget {\r\n position: fixed;\r\n bottom: 0;\r\n right: 0;\r\n width: 190px;\r\n height: 190px;\r\n z-index: 2147483647;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\r\n }\r\n\r\n /* ── Toggle (FAB) ─────────────────────────────────── */\r\n .btn-toggle {\r\n position: absolute;\r\n bottom: 24px;\r\n right: 24px;\r\n width: 44px;\r\n height: 44px;\r\n border-radius: 50%;\r\n border: none;\r\n cursor: grab;\r\n touch-action: none;\r\n font-size: 19px;\r\n background: ${rec\r\n ? 'linear-gradient(135deg,#f85149 0%,#da3633 100%)'\r\n : 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'};\r\n color: #fff;\r\n box-shadow: ${rec\r\n ? '0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13)'\r\n : '0 4px 20px rgba(47,129,247,.45),0 0 0 4px rgba(47,129,247,.11)'};\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transition: transform .18s, box-shadow .2s;\r\n z-index: 2;\r\n ${rec ? 'animation: toggle-pulse 2s ease-in-out infinite;' : ''}\r\n }\r\n .btn-toggle:hover { transform: scale(1.1); }\r\n .btn-toggle:active { transform: scale(0.93); cursor: grabbing; }\r\n\r\n @keyframes toggle-pulse {\r\n 0%,100% { box-shadow: 0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13); }\r\n 50% { box-shadow: 0 6px 28px rgba(248,81,73,.75),0 0 0 8px rgba(248,81,73,.06); }\r\n }\r\n\r\n /* ── Pause button ────────────────────────────────── */\r\n .btn-pause {\r\n position: absolute;\r\n bottom: 78px;\r\n right: 24px;\r\n width: 34px;\r\n height: 34px;\r\n border-radius: 50%;\r\n border: none;\r\n cursor: pointer;\r\n font-size: 15px;\r\n display: ${rec ? 'flex' : 'none'};\r\n align-items: center;\r\n justify-content: center;\r\n background: ${paused\r\n ? 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'\r\n : 'rgba(13,17,23,0.85)'};\r\n color: ${paused ? '#fff' : '#e3b341'};\r\n box-shadow: 0 2px 12px rgba(0,0,0,.4), 0 0 0 1px rgba(48,54,61,.8);\r\n transition: transform .15s, background .2s, color .2s;\r\n z-index: 2;\r\n }\r\n .btn-pause:hover { transform: scale(1.12); }\r\n .btn-pause:active { transform: scale(0.93); }\r\n\r\n /* ── Action menu (labelled grid popover) ─────────── */\r\n .action-menu {\r\n position: absolute;\r\n display: grid;\r\n grid-template-columns: repeat(3, 1fr);\r\n gap: 4px;\r\n padding: 8px;\r\n width: 174px;\r\n background: rgba(13,17,23,.97);\r\n border: 1px solid rgba(48,54,61,.9);\r\n border-radius: 12px;\r\n box-shadow: 0 8px 28px rgba(0,0,0,.5);\r\n backdrop-filter: blur(14px);\r\n -webkit-backdrop-filter: blur(14px);\r\n opacity: 0;\r\n transform: scale(0.9);\r\n pointer-events: none;\r\n transition: opacity .16s, transform .2s cubic-bezier(.34,1.56,.64,1);\r\n z-index: 3;\r\n }\r\n .widget:hover .action-menu {\r\n opacity: 1;\r\n transform: scale(1);\r\n pointer-events: all;\r\n }\r\n\r\n .action-item {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: flex-start;\r\n gap: 3px;\r\n padding: 8px 4px;\r\n border: none;\r\n border-radius: 8px;\r\n cursor: pointer;\r\n background: transparent;\r\n color: #c9d1d9;\r\n font-size: 18px;\r\n line-height: 1;\r\n transition: background .12s;\r\n }\r\n .action-item:hover { background: #21262d; }\r\n .action-item .label {\r\n font-size: 9px;\r\n font-weight: 500;\r\n color: #8b949e;\r\n white-space: nowrap;\r\n }\r\n .action-item:hover .label { color: #e6edf3; }\r\n\r\n /* Per-direction anchors */\r\n ${directionBlocks()}\r\n\r\n /* ── REC / PAUSED badge ──────────────────────────── */\r\n .rec-badge {\r\n position: fixed;\r\n top: 14px;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n background: ${paused\r\n ? 'linear-gradient(90deg,#e3b341,#d29922)'\r\n : 'linear-gradient(90deg,#f85149,#da3633)'};\r\n color: #fff;\r\n padding: 3px 16px;\r\n border-radius: 20px;\r\n font-size: 10px;\r\n font-weight: 700;\r\n letter-spacing: 2px;\r\n text-transform: uppercase;\r\n z-index: 2147483647;\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\r\n box-shadow: ${paused\r\n ? '0 4px 16px rgba(227,179,65,.4)'\r\n : '0 4px 16px rgba(248,81,73,.4)'};\r\n display: ${rec ? 'block' : 'none'};\r\n ${!paused ? 'animation: rec-pulse 1.8s ease-in-out infinite;' : ''}\r\n }\r\n @keyframes rec-pulse {\r\n 0%,100% { opacity: 1; }\r\n 50% { opacity: 0.6; }\r\n }\r\n `;\r\n}\r\n","export function renderRecorderWidget(rec: boolean, paused: boolean, t: (key: string) => string): string {\r\n return `\r\n <div class=\"widget\">\r\n <div class=\"action-menu\">\r\n <button class=\"action-item\" data-action=\"config\">\r\n <span class=\"ico\">⚙️</span><span class=\"label\">${t('RECORDER.BTN_CONFIG')}</span></button>\r\n <button class=\"action-item\" data-action=\"browse\">\r\n <span class=\"ico\">📁</span><span class=\"label\">${t('RECORDER.BTN_FILES')}</span></button>\r\n <button class=\"action-item\" data-action=\"commands\">\r\n <span class=\"ico\">⌨️</span><span class=\"label\">${t('RECORDER.BTN_COMMANDS')}</span></button>\r\n <button class=\"action-item\" data-action=\"tests\">\r\n <span class=\"ico\">📋</span><span class=\"label\">${t('RECORDER.BTN_TESTS')}</span></button>\r\n <button class=\"action-item\" data-action=\"help\">\r\n <span class=\"ico\">❓</span><span class=\"label\">${t('RECORDER.BTN_HELP')}</span></button>\r\n </div>\r\n <button class=\"btn-pause\" data-action=\"pause\"\r\n title=\"${paused ? t('RECORDER.RESUME_TITLE') : t('RECORDER.PAUSE_TITLE')}\">\r\n ${paused ? '▶' : '⏸'}\r\n </button>\r\n <button class=\"btn-toggle\" data-action=\"toggle\"\r\n title=\"${rec ? t('RECORDER.STOP_TITLE') : t('RECORDER.START_TITLE')}\">\r\n ${rec ? '⏹' : '⏺'}\r\n </button>\r\n </div>\r\n <div class=\"rec-badge\">${paused ? t('RECORDER.BADGE_PAUSED') : t('RECORDER.BADGE_REC')}</div>`;\r\n}\r\n"],"mappings":"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","names":["tag","container","selector","rect","history","input","folderInput","i","j","Swal"]}
|