lib-e2e-cypress-for-dummys-ts 0.2.0 → 0.5.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/dist/index.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  type Lang = 'es' | 'en' | 'fr' | 'it' | 'de';
2
2
  declare const SUPPORTED_LANGS: Lang[];
3
3
  declare function isLang(value: string): value is Lang;
4
+ /** BCP-47 locale used for date/number formatting per UI language. */
5
+ declare const LOCALE_BY_LANG: Record<Lang, string>;
6
+ /** Returns the formatting locale for a UI language (falls back to es-ES). */
7
+ declare function localeForLang(lang: string): string;
4
8
 
5
9
  declare const INPUT_TYPES: readonly ["text", "password", "email", "search", "tel", "url", "number", "textarea"];
6
10
  type InputType = (typeof INPUT_TYPES)[number];
@@ -22,50 +26,7 @@ interface DBSchema {
22
26
  stores: DBStore[];
23
27
  }
24
28
  declare const DB_SCHEMA: DBSchema;
25
- declare const DB_STORE_NAMES: ["tests", "commands", "interceptors", "configuration"];
26
-
27
- declare class TranslationService {
28
- private lang;
29
- private readonly translations;
30
- constructor();
31
- setLang(lang: Lang): void;
32
- getLang(): Lang;
33
- translate(key: string): string;
34
- detectLang(): Lang;
35
- }
36
- declare const translationService: TranslationService;
37
-
38
- declare class TransformationService {
39
- toLang(lang: string): Lang;
40
- generateItDescription(description: string, commands: string[]): string;
41
- }
42
- declare const transformationService: TransformationService;
43
-
44
- interface DirectoryNode {
45
- name: string;
46
- kind: 'directory';
47
- children: (DirectoryNode | FileNode)[];
48
- }
49
- interface FileNode {
50
- name: string;
51
- kind: 'file';
52
- }
53
- declare class AdvancedTestTransformationService {
54
- insertBeforeEach(content: string, interceptors: string, alertFn?: (msg: string) => void): string;
55
- insertItBlock(content: string, itBlock: string, alertFn?: (msg: string) => void): string;
56
- isFile(file: unknown): boolean;
57
- scanDirectory(dirHandle: FileSystemDirectoryHandle): Promise<DirectoryNode>;
58
- }
59
- declare const advancedTestTransformationService: AdvancedTestTransformationService;
60
-
61
- declare class Subject<T> {
62
- private _value;
63
- private listeners;
64
- constructor(initialValue: T);
65
- next(value: T): void;
66
- getValue(): T;
67
- subscribe(fn: (v: T) => void): () => void;
68
- }
29
+ declare const DB_STORE_NAMES: ["tests", "commands", "interceptors", "configuration", "activeSession"];
69
30
 
70
31
  type SelectorStrategy = 'data-cy' | 'data-testid' | 'aria-label' | 'id';
71
32
  declare class RecordingService {
@@ -77,10 +38,22 @@ declare class RecordingService {
77
38
  private readonly inputDebounceTimers;
78
39
  private readonly abort;
79
40
  selectorStrategy: SelectorStrategy;
41
+ /** Stable id of the current live session (null when none has started). */
42
+ sessionId: string | null;
43
+ private startedAt;
80
44
  private readonly origPushState;
81
45
  private readonly origReplaceState;
82
46
  constructor();
83
47
  startRecording(): void;
48
+ /**
49
+ * Rehydrates a previously persisted session WITHOUT running the startRecording
50
+ * bootstrap (no viewport/visit/hide). Used to continue a recording across a
51
+ * micro-frontend crossing or a same-origin reload.
52
+ * See docs/specs/006-cross-app-recording-continuity.md.
53
+ */
54
+ restoreSession(state: ActiveSessionState): void;
55
+ /** Full snapshot of the live session for persistence. */
56
+ getSessionSnapshot(): ActiveSessionState;
84
57
  stopRecording(): void;
85
58
  toggleRecording(): void;
86
59
  pauseRecording(): void;
@@ -102,6 +75,12 @@ declare class RecordingService {
102
75
  onInterceptorsChange(fn: (ints: string[]) => void): () => void;
103
76
  onRecordingChange(fn: (isRecording: boolean) => void): () => void;
104
77
  onPauseChange(fn: (isPaused: boolean) => void): () => void;
78
+ /**
79
+ * Fires a full session snapshot whenever any persisted field changes
80
+ * (commands, interceptors, recording or paused state). Drives the debounced
81
+ * persistence of the live session. Returns a combined unsubscribe.
82
+ */
83
+ onSessionChange(fn: (state: ActiveSessionState) => void): () => void;
105
84
  onSelectorNotFound(fn: (target: HTMLElement, action: 'click') => void): () => void;
106
85
  destroy(): void;
107
86
  private listenToClicks;
@@ -120,11 +99,88 @@ declare class RecordingService {
120
99
  private urlToWildcard;
121
100
  }
122
101
 
102
+ /**
103
+ * A live, in-progress recording session, persisted so it can survive a
104
+ * micro-frontend crossing (single-spa app swap) or an accidental same-origin
105
+ * reload. Only an actively-recording session is ever stored/resumed.
106
+ *
107
+ * The full payload lives in IndexedDB; a lightweight breadcrumb (sessionId +
108
+ * isRecording + updatedAt) is mirrored to localStorage for synchronous detection.
109
+ *
110
+ * See docs/specs/006-cross-app-recording-continuity.md.
111
+ */
112
+ interface ActiveSessionState {
113
+ /** Stable id for the session, generated when recording starts. */
114
+ sessionId: string;
115
+ isRecording: boolean;
116
+ isPaused: boolean;
117
+ commands: string[];
118
+ interceptors: string[];
119
+ selectorStrategy: SelectorStrategy;
120
+ /** Epoch ms when the session started recording. */
121
+ startedAt: number;
122
+ /** Epoch ms of the last mutation — acts as the recency heartbeat. */
123
+ updatedAt: number;
124
+ }
125
+ /** localStorage key for the synchronous "is a session active?" breadcrumb. */
126
+ declare const ACTIVE_SESSION_BREADCRUMB_KEY = "e2e-active-session";
127
+ /** Configuration key (in the `configuration` store) for the resume recency TTL. */
128
+ declare const RESUME_TTL_CONFIG_KEY = "resumeRecencyTtlMinutes";
129
+ /** Default minutes within which an active session resumes silently. */
130
+ declare const DEFAULT_RESUME_TTL_MINUTES = 30;
131
+
132
+ declare class TranslationService {
133
+ private readonly lang$;
134
+ private readonly translations;
135
+ constructor();
136
+ setLang(lang: Lang): void;
137
+ getLang(): Lang;
138
+ /** Subscribe to language changes; returns an unsubscribe function. */
139
+ onLangChange(fn: (lang: Lang) => void): () => void;
140
+ translate(key: string): string;
141
+ detectLang(): Lang;
142
+ }
143
+ declare const translationService: TranslationService;
144
+
145
+ declare class TransformationService {
146
+ toLang(lang: string): Lang;
147
+ generateItDescription(description: string, commands: string[]): string;
148
+ }
149
+ declare const transformationService: TransformationService;
150
+
151
+ interface DirectoryNode {
152
+ name: string;
153
+ kind: 'directory';
154
+ children: (DirectoryNode | FileNode)[];
155
+ }
156
+ interface FileNode {
157
+ name: string;
158
+ kind: 'file';
159
+ }
160
+ declare class AdvancedTestTransformationService {
161
+ insertBeforeEach(content: string, interceptors: string, alertFn?: (msg: string) => void): string;
162
+ insertItBlock(content: string, itBlock: string, alertFn?: (msg: string) => void): string;
163
+ buildBlockComment(notes: string): string;
164
+ isFile(file: unknown): boolean;
165
+ scanDirectory(dirHandle: FileSystemDirectoryHandle): Promise<DirectoryNode>;
166
+ }
167
+ declare const advancedTestTransformationService: AdvancedTestTransformationService;
168
+
169
+ declare class Subject<T> {
170
+ private _value;
171
+ private listeners;
172
+ constructor(initialValue: T);
173
+ next(value: T): void;
174
+ getValue(): T;
175
+ subscribe(fn: (v: T) => void): () => void;
176
+ }
177
+
123
178
  interface TestRecord {
124
179
  id: number;
125
180
  name: string;
126
181
  createdAt: number;
127
182
  tags?: string[];
183
+ notes?: string;
128
184
  }
129
185
  interface CommandRecord {
130
186
  id: number;
@@ -156,7 +212,7 @@ declare class PersistenceService {
156
212
  private _db;
157
213
  constructor(dbName?: string);
158
214
  private getDB;
159
- insertTest(name: string, commands?: string[], interceptors?: string[], tags?: string[]): Promise<number>;
215
+ insertTest(name: string, commands?: string[], interceptors?: string[], tags?: string[], notes?: string): Promise<number>;
160
216
  getAllTests(): Promise<TestWithDetails[]>;
161
217
  getTestById(testId: number): Promise<TestDetail | null>;
162
218
  deleteTest(id: number): Promise<void>;
@@ -172,6 +228,12 @@ declare class PersistenceService {
172
228
  setConfigKey(key: string, value: unknown): Promise<void>;
173
229
  getConfig(key: string): Promise<Record<string, unknown> | null>;
174
230
  getGeneralConfig(): Promise<ConfigRecord | null>;
231
+ /** Upserts the live recording session (single record, fixed key). */
232
+ saveActiveSession(state: ActiveSessionState): Promise<void>;
233
+ /** Returns the persisted live session, or null when none is stored. */
234
+ getActiveSession(): Promise<ActiveSessionState | null>;
235
+ /** Removes the live session record. Safe to call when none exists. */
236
+ clearActiveSession(): Promise<void>;
175
237
  clearAllData(): Promise<void>;
176
238
  ingestFileData(tests: Record<string, unknown>[], interceptors: Record<string, unknown>[]): Promise<void>;
177
239
  requestDirectoryPermissions(): Promise<void>;
@@ -210,6 +272,63 @@ declare function setSwal2DataCyAttribute(dataCy?: string): void;
210
272
 
211
273
  declare function showToast(message: string, isSuccess?: boolean): void;
212
274
 
275
+ /** How the user chose which tests to export. */
276
+ type ExportMode = 'all' | 'manual' | 'tags';
277
+ interface ExportSelectionOptions {
278
+ /** Test ids to include in `manual` mode. */
279
+ ids?: Iterable<number>;
280
+ /** Tags to match in `tags` mode. */
281
+ tags?: Iterable<string>;
282
+ }
283
+ /**
284
+ * Returns the subset of tests to export for a given selection mode.
285
+ *
286
+ * - `all` → every test (a shallow copy).
287
+ * - `manual` → tests whose id is in `opts.ids`. Empty/absent ids → none.
288
+ * - `tags` → tests carrying at least one of `opts.tags` (OR semantics).
289
+ * Empty/absent tags → none.
290
+ *
291
+ * Pure: never mutates its inputs.
292
+ */
293
+ declare function selectTestsForExport(tests: TestWithDetails[], mode: ExportMode, opts?: ExportSelectionOptions): TestWithDetails[];
294
+
295
+ /**
296
+ * True when a hostname refers to the local machine — used to gate dev-only
297
+ * features (e.g. launching a Cypress run via the local runner) so they are
298
+ * offered only when the app is served locally, not from a deployed environment.
299
+ *
300
+ * Treats as local: localhost, *.localhost, 127.0.0.1, ::1, 0.0.0.0, and the
301
+ * empty hostname (e.g. file:// URLs). Case-insensitive.
302
+ */
303
+ declare function isLocalHost(hostname: string): boolean;
304
+
305
+ declare class SelectorPickerElement extends HTMLElement {
306
+ targetElement: HTMLElement | null;
307
+ recording: RecordingService;
308
+ translation: TranslationService;
309
+ private shadow;
310
+ private ancestors;
311
+ private rows;
312
+ private selectedIndex;
313
+ private keyHandler;
314
+ private unsubRecording;
315
+ private unsubPause;
316
+ constructor();
317
+ connectedCallback(): void;
318
+ disconnectedCallback(): void;
319
+ private t;
320
+ private buildAncestors;
321
+ private findBestIndex;
322
+ private render;
323
+ private attachKeyListener;
324
+ private detachKeyListener;
325
+ private attachRowClickListeners;
326
+ private subscribeToRecordingChanges;
327
+ private confirm;
328
+ private cancel;
329
+ private closeSilently;
330
+ }
331
+
213
332
  declare class TestPrevisualizerElement extends HTMLElement {
214
333
  private shadow;
215
334
  private _commands;
@@ -238,6 +357,7 @@ declare class SaveTestElement extends HTMLElement {
238
357
  private shadow;
239
358
  private _step;
240
359
  description: string;
360
+ notes: string;
241
361
  tags: string[];
242
362
  translation: TranslationService;
243
363
  constructor();
@@ -290,6 +410,13 @@ declare class ConfigurationElement extends HTMLElement {
290
410
  advancedHttpConfig: boolean;
291
411
  selectorStrategy: SelectorStrategy;
292
412
  smartSelectorEnabled: boolean;
413
+ startHidden: boolean;
414
+ resumeTtlMinutes: number;
415
+ isExporting: boolean;
416
+ exportMode: ExportMode;
417
+ exportTests: TestWithDetails[];
418
+ exportSelectedIds: Set<number>;
419
+ exportSelectedTags: Set<string>;
293
420
  private filesystemGranted;
294
421
  private cypressFolderName;
295
422
  constructor();
@@ -298,11 +425,23 @@ declare class ConfigurationElement extends HTMLElement {
298
425
  private loadConfig;
299
426
  onLanguageChange(lang: string): Promise<void>;
300
427
  onAdvancedHttpConfigChange(checked: boolean): void;
428
+ onStartHiddenChange(checked: boolean): Promise<void>;
429
+ onResumeTtlChange(minutes: number): Promise<void>;
301
430
  onSmartSelectorChange(enabled: boolean): Promise<void>;
302
431
  onSelectorStrategyChange(strategy: SelectorStrategy): Promise<void>;
303
432
  changeFolder(): Promise<void>;
304
433
  revokeAccess(): Promise<void>;
434
+ private downloadTests;
435
+ /** Downloads every saved test (used by the "Todo" mode and as a direct API). */
305
436
  exportAllData(): Promise<void>;
437
+ /** Opens the export selection dialog, loading the current tests. */
438
+ openExportDialog(): Promise<void>;
439
+ cancelExport(): void;
440
+ setExportMode(mode: ExportMode): void;
441
+ toggleExportTest(id: number): void;
442
+ toggleExportTag(tag: string): void;
443
+ /** Downloads the tests resolved by the current mode + selection. No-op if empty. */
444
+ confirmExport(): void;
306
445
  importAllData(file: File): Promise<void>;
307
446
  private render;
308
447
  }
@@ -320,10 +459,12 @@ declare class AdvancedTestEditorElement extends HTMLElement {
320
459
  selectedFileContent: string | null;
321
460
  testItBlock: string;
322
461
  interceptorsBlock: string;
462
+ testNotes: string;
323
463
  isPreviewMode: boolean;
324
464
  previewFileName: string | null;
325
465
  previewFileContent: string | null;
326
466
  isCreatingFile: boolean;
467
+ isCreatingFolder: boolean;
327
468
  collapsedDirs: Set<string>;
328
469
  sidebarWidth: number;
329
470
  private hasPermission;
@@ -336,6 +477,7 @@ declare class AdvancedTestEditorElement extends HTMLElement {
336
477
  private init;
337
478
  getFoldersData(): Promise<void>;
338
479
  createNewFile(rawName: string): Promise<void>;
480
+ createNewFolder(rawName: string): Promise<void>;
339
481
  refreshTree(): Promise<void>;
340
482
  saveCommandsToFile(): Promise<void>;
341
483
  onFileClick(file: unknown): Promise<void>;
@@ -357,11 +499,18 @@ declare class FilePreviewElement extends HTMLElement {
357
499
  translation: TranslationService;
358
500
  itBlock: string;
359
501
  interceptorsBlock: string;
502
+ notes: string;
360
503
  commands: string[];
361
504
  interceptors: string[];
505
+ /** Endpoint of the local Cypress runner. Configurable; defaults to the bundled runner's port. */
506
+ runnerUrl: string;
507
+ /** Whether the app is served locally — gates the launch button. Overridable for tests. */
508
+ isLocal: boolean;
362
509
  private _fileContent;
363
510
  private _originalContent;
364
511
  private _showDiff;
512
+ private _runState;
513
+ private _runOutput;
365
514
  constructor();
366
515
  connectedCallback(): void;
367
516
  private t;
@@ -369,9 +518,21 @@ declare class FilePreviewElement extends HTMLElement {
369
518
  set fileContent(v: string | null);
370
519
  saveFile(): void;
371
520
  onClose(): void;
521
+ /**
522
+ * Runs the current spec headless via the local runner and shows the result.
523
+ * No-op off localhost. Never throws — connection failures surface as an
524
+ * "error" state + toast instead of an unhandled rejection.
525
+ */
372
526
  launchTest(specPath?: string): Promise<void>;
373
527
  copyToClipboard(text: string): void;
374
528
  toggleDiff(): void;
529
+ /**
530
+ * Merges the it() and beforeEach() blocks into the current editor content
531
+ * using the same logic as the automatic "Insert into file" action, so the
532
+ * user does not have to copy/paste manually. Leaves the content untouched
533
+ * (and warns) when the file has no valid describe() block to insert into.
534
+ */
535
+ insertBlocks(): void;
375
536
  private render;
376
537
  }
377
538
 
@@ -384,6 +545,9 @@ declare class LibE2eRecorderElement extends HTMLElement {
384
545
  private interceptorsUnsub?;
385
546
  private pauseUnsub?;
386
547
  private selectorNotFoundUnsub?;
548
+ private langUnsub?;
549
+ private sessionUnsub?;
550
+ private sessionSaveTimer?;
387
551
  private controlFirstTimeData;
388
552
  private _previsualizerRef;
389
553
  private httpMonitor?;
@@ -391,6 +555,7 @@ declare class LibE2eRecorderElement extends HTMLElement {
391
555
  recording: RecordingService;
392
556
  persistence: PersistenceService;
393
557
  translation: TranslationService;
558
+ isVisible: boolean;
394
559
  isRecording: boolean;
395
560
  isPaused: boolean;
396
561
  cypressCommands: string[];
@@ -407,11 +572,34 @@ declare class LibE2eRecorderElement extends HTMLElement {
407
572
  private initLanguage;
408
573
  private initSubscriptions;
409
574
  private showSelectorPicker;
575
+ private initVisibility;
410
576
  private initSelectorStrategy;
577
+ /**
578
+ * On mount, detect a persisted live recording session and either resume it
579
+ * silently (recent) or prompt continue/discard (stale). No-op when there is
580
+ * no actively-recording session.
581
+ */
582
+ private initSessionContinuity;
583
+ private getResumeTtlMinutes;
584
+ /** Rehydrates the recorder from a persisted session (no bootstrap re-emitted). */
585
+ private resumeSessionState;
586
+ private promptResumeOrDiscard;
587
+ /** Debounced persistence of the live session; clears it the moment recording stops. */
588
+ private persistActiveSession;
589
+ private writeSessionBreadcrumb;
590
+ private flushActiveSessionOnDisconnect;
591
+ private clearSessionPersistence;
592
+ /** True when a synchronous breadcrumb marks an active recording session. */
593
+ hasActiveSession(): boolean;
594
+ /** Programmatically resume the persisted session, if any. */
595
+ resumeSession(): void;
596
+ /** Discard the persisted live session (breadcrumb + DB record). */
597
+ discardSession(): void;
411
598
  toggle(): void;
412
599
  togglePause(): void;
413
600
  setLanguage(lang?: string): void;
414
601
  handleKeyboardEvent(event: KeyboardEvent): void;
602
+ toggleVisibility(): void;
415
603
  private saveRecordingHistory;
416
604
  recoverLastRecording(): void;
417
605
  clearRecordingHistory(): void;
@@ -435,6 +623,6 @@ declare class LibE2eRecorderElement extends HTMLElement {
435
623
  private render;
436
624
  }
437
625
 
438
- declare const VERSION = "0.1.0";
626
+ declare const VERSION = "0.5.0";
439
627
 
440
- export { AdvancedTestEditorElement, AdvancedTestTransformationService, ConfigurationElement, type DBSchema, type DBStore, type DBStoreIndex, DB_SCHEMA, DB_STORE_NAMES, type DirectoryNode, type FileNode, FilePreviewElement, HttpMonitor, INPUT_TYPES, type InputType, LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, type Lang, LibE2eRecorderElement, PersistenceService, RecordingService, SCROLLBAR_STYLES, SUPPORTED_LANGS, SaveTestElement, type SelectorStrategy, Subject, type TestDetail, TestEditorElement, TestPrevisualizerElement, type TestWithDetails, TransformationService, TranslationService, VERSION, advancedTestTransformationService, generateAlias, injectStyles, isLang, makeModalResizable, makeSwalDraggable, makeSwalDraggableByContentId, persistenceService, setSwal2DataCyAttribute, showToast, transformationService, translationService };
628
+ export { ACTIVE_SESSION_BREADCRUMB_KEY, type ActiveSessionState, AdvancedTestEditorElement, AdvancedTestTransformationService, ConfigurationElement, type DBSchema, type DBStore, type DBStoreIndex, DB_SCHEMA, DB_STORE_NAMES, DEFAULT_RESUME_TTL_MINUTES, type DirectoryNode, type ExportMode, type ExportSelectionOptions, type FileNode, FilePreviewElement, HttpMonitor, INPUT_TYPES, type InputType, LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, LOCALE_BY_LANG, type Lang, LibE2eRecorderElement, PersistenceService, RESUME_TTL_CONFIG_KEY, RecordingService, SCROLLBAR_STYLES, SUPPORTED_LANGS, SaveTestElement, SelectorPickerElement, type SelectorStrategy, Subject, type TestDetail, TestEditorElement, TestPrevisualizerElement, type TestWithDetails, TransformationService, TranslationService, VERSION, advancedTestTransformationService, generateAlias, injectStyles, isLang, isLocalHost, localeForLang, makeModalResizable, makeSwalDraggable, makeSwalDraggableByContentId, persistenceService, selectTestsForExport, setSwal2DataCyAttribute, showToast, transformationService, translationService };