lib-e2e-cypress-for-dummys-ts 0.3.0 → 0.6.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.cts 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,51 +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
- buildBlockComment(notes: string): string;
57
- isFile(file: unknown): boolean;
58
- scanDirectory(dirHandle: FileSystemDirectoryHandle): Promise<DirectoryNode>;
59
- }
60
- declare const advancedTestTransformationService: AdvancedTestTransformationService;
61
-
62
- declare class Subject<T> {
63
- private _value;
64
- private listeners;
65
- constructor(initialValue: T);
66
- next(value: T): void;
67
- getValue(): T;
68
- subscribe(fn: (v: T) => void): () => void;
69
- }
29
+ declare const DB_STORE_NAMES: ["tests", "commands", "interceptors", "configuration", "activeSession"];
70
30
 
71
31
  type SelectorStrategy = 'data-cy' | 'data-testid' | 'aria-label' | 'id';
72
32
  declare class RecordingService {
@@ -78,10 +38,22 @@ declare class RecordingService {
78
38
  private readonly inputDebounceTimers;
79
39
  private readonly abort;
80
40
  selectorStrategy: SelectorStrategy;
41
+ /** Stable id of the current live session (null when none has started). */
42
+ sessionId: string | null;
43
+ private startedAt;
81
44
  private readonly origPushState;
82
45
  private readonly origReplaceState;
83
46
  constructor();
84
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;
85
57
  stopRecording(): void;
86
58
  toggleRecording(): void;
87
59
  pauseRecording(): void;
@@ -103,6 +75,12 @@ declare class RecordingService {
103
75
  onInterceptorsChange(fn: (ints: string[]) => void): () => void;
104
76
  onRecordingChange(fn: (isRecording: boolean) => void): () => void;
105
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;
106
84
  onSelectorNotFound(fn: (target: HTMLElement, action: 'click') => void): () => void;
107
85
  destroy(): void;
108
86
  private listenToClicks;
@@ -121,6 +99,82 @@ declare class RecordingService {
121
99
  private urlToWildcard;
122
100
  }
123
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
+
124
178
  interface TestRecord {
125
179
  id: number;
126
180
  name: string;
@@ -174,6 +228,12 @@ declare class PersistenceService {
174
228
  setConfigKey(key: string, value: unknown): Promise<void>;
175
229
  getConfig(key: string): Promise<Record<string, unknown> | null>;
176
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>;
177
237
  clearAllData(): Promise<void>;
178
238
  ingestFileData(tests: Record<string, unknown>[], interceptors: Record<string, unknown>[]): Promise<void>;
179
239
  requestDirectoryPermissions(): Promise<void>;
@@ -212,6 +272,95 @@ declare function setSwal2DataCyAttribute(dataCy?: string): void;
212
272
 
213
273
  declare function showToast(message: string, isSuccess?: boolean): void;
214
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
+ /**
306
+ * Geometry helpers for the draggable recording widget (spec 007).
307
+ * Pure functions — no DOM — so the drag/clamp/expansion logic is unit-testable
308
+ * without real layout (jsdom returns 0-sized rects).
309
+ */
310
+ type ExpandDirection = 'up-left' | 'up-right' | 'down-left' | 'down-right';
311
+ interface Point {
312
+ x: number;
313
+ y: number;
314
+ }
315
+ /** Toggle radius (44/2) + small gap, so the toggle never touches the edge. */
316
+ declare const TOGGLE_MARGIN = 30;
317
+ /** Pixels the pointer must travel before a press becomes a drag (vs a click). */
318
+ declare const DRAG_THRESHOLD = 5;
319
+ /**
320
+ * Toggle-centre offset inside the 190×190 widget box, per expansion direction.
321
+ * The toggle sits at the box corner nearest the screen edge so the arc always
322
+ * expands toward the viewport interior (and stays inside the box / on screen).
323
+ */
324
+ declare function boxOffsetForDirection(dir: ExpandDirection): Point;
325
+ /** Clamps the toggle-centre so the toggle button stays fully on screen. */
326
+ declare function clampTogglePosition(x: number, y: number, vw: number, vh: number, margin?: number): Point;
327
+ /**
328
+ * Chooses the radial expansion direction so the menu opens toward the centre of
329
+ * the viewport (top half → expand down; left half → expand right).
330
+ */
331
+ declare function resolveExpandDirection(x: number, y: number, vw: number, vh: number): ExpandDirection;
332
+ /** Default toggle-centre (bottom-right corner), matching the original CSS anchor. */
333
+ declare function defaultTogglePosition(vw: number, vh: number): Point;
334
+ /** Box top-left for a given (clamped) toggle-centre and direction. */
335
+ declare function boxTopLeftFor(toggleCentre: Point, dir: ExpandDirection): Point;
336
+
337
+ declare class SelectorPickerElement extends HTMLElement {
338
+ targetElement: HTMLElement | null;
339
+ recording: RecordingService;
340
+ translation: TranslationService;
341
+ private shadow;
342
+ private ancestors;
343
+ private rows;
344
+ private selectedIndex;
345
+ private keyHandler;
346
+ private unsubRecording;
347
+ private unsubPause;
348
+ constructor();
349
+ connectedCallback(): void;
350
+ disconnectedCallback(): void;
351
+ private t;
352
+ private buildAncestors;
353
+ private findBestIndex;
354
+ private render;
355
+ private attachKeyListener;
356
+ private detachKeyListener;
357
+ private attachRowClickListeners;
358
+ private subscribeToRecordingChanges;
359
+ private confirm;
360
+ private cancel;
361
+ private closeSilently;
362
+ }
363
+
215
364
  declare class TestPrevisualizerElement extends HTMLElement {
216
365
  private shadow;
217
366
  private _commands;
@@ -294,6 +443,12 @@ declare class ConfigurationElement extends HTMLElement {
294
443
  selectorStrategy: SelectorStrategy;
295
444
  smartSelectorEnabled: boolean;
296
445
  startHidden: boolean;
446
+ resumeTtlMinutes: number;
447
+ isExporting: boolean;
448
+ exportMode: ExportMode;
449
+ exportTests: TestWithDetails[];
450
+ exportSelectedIds: Set<number>;
451
+ exportSelectedTags: Set<string>;
297
452
  private filesystemGranted;
298
453
  private cypressFolderName;
299
454
  constructor();
@@ -303,11 +458,23 @@ declare class ConfigurationElement extends HTMLElement {
303
458
  onLanguageChange(lang: string): Promise<void>;
304
459
  onAdvancedHttpConfigChange(checked: boolean): void;
305
460
  onStartHiddenChange(checked: boolean): Promise<void>;
461
+ onResumeTtlChange(minutes: number): Promise<void>;
462
+ onResetWidgetPosition(): void;
306
463
  onSmartSelectorChange(enabled: boolean): Promise<void>;
307
464
  onSelectorStrategyChange(strategy: SelectorStrategy): Promise<void>;
308
465
  changeFolder(): Promise<void>;
309
466
  revokeAccess(): Promise<void>;
467
+ private downloadTests;
468
+ /** Downloads every saved test (used by the "Todo" mode and as a direct API). */
310
469
  exportAllData(): Promise<void>;
470
+ /** Opens the export selection dialog, loading the current tests. */
471
+ openExportDialog(): Promise<void>;
472
+ cancelExport(): void;
473
+ setExportMode(mode: ExportMode): void;
474
+ toggleExportTest(id: number): void;
475
+ toggleExportTag(tag: string): void;
476
+ /** Downloads the tests resolved by the current mode + selection. No-op if empty. */
477
+ confirmExport(): void;
311
478
  importAllData(file: File): Promise<void>;
312
479
  private render;
313
480
  }
@@ -330,6 +497,7 @@ declare class AdvancedTestEditorElement extends HTMLElement {
330
497
  previewFileName: string | null;
331
498
  previewFileContent: string | null;
332
499
  isCreatingFile: boolean;
500
+ isCreatingFolder: boolean;
333
501
  collapsedDirs: Set<string>;
334
502
  sidebarWidth: number;
335
503
  private hasPermission;
@@ -342,6 +510,7 @@ declare class AdvancedTestEditorElement extends HTMLElement {
342
510
  private init;
343
511
  getFoldersData(): Promise<void>;
344
512
  createNewFile(rawName: string): Promise<void>;
513
+ createNewFolder(rawName: string): Promise<void>;
345
514
  refreshTree(): Promise<void>;
346
515
  saveCommandsToFile(): Promise<void>;
347
516
  onFileClick(file: unknown): Promise<void>;
@@ -363,11 +532,18 @@ declare class FilePreviewElement extends HTMLElement {
363
532
  translation: TranslationService;
364
533
  itBlock: string;
365
534
  interceptorsBlock: string;
535
+ notes: string;
366
536
  commands: string[];
367
537
  interceptors: string[];
538
+ /** Endpoint of the local Cypress runner. Configurable; defaults to the bundled runner's port. */
539
+ runnerUrl: string;
540
+ /** Whether the app is served locally — gates the launch button. Overridable for tests. */
541
+ isLocal: boolean;
368
542
  private _fileContent;
369
543
  private _originalContent;
370
544
  private _showDiff;
545
+ private _runState;
546
+ private _runOutput;
371
547
  constructor();
372
548
  connectedCallback(): void;
373
549
  private t;
@@ -375,9 +551,21 @@ declare class FilePreviewElement extends HTMLElement {
375
551
  set fileContent(v: string | null);
376
552
  saveFile(): void;
377
553
  onClose(): void;
554
+ /**
555
+ * Runs the current spec headless via the local runner and shows the result.
556
+ * No-op off localhost. Never throws — connection failures surface as an
557
+ * "error" state + toast instead of an unhandled rejection.
558
+ */
378
559
  launchTest(specPath?: string): Promise<void>;
379
560
  copyToClipboard(text: string): void;
380
561
  toggleDiff(): void;
562
+ /**
563
+ * Merges the it() and beforeEach() blocks into the current editor content
564
+ * using the same logic as the automatic "Insert into file" action, so the
565
+ * user does not have to copy/paste manually. Leaves the content untouched
566
+ * (and warns) when the file has no valid describe() block to insert into.
567
+ */
568
+ insertBlocks(): void;
381
569
  private render;
382
570
  }
383
571
 
@@ -390,7 +578,17 @@ declare class LibE2eRecorderElement extends HTMLElement {
390
578
  private interceptorsUnsub?;
391
579
  private pauseUnsub?;
392
580
  private selectorNotFoundUnsub?;
581
+ private langUnsub?;
582
+ private sessionUnsub?;
583
+ private sessionSaveTimer?;
393
584
  private controlFirstTimeData;
585
+ private togglePos;
586
+ private expandDir;
587
+ private dragState?;
588
+ private suppressNextToggleClick;
589
+ private widgetPointerMove?;
590
+ private widgetPointerUp?;
591
+ private widgetResize?;
394
592
  private _previsualizerRef;
395
593
  private httpMonitor?;
396
594
  private smartSelectorEnabled;
@@ -416,6 +614,36 @@ declare class LibE2eRecorderElement extends HTMLElement {
416
614
  private showSelectorPicker;
417
615
  private initVisibility;
418
616
  private initSelectorStrategy;
617
+ /**
618
+ * On mount, detect a persisted live recording session and either resume it
619
+ * silently (recent) or prompt continue/discard (stale). No-op when there is
620
+ * no actively-recording session.
621
+ */
622
+ private initSessionContinuity;
623
+ private getResumeTtlMinutes;
624
+ /** Rehydrates the recorder from a persisted session (no bootstrap re-emitted). */
625
+ private resumeSessionState;
626
+ private promptResumeOrDiscard;
627
+ /** Debounced persistence of the live session; clears it the moment recording stops. */
628
+ private persistActiveSession;
629
+ private writeSessionBreadcrumb;
630
+ private flushActiveSessionOnDisconnect;
631
+ private clearSessionPersistence;
632
+ /** True when a synchronous breadcrumb marks an active recording session. */
633
+ hasActiveSession(): boolean;
634
+ /** Programmatically resume the persisted session, if any. */
635
+ resumeSession(): void;
636
+ /** Discard the persisted live session (breadcrumb + DB record). */
637
+ discardSession(): void;
638
+ /** Loads a previously saved widget position and applies it. */
639
+ private initWidgetPosition;
640
+ /** Positions the `.widget` box from the (clamped) toggle centre and orients the arc. */
641
+ private applyWidgetPosition;
642
+ private beginWidgetDrag;
643
+ private onWidgetPointerMove;
644
+ private onWidgetPointerUp;
645
+ /** Resets the widget to its default corner and clears the saved position. */
646
+ resetWidgetPosition(): void;
419
647
  toggle(): void;
420
648
  togglePause(): void;
421
649
  setLanguage(lang?: string): void;
@@ -444,6 +672,6 @@ declare class LibE2eRecorderElement extends HTMLElement {
444
672
  private render;
445
673
  }
446
674
 
447
- declare const VERSION = "0.1.0";
675
+ declare const VERSION = "0.6.0";
448
676
 
449
- 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 };
677
+ 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, DRAG_THRESHOLD, type DirectoryNode, type ExpandDirection, 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, type Point, RESUME_TTL_CONFIG_KEY, RecordingService, SCROLLBAR_STYLES, SUPPORTED_LANGS, SaveTestElement, SelectorPickerElement, type SelectorStrategy, Subject, TOGGLE_MARGIN, type TestDetail, TestEditorElement, TestPrevisualizerElement, type TestWithDetails, TransformationService, TranslationService, VERSION, advancedTestTransformationService, boxOffsetForDirection, boxTopLeftFor, clampTogglePosition, defaultTogglePosition, generateAlias, injectStyles, isLang, isLocalHost, localeForLang, makeModalResizable, makeSwalDraggable, makeSwalDraggableByContentId, persistenceService, resolveExpandDirection, selectTestsForExport, setSwal2DataCyAttribute, showToast, transformationService, translationService };