lib-e2e-cypress-for-dummys-ts 0.9.0 → 1.0.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/LICENSE +21 -0
- package/README.md +767 -707
- package/dist/{chunk-CQEDHL7A.js → chunk-24WFAT4W.js} +40 -7
- package/dist/chunk-24WFAT4W.js.map +1 -0
- package/dist/index.cjs +1467 -628
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -62
- package/dist/index.d.ts +46 -62
- package/dist/index.js +1416 -607
- package/dist/index.js.map +1 -1
- package/dist/runner.js +18 -2
- package/dist/selector-picker-KJUXPXHH.js +7 -0
- package/package.json +74 -74
- package/dist/chunk-CQEDHL7A.js.map +0 -1
- package/dist/selector-picker-JM5HID3Z.js +0 -7
- /package/dist/{selector-picker-JM5HID3Z.js.map → selector-picker-KJUXPXHH.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,41 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
+
// src/utils/code-format.utils.ts
|
|
34
|
+
function gcd(a, b) {
|
|
35
|
+
while (b) {
|
|
36
|
+
const t = b;
|
|
37
|
+
b = a % b;
|
|
38
|
+
a = t;
|
|
39
|
+
}
|
|
40
|
+
return a;
|
|
41
|
+
}
|
|
42
|
+
function escapeSingleQuotes(value) {
|
|
43
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
44
|
+
}
|
|
45
|
+
function escapeCssAttrValue(value) {
|
|
46
|
+
return value.replace(/"/g, '\\"');
|
|
47
|
+
}
|
|
48
|
+
function normalizeBlock(code, baseIndent) {
|
|
49
|
+
const lines = code.split("\n").map((l) => l.trimEnd());
|
|
50
|
+
const nonEmpty = lines.filter((l) => l.trim().length > 0);
|
|
51
|
+
if (!nonEmpty.length) return "";
|
|
52
|
+
const indents = nonEmpty.map((l) => l.length - l.trimStart().length);
|
|
53
|
+
const minIndent = Math.min(...indents);
|
|
54
|
+
const relIndents = [...new Set(indents.map((n) => n - minIndent).filter((n) => n > 0))];
|
|
55
|
+
const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;
|
|
56
|
+
return lines.map((l) => {
|
|
57
|
+
if (!l.trim()) return "";
|
|
58
|
+
const level = Math.round((l.length - l.trimStart().length - minIndent) / step);
|
|
59
|
+
return baseIndent + " ".repeat(level) + l.trimStart();
|
|
60
|
+
}).join("\n");
|
|
61
|
+
}
|
|
62
|
+
var init_code_format_utils = __esm({
|
|
63
|
+
"src/utils/code-format.utils.ts"() {
|
|
64
|
+
"use strict";
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
33
68
|
// src/utils/selector-quality.utils.ts
|
|
34
69
|
function getSelectorQuality(el) {
|
|
35
70
|
if (el.hasAttribute("data-cy") || el.hasAttribute("data-testid") || el.hasAttribute("aria-label")) {
|
|
@@ -46,11 +81,11 @@ function getSelectorQuality(el) {
|
|
|
46
81
|
}
|
|
47
82
|
function buildPickerSelector(el) {
|
|
48
83
|
const dataCy = el.getAttribute("data-cy");
|
|
49
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
84
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
50
85
|
const dataTestid = el.getAttribute("data-testid");
|
|
51
|
-
if (dataTestid) return `[data-testid="${dataTestid}"]`;
|
|
86
|
+
if (dataTestid) return `[data-testid="${escapeCssAttrValue(dataTestid)}"]`;
|
|
52
87
|
const ariaLabel = el.getAttribute("aria-label");
|
|
53
|
-
if (ariaLabel) return `[aria-label="${ariaLabel}"]`;
|
|
88
|
+
if (ariaLabel) return `[aria-label="${escapeCssAttrValue(ariaLabel)}"]`;
|
|
54
89
|
const rawId = el.id;
|
|
55
90
|
if (rawId && rawId.length < 25 && /^[a-zA-Z][\w-]*$/.test(rawId) && !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) && !/^\d+$/.test(rawId)) {
|
|
56
91
|
return `#${rawId}`;
|
|
@@ -84,6 +119,7 @@ var FORBIDDEN_ID_PREFIXES;
|
|
|
84
119
|
var init_selector_quality_utils = __esm({
|
|
85
120
|
"src/utils/selector-quality.utils.ts"() {
|
|
86
121
|
"use strict";
|
|
122
|
+
init_code_format_utils();
|
|
87
123
|
FORBIDDEN_ID_PREFIXES = [
|
|
88
124
|
"cdk-",
|
|
89
125
|
"mat-",
|
|
@@ -314,6 +350,7 @@ var init_selector_picker = __esm({
|
|
|
314
350
|
"src/components/selector-picker/selector-picker.ts"() {
|
|
315
351
|
"use strict";
|
|
316
352
|
init_selector_quality_utils();
|
|
353
|
+
init_code_format_utils();
|
|
317
354
|
init_selector_picker_styles();
|
|
318
355
|
init_selector_picker_template();
|
|
319
356
|
OWN_DATA_CY = "lib-e2e-cypress-for-dummys";
|
|
@@ -433,7 +470,7 @@ var init_selector_picker = __esm({
|
|
|
433
470
|
confirm(index) {
|
|
434
471
|
const row = this.rows[index];
|
|
435
472
|
if (!row) return;
|
|
436
|
-
const command = `cy.get('${row.selector}').click()`;
|
|
473
|
+
const command = `cy.get('${escapeSingleQuotes(row.selector)}').click()`;
|
|
437
474
|
this.recording.appendCommand(command);
|
|
438
475
|
this.dispatchEvent(new CustomEvent("selectorchosen", { detail: command, bubbles: true, composed: true }));
|
|
439
476
|
this.closeSilently();
|
|
@@ -451,8 +488,8 @@ var init_selector_picker = __esm({
|
|
|
451
488
|
this.remove();
|
|
452
489
|
}
|
|
453
490
|
};
|
|
454
|
-
if (!customElements.get("selector-picker")) {
|
|
455
|
-
customElements.define("selector-picker", SelectorPickerElement);
|
|
491
|
+
if (!customElements.get("lib-e2e-selector-picker")) {
|
|
492
|
+
customElements.define("lib-e2e-selector-picker", SelectorPickerElement);
|
|
456
493
|
}
|
|
457
494
|
}
|
|
458
495
|
});
|
|
@@ -460,14 +497,11 @@ var init_selector_picker = __esm({
|
|
|
460
497
|
// src/index.ts
|
|
461
498
|
var index_exports = {};
|
|
462
499
|
__export(index_exports, {
|
|
463
|
-
ACTIVE_SESSION_BREADCRUMB_KEY: () => ACTIVE_SESSION_BREADCRUMB_KEY,
|
|
464
500
|
AdvancedTestEditorElement: () => AdvancedTestEditorElement,
|
|
465
501
|
AdvancedTestTransformationService: () => AdvancedTestTransformationService,
|
|
466
502
|
ConfigurationElement: () => ConfigurationElement,
|
|
467
503
|
DB_SCHEMA: () => DB_SCHEMA,
|
|
468
504
|
DB_STORE_NAMES: () => DB_STORE_NAMES,
|
|
469
|
-
DEFAULT_RESUME_TTL_MINUTES: () => DEFAULT_RESUME_TTL_MINUTES,
|
|
470
|
-
DRAG_THRESHOLD: () => DRAG_THRESHOLD,
|
|
471
505
|
FilePreviewElement: () => FilePreviewElement,
|
|
472
506
|
HelpPanelElement: () => HelpPanelElement,
|
|
473
507
|
HttpMonitor: () => HttpMonitor,
|
|
@@ -476,24 +510,16 @@ __export(index_exports, {
|
|
|
476
510
|
LOCALE_BY_LANG: () => LOCALE_BY_LANG,
|
|
477
511
|
LibE2eRecorderElement: () => LibE2eRecorderElement,
|
|
478
512
|
PersistenceService: () => PersistenceService,
|
|
479
|
-
RESUME_TTL_CONFIG_KEY: () => RESUME_TTL_CONFIG_KEY,
|
|
480
513
|
RecordingService: () => RecordingService,
|
|
481
514
|
SCROLLBAR_STYLES: () => SCROLLBAR_STYLES,
|
|
482
515
|
SUPPORTED_LANGS: () => SUPPORTED_LANGS,
|
|
483
516
|
SaveTestElement: () => SaveTestElement,
|
|
484
517
|
SelectorPickerElement: () => SelectorPickerElement,
|
|
485
|
-
Subject: () => Subject,
|
|
486
|
-
TOGGLE_MARGIN: () => TOGGLE_MARGIN,
|
|
487
518
|
TestEditorElement: () => TestEditorElement,
|
|
488
519
|
TestPrevisualizerElement: () => TestPrevisualizerElement,
|
|
489
520
|
TransformationService: () => TransformationService,
|
|
490
521
|
TranslationService: () => TranslationService,
|
|
491
522
|
VERSION: () => VERSION,
|
|
492
|
-
advancedTestTransformationService: () => advancedTestTransformationService,
|
|
493
|
-
boxOffsetForDirection: () => boxOffsetForDirection,
|
|
494
|
-
boxTopLeftFor: () => boxTopLeftFor,
|
|
495
|
-
clampTogglePosition: () => clampTogglePosition,
|
|
496
|
-
defaultTogglePosition: () => defaultTogglePosition,
|
|
497
523
|
generateAlias: () => generateAlias,
|
|
498
524
|
inferAssertionCommand: () => inferAssertionCommand,
|
|
499
525
|
injectStyles: () => injectStyles,
|
|
@@ -502,14 +528,8 @@ __export(index_exports, {
|
|
|
502
528
|
localeForLang: () => localeForLang,
|
|
503
529
|
makeModalResizable: () => makeModalResizable,
|
|
504
530
|
makeSwalDraggable: () => makeSwalDraggable,
|
|
505
|
-
makeSwalDraggableByContentId: () => makeSwalDraggableByContentId,
|
|
506
|
-
persistenceService: () => persistenceService,
|
|
507
|
-
resolveExpandDirection: () => resolveExpandDirection,
|
|
508
531
|
selectTestsForExport: () => selectTestsForExport,
|
|
509
|
-
|
|
510
|
-
showToast: () => showToast,
|
|
511
|
-
transformationService: () => transformationService,
|
|
512
|
-
translationService: () => translationService
|
|
532
|
+
showToast: () => showToast
|
|
513
533
|
});
|
|
514
534
|
module.exports = __toCommonJS(index_exports);
|
|
515
535
|
|
|
@@ -598,11 +618,6 @@ var DB_SCHEMA = {
|
|
|
598
618
|
};
|
|
599
619
|
var DB_STORE_NAMES = DB_SCHEMA.stores.map((s) => s.name);
|
|
600
620
|
|
|
601
|
-
// src/models/active-session.model.ts
|
|
602
|
-
var ACTIVE_SESSION_BREADCRUMB_KEY = "e2e-active-session";
|
|
603
|
-
var RESUME_TTL_CONFIG_KEY = "resumeRecencyTtlMinutes";
|
|
604
|
-
var DEFAULT_RESUME_TTL_MINUTES = 30;
|
|
605
|
-
|
|
606
621
|
// src/utils/subject.ts
|
|
607
622
|
var Subject = class {
|
|
608
623
|
_value;
|
|
@@ -650,7 +665,10 @@ var I18N_ES = {
|
|
|
650
665
|
NOTES_PLACEHOLDER: "Qu\xE9 valida este test, condiciones previas, etc.",
|
|
651
666
|
TICKET_LABEL: "Ticket / Issue (opcional):",
|
|
652
667
|
TICKET_PLACEHOLDER: "Ej: PROJ-123, #42",
|
|
653
|
-
TICKET_WARN: "ID no v\xE1lido para el proveedor configurado (se guardar\xE1 igualmente)"
|
|
668
|
+
TICKET_WARN: "ID no v\xE1lido para el proveedor configurado (se guardar\xE1 igualmente)",
|
|
669
|
+
CONFIRM_DISCARD: "\xBFSeguro que quieres descartar el test grabado? Se perder\xE1n todos los pasos registrados.",
|
|
670
|
+
CONFIRM_DISCARD_BTN: "S\xED, descartar",
|
|
671
|
+
BACK_BTN: "Volver"
|
|
654
672
|
},
|
|
655
673
|
TEST_EDITOR: {
|
|
656
674
|
NO_TAGS: "Sin etiquetas",
|
|
@@ -732,7 +750,32 @@ var I18N_ES = {
|
|
|
732
750
|
ISSUE_TRACKER_SUB: "A\xF1ade un ID de ticket al guardar y genera un enlace clickable en el listado.",
|
|
733
751
|
ISSUE_TRACKER_PROVIDER: "Proveedor",
|
|
734
752
|
ISSUE_TRACKER_BASE_URL: "URL base",
|
|
735
|
-
ISSUE_TRACKER_BASE_URL_PH: "Ej: https://miproyecto.atlassian.net"
|
|
753
|
+
ISSUE_TRACKER_BASE_URL_PH: "Ej: https://miproyecto.atlassian.net",
|
|
754
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
755
|
+
LOGIN_SETUP_NOT_CONFIGURED: "No configurado",
|
|
756
|
+
LOGIN_SETUP_SET_UP_BTN: "Configurar",
|
|
757
|
+
LOGIN_SETUP_TITLE: "Configuraci\xF3n de login",
|
|
758
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Crear scaffold",
|
|
759
|
+
LOGIN_SETUP_SELECT_EXISTING: "Seleccionar fichero existente",
|
|
760
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Nombre del fichero",
|
|
761
|
+
LOGIN_SETUP_FILE_NAME_PH: "Ej: cypress/common-services/login.service.ts",
|
|
762
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-escanear",
|
|
763
|
+
LOGIN_SETUP_FUNCTIONS_DETECTED: "Funciones detectadas",
|
|
764
|
+
LOGIN_SETUP_BLOCK_ASSIGN: "Asignaci\xF3n de bloques",
|
|
765
|
+
LOGIN_SETUP_NO_FUNCTIONS: "No se encontraron funciones exportadas. Rellena el scaffold y re-escanea.",
|
|
766
|
+
LOGIN_SETUP_BEFORE_LABEL: "Funci\xF3n before() (una vez por suite)",
|
|
767
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "Funci\xF3n beforeEach() (antes de cada test)",
|
|
768
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Ninguna \u2014",
|
|
769
|
+
LOGIN_SETUP_SUMMARY: "Fichero: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
770
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Guardar",
|
|
771
|
+
LOGIN_SETUP_CLEAR_BTN: "Eliminar configuraci\xF3n",
|
|
772
|
+
LOGIN_SETUP_CANCEL_BTN: "Cancelar",
|
|
773
|
+
LOGIN_SETUP_SOURCE_LABEL: "Origen del fichero de login",
|
|
774
|
+
LOGIN_SETUP_CREATE_SUB: "Genera un scaffold con funciones de ejemplo",
|
|
775
|
+
LOGIN_SETUP_SELECT_SUB: "Apunta a un servicio de login existente",
|
|
776
|
+
LOGIN_SETUP_INJECT_TITLE: "\xBFA\xF1adir bloques de login?",
|
|
777
|
+
LOGIN_SETUP_INJECT_TEXT: "Este fichero no tiene los bloques de login configurados. \xBFQuieres a\xF1adir el import y los bloques before/beforeEach ahora?",
|
|
778
|
+
LOGIN_SETUP_INJECT_CONFIRM: "S\xED, a\xF1adir"
|
|
736
779
|
},
|
|
737
780
|
SELECTOR_PICKER: {
|
|
738
781
|
TITLE: "Selecciona un elemento del DOM",
|
|
@@ -823,6 +866,9 @@ var I18N_ES = {
|
|
|
823
866
|
FILE_SAVE_ERROR_TOAST: "Error al guardar el archivo",
|
|
824
867
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures escritos en cypress/fixtures",
|
|
825
868
|
FIXTURES_NO_FOLDER_TOAST: "No se pudieron escribir los fixtures (configura la carpeta Cypress)",
|
|
869
|
+
FILE_UPLOAD_MANUAL_TOAST: "A\xF1ade {files} a cypress/fixtures/ antes de ejecutar el test.",
|
|
870
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copiado/s a cypress/fixtures/.",
|
|
871
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "No se pudo copiar {files} a cypress/fixtures/. A\xF1\xE1delo manualmente.",
|
|
826
872
|
BTN_CONFIG: "Config",
|
|
827
873
|
BTN_FILES: "Ficheros",
|
|
828
874
|
BTN_COMMANDS: "Comandos",
|
|
@@ -870,7 +916,7 @@ var I18N_ES = {
|
|
|
870
916
|
SEC_PANELS: "\u{1F5C2} Paneles",
|
|
871
917
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 guardados: filtrar por tag, copiar, combinar, exportar.",
|
|
872
918
|
PANEL_COMMANDS: "\u2328\uFE0F Comandos \u2014 de la grabaci\xF3n actual: reordenar, borrar, a\xF1adir aserciones.",
|
|
873
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 idioma, selector, HTTP, carpeta Cypress, datos, visibilidad, posici\xF3n.",
|
|
919
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 idioma, selector, HTTP, carpeta Cypress, login setup, datos, visibilidad, posici\xF3n.",
|
|
874
920
|
PANEL_FILES: "\u{1F4C1} Ficheros \u2014 inserta tests en tus .cy.ts y lanza el runner.",
|
|
875
921
|
SEC_SELECTOR: "\u{1F50E} Selectores",
|
|
876
922
|
SELECTOR_1: "Elige el atributo preferido (data-cy, data-testid, aria-label, id) en Config.",
|
|
@@ -883,6 +929,7 @@ var I18N_ES = {
|
|
|
883
929
|
ADV_RUNNER: "Runner local: npx lib-e2e-cypress-runner para lanzar un spec headless desde el editor.",
|
|
884
930
|
ADV_CROSSAPP: "Cross-app: la grabaci\xF3n sobrevive al cambiar de micro-frontend (mismo origen).",
|
|
885
931
|
ADV_DRAG: "Arrastra el bot\xF3n \u23FA para mover el widget; recuerda su posici\xF3n.",
|
|
932
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
886
933
|
CLOSE: "Cerrar",
|
|
887
934
|
TAB_REFERENCE: "Referencia r\xE1pida",
|
|
888
935
|
TAB_GUIDE: "Gu\xEDa de uso",
|
|
@@ -900,13 +947,13 @@ var I18N_ES = {
|
|
|
900
947
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
901
948
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
902
949
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
950
|
+
G_COV_7: "Login Setup: configura tu funci\xF3n de login en Ctrl+3 \u2192 Login Setup y el grabador a\xF1ade los bloques before()/beforeEach() a cada test nuevo.",
|
|
903
951
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
904
952
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
905
953
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
906
954
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
907
955
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
908
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
909
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
956
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
910
957
|
}
|
|
911
958
|
};
|
|
912
959
|
|
|
@@ -937,7 +984,10 @@ var I18N_EN = {
|
|
|
937
984
|
NOTES_PLACEHOLDER: "What this test validates, preconditions, etc.",
|
|
938
985
|
TICKET_LABEL: "Ticket / Issue (optional):",
|
|
939
986
|
TICKET_PLACEHOLDER: "E.g.: PROJ-123, #42",
|
|
940
|
-
TICKET_WARN: "Invalid ID for the configured provider (will be saved anyway)"
|
|
987
|
+
TICKET_WARN: "Invalid ID for the configured provider (will be saved anyway)",
|
|
988
|
+
CONFIRM_DISCARD: "Are you sure you want to discard this recording? All recorded steps will be lost.",
|
|
989
|
+
CONFIRM_DISCARD_BTN: "Yes, discard",
|
|
990
|
+
BACK_BTN: "Go back"
|
|
941
991
|
},
|
|
942
992
|
TEST_EDITOR: {
|
|
943
993
|
NO_TAGS: "No tags",
|
|
@@ -1019,7 +1069,32 @@ var I18N_EN = {
|
|
|
1019
1069
|
ISSUE_TRACKER_SUB: "Add a ticket ID when saving and generate a clickable link in the test list.",
|
|
1020
1070
|
ISSUE_TRACKER_PROVIDER: "Provider",
|
|
1021
1071
|
ISSUE_TRACKER_BASE_URL: "Base URL",
|
|
1022
|
-
ISSUE_TRACKER_BASE_URL_PH: "E.g.: https://myproject.atlassian.net"
|
|
1072
|
+
ISSUE_TRACKER_BASE_URL_PH: "E.g.: https://myproject.atlassian.net",
|
|
1073
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
1074
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Not configured",
|
|
1075
|
+
LOGIN_SETUP_SET_UP_BTN: "Set up",
|
|
1076
|
+
LOGIN_SETUP_TITLE: "Login setup",
|
|
1077
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Create scaffold",
|
|
1078
|
+
LOGIN_SETUP_SELECT_EXISTING: "Select existing file",
|
|
1079
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "File name",
|
|
1080
|
+
LOGIN_SETUP_FILE_NAME_PH: "E.g.: cypress/common-services/login.service.ts",
|
|
1081
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-scan",
|
|
1082
|
+
LOGIN_SETUP_FUNCTIONS_DETECTED: "Detected functions",
|
|
1083
|
+
LOGIN_SETUP_BLOCK_ASSIGN: "Block assignment",
|
|
1084
|
+
LOGIN_SETUP_NO_FUNCTIONS: "No exported functions found. Fill in the scaffold and re-scan.",
|
|
1085
|
+
LOGIN_SETUP_BEFORE_LABEL: "before() function (once per suite)",
|
|
1086
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "beforeEach() function (before every test)",
|
|
1087
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 None \u2014",
|
|
1088
|
+
LOGIN_SETUP_SUMMARY: "File: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
1089
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Save",
|
|
1090
|
+
LOGIN_SETUP_CLEAR_BTN: "Remove configuration",
|
|
1091
|
+
LOGIN_SETUP_CANCEL_BTN: "Cancel",
|
|
1092
|
+
LOGIN_SETUP_SOURCE_LABEL: "Login file source",
|
|
1093
|
+
LOGIN_SETUP_CREATE_SUB: "Generate a scaffold with sample functions",
|
|
1094
|
+
LOGIN_SETUP_SELECT_SUB: "Point to an existing login service file",
|
|
1095
|
+
LOGIN_SETUP_INJECT_TITLE: "Add login blocks?",
|
|
1096
|
+
LOGIN_SETUP_INJECT_TEXT: "This file does not have the configured login blocks. Do you want to add the import and before/beforeEach blocks now?",
|
|
1097
|
+
LOGIN_SETUP_INJECT_CONFIRM: "Yes, add them"
|
|
1023
1098
|
},
|
|
1024
1099
|
SELECTOR_PICKER: {
|
|
1025
1100
|
TITLE: "Select a DOM element",
|
|
@@ -1110,6 +1185,9 @@ var I18N_EN = {
|
|
|
1110
1185
|
FILE_SAVE_ERROR_TOAST: "Error saving the file",
|
|
1111
1186
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures written to cypress/fixtures",
|
|
1112
1187
|
FIXTURES_NO_FOLDER_TOAST: "Could not write fixtures (configure the Cypress folder)",
|
|
1188
|
+
FILE_UPLOAD_MANUAL_TOAST: "Add {files} to cypress/fixtures/ before running the test.",
|
|
1189
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copied to cypress/fixtures/.",
|
|
1190
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "Could not copy {files} to cypress/fixtures/. Add it manually.",
|
|
1113
1191
|
BTN_CONFIG: "Config",
|
|
1114
1192
|
BTN_FILES: "Files",
|
|
1115
1193
|
BTN_COMMANDS: "Commands",
|
|
@@ -1157,7 +1235,7 @@ var I18N_EN = {
|
|
|
1157
1235
|
SEC_PANELS: "\u{1F5C2} Panels",
|
|
1158
1236
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 saved tests: filter by tag, copy, combine, export.",
|
|
1159
1237
|
PANEL_COMMANDS: "\u2328\uFE0F Commands \u2014 current recording: reorder, delete, add assertions.",
|
|
1160
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 language, selector, HTTP, Cypress folder, data, visibility, position.",
|
|
1238
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 language, selector, HTTP, Cypress folder, login setup, data, visibility, position.",
|
|
1161
1239
|
PANEL_FILES: "\u{1F4C1} Files \u2014 insert tests into your .cy.ts and launch the runner.",
|
|
1162
1240
|
SEC_SELECTOR: "\u{1F50E} Selectors",
|
|
1163
1241
|
SELECTOR_1: "Choose the preferred attribute (data-cy, data-testid, aria-label, id) in Config.",
|
|
@@ -1170,6 +1248,7 @@ var I18N_EN = {
|
|
|
1170
1248
|
ADV_RUNNER: "Local runner: npx lib-e2e-cypress-runner to run a spec headless from the editor.",
|
|
1171
1249
|
ADV_CROSSAPP: "Cross-app: the recording survives switching micro-frontend (same origin).",
|
|
1172
1250
|
ADV_DRAG: "Drag the \u23FA button to move the widget; its position is remembered.",
|
|
1251
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): point to your login service; the recorder automatically injects before()/beforeEach() blocks into each new test.",
|
|
1173
1252
|
CLOSE: "Close",
|
|
1174
1253
|
TAB_REFERENCE: "Quick reference",
|
|
1175
1254
|
TAB_GUIDE: "Usage guide",
|
|
@@ -1187,13 +1266,13 @@ var I18N_EN = {
|
|
|
1187
1266
|
G_COV_4: "Reliable selector (data-cy/testid/aria/id) and a picker when none is obvious.",
|
|
1188
1267
|
G_COV_5: "Automatic assertions (Alt+click) and the manual builder.",
|
|
1189
1268
|
G_COV_6: "Continuity when switching micro-frontend (same origin), invisible mode and i18n.",
|
|
1269
|
+
G_COV_7: "Login Setup: configure your login function under Ctrl+3 \u2192 Login Setup; the recorder adds before()/beforeEach() blocks to every new test.",
|
|
1190
1270
|
G_SEC_NOTCOVERED: "\u{1F6AB} What it does NOT cover (yet)",
|
|
1191
1271
|
G_NC_1: "Different origins / subdomains (same origin only).",
|
|
1192
1272
|
G_NC_2: "File upload (selectFile), drag & drop, and hover.",
|
|
1193
1273
|
G_NC_3: "The Tab key (Cypress can't .type() it).",
|
|
1194
1274
|
G_NC_4: "DELETE requests (intentionally ignored).",
|
|
1195
|
-
G_NC_5: "Third-party iframes and Shadow DOM may not be captured."
|
|
1196
|
-
G_NC_6: "Programmatic login generation (on the roadmap)."
|
|
1275
|
+
G_NC_5: "Third-party iframes and Shadow DOM may not be captured."
|
|
1197
1276
|
}
|
|
1198
1277
|
};
|
|
1199
1278
|
|
|
@@ -1224,8 +1303,11 @@ var I18N_FR = {
|
|
|
1224
1303
|
NOTES_PLACEHOLDER: "Ce que ce test valide, conditions pr\xE9alables, etc.",
|
|
1225
1304
|
TICKET_LABEL: "Ticket / Issue (optionnel) :",
|
|
1226
1305
|
TICKET_PLACEHOLDER: "Ex : PROJ-123, #42",
|
|
1227
|
-
TICKET_WARN: "ID non valide pour le fournisseur configur\xE9 (sera enregistr\xE9 quand m\xEAme)"
|
|
1306
|
+
TICKET_WARN: "ID non valide pour le fournisseur configur\xE9 (sera enregistr\xE9 quand m\xEAme)",
|
|
1228
1307
|
// TODO: translate
|
|
1308
|
+
CONFIRM_DISCARD: "\xCAtes-vous s\xFBr de vouloir abandonner cet enregistrement ? Toutes les \xE9tapes enregistr\xE9es seront perdues.",
|
|
1309
|
+
CONFIRM_DISCARD_BTN: "Oui, abandonner",
|
|
1310
|
+
BACK_BTN: "Retour"
|
|
1229
1311
|
},
|
|
1230
1312
|
TEST_EDITOR: {
|
|
1231
1313
|
NO_TAGS: "Sans \xE9tiquettes",
|
|
@@ -1307,7 +1389,32 @@ var I18N_FR = {
|
|
|
1307
1389
|
ISSUE_TRACKER_SUB: "Ajoutez un ID de ticket lors de l'enregistrement et g\xE9n\xE9rez un lien cliquable.",
|
|
1308
1390
|
ISSUE_TRACKER_PROVIDER: "Fournisseur",
|
|
1309
1391
|
ISSUE_TRACKER_BASE_URL: "URL de base",
|
|
1310
|
-
ISSUE_TRACKER_BASE_URL_PH: "Ex : https://monprojet.atlassian.net"
|
|
1392
|
+
ISSUE_TRACKER_BASE_URL_PH: "Ex : https://monprojet.atlassian.net",
|
|
1393
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
1394
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Non configur\xE9",
|
|
1395
|
+
LOGIN_SETUP_SET_UP_BTN: "Configurer",
|
|
1396
|
+
LOGIN_SETUP_TITLE: "Configuration du login",
|
|
1397
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Cr\xE9er un scaffold",
|
|
1398
|
+
LOGIN_SETUP_SELECT_EXISTING: "S\xE9lectionner un fichier existant",
|
|
1399
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Nom du fichier",
|
|
1400
|
+
LOGIN_SETUP_FILE_NAME_PH: "Ex : cypress/common-services/login.service.ts",
|
|
1401
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-scanner",
|
|
1402
|
+
LOGIN_SETUP_FUNCTIONS_DETECTED: "Fonctions d\xE9tect\xE9es",
|
|
1403
|
+
LOGIN_SETUP_BLOCK_ASSIGN: "Affectation des blocs",
|
|
1404
|
+
LOGIN_SETUP_NO_FUNCTIONS: "Aucune fonction export\xE9e trouv\xE9e. Remplissez le scaffold et re-scannez.",
|
|
1405
|
+
LOGIN_SETUP_BEFORE_LABEL: "Fonction before() (une fois par suite)",
|
|
1406
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "Fonction beforeEach() (avant chaque test)",
|
|
1407
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Aucune \u2014",
|
|
1408
|
+
LOGIN_SETUP_SUMMARY: "Fichier : {file} \xB7 before : {before} \xB7 beforeEach : {beforeEach}",
|
|
1409
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Enregistrer",
|
|
1410
|
+
LOGIN_SETUP_CLEAR_BTN: "Supprimer la configuration",
|
|
1411
|
+
LOGIN_SETUP_CANCEL_BTN: "Annuler",
|
|
1412
|
+
LOGIN_SETUP_SOURCE_LABEL: "Source du fichier de login",
|
|
1413
|
+
LOGIN_SETUP_CREATE_SUB: "G\xE9n\xE9rer un scaffold avec des fonctions exemples",
|
|
1414
|
+
LOGIN_SETUP_SELECT_SUB: "Pointer vers un fichier de service de login existant",
|
|
1415
|
+
LOGIN_SETUP_INJECT_TITLE: "Ajouter les blocs de login ?",
|
|
1416
|
+
LOGIN_SETUP_INJECT_TEXT: "Ce fichier ne contient pas les blocs de login configur\xE9s. Voulez-vous ajouter l'import et les blocs before/beforeEach maintenant ?",
|
|
1417
|
+
LOGIN_SETUP_INJECT_CONFIRM: "Oui, ajouter"
|
|
1311
1418
|
},
|
|
1312
1419
|
SELECTOR_PICKER: {
|
|
1313
1420
|
TITLE: "S\xE9lectionnez un \xE9l\xE9ment du DOM",
|
|
@@ -1398,6 +1505,12 @@ var I18N_FR = {
|
|
|
1398
1505
|
FILE_SAVE_ERROR_TOAST: "Erreur lors de l'enregistrement",
|
|
1399
1506
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures \xE9crites dans cypress/fixtures",
|
|
1400
1507
|
FIXTURES_NO_FOLDER_TOAST: "Impossible d'\xE9crire les fixtures (configure le dossier Cypress)",
|
|
1508
|
+
FILE_UPLOAD_MANUAL_TOAST: "Ajoutez {files} \xE0 cypress/fixtures/ avant d'ex\xE9cuter le test.",
|
|
1509
|
+
// TODO: translate
|
|
1510
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copi\xE9(s) dans cypress/fixtures/.",
|
|
1511
|
+
// TODO: translate
|
|
1512
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "Impossible de copier {files} vers cypress/fixtures/. Ajoutez-le manuellement.",
|
|
1513
|
+
// TODO: translate
|
|
1401
1514
|
BTN_CONFIG: "Config",
|
|
1402
1515
|
BTN_FILES: "Fichiers",
|
|
1403
1516
|
BTN_COMMANDS: "Commandes",
|
|
@@ -1445,7 +1558,7 @@ var I18N_FR = {
|
|
|
1445
1558
|
SEC_PANELS: "\u{1F5C2} Panneaux",
|
|
1446
1559
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 enregistr\xE9s : filtrer par tag, copier, combiner, exporter.",
|
|
1447
1560
|
PANEL_COMMANDS: "\u2328\uFE0F Commandes \u2014 enregistrement en cours : r\xE9ordonner, supprimer, ajouter des assertions.",
|
|
1448
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 langue, s\xE9lecteur, HTTP, dossier Cypress, donn\xE9es, visibilit\xE9, position.",
|
|
1561
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 langue, s\xE9lecteur, HTTP, dossier Cypress, login setup, donn\xE9es, visibilit\xE9, position.",
|
|
1449
1562
|
PANEL_FILES: "\u{1F4C1} Fichiers \u2014 ins\xE8re des tests dans tes .cy.ts et lance le runner.",
|
|
1450
1563
|
SEC_SELECTOR: "\u{1F50E} S\xE9lecteurs",
|
|
1451
1564
|
SELECTOR_1: "Choisis l'attribut pr\xE9f\xE9r\xE9 (data-cy, data-testid, aria-label, id) dans Config.",
|
|
@@ -1458,6 +1571,8 @@ var I18N_FR = {
|
|
|
1458
1571
|
ADV_RUNNER: "Runner local : npx lib-e2e-cypress-runner pour lancer un spec headless depuis l'\xE9diteur.",
|
|
1459
1572
|
ADV_CROSSAPP: "Cross-app : l'enregistrement survit au changement de micro-frontend (m\xEAme origine).",
|
|
1460
1573
|
ADV_DRAG: "Fais glisser le bouton \u23FA pour d\xE9placer le widget ; sa position est m\xE9moris\xE9e.",
|
|
1574
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
1575
|
+
// TODO: translate (fr)
|
|
1461
1576
|
CLOSE: "Fermer",
|
|
1462
1577
|
TAB_REFERENCE: "R\xE9f\xE9rence rapide",
|
|
1463
1578
|
TAB_GUIDE: "Guide d'utilisation",
|
|
@@ -1476,13 +1591,14 @@ var I18N_FR = {
|
|
|
1476
1591
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
1477
1592
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
1478
1593
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
1594
|
+
G_COV_7: "Login Setup: configura tu funci\xF3n de login en Ctrl+3 \u2192 Login Setup y el grabador a\xF1ade los bloques before()/beforeEach() a cada test nuevo.",
|
|
1595
|
+
// TODO: translate (fr)
|
|
1479
1596
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
1480
1597
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
1481
1598
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
1482
1599
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
1483
1600
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
1484
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1485
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
1601
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1486
1602
|
}
|
|
1487
1603
|
};
|
|
1488
1604
|
|
|
@@ -1513,8 +1629,11 @@ var I18N_IT = {
|
|
|
1513
1629
|
NOTES_PLACEHOLDER: "Cosa valida questo test, condizioni preliminari, ecc.",
|
|
1514
1630
|
TICKET_LABEL: "Ticket / Issue (opzionale):",
|
|
1515
1631
|
TICKET_PLACEHOLDER: "Es: PROJ-123, #42",
|
|
1516
|
-
TICKET_WARN: "ID non valido per il provider configurato (verr\xE0 salvato comunque)"
|
|
1632
|
+
TICKET_WARN: "ID non valido per il provider configurato (verr\xE0 salvato comunque)",
|
|
1517
1633
|
// TODO: translate
|
|
1634
|
+
CONFIRM_DISCARD: "Sei sicuro di voler scartare questa registrazione? Tutti i passi registrati andranno persi.",
|
|
1635
|
+
CONFIRM_DISCARD_BTN: "S\xEC, scarta",
|
|
1636
|
+
BACK_BTN: "Indietro"
|
|
1518
1637
|
},
|
|
1519
1638
|
TEST_EDITOR: {
|
|
1520
1639
|
NO_TAGS: "Nessuna etichetta",
|
|
@@ -1596,7 +1715,32 @@ var I18N_IT = {
|
|
|
1596
1715
|
ISSUE_TRACKER_SUB: "Aggiungi un ID ticket al salvataggio e genera un link cliccabile nell'elenco.",
|
|
1597
1716
|
ISSUE_TRACKER_PROVIDER: "Provider",
|
|
1598
1717
|
ISSUE_TRACKER_BASE_URL: "URL base",
|
|
1599
|
-
ISSUE_TRACKER_BASE_URL_PH: "Es: https://mioprogetto.atlassian.net"
|
|
1718
|
+
ISSUE_TRACKER_BASE_URL_PH: "Es: https://mioprogetto.atlassian.net",
|
|
1719
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
1720
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Non configurato",
|
|
1721
|
+
LOGIN_SETUP_SET_UP_BTN: "Configura",
|
|
1722
|
+
LOGIN_SETUP_TITLE: "Configurazione del login",
|
|
1723
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Crea scaffold",
|
|
1724
|
+
LOGIN_SETUP_SELECT_EXISTING: "Seleziona file esistente",
|
|
1725
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Nome del file",
|
|
1726
|
+
LOGIN_SETUP_FILE_NAME_PH: "Es: cypress/common-services/login.service.ts",
|
|
1727
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-scansiona",
|
|
1728
|
+
LOGIN_SETUP_FUNCTIONS_DETECTED: "Funzioni rilevate",
|
|
1729
|
+
LOGIN_SETUP_BLOCK_ASSIGN: "Assegnazione dei blocchi",
|
|
1730
|
+
LOGIN_SETUP_NO_FUNCTIONS: "Nessuna funzione esportata trovata. Compila lo scaffold e ri-scansiona.",
|
|
1731
|
+
LOGIN_SETUP_BEFORE_LABEL: "Funzione before() (una volta per suite)",
|
|
1732
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "Funzione beforeEach() (prima di ogni test)",
|
|
1733
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Nessuna \u2014",
|
|
1734
|
+
LOGIN_SETUP_SUMMARY: "File: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
1735
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Salva",
|
|
1736
|
+
LOGIN_SETUP_CLEAR_BTN: "Rimuovi configurazione",
|
|
1737
|
+
LOGIN_SETUP_CANCEL_BTN: "Annulla",
|
|
1738
|
+
LOGIN_SETUP_SOURCE_LABEL: "Sorgente del file di login",
|
|
1739
|
+
LOGIN_SETUP_CREATE_SUB: "Genera uno scaffold con funzioni di esempio",
|
|
1740
|
+
LOGIN_SETUP_SELECT_SUB: "Punta a un file di servizio di login esistente",
|
|
1741
|
+
LOGIN_SETUP_INJECT_TITLE: "Aggiungere i blocchi di login?",
|
|
1742
|
+
LOGIN_SETUP_INJECT_TEXT: "Questo file non contiene i blocchi di login configurati. Vuoi aggiungere l'import e i blocchi before/beforeEach ora?",
|
|
1743
|
+
LOGIN_SETUP_INJECT_CONFIRM: "S\xEC, aggiungi"
|
|
1600
1744
|
},
|
|
1601
1745
|
SELECTOR_PICKER: {
|
|
1602
1746
|
TITLE: "Seleziona un elemento DOM",
|
|
@@ -1687,6 +1831,12 @@ var I18N_IT = {
|
|
|
1687
1831
|
FILE_SAVE_ERROR_TOAST: "Errore durante il salvataggio",
|
|
1688
1832
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixture scritte in cypress/fixtures",
|
|
1689
1833
|
FIXTURES_NO_FOLDER_TOAST: "Impossibile scrivere le fixture (configura la cartella Cypress)",
|
|
1834
|
+
FILE_UPLOAD_MANUAL_TOAST: "Aggiungi {files} a cypress/fixtures/ prima di eseguire il test.",
|
|
1835
|
+
// TODO: translate
|
|
1836
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copiato/i in cypress/fixtures/.",
|
|
1837
|
+
// TODO: translate
|
|
1838
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "Impossibile copiare {files} in cypress/fixtures/. Aggiungilo manualmente.",
|
|
1839
|
+
// TODO: translate
|
|
1690
1840
|
BTN_CONFIG: "Config",
|
|
1691
1841
|
BTN_FILES: "File",
|
|
1692
1842
|
BTN_COMMANDS: "Comandi",
|
|
@@ -1734,7 +1884,7 @@ var I18N_IT = {
|
|
|
1734
1884
|
SEC_PANELS: "\u{1F5C2} Pannelli",
|
|
1735
1885
|
PANEL_TESTS: "\u{1F4CB} Test \u2014 salvati: filtra per tag, copia, combina, esporta.",
|
|
1736
1886
|
PANEL_COMMANDS: "\u2328\uFE0F Comandi \u2014 registrazione corrente: riordina, elimina, aggiungi asserzioni.",
|
|
1737
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 lingua, selettore, HTTP, cartella Cypress, dati, visibilit\xE0, posizione.",
|
|
1887
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 lingua, selettore, HTTP, cartella Cypress, login setup, dati, visibilit\xE0, posizione.",
|
|
1738
1888
|
PANEL_FILES: "\u{1F4C1} File \u2014 inserisci test nei tuoi .cy.ts e avvia il runner.",
|
|
1739
1889
|
SEC_SELECTOR: "\u{1F50E} Selettori",
|
|
1740
1890
|
SELECTOR_1: "Scegli l'attributo preferito (data-cy, data-testid, aria-label, id) in Config.",
|
|
@@ -1747,6 +1897,8 @@ var I18N_IT = {
|
|
|
1747
1897
|
ADV_RUNNER: "Runner locale: npx lib-e2e-cypress-runner per eseguire uno spec headless dall'editor.",
|
|
1748
1898
|
ADV_CROSSAPP: "Cross-app: la registrazione sopravvive al cambio di micro-frontend (stessa origine).",
|
|
1749
1899
|
ADV_DRAG: "Trascina il pulsante \u23FA per spostare il widget; la posizione viene ricordata.",
|
|
1900
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
1901
|
+
// TODO: translate (it)
|
|
1750
1902
|
CLOSE: "Chiudi",
|
|
1751
1903
|
TAB_REFERENCE: "Riferimento rapido",
|
|
1752
1904
|
TAB_GUIDE: "Guida all'uso",
|
|
@@ -1765,13 +1917,14 @@ var I18N_IT = {
|
|
|
1765
1917
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
1766
1918
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
1767
1919
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
1920
|
+
G_COV_7: "Login Setup: configura tu funci\xF3n de login en Ctrl+3 \u2192 Login Setup y el grabador a\xF1ade los bloques before()/beforeEach() a cada test nuevo.",
|
|
1921
|
+
// TODO: translate (it)
|
|
1768
1922
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
1769
1923
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
1770
1924
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
1771
1925
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
1772
1926
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
1773
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1774
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
1927
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1775
1928
|
}
|
|
1776
1929
|
};
|
|
1777
1930
|
|
|
@@ -1802,8 +1955,11 @@ var I18N_DE = {
|
|
|
1802
1955
|
NOTES_PLACEHOLDER: "Was dieser Test validiert, Voraussetzungen usw.",
|
|
1803
1956
|
TICKET_LABEL: "Ticket / Issue (optional):",
|
|
1804
1957
|
TICKET_PLACEHOLDER: "Z. B.: PROJ-123, #42",
|
|
1805
|
-
TICKET_WARN: "Ung\xFCltige ID f\xFCr den konfigurierten Anbieter (wird trotzdem gespeichert)"
|
|
1958
|
+
TICKET_WARN: "Ung\xFCltige ID f\xFCr den konfigurierten Anbieter (wird trotzdem gespeichert)",
|
|
1806
1959
|
// TODO: translate
|
|
1960
|
+
CONFIRM_DISCARD: "Sind Sie sicher, dass Sie diese Aufzeichnung verwerfen m\xF6chten? Alle aufgezeichneten Schritte gehen verloren.",
|
|
1961
|
+
CONFIRM_DISCARD_BTN: "Ja, verwerfen",
|
|
1962
|
+
BACK_BTN: "Zur\xFCck"
|
|
1807
1963
|
},
|
|
1808
1964
|
TEST_EDITOR: {
|
|
1809
1965
|
NO_TAGS: "Keine Tags",
|
|
@@ -1885,7 +2041,32 @@ var I18N_DE = {
|
|
|
1885
2041
|
ISSUE_TRACKER_SUB: "F\xFCge beim Speichern eine Ticket-ID hinzu und erstelle einen klickbaren Link.",
|
|
1886
2042
|
ISSUE_TRACKER_PROVIDER: "Anbieter",
|
|
1887
2043
|
ISSUE_TRACKER_BASE_URL: "Basis-URL",
|
|
1888
|
-
ISSUE_TRACKER_BASE_URL_PH: "Z. B.: https://meinprojekt.atlassian.net"
|
|
2044
|
+
ISSUE_TRACKER_BASE_URL_PH: "Z. B.: https://meinprojekt.atlassian.net",
|
|
2045
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
2046
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Nicht konfiguriert",
|
|
2047
|
+
LOGIN_SETUP_SET_UP_BTN: "Einrichten",
|
|
2048
|
+
LOGIN_SETUP_TITLE: "Login-Konfiguration",
|
|
2049
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Scaffold erstellen",
|
|
2050
|
+
LOGIN_SETUP_SELECT_EXISTING: "Vorhandene Datei ausw\xE4hlen",
|
|
2051
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Dateiname",
|
|
2052
|
+
LOGIN_SETUP_FILE_NAME_PH: "Z. B.: cypress/common-services/login.service.ts",
|
|
2053
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Erneut scannen",
|
|
2054
|
+
LOGIN_SETUP_FUNCTIONS_DETECTED: "Erkannte Funktionen",
|
|
2055
|
+
LOGIN_SETUP_BLOCK_ASSIGN: "Blockzuweisung",
|
|
2056
|
+
LOGIN_SETUP_NO_FUNCTIONS: "Keine exportierten Funktionen gefunden. Scaffold ausf\xFCllen und erneut scannen.",
|
|
2057
|
+
LOGIN_SETUP_BEFORE_LABEL: "before()-Funktion (einmal pro Suite)",
|
|
2058
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "beforeEach()-Funktion (vor jedem Test)",
|
|
2059
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Keine \u2014",
|
|
2060
|
+
LOGIN_SETUP_SUMMARY: "Datei: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
2061
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Speichern",
|
|
2062
|
+
LOGIN_SETUP_CLEAR_BTN: "Konfiguration entfernen",
|
|
2063
|
+
LOGIN_SETUP_CANCEL_BTN: "Abbrechen",
|
|
2064
|
+
LOGIN_SETUP_SOURCE_LABEL: "Quelle der Login-Datei",
|
|
2065
|
+
LOGIN_SETUP_CREATE_SUB: "Scaffold mit Beispielfunktionen erstellen",
|
|
2066
|
+
LOGIN_SETUP_SELECT_SUB: "Auf eine vorhandene Login-Service-Datei verweisen",
|
|
2067
|
+
LOGIN_SETUP_INJECT_TITLE: "Login-Bl\xF6cke hinzuf\xFCgen?",
|
|
2068
|
+
LOGIN_SETUP_INJECT_TEXT: "Diese Datei enth\xE4lt die konfigurierten Login-Bl\xF6cke nicht. M\xF6chten Sie jetzt den Import und die before/beforeEach-Bl\xF6cke hinzuf\xFCgen?",
|
|
2069
|
+
LOGIN_SETUP_INJECT_CONFIRM: "Ja, hinzuf\xFCgen"
|
|
1889
2070
|
},
|
|
1890
2071
|
SELECTOR_PICKER: {
|
|
1891
2072
|
TITLE: "DOM-Element ausw\xE4hlen",
|
|
@@ -1976,6 +2157,12 @@ var I18N_DE = {
|
|
|
1976
2157
|
FILE_SAVE_ERROR_TOAST: "Fehler beim Speichern",
|
|
1977
2158
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures in cypress/fixtures geschrieben",
|
|
1978
2159
|
FIXTURES_NO_FOLDER_TOAST: "Fixtures konnten nicht geschrieben werden (Cypress-Ordner konfigurieren)",
|
|
2160
|
+
FILE_UPLOAD_MANUAL_TOAST: "F\xFCge {files} zu cypress/fixtures/ hinzu, bevor du den Test ausf\xFChrst.",
|
|
2161
|
+
// TODO: translate
|
|
2162
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} nach cypress/fixtures/ kopiert.",
|
|
2163
|
+
// TODO: translate
|
|
2164
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "{files} konnte nicht nach cypress/fixtures/ kopiert werden. F\xFCge es manuell hinzu.",
|
|
2165
|
+
// TODO: translate
|
|
1979
2166
|
BTN_CONFIG: "Config",
|
|
1980
2167
|
BTN_FILES: "Dateien",
|
|
1981
2168
|
BTN_COMMANDS: "Befehle",
|
|
@@ -2023,7 +2210,7 @@ var I18N_DE = {
|
|
|
2023
2210
|
SEC_PANELS: "\u{1F5C2} Panels",
|
|
2024
2211
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 gespeichert: nach Tag filtern, kopieren, kombinieren, exportieren.",
|
|
2025
2212
|
PANEL_COMMANDS: "\u2328\uFE0F Befehle \u2014 aktuelle Aufzeichnung: umsortieren, l\xF6schen, Assertions hinzuf\xFCgen.",
|
|
2026
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 Sprache, Selektor, HTTP, Cypress-Ordner, Daten, Sichtbarkeit, Position.",
|
|
2213
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 Sprache, Selektor, HTTP, Cypress-Ordner, Login-Setup, Daten, Sichtbarkeit, Position.",
|
|
2027
2214
|
PANEL_FILES: "\u{1F4C1} Dateien \u2014 Tests in deine .cy.ts einf\xFCgen und den Runner starten.",
|
|
2028
2215
|
SEC_SELECTOR: "\u{1F50E} Selektoren",
|
|
2029
2216
|
SELECTOR_1: "W\xE4hle das bevorzugte Attribut (data-cy, data-testid, aria-label, id) unter Config.",
|
|
@@ -2036,6 +2223,8 @@ var I18N_DE = {
|
|
|
2036
2223
|
ADV_RUNNER: "Lokaler Runner: npx lib-e2e-cypress-runner, um einen Spec headless aus dem Editor zu starten.",
|
|
2037
2224
|
ADV_CROSSAPP: "Cross-App: die Aufzeichnung \xFCbersteht den Wechsel des Micro-Frontends (gleicher Origin).",
|
|
2038
2225
|
ADV_DRAG: "Ziehe den \u23FA-Button, um das Widget zu verschieben; die Position wird gemerkt.",
|
|
2226
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
2227
|
+
// TODO: translate (de)
|
|
2039
2228
|
CLOSE: "Schlie\xDFen",
|
|
2040
2229
|
TAB_REFERENCE: "Kurzreferenz",
|
|
2041
2230
|
TAB_GUIDE: "Nutzungsleitfaden",
|
|
@@ -2054,13 +2243,14 @@ var I18N_DE = {
|
|
|
2054
2243
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
2055
2244
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
2056
2245
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
2246
|
+
G_COV_7: "Login Setup: configura tu funci\xF3n de login en Ctrl+3 \u2192 Login Setup y el grabador a\xF1ade los bloques before()/beforeEach() a cada test nuevo.",
|
|
2247
|
+
// TODO: translate (de)
|
|
2057
2248
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
2058
2249
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
2059
2250
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
2060
2251
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
2061
2252
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
2062
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
2063
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
2253
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
2064
2254
|
}
|
|
2065
2255
|
};
|
|
2066
2256
|
|
|
@@ -2103,34 +2293,8 @@ var TranslationService = class {
|
|
|
2103
2293
|
};
|
|
2104
2294
|
var translationService = new TranslationService();
|
|
2105
2295
|
|
|
2106
|
-
// src/utils/code-format.utils.ts
|
|
2107
|
-
function gcd(a, b) {
|
|
2108
|
-
while (b) {
|
|
2109
|
-
const t = b;
|
|
2110
|
-
b = a % b;
|
|
2111
|
-
a = t;
|
|
2112
|
-
}
|
|
2113
|
-
return a;
|
|
2114
|
-
}
|
|
2115
|
-
function escapeSingleQuotes(value) {
|
|
2116
|
-
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
2117
|
-
}
|
|
2118
|
-
function normalizeBlock(code, baseIndent) {
|
|
2119
|
-
const lines = code.split("\n").map((l) => l.trimEnd());
|
|
2120
|
-
const nonEmpty = lines.filter((l) => l.trim().length > 0);
|
|
2121
|
-
if (!nonEmpty.length) return "";
|
|
2122
|
-
const indents = nonEmpty.map((l) => l.length - l.trimStart().length);
|
|
2123
|
-
const minIndent = Math.min(...indents);
|
|
2124
|
-
const relIndents = [...new Set(indents.map((n) => n - minIndent).filter((n) => n > 0))];
|
|
2125
|
-
const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;
|
|
2126
|
-
return lines.map((l) => {
|
|
2127
|
-
if (!l.trim()) return "";
|
|
2128
|
-
const level = Math.round((l.length - l.trimStart().length - minIndent) / step);
|
|
2129
|
-
return baseIndent + " ".repeat(level) + l.trimStart();
|
|
2130
|
-
}).join("\n");
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2133
2296
|
// src/services/transformation.service.ts
|
|
2297
|
+
init_code_format_utils();
|
|
2134
2298
|
var TransformationService = class {
|
|
2135
2299
|
toLang(lang) {
|
|
2136
2300
|
return isLang(lang) ? lang : "en";
|
|
@@ -2195,9 +2359,11 @@ var advancedTestTransformationService = new AdvancedTestTransformationService();
|
|
|
2195
2359
|
init_selector_quality_utils();
|
|
2196
2360
|
|
|
2197
2361
|
// src/utils/assertion.utils.ts
|
|
2362
|
+
init_code_format_utils();
|
|
2198
2363
|
var MAX_TEXT_LENGTH = 60;
|
|
2199
2364
|
function inferAssertionCommand(el, selector) {
|
|
2200
|
-
const
|
|
2365
|
+
const safeSelector = escapeSingleQuotes(selector);
|
|
2366
|
+
const should = (body) => `cy.get('${safeSelector}').should(${body})`;
|
|
2201
2367
|
const tag = el.tagName.toLowerCase();
|
|
2202
2368
|
if (tag === "input") {
|
|
2203
2369
|
const input = el;
|
|
@@ -2219,6 +2385,7 @@ function inferAssertionCommand(el, selector) {
|
|
|
2219
2385
|
}
|
|
2220
2386
|
|
|
2221
2387
|
// src/services/recording.service.ts
|
|
2388
|
+
init_code_format_utils();
|
|
2222
2389
|
var OWN_SELECTOR = '[data-cy="lib-e2e-cypress-for-dummys"]';
|
|
2223
2390
|
function createSessionId() {
|
|
2224
2391
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
@@ -2234,6 +2401,7 @@ var RecordingService = class {
|
|
|
2234
2401
|
selectorNotFound$ = new Subject(null);
|
|
2235
2402
|
inputDebounceTimers = /* @__PURE__ */ new Map();
|
|
2236
2403
|
fixtures = /* @__PURE__ */ new Map();
|
|
2404
|
+
uploadedFiles = /* @__PURE__ */ new Map();
|
|
2237
2405
|
abort = new AbortController();
|
|
2238
2406
|
selectorStrategy = "data-cy";
|
|
2239
2407
|
/** Stable id of the current live session (null when none has started). */
|
|
@@ -2260,7 +2428,7 @@ var RecordingService = class {
|
|
|
2260
2428
|
this.isPaused$.next(false);
|
|
2261
2429
|
this.isRecording$.next(true);
|
|
2262
2430
|
this.addCommand(`cy.viewport(1900, 1200)`);
|
|
2263
|
-
this.addCommand(`cy.visit('${window.location.pathname}')`);
|
|
2431
|
+
this.addCommand(`cy.visit('${escapeSingleQuotes(window.location.pathname)}')`);
|
|
2264
2432
|
this.addCommand(`cy.get('[data-cy="lib-e2e-cypress-for-dummys"]').invoke('hide');`);
|
|
2265
2433
|
}
|
|
2266
2434
|
/**
|
|
@@ -2343,8 +2511,8 @@ var RecordingService = class {
|
|
|
2343
2511
|
}
|
|
2344
2512
|
registerInterceptor(method, url, alias, fixtureFile) {
|
|
2345
2513
|
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2346
|
-
const wildcard = this.urlToWildcard(url, method);
|
|
2347
|
-
const command = fixtureFile ? `cy.intercept('${method}', '${wildcard}', { fixture: '${fixtureFile}' }).as('${alias}')` : `cy.intercept('${method}', '${wildcard}').as('${alias}')`;
|
|
2514
|
+
const wildcard = escapeSingleQuotes(this.urlToWildcard(url, method));
|
|
2515
|
+
const command = fixtureFile ? `cy.intercept('${method}', '${wildcard}', { fixture: '${escapeSingleQuotes(fixtureFile)}' }).as('${alias}')` : `cy.intercept('${method}', '${wildcard}').as('${alias}')`;
|
|
2348
2516
|
const current = this.interceptors$.getValue();
|
|
2349
2517
|
if (!current.includes(command)) {
|
|
2350
2518
|
this.interceptors$.next([...current, command]);
|
|
@@ -2358,10 +2526,20 @@ var RecordingService = class {
|
|
|
2358
2526
|
getFixturesSnapshot() {
|
|
2359
2527
|
return [...this.fixtures.entries()].map(([name, content]) => ({ name, content }));
|
|
2360
2528
|
}
|
|
2529
|
+
addUploadedFile(filename, bytes) {
|
|
2530
|
+
this.uploadedFiles.set(filename, bytes);
|
|
2531
|
+
}
|
|
2532
|
+
getUploadedFilesSnapshot() {
|
|
2533
|
+
return [...this.uploadedFiles.entries()].map(([filename, bytes]) => ({ filename, bytes }));
|
|
2534
|
+
}
|
|
2535
|
+
clearUploadedFiles() {
|
|
2536
|
+
this.uploadedFiles.clear();
|
|
2537
|
+
}
|
|
2361
2538
|
clearCommands() {
|
|
2362
2539
|
this.commands$.next([]);
|
|
2363
2540
|
this.interceptors$.next([]);
|
|
2364
2541
|
this.fixtures.clear();
|
|
2542
|
+
this.uploadedFiles.clear();
|
|
2365
2543
|
}
|
|
2366
2544
|
clearInterceptors() {
|
|
2367
2545
|
this.interceptors$.next([]);
|
|
@@ -2481,7 +2659,8 @@ var RecordingService = class {
|
|
|
2481
2659
|
if (e.altKey) return;
|
|
2482
2660
|
const selector = this.resolveSelectorFor(e.target);
|
|
2483
2661
|
if (!selector) return;
|
|
2484
|
-
const
|
|
2662
|
+
const safeSelector = escapeSingleQuotes(selector);
|
|
2663
|
+
const clickCmd = `cy.get('${safeSelector}').click()`;
|
|
2485
2664
|
let cmds = this.commands$.getValue();
|
|
2486
2665
|
let removed = 0;
|
|
2487
2666
|
while (removed < 2 && cmds.length > 0 && cmds[cmds.length - 1] === clickCmd) {
|
|
@@ -2489,7 +2668,7 @@ var RecordingService = class {
|
|
|
2489
2668
|
removed++;
|
|
2490
2669
|
}
|
|
2491
2670
|
if (removed > 0) this.commands$.next(cmds);
|
|
2492
|
-
this.addCommand(`cy.get('${
|
|
2671
|
+
this.addCommand(`cy.get('${safeSelector}').dblclick()`);
|
|
2493
2672
|
},
|
|
2494
2673
|
{ signal: this.abort.signal }
|
|
2495
2674
|
);
|
|
@@ -2501,7 +2680,7 @@ var RecordingService = class {
|
|
|
2501
2680
|
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2502
2681
|
const selector = this.resolveSelectorFor(e.target);
|
|
2503
2682
|
if (!selector) return;
|
|
2504
|
-
this.addCommand(`cy.get('${selector}').rightclick()`);
|
|
2683
|
+
this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').rightclick()`);
|
|
2505
2684
|
},
|
|
2506
2685
|
{ signal: this.abort.signal }
|
|
2507
2686
|
);
|
|
@@ -2521,7 +2700,7 @@ var RecordingService = class {
|
|
|
2521
2700
|
if (!selector) return;
|
|
2522
2701
|
this.flushInputDebounce(target);
|
|
2523
2702
|
const token = key === "Enter" ? "{enter}" : "{esc}";
|
|
2524
|
-
this.addCommand(`cy.get('${selector}').type('${token}')`);
|
|
2703
|
+
this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').type('${token}')`);
|
|
2525
2704
|
},
|
|
2526
2705
|
{ signal: this.abort.signal }
|
|
2527
2706
|
);
|
|
@@ -2545,19 +2724,52 @@ var RecordingService = class {
|
|
|
2545
2724
|
if (!this.isRecording$.getValue()) return;
|
|
2546
2725
|
const target = e.target;
|
|
2547
2726
|
if (!target || this.isOwnElement(target)) return;
|
|
2548
|
-
|
|
2727
|
+
const tag = target.tagName.toLowerCase();
|
|
2728
|
+
if (tag === "select") {
|
|
2549
2729
|
this.handleSelectEvent(target);
|
|
2730
|
+
} else if (tag === "input") {
|
|
2731
|
+
const type = (target.getAttribute("type") ?? "").toLowerCase();
|
|
2732
|
+
if (type === "file") {
|
|
2733
|
+
void this.handleFileInputChange(target);
|
|
2734
|
+
}
|
|
2550
2735
|
}
|
|
2551
2736
|
},
|
|
2552
2737
|
{ signal: this.abort.signal }
|
|
2553
2738
|
);
|
|
2554
2739
|
}
|
|
2740
|
+
async handleFileInputChange(target) {
|
|
2741
|
+
if (this.isPaused$.getValue()) return;
|
|
2742
|
+
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2743
|
+
if (!container) return;
|
|
2744
|
+
const selector = this.getReliableSelector(container);
|
|
2745
|
+
if (!selector || this.isOwnSelector(selector)) return;
|
|
2746
|
+
const files = Array.from(target.files ?? []);
|
|
2747
|
+
if (!files.length) return;
|
|
2748
|
+
const paths = files.map((f) => `'cypress/fixtures/${escapeSingleQuotes(f.name)}'`);
|
|
2749
|
+
const pathArg = paths.length === 1 ? paths[0] : `[${paths.join(", ")}]`;
|
|
2750
|
+
this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').selectFile(${pathArg})`);
|
|
2751
|
+
for (const file of files) {
|
|
2752
|
+
const bytes = await this.readFileAsArrayBuffer(file);
|
|
2753
|
+
this.addUploadedFile(file.name, bytes);
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
readFileAsArrayBuffer(file) {
|
|
2757
|
+
if (typeof file.arrayBuffer === "function") {
|
|
2758
|
+
return file.arrayBuffer();
|
|
2759
|
+
}
|
|
2760
|
+
return new Promise((resolve, reject) => {
|
|
2761
|
+
const reader = new FileReader();
|
|
2762
|
+
reader.onload = () => resolve(reader.result);
|
|
2763
|
+
reader.onerror = () => reject(reader.error);
|
|
2764
|
+
reader.readAsArrayBuffer(file);
|
|
2765
|
+
});
|
|
2766
|
+
}
|
|
2555
2767
|
listenToRouteChanges() {
|
|
2556
2768
|
let lastUrl = window.location.pathname + window.location.search + window.location.hash;
|
|
2557
2769
|
const addUrlCommand = (newUrl) => {
|
|
2558
2770
|
if (!this.isRecording$.getValue()) return;
|
|
2559
2771
|
if (newUrl === lastUrl) return;
|
|
2560
|
-
this.addCommand(`cy.url().should('include', '${newUrl}')`);
|
|
2772
|
+
this.addCommand(`cy.url().should('include', '${escapeSingleQuotes(newUrl)}')`);
|
|
2561
2773
|
lastUrl = newUrl;
|
|
2562
2774
|
};
|
|
2563
2775
|
const wrapMethod = (type) => {
|
|
@@ -2658,7 +2870,8 @@ var RecordingService = class {
|
|
|
2658
2870
|
if (matSelect) dataCy = matSelect.closest("[data-cy]")?.getAttribute("data-cy") ?? null;
|
|
2659
2871
|
if (!dataCy) dataCy = target.closest("[data-cy]")?.getAttribute("data-cy") ?? null;
|
|
2660
2872
|
if (dataCy) {
|
|
2661
|
-
|
|
2873
|
+
const safeSel = escapeSingleQuotes(`[data-cy="${escapeCssAttrValue(dataCy)}"]`);
|
|
2874
|
+
this.addCommand(`cy.get('${safeSel}').click()`);
|
|
2662
2875
|
return;
|
|
2663
2876
|
}
|
|
2664
2877
|
if (selector) {
|
|
@@ -2690,7 +2903,7 @@ var RecordingService = class {
|
|
|
2690
2903
|
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2691
2904
|
if (!container) return;
|
|
2692
2905
|
const selector = this.getReliableSelector(container);
|
|
2693
|
-
const value = target.value
|
|
2906
|
+
const value = escapeSingleQuotes(target.value);
|
|
2694
2907
|
this.addGenericCommand({
|
|
2695
2908
|
selector,
|
|
2696
2909
|
action: (s) => `cy.get('${s}').clear().type('${value}')`
|
|
@@ -2709,7 +2922,7 @@ var RecordingService = class {
|
|
|
2709
2922
|
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2710
2923
|
if (!container) return;
|
|
2711
2924
|
const selector = this.getReliableSelector(container);
|
|
2712
|
-
const value = target.value
|
|
2925
|
+
const value = escapeSingleQuotes(target.value);
|
|
2713
2926
|
this.addGenericCommand({
|
|
2714
2927
|
selector,
|
|
2715
2928
|
action: (s) => `cy.get('${s}').select('${value}')`
|
|
@@ -2718,7 +2931,7 @@ var RecordingService = class {
|
|
|
2718
2931
|
// ── Shared helpers ────────────────────────────────────────────────────────
|
|
2719
2932
|
addGenericCommand(opts) {
|
|
2720
2933
|
if (!opts.selector || this.isOwnSelector(opts.selector)) return;
|
|
2721
|
-
this.addCommand(opts.action(opts.selector));
|
|
2934
|
+
this.addCommand(opts.action(escapeSingleQuotes(opts.selector)));
|
|
2722
2935
|
}
|
|
2723
2936
|
getReliableSelector(el) {
|
|
2724
2937
|
const strategy = this.selectorStrategy;
|
|
@@ -2730,20 +2943,20 @@ var RecordingService = class {
|
|
|
2730
2943
|
const validId = rawId && rawId.length < 25 && /^[a-zA-Z][\w-]*$/.test(rawId) && !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) && !/^\d+$/.test(rawId) ? rawId : null;
|
|
2731
2944
|
switch (strategy) {
|
|
2732
2945
|
case "data-testid":
|
|
2733
|
-
if (dataTestid) return `[data-testid="${dataTestid}"]`;
|
|
2734
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2946
|
+
if (dataTestid) return `[data-testid="${escapeCssAttrValue(dataTestid)}"]`;
|
|
2947
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2735
2948
|
return validId ? `#${validId}` : null;
|
|
2736
2949
|
case "aria-label":
|
|
2737
|
-
if (ariaLabel) return `[aria-label="${ariaLabel}"]`;
|
|
2738
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2950
|
+
if (ariaLabel) return `[aria-label="${escapeCssAttrValue(ariaLabel)}"]`;
|
|
2951
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2739
2952
|
return validId ? `#${validId}` : null;
|
|
2740
2953
|
case "id":
|
|
2741
2954
|
if (validId) return `#${validId}`;
|
|
2742
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2743
|
-
return dataTestid ? `[data-testid="${dataTestid}"]` : null;
|
|
2955
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2956
|
+
return dataTestid ? `[data-testid="${escapeCssAttrValue(dataTestid)}"]` : null;
|
|
2744
2957
|
default:
|
|
2745
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2746
|
-
if (dataDotCy) return `[data.cy="${dataDotCy}"]`;
|
|
2958
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2959
|
+
if (dataDotCy) return `[data.cy="${escapeCssAttrValue(dataDotCy)}"]`;
|
|
2747
2960
|
return validId ? `#${validId}` : null;
|
|
2748
2961
|
}
|
|
2749
2962
|
}
|
|
@@ -2769,8 +2982,41 @@ var RecordingService = class {
|
|
|
2769
2982
|
|
|
2770
2983
|
// src/services/persistence.service.ts
|
|
2771
2984
|
var import_idb = require("idb");
|
|
2985
|
+
init_code_format_utils();
|
|
2986
|
+
|
|
2987
|
+
// src/models/issue-tracker.model.ts
|
|
2988
|
+
var ISSUE_TRACKER_PRESETS = {
|
|
2989
|
+
jira: { id: "jira", label: "Jira", urlPattern: "{baseUrl}/browse/{id}", idPattern: /^[A-Z][A-Z0-9]+-\d+$/ },
|
|
2990
|
+
github: { id: "github", label: "GitHub Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
2991
|
+
gitlab: { id: "gitlab", label: "GitLab Issues", urlPattern: "{baseUrl}/-/issues/{id}", idPattern: /^\d+$/ },
|
|
2992
|
+
azure: { id: "azure", label: "Azure DevOps", urlPattern: "{baseUrl}/_workitems/edit/{id}", idPattern: /^\d+$/ },
|
|
2993
|
+
bitbucket: { id: "bitbucket", label: "Bitbucket Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
2994
|
+
custom: { id: "custom", label: "Custom", urlPattern: "{baseUrl}/{id}", idPattern: /.+/ }
|
|
2995
|
+
};
|
|
2996
|
+
var DEFAULT_ISSUE_TRACKER_CONFIG = {
|
|
2997
|
+
enabled: false,
|
|
2998
|
+
provider: "jira",
|
|
2999
|
+
baseUrl: ""
|
|
3000
|
+
};
|
|
3001
|
+
|
|
3002
|
+
// src/utils/ticket.utils.ts
|
|
3003
|
+
function buildTicketUrl(ticketId, config) {
|
|
3004
|
+
if (!config.enabled || !ticketId.trim() || !config.baseUrl.trim()) return null;
|
|
3005
|
+
const preset = ISSUE_TRACKER_PRESETS[config.provider];
|
|
3006
|
+
const base = config.baseUrl.replace(/\/+$/, "");
|
|
3007
|
+
return preset.urlPattern.replace("{baseUrl}", base).replace("{id}", encodeURIComponent(ticketId.trim()));
|
|
3008
|
+
}
|
|
3009
|
+
function buildTicketComment(ticketId) {
|
|
3010
|
+
return `// Ticket: ${ticketId.trim()}`;
|
|
3011
|
+
}
|
|
3012
|
+
function isValidTicketId(ticketId, provider) {
|
|
3013
|
+
if (!ticketId.trim()) return false;
|
|
3014
|
+
return ISSUE_TRACKER_PRESETS[provider].idPattern.test(ticketId.trim());
|
|
3015
|
+
}
|
|
3016
|
+
|
|
3017
|
+
// src/services/persistence.service.ts
|
|
2772
3018
|
var ACTIVE_SESSION_ID = 1;
|
|
2773
|
-
var PersistenceService = class {
|
|
3019
|
+
var PersistenceService = class _PersistenceService {
|
|
2774
3020
|
// dbName is overridable so tests can use unique names for isolation.
|
|
2775
3021
|
constructor(dbName = DB_SCHEMA.name) {
|
|
2776
3022
|
this.dbName = dbName;
|
|
@@ -2823,7 +3069,8 @@ var PersistenceService = class {
|
|
|
2823
3069
|
if (!record) return null;
|
|
2824
3070
|
const commands = await this.getCommandStrings(testId);
|
|
2825
3071
|
const interceptors = await this.getInterceptorStrings(testId);
|
|
2826
|
-
const
|
|
3072
|
+
const ticketComment = record.ticketId ? buildTicketComment(record.ticketId) + "\n" : "";
|
|
3073
|
+
const itBlock = `${ticketComment}it('${escapeSingleQuotes(record.name)}', () => {
|
|
2827
3074
|
${commands.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
2828
3075
|
});`;
|
|
2829
3076
|
const interceptorsBlock = interceptors.length ? " // Auto-generated Cypress interceptors\n" + interceptors.map((i) => normalizeBlock(i, " ")).join("\n") + "\n" : "";
|
|
@@ -2904,6 +3151,30 @@ ${commands.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
|
2904
3151
|
const records = await db.getAll("configuration");
|
|
2905
3152
|
return records[0] ?? null;
|
|
2906
3153
|
}
|
|
3154
|
+
// ── Login setup config ───────────────────────────────────────────────────
|
|
3155
|
+
static LOGIN_SETUP_KEY = "loginSetupConfig";
|
|
3156
|
+
async saveLoginSetup(config) {
|
|
3157
|
+
await this.setConfigKey(_PersistenceService.LOGIN_SETUP_KEY, JSON.stringify(config));
|
|
3158
|
+
}
|
|
3159
|
+
async getLoginSetup() {
|
|
3160
|
+
const record = await this.getConfig(_PersistenceService.LOGIN_SETUP_KEY);
|
|
3161
|
+
if (!record) return null;
|
|
3162
|
+
const raw = record[_PersistenceService.LOGIN_SETUP_KEY];
|
|
3163
|
+
if (typeof raw !== "string") return null;
|
|
3164
|
+
try {
|
|
3165
|
+
return JSON.parse(raw);
|
|
3166
|
+
} catch {
|
|
3167
|
+
return null;
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
async clearLoginSetup() {
|
|
3171
|
+
const db = await this.getDB();
|
|
3172
|
+
const records = await db.getAll("configuration");
|
|
3173
|
+
if (!records.length) return;
|
|
3174
|
+
const current = { ...records[0] };
|
|
3175
|
+
delete current[_PersistenceService.LOGIN_SETUP_KEY];
|
|
3176
|
+
await db.put("configuration", current);
|
|
3177
|
+
}
|
|
2907
3178
|
// ── Active recording session ──────────────────────────────────────────────
|
|
2908
3179
|
/** Upserts the live recording session (single record, fixed key). */
|
|
2909
3180
|
async saveActiveSession(state) {
|
|
@@ -2946,6 +3217,24 @@ ${commands.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
|
2946
3217
|
}
|
|
2947
3218
|
await this.bulkInsertWithoutId("interceptors", interceptors);
|
|
2948
3219
|
}
|
|
3220
|
+
async hasDirectoryAccess() {
|
|
3221
|
+
const config = await this.getGeneralConfig();
|
|
3222
|
+
return !!config?.["cypressDirectoryHandle"];
|
|
3223
|
+
}
|
|
3224
|
+
async writeUploadedFile(filename, bytes) {
|
|
3225
|
+
const config = await this.getGeneralConfig();
|
|
3226
|
+
const dirHandle = config?.["cypressDirectoryHandle"];
|
|
3227
|
+
if (!dirHandle) throw new Error("No Cypress folder configured");
|
|
3228
|
+
const perm = dirHandle;
|
|
3229
|
+
let state = await perm.queryPermission({ mode: "readwrite" });
|
|
3230
|
+
if (state !== "granted") state = await perm.requestPermission({ mode: "readwrite" });
|
|
3231
|
+
if (state !== "granted") throw new Error("Write permission denied");
|
|
3232
|
+
const fixturesDir = await dirHandle.getDirectoryHandle("fixtures", { create: true });
|
|
3233
|
+
const fileHandle = await fixturesDir.getFileHandle(filename, { create: true });
|
|
3234
|
+
const writable = await fileHandle.createWritable();
|
|
3235
|
+
await writable.write(bytes);
|
|
3236
|
+
await writable.close();
|
|
3237
|
+
}
|
|
2949
3238
|
async requestDirectoryPermissions() {
|
|
2950
3239
|
if (!("showDirectoryPicker" in window)) {
|
|
2951
3240
|
throw new Error("File System Access API not supported");
|
|
@@ -2988,7 +3277,57 @@ ${commands.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
|
2988
3277
|
}
|
|
2989
3278
|
}
|
|
2990
3279
|
};
|
|
2991
|
-
|
|
3280
|
+
|
|
3281
|
+
// src/services/http-monitor.ts
|
|
3282
|
+
init_code_format_utils();
|
|
3283
|
+
|
|
3284
|
+
// src/utils/redact.utils.ts
|
|
3285
|
+
var SENSITIVE_SUBSTRINGS = [
|
|
3286
|
+
"password",
|
|
3287
|
+
"passwd",
|
|
3288
|
+
"passphrase",
|
|
3289
|
+
"secret",
|
|
3290
|
+
"token",
|
|
3291
|
+
// access_token, refresh_token, id_token, csrf_token…
|
|
3292
|
+
"apikey",
|
|
3293
|
+
// api_key, x-api-key — NOT bare "key" (avoids "normalKey")
|
|
3294
|
+
"authorization",
|
|
3295
|
+
"cookie",
|
|
3296
|
+
"credential",
|
|
3297
|
+
"privatekey",
|
|
3298
|
+
"sessionid",
|
|
3299
|
+
"creditcard",
|
|
3300
|
+
"cardnumber",
|
|
3301
|
+
"cvv"
|
|
3302
|
+
];
|
|
3303
|
+
var SENSITIVE_EXACT = /* @__PURE__ */ new Set([
|
|
3304
|
+
"auth",
|
|
3305
|
+
"pwd",
|
|
3306
|
+
"pin",
|
|
3307
|
+
"otp",
|
|
3308
|
+
"ssn"
|
|
3309
|
+
]);
|
|
3310
|
+
function normalizeKey(key) {
|
|
3311
|
+
return key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
3312
|
+
}
|
|
3313
|
+
function isSensitiveKey(key) {
|
|
3314
|
+
const normalized = normalizeKey(key);
|
|
3315
|
+
if (SENSITIVE_EXACT.has(normalized)) return true;
|
|
3316
|
+
return SENSITIVE_SUBSTRINGS.some((s) => normalized.includes(s));
|
|
3317
|
+
}
|
|
3318
|
+
function redactSensitiveFields(obj) {
|
|
3319
|
+
if (Array.isArray(obj)) {
|
|
3320
|
+
return obj.map(redactSensitiveFields);
|
|
3321
|
+
}
|
|
3322
|
+
if (obj !== null && typeof obj === "object") {
|
|
3323
|
+
const result = {};
|
|
3324
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
3325
|
+
result[key] = isSensitiveKey(key) ? "[REDACTED]" : redactSensitiveFields(value);
|
|
3326
|
+
}
|
|
3327
|
+
return result;
|
|
3328
|
+
}
|
|
3329
|
+
return obj;
|
|
3330
|
+
}
|
|
2992
3331
|
|
|
2993
3332
|
// src/services/http-monitor.ts
|
|
2994
3333
|
var INTERCEPTED_METHODS = ["GET", "POST", "PUT"];
|
|
@@ -3001,8 +3340,12 @@ function generateAlias(method, url) {
|
|
|
3001
3340
|
return `${method.toLowerCase()}-intercepted-request`;
|
|
3002
3341
|
}
|
|
3003
3342
|
}
|
|
3343
|
+
var SAFE_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
3004
3344
|
function buildValidations(base, obj) {
|
|
3005
|
-
return Object.keys(obj).filter((key) => key !== "id" && key !== "uid").map((key) =>
|
|
3345
|
+
return Object.keys(obj).filter((key) => key !== "id" && key !== "uid").map((key) => {
|
|
3346
|
+
const accessor = SAFE_IDENTIFIER.test(key) ? `.${key}` : `['${escapeSingleQuotes(key)}']`;
|
|
3347
|
+
return `expect(${base}${accessor}).to.equal(${JSON.stringify(obj[key])});`;
|
|
3348
|
+
}).join("\n");
|
|
3006
3349
|
}
|
|
3007
3350
|
function buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody) {
|
|
3008
3351
|
if (extendedHttp && method === "GET" && responseBody) {
|
|
@@ -3054,20 +3397,143 @@ function resolveMethod(input, init) {
|
|
|
3054
3397
|
if (input instanceof Request) return input.method.toUpperCase();
|
|
3055
3398
|
return "GET";
|
|
3056
3399
|
}
|
|
3400
|
+
async function _handleFetchInterception(recording, input, init, responseClone) {
|
|
3401
|
+
const method = resolveMethod(input, init);
|
|
3402
|
+
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3403
|
+
const url = resolveUrl(input);
|
|
3404
|
+
const alias = generateAlias(method, url);
|
|
3405
|
+
recording.registerInterceptor(method, url, alias);
|
|
3406
|
+
const extendedHttp = localStorage.getItem("extendedHttpCommands") === "true";
|
|
3407
|
+
const fixtureMode = localStorage.getItem("fixtureMode") === "true";
|
|
3408
|
+
const requestBody = extendedHttp ? parseRequestBody(init) : null;
|
|
3409
|
+
let responseText = null;
|
|
3410
|
+
let responseBody = null;
|
|
3411
|
+
if (extendedHttp || fixtureMode && method === "GET") {
|
|
3412
|
+
try {
|
|
3413
|
+
responseText = await responseClone.text();
|
|
3414
|
+
if (extendedHttp) responseBody = parseJsonObject(responseText);
|
|
3415
|
+
} catch {
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
if (fixtureMode && method === "GET" && responseText !== null) {
|
|
3419
|
+
const pretty = prettyJsonOrNull(responseText);
|
|
3420
|
+
if (pretty !== null) {
|
|
3421
|
+
const redacted = redactSensitiveFields(JSON.parse(pretty));
|
|
3422
|
+
recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
const cmd = buildCyWaitCommand(
|
|
3426
|
+
method,
|
|
3427
|
+
alias,
|
|
3428
|
+
extendedHttp,
|
|
3429
|
+
requestBody ? redactSensitiveFields(requestBody) : null,
|
|
3430
|
+
responseBody ? redactSensitiveFields(responseBody) : null
|
|
3431
|
+
);
|
|
3432
|
+
recording.addCommand(cmd);
|
|
3433
|
+
}
|
|
3434
|
+
function _handleXhrInterception(recording, method, url, requestBody, responseText) {
|
|
3435
|
+
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3436
|
+
const alias = generateAlias(method, url);
|
|
3437
|
+
recording.registerInterceptor(method, url, alias);
|
|
3438
|
+
if (localStorage.getItem("fixtureMode") === "true" && method === "GET") {
|
|
3439
|
+
const pretty = prettyJsonOrNull(responseText);
|
|
3440
|
+
if (pretty !== null) {
|
|
3441
|
+
const redacted = redactSensitiveFields(JSON.parse(pretty));
|
|
3442
|
+
recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
const extendedHttp = localStorage.getItem("extendedHttpCommands") === "true";
|
|
3446
|
+
const responseBody = extendedHttp ? parseJsonObject(responseText) : null;
|
|
3447
|
+
const cmd = buildCyWaitCommand(
|
|
3448
|
+
method,
|
|
3449
|
+
alias,
|
|
3450
|
+
extendedHttp,
|
|
3451
|
+
requestBody ? redactSensitiveFields(requestBody) : null,
|
|
3452
|
+
responseBody ? redactSensitiveFields(responseBody) : null
|
|
3453
|
+
);
|
|
3454
|
+
recording.addCommand(cmd);
|
|
3455
|
+
}
|
|
3456
|
+
var _refCount = 0;
|
|
3457
|
+
var _originalFetch = null;
|
|
3458
|
+
var _originalXHR = null;
|
|
3459
|
+
var _recordings = /* @__PURE__ */ new Set();
|
|
3460
|
+
function _patchFetch() {
|
|
3461
|
+
const orig = window.fetch;
|
|
3462
|
+
_originalFetch = orig;
|
|
3463
|
+
window.fetch = async (input, init) => {
|
|
3464
|
+
const response = await orig(input, init);
|
|
3465
|
+
try {
|
|
3466
|
+
const active = [..._recordings];
|
|
3467
|
+
if (active.length > 0) {
|
|
3468
|
+
await Promise.all(
|
|
3469
|
+
active.map((rec) => _handleFetchInterception(rec, input, init, response.clone()).catch(() => {
|
|
3470
|
+
}))
|
|
3471
|
+
);
|
|
3472
|
+
}
|
|
3473
|
+
} catch {
|
|
3474
|
+
}
|
|
3475
|
+
return response;
|
|
3476
|
+
};
|
|
3477
|
+
}
|
|
3478
|
+
function _restoreFetch() {
|
|
3479
|
+
if (!_originalFetch) return;
|
|
3480
|
+
window.fetch = _originalFetch;
|
|
3481
|
+
_originalFetch = null;
|
|
3482
|
+
}
|
|
3483
|
+
function _patchXhr() {
|
|
3484
|
+
const OrigXHR = window.XMLHttpRequest;
|
|
3485
|
+
_originalXHR = OrigXHR;
|
|
3486
|
+
window.XMLHttpRequest = class extends OrigXHR {
|
|
3487
|
+
_xhrMethod = "GET";
|
|
3488
|
+
_xhrUrl = "";
|
|
3489
|
+
_xhrRequestBody = null;
|
|
3490
|
+
open(method, url, async = true, user, password) {
|
|
3491
|
+
this._xhrMethod = method.toUpperCase();
|
|
3492
|
+
this._xhrUrl = url instanceof URL ? url.href : url;
|
|
3493
|
+
super.open(method, url, async, user, password);
|
|
3494
|
+
}
|
|
3495
|
+
send(body) {
|
|
3496
|
+
if (typeof body === "string") {
|
|
3497
|
+
this._xhrRequestBody = parseJsonObject(body);
|
|
3498
|
+
}
|
|
3499
|
+
this.addEventListener("load", () => {
|
|
3500
|
+
try {
|
|
3501
|
+
for (const rec of _recordings) {
|
|
3502
|
+
_handleXhrInterception(rec, this._xhrMethod, this._xhrUrl, this._xhrRequestBody, this.responseText);
|
|
3503
|
+
}
|
|
3504
|
+
} catch {
|
|
3505
|
+
}
|
|
3506
|
+
});
|
|
3507
|
+
super.send(body);
|
|
3508
|
+
}
|
|
3509
|
+
};
|
|
3510
|
+
}
|
|
3511
|
+
function _restoreXhr() {
|
|
3512
|
+
if (!_originalXHR) return;
|
|
3513
|
+
window.XMLHttpRequest = _originalXHR;
|
|
3514
|
+
_originalXHR = null;
|
|
3515
|
+
}
|
|
3057
3516
|
var HttpMonitor = class {
|
|
3058
3517
|
constructor(recording) {
|
|
3059
3518
|
this.recording = recording;
|
|
3060
3519
|
}
|
|
3061
3520
|
recording;
|
|
3062
|
-
originalFetch = null;
|
|
3063
|
-
originalXHR = null;
|
|
3064
3521
|
install() {
|
|
3065
|
-
this.
|
|
3066
|
-
|
|
3522
|
+
_recordings.add(this.recording);
|
|
3523
|
+
_refCount++;
|
|
3524
|
+
if (_refCount === 1) {
|
|
3525
|
+
_patchFetch();
|
|
3526
|
+
_patchXhr();
|
|
3527
|
+
}
|
|
3067
3528
|
}
|
|
3068
3529
|
uninstall() {
|
|
3069
|
-
this.
|
|
3070
|
-
|
|
3530
|
+
_recordings.delete(this.recording);
|
|
3531
|
+
if (_refCount <= 0) return;
|
|
3532
|
+
_refCount--;
|
|
3533
|
+
if (_refCount === 0) {
|
|
3534
|
+
_restoreFetch();
|
|
3535
|
+
_restoreXhr();
|
|
3536
|
+
}
|
|
3071
3537
|
}
|
|
3072
3538
|
isExtendedHttpEnabled() {
|
|
3073
3539
|
return localStorage.getItem("extendedHttpCommands") === "true";
|
|
@@ -3075,100 +3541,6 @@ var HttpMonitor = class {
|
|
|
3075
3541
|
isFixtureModeEnabled() {
|
|
3076
3542
|
return localStorage.getItem("fixtureMode") === "true";
|
|
3077
3543
|
}
|
|
3078
|
-
installFetch() {
|
|
3079
|
-
if (this.originalFetch) return;
|
|
3080
|
-
const originalFetch = window.fetch;
|
|
3081
|
-
this.originalFetch = originalFetch;
|
|
3082
|
-
window.fetch = async (input, init) => {
|
|
3083
|
-
const response = await originalFetch(input, init);
|
|
3084
|
-
try {
|
|
3085
|
-
await this.handleFetchInterception(input, init, response.clone());
|
|
3086
|
-
} catch {
|
|
3087
|
-
}
|
|
3088
|
-
return response;
|
|
3089
|
-
};
|
|
3090
|
-
}
|
|
3091
|
-
uninstallFetch() {
|
|
3092
|
-
if (!this.originalFetch) return;
|
|
3093
|
-
window.fetch = this.originalFetch;
|
|
3094
|
-
this.originalFetch = null;
|
|
3095
|
-
}
|
|
3096
|
-
installXhr() {
|
|
3097
|
-
if (this.originalXHR) return;
|
|
3098
|
-
this.originalXHR = window.XMLHttpRequest;
|
|
3099
|
-
const OrigXHR = this.originalXHR;
|
|
3100
|
-
const handleXhrInterception = this.handleXhrInterception.bind(this);
|
|
3101
|
-
window.XMLHttpRequest = class extends OrigXHR {
|
|
3102
|
-
_xhrMethod = "GET";
|
|
3103
|
-
_xhrUrl = "";
|
|
3104
|
-
_xhrRequestBody = null;
|
|
3105
|
-
open(method, url, async = true, user, password) {
|
|
3106
|
-
this._xhrMethod = method.toUpperCase();
|
|
3107
|
-
this._xhrUrl = url instanceof URL ? url.href : url;
|
|
3108
|
-
super.open(method, url, async, user, password);
|
|
3109
|
-
}
|
|
3110
|
-
send(body) {
|
|
3111
|
-
if (typeof body === "string") {
|
|
3112
|
-
this._xhrRequestBody = parseJsonObject(body);
|
|
3113
|
-
}
|
|
3114
|
-
this.addEventListener("load", () => {
|
|
3115
|
-
try {
|
|
3116
|
-
handleXhrInterception(
|
|
3117
|
-
this._xhrMethod,
|
|
3118
|
-
this._xhrUrl,
|
|
3119
|
-
this._xhrRequestBody,
|
|
3120
|
-
this.responseText
|
|
3121
|
-
);
|
|
3122
|
-
} catch {
|
|
3123
|
-
}
|
|
3124
|
-
});
|
|
3125
|
-
super.send(body);
|
|
3126
|
-
}
|
|
3127
|
-
};
|
|
3128
|
-
}
|
|
3129
|
-
uninstallXhr() {
|
|
3130
|
-
if (!this.originalXHR) return;
|
|
3131
|
-
window.XMLHttpRequest = this.originalXHR;
|
|
3132
|
-
this.originalXHR = null;
|
|
3133
|
-
}
|
|
3134
|
-
async handleFetchInterception(input, init, responseClone) {
|
|
3135
|
-
const method = resolveMethod(input, init);
|
|
3136
|
-
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3137
|
-
const url = resolveUrl(input);
|
|
3138
|
-
const alias = generateAlias(method, url);
|
|
3139
|
-
this.recording.registerInterceptor(method, url, alias);
|
|
3140
|
-
const extendedHttp = this.isExtendedHttpEnabled();
|
|
3141
|
-
const fixtureMode = this.isFixtureModeEnabled();
|
|
3142
|
-
const requestBody = extendedHttp ? parseRequestBody(init) : null;
|
|
3143
|
-
let responseText = null;
|
|
3144
|
-
let responseBody = null;
|
|
3145
|
-
if (extendedHttp || fixtureMode && method === "GET") {
|
|
3146
|
-
try {
|
|
3147
|
-
responseText = await responseClone.text();
|
|
3148
|
-
if (extendedHttp) responseBody = parseJsonObject(responseText);
|
|
3149
|
-
} catch {
|
|
3150
|
-
}
|
|
3151
|
-
}
|
|
3152
|
-
if (fixtureMode && method === "GET" && responseText !== null) {
|
|
3153
|
-
const pretty = prettyJsonOrNull(responseText);
|
|
3154
|
-
if (pretty !== null) this.recording.registerFixture(`${alias}.json`, pretty);
|
|
3155
|
-
}
|
|
3156
|
-
const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);
|
|
3157
|
-
this.recording.addCommand(cmd);
|
|
3158
|
-
}
|
|
3159
|
-
handleXhrInterception(method, url, requestBody, responseText) {
|
|
3160
|
-
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3161
|
-
const alias = generateAlias(method, url);
|
|
3162
|
-
this.recording.registerInterceptor(method, url, alias);
|
|
3163
|
-
if (this.isFixtureModeEnabled() && method === "GET") {
|
|
3164
|
-
const pretty = prettyJsonOrNull(responseText);
|
|
3165
|
-
if (pretty !== null) this.recording.registerFixture(`${alias}.json`, pretty);
|
|
3166
|
-
}
|
|
3167
|
-
const extendedHttp = this.isExtendedHttpEnabled();
|
|
3168
|
-
const responseBody = extendedHttp ? parseJsonObject(responseText) : null;
|
|
3169
|
-
const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);
|
|
3170
|
-
this.recording.addCommand(cmd);
|
|
3171
|
-
}
|
|
3172
3544
|
};
|
|
3173
3545
|
|
|
3174
3546
|
// src/utils/styles.utils.ts
|
|
@@ -3400,23 +3772,24 @@ function makeSwalDraggable() {
|
|
|
3400
3772
|
if (!dragArea) return;
|
|
3401
3773
|
applyDraggable(swal, dragArea);
|
|
3402
3774
|
}
|
|
3403
|
-
function makeSwalDraggableByContentId(contentId) {
|
|
3404
|
-
const content = document.getElementById(contentId);
|
|
3405
|
-
if (!content) {
|
|
3406
|
-
makeSwalDraggable();
|
|
3407
|
-
return;
|
|
3408
|
-
}
|
|
3409
|
-
const swal = content.closest(".swal2-popup") ?? document.querySelector(".swal2-popup");
|
|
3410
|
-
if (!swal) return;
|
|
3411
|
-
const dragArea = resolveDragArea(swal);
|
|
3412
|
-
if (!dragArea) return;
|
|
3413
|
-
applyDraggable(swal, dragArea);
|
|
3414
|
-
}
|
|
3415
3775
|
function setSwal2DataCyAttribute(dataCy = "lib-e2e-cypress-for-dummys") {
|
|
3416
3776
|
document.querySelector(".swal2-container")?.setAttribute("data-cy", dataCy);
|
|
3417
3777
|
document.querySelector(".swal2-html-container")?.setAttribute("data-cy", dataCy);
|
|
3418
3778
|
document.querySelector(".swal2-title")?.setAttribute("data-cy", dataCy);
|
|
3419
3779
|
}
|
|
3780
|
+
function ensurePopupDimensions(popup, heightPx) {
|
|
3781
|
+
if (!popup) return;
|
|
3782
|
+
popup.style.height = `${heightPx}px`;
|
|
3783
|
+
const htmlContainer = popup.querySelector(".swal2-html-container");
|
|
3784
|
+
if (!htmlContainer) return;
|
|
3785
|
+
htmlContainer.style.flex = "1";
|
|
3786
|
+
htmlContainer.style.minHeight = "0";
|
|
3787
|
+
htmlContainer.style.overflow = "hidden";
|
|
3788
|
+
htmlContainer.style.padding = "0";
|
|
3789
|
+
htmlContainer.style.margin = "0";
|
|
3790
|
+
htmlContainer.style.display = "flex";
|
|
3791
|
+
htmlContainer.style.flexDirection = "column";
|
|
3792
|
+
}
|
|
3420
3793
|
|
|
3421
3794
|
// src/utils/toast.utils.ts
|
|
3422
3795
|
function showToast(message, isSuccess = true) {
|
|
@@ -3457,37 +3830,6 @@ function isLocalHost(hostname) {
|
|
|
3457
3830
|
return h === "localhost" || h.endsWith(".localhost") || h === "127.0.0.1" || h === "::1" || h === "0.0.0.0";
|
|
3458
3831
|
}
|
|
3459
3832
|
|
|
3460
|
-
// src/utils/widget-position.utils.ts
|
|
3461
|
-
var TOGGLE_MARGIN = 30;
|
|
3462
|
-
var DRAG_THRESHOLD = 5;
|
|
3463
|
-
var DEFAULT_EDGE_OFFSET = 46;
|
|
3464
|
-
function boxOffsetForDirection(dir) {
|
|
3465
|
-
return {
|
|
3466
|
-
x: dir.endsWith("left") ? 144 : 46,
|
|
3467
|
-
y: dir.startsWith("up") ? 144 : 46
|
|
3468
|
-
};
|
|
3469
|
-
}
|
|
3470
|
-
function clampTogglePosition(x, y, vw, vh, margin = TOGGLE_MARGIN) {
|
|
3471
|
-
const maxX = Math.max(margin, vw - margin);
|
|
3472
|
-
const maxY = Math.max(margin, vh - margin);
|
|
3473
|
-
return {
|
|
3474
|
-
x: Math.min(Math.max(x, margin), maxX),
|
|
3475
|
-
y: Math.min(Math.max(y, margin), maxY)
|
|
3476
|
-
};
|
|
3477
|
-
}
|
|
3478
|
-
function resolveExpandDirection(x, y, vw, vh) {
|
|
3479
|
-
const vertical = y < vh / 2 ? "down" : "up";
|
|
3480
|
-
const horizontal = x < vw / 2 ? "right" : "left";
|
|
3481
|
-
return `${vertical}-${horizontal}`;
|
|
3482
|
-
}
|
|
3483
|
-
function defaultTogglePosition(vw, vh) {
|
|
3484
|
-
return { x: vw - DEFAULT_EDGE_OFFSET, y: vh - DEFAULT_EDGE_OFFSET };
|
|
3485
|
-
}
|
|
3486
|
-
function boxTopLeftFor(toggleCentre, dir) {
|
|
3487
|
-
const off = boxOffsetForDirection(dir);
|
|
3488
|
-
return { x: toggleCentre.x - off.x, y: toggleCentre.y - off.y };
|
|
3489
|
-
}
|
|
3490
|
-
|
|
3491
3833
|
// src/index.ts
|
|
3492
3834
|
init_selector_picker();
|
|
3493
3835
|
|
|
@@ -3689,35 +4031,8 @@ var TestPrevisualizerElement = class extends HTMLElement {
|
|
|
3689
4031
|
}
|
|
3690
4032
|
}
|
|
3691
4033
|
};
|
|
3692
|
-
if (!customElements.get("test-previsualizer")) {
|
|
3693
|
-
customElements.define("test-previsualizer", TestPrevisualizerElement);
|
|
3694
|
-
}
|
|
3695
|
-
|
|
3696
|
-
// src/models/issue-tracker.model.ts
|
|
3697
|
-
var ISSUE_TRACKER_PRESETS = {
|
|
3698
|
-
jira: { id: "jira", label: "Jira", urlPattern: "{baseUrl}/browse/{id}", idPattern: /^[A-Z][A-Z0-9]+-\d+$/ },
|
|
3699
|
-
github: { id: "github", label: "GitHub Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
3700
|
-
gitlab: { id: "gitlab", label: "GitLab Issues", urlPattern: "{baseUrl}/-/issues/{id}", idPattern: /^\d+$/ },
|
|
3701
|
-
azure: { id: "azure", label: "Azure DevOps", urlPattern: "{baseUrl}/_workitems/edit/{id}", idPattern: /^\d+$/ },
|
|
3702
|
-
bitbucket: { id: "bitbucket", label: "Bitbucket Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
3703
|
-
custom: { id: "custom", label: "Custom", urlPattern: "{baseUrl}/{id}", idPattern: /.+/ }
|
|
3704
|
-
};
|
|
3705
|
-
var DEFAULT_ISSUE_TRACKER_CONFIG = {
|
|
3706
|
-
enabled: false,
|
|
3707
|
-
provider: "jira",
|
|
3708
|
-
baseUrl: ""
|
|
3709
|
-
};
|
|
3710
|
-
|
|
3711
|
-
// src/utils/ticket.utils.ts
|
|
3712
|
-
function buildTicketUrl(ticketId, config) {
|
|
3713
|
-
if (!config.enabled || !ticketId.trim() || !config.baseUrl.trim()) return null;
|
|
3714
|
-
const preset = ISSUE_TRACKER_PRESETS[config.provider];
|
|
3715
|
-
const base = config.baseUrl.replace(/\/+$/, "");
|
|
3716
|
-
return preset.urlPattern.replace("{baseUrl}", base).replace("{id}", encodeURIComponent(ticketId.trim()));
|
|
3717
|
-
}
|
|
3718
|
-
function isValidTicketId(ticketId, provider) {
|
|
3719
|
-
if (!ticketId.trim()) return false;
|
|
3720
|
-
return ISSUE_TRACKER_PRESETS[provider].idPattern.test(ticketId.trim());
|
|
4034
|
+
if (!customElements.get("lib-e2e-test-previsualizer")) {
|
|
4035
|
+
customElements.define("lib-e2e-test-previsualizer", TestPrevisualizerElement);
|
|
3721
4036
|
}
|
|
3722
4037
|
|
|
3723
4038
|
// src/components/save-test/save-test.styles.ts
|
|
@@ -3781,10 +4096,21 @@ var SAVE_TEST_STYLES = `
|
|
|
3781
4096
|
transition: color 0.12s; padding: 0; background: none; border: none;
|
|
3782
4097
|
}
|
|
3783
4098
|
.chip-del:hover { color: #f85149; filter: none; }
|
|
4099
|
+
.discard-warn { color: #e6edf3; font-size: 13px; margin-bottom: 20px; line-height: 1.5; }
|
|
3784
4100
|
`;
|
|
3785
4101
|
|
|
3786
4102
|
// src/components/save-test/save-test.template.ts
|
|
3787
4103
|
init_html_utils();
|
|
4104
|
+
function renderSaveTestConfirmDiscard(t) {
|
|
4105
|
+
return `
|
|
4106
|
+
<div class="container">
|
|
4107
|
+
<p class="discard-warn">\u26A0 ${t("SAVE_TEST.CONFIRM_DISCARD")}</p>
|
|
4108
|
+
<div class="btn-row">
|
|
4109
|
+
<button class="btn-danger" id="btn-confirm-discard">${t("SAVE_TEST.CONFIRM_DISCARD_BTN")}</button>
|
|
4110
|
+
<button id="btn-back-discard">${t("SAVE_TEST.BACK_BTN")}</button>
|
|
4111
|
+
</div>
|
|
4112
|
+
</div>`;
|
|
4113
|
+
}
|
|
3788
4114
|
function renderSaveTestAsk(t) {
|
|
3789
4115
|
return `
|
|
3790
4116
|
<div class="container">
|
|
@@ -3830,6 +4156,7 @@ function renderSaveTestDesc(description, notes, tags, ticketId, issueTrackerEnab
|
|
|
3830
4156
|
var SaveTestElement = class extends HTMLElement {
|
|
3831
4157
|
shadow;
|
|
3832
4158
|
_step = "ask";
|
|
4159
|
+
_stepBeforeDiscard = "ask";
|
|
3833
4160
|
description = "";
|
|
3834
4161
|
notes = "";
|
|
3835
4162
|
tags = [];
|
|
@@ -3857,8 +4184,17 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
3857
4184
|
this.dispatch("saveandexport", { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() });
|
|
3858
4185
|
}
|
|
3859
4186
|
cancel() {
|
|
4187
|
+
this._stepBeforeDiscard = this._step === "confirm-discard" ? "ask" : this._step;
|
|
4188
|
+
this._step = "confirm-discard";
|
|
4189
|
+
this.render();
|
|
4190
|
+
}
|
|
4191
|
+
confirmDiscard() {
|
|
3860
4192
|
this.dispatch("savetest", { description: null, notes: "", tags: [], ticketId: "" });
|
|
3861
4193
|
}
|
|
4194
|
+
backFromDiscard() {
|
|
4195
|
+
this._step = this._stepBeforeDiscard;
|
|
4196
|
+
this.render();
|
|
4197
|
+
}
|
|
3862
4198
|
restartComponent() {
|
|
3863
4199
|
this._step = "ask";
|
|
3864
4200
|
this.description = "";
|
|
@@ -3889,6 +4225,12 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
3889
4225
|
this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));
|
|
3890
4226
|
}
|
|
3891
4227
|
render() {
|
|
4228
|
+
if (this._step === "confirm-discard") {
|
|
4229
|
+
this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestConfirmDiscard(this.t.bind(this))}`;
|
|
4230
|
+
this.shadow.getElementById("btn-confirm-discard")?.addEventListener("click", () => this.confirmDiscard());
|
|
4231
|
+
this.shadow.getElementById("btn-back-discard")?.addEventListener("click", () => this.backFromDiscard());
|
|
4232
|
+
return;
|
|
4233
|
+
}
|
|
3892
4234
|
if (this._step === "ask") {
|
|
3893
4235
|
this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestAsk(this.t.bind(this))}`;
|
|
3894
4236
|
this.shadow.getElementById("btn-yes")?.addEventListener("click", () => this.askSave());
|
|
@@ -3930,10 +4272,13 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
3930
4272
|
}
|
|
3931
4273
|
}
|
|
3932
4274
|
};
|
|
3933
|
-
if (!customElements.get("save-test")) {
|
|
3934
|
-
customElements.define("save-test", SaveTestElement);
|
|
4275
|
+
if (!customElements.get("lib-e2e-save-test")) {
|
|
4276
|
+
customElements.define("lib-e2e-save-test", SaveTestElement);
|
|
3935
4277
|
}
|
|
3936
4278
|
|
|
4279
|
+
// src/components/test-editor/test-editor.ts
|
|
4280
|
+
init_code_format_utils();
|
|
4281
|
+
|
|
3937
4282
|
// src/components/test-editor/test-editor.styles.ts
|
|
3938
4283
|
var TEST_EDITOR_STYLES = `
|
|
3939
4284
|
:host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }
|
|
@@ -4156,6 +4501,7 @@ function highlightLine(line) {
|
|
|
4156
4501
|
}
|
|
4157
4502
|
|
|
4158
4503
|
// src/components/test-editor/test-editor.template.ts
|
|
4504
|
+
init_code_format_utils();
|
|
4159
4505
|
function renderTestRow(test, i, state, t) {
|
|
4160
4506
|
const { selectMode, selectedIds, expandedIndex, interceptorsByTest, locale, issueTrackerConfig } = state;
|
|
4161
4507
|
const expanded = expandedIndex === i;
|
|
@@ -4164,7 +4510,9 @@ function renderTestRow(test, i, state, t) {
|
|
|
4164
4510
|
const tagsHtml = (test.tags ?? []).length ? `<span class="test-tags">${(test.tags ?? []).map((tag) => `<span class="test-tag">${escHtml(tag)}</span>`).join("")}</span>` : "";
|
|
4165
4511
|
const checkbox = selectMode ? `<input type="checkbox" ${selectedIds.has(test.id) ? "checked" : ""} data-select="${test.id}" />` : "";
|
|
4166
4512
|
const hasIcps = (test.interceptors ?? []).length > 0;
|
|
4167
|
-
const
|
|
4513
|
+
const ticketId = test.ticketId;
|
|
4514
|
+
const ticketComment = ticketId ? buildTicketComment(ticketId) + "\n" : "";
|
|
4515
|
+
const itBlockCode = `${ticketComment}it('${escapeSingleQuotes(test.name)}', () => {
|
|
4168
4516
|
${(test.commands ?? []).map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4169
4517
|
});`;
|
|
4170
4518
|
const icpBlockCode = icps.length ? `beforeEach(() => {
|
|
@@ -4172,7 +4520,6 @@ ${(test.commands ?? []).map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
|
4172
4520
|
${icps.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4173
4521
|
});` : "";
|
|
4174
4522
|
const notesHtml = expanded && test.notes ? `<p class="test-notes">${escHtml(test.notes)}</p>` : "";
|
|
4175
|
-
const ticketId = test.ticketId;
|
|
4176
4523
|
const ticketUrl = ticketId ? buildTicketUrl(ticketId, issueTrackerConfig) : null;
|
|
4177
4524
|
const ticketHtml = ticketId ? ticketUrl ? `<a class="ticket-link" href="${escAttr(ticketUrl)}" target="_blank" rel="noopener noreferrer" title="${t("TEST_EDITOR.TICKET_LINK_TITLE")}">${escHtml(ticketId)}</a>` : `<span class="ticket-badge">${escHtml(ticketId)}</span>` : "";
|
|
4178
4525
|
const body = expanded ? `
|
|
@@ -4421,8 +4768,90 @@ ${beforeEach}${itBlocks}
|
|
|
4421
4768
|
});
|
|
4422
4769
|
}
|
|
4423
4770
|
};
|
|
4424
|
-
if (!customElements.get("test-editor")) {
|
|
4425
|
-
customElements.define("test-editor", TestEditorElement);
|
|
4771
|
+
if (!customElements.get("lib-e2e-test-editor")) {
|
|
4772
|
+
customElements.define("lib-e2e-test-editor", TestEditorElement);
|
|
4773
|
+
}
|
|
4774
|
+
|
|
4775
|
+
// src/models/active-session.model.ts
|
|
4776
|
+
var ACTIVE_SESSION_BREADCRUMB_KEY = "e2e-active-session";
|
|
4777
|
+
var RESUME_TTL_CONFIG_KEY = "resumeRecencyTtlMinutes";
|
|
4778
|
+
var DEFAULT_RESUME_TTL_MINUTES = 30;
|
|
4779
|
+
|
|
4780
|
+
// src/utils/login-setup.utils.ts
|
|
4781
|
+
var EXPORT_FN_RE = /^(?!\/\/).*\bexport\s+(?:async\s+)?function\s+(\w+)|^(?!\/\/).*\bexport\s+const\s+(\w+)\s*=\s*(?:async\s*)?\(/gm;
|
|
4782
|
+
function extractExportedFunctions(fileContent) {
|
|
4783
|
+
const names = [];
|
|
4784
|
+
let match;
|
|
4785
|
+
const re = new RegExp(EXPORT_FN_RE.source, EXPORT_FN_RE.flags);
|
|
4786
|
+
while ((match = re.exec(fileContent)) !== null) {
|
|
4787
|
+
const name = match[1] ?? match[2];
|
|
4788
|
+
if (name) names.push(name);
|
|
4789
|
+
}
|
|
4790
|
+
return names;
|
|
4791
|
+
}
|
|
4792
|
+
function buildLoginScaffold() {
|
|
4793
|
+
return [
|
|
4794
|
+
"/**",
|
|
4795
|
+
" * Login service scaffold \u2014 fill in your own auth logic.",
|
|
4796
|
+
" * This file is not committed to source control.",
|
|
4797
|
+
" */",
|
|
4798
|
+
"",
|
|
4799
|
+
"export function fetchAuthToken() {",
|
|
4800
|
+
" // TODO: implement \u2014 retrieve and return your auth token",
|
|
4801
|
+
"}",
|
|
4802
|
+
"",
|
|
4803
|
+
"export function setupRequestInterceptors() {",
|
|
4804
|
+
" // TODO: implement \u2014 configure cy.intercept() or set localStorage/cookies",
|
|
4805
|
+
"}",
|
|
4806
|
+
""
|
|
4807
|
+
].join("\n");
|
|
4808
|
+
}
|
|
4809
|
+
function buildLoginImportPath(fromFilePath, toServiceFilePath) {
|
|
4810
|
+
const fromParts = fromFilePath.replace(/\\/g, "/").split("/");
|
|
4811
|
+
const toParts = toServiceFilePath.replace(/\\/g, "/").split("/");
|
|
4812
|
+
fromParts.pop();
|
|
4813
|
+
let common = 0;
|
|
4814
|
+
while (common < fromParts.length && common < toParts.length - 1 && fromParts[common] === toParts[common]) {
|
|
4815
|
+
common++;
|
|
4816
|
+
}
|
|
4817
|
+
const ups = fromParts.length - common;
|
|
4818
|
+
const downs = toParts.slice(common);
|
|
4819
|
+
const serviceFile = downs[downs.length - 1].replace(/\.ts$/, "");
|
|
4820
|
+
const prefix = ups === 0 ? "." : Array(ups).fill("..").join("/");
|
|
4821
|
+
const middle = downs.slice(0, -1);
|
|
4822
|
+
return [prefix, ...middle, serviceFile].join("/");
|
|
4823
|
+
}
|
|
4824
|
+
function hasLoginBlocks(content, fnNames) {
|
|
4825
|
+
return fnNames.some((fn) => new RegExp(`\\b${fn}\\s*\\(`).test(content));
|
|
4826
|
+
}
|
|
4827
|
+
function injectLoginBlocksIntoExisting(content, importLine, beforeBlock, beforeEachBlock) {
|
|
4828
|
+
let result = content;
|
|
4829
|
+
if (importLine && !content.includes(importLine)) {
|
|
4830
|
+
result = `${importLine}
|
|
4831
|
+
|
|
4832
|
+
${result}`;
|
|
4833
|
+
}
|
|
4834
|
+
const blocks = [beforeBlock, beforeEachBlock].filter(Boolean).join("");
|
|
4835
|
+
if (blocks) {
|
|
4836
|
+
const describeMatch = result.match(/(describe\s*\(.*?{)/s);
|
|
4837
|
+
if (describeMatch) {
|
|
4838
|
+
const insertPos = (describeMatch.index ?? 0) + describeMatch[0].length;
|
|
4839
|
+
result = result.slice(0, insertPos) + "\n" + blocks + result.slice(insertPos);
|
|
4840
|
+
}
|
|
4841
|
+
}
|
|
4842
|
+
return result;
|
|
4843
|
+
}
|
|
4844
|
+
function buildLoginBlocks(importPath, beforeFn, beforeEachFn) {
|
|
4845
|
+
if (!beforeFn && !beforeEachFn) {
|
|
4846
|
+
return { importLine: "", beforeBlock: "", beforeEachBlock: "" };
|
|
4847
|
+
}
|
|
4848
|
+
const fns = [...new Set([beforeFn, beforeEachFn].filter(Boolean))];
|
|
4849
|
+
const importLine = `import { ${fns.join(", ")} } from '${importPath}';`;
|
|
4850
|
+
const beforeBlock = beforeFn ? ` before(() => { ${beforeFn}(); });
|
|
4851
|
+
` : "";
|
|
4852
|
+
const beforeEachBlock = beforeEachFn ? ` beforeEach(() => { ${beforeEachFn}(); });
|
|
4853
|
+
` : "";
|
|
4854
|
+
return { importLine, beforeBlock, beforeEachBlock };
|
|
4426
4855
|
}
|
|
4427
4856
|
|
|
4428
4857
|
// src/components/configuration/configuration.styles.ts
|
|
@@ -4583,6 +5012,99 @@ var CONFIGURATION_STYLES = `
|
|
|
4583
5012
|
.btn-export-confirm { background: #238636; border-color: #238636; color: #fff; }
|
|
4584
5013
|
.btn-export-confirm:hover:not(:disabled) { background: #2ea043; border-color: #2ea043; }
|
|
4585
5014
|
.btn-export-confirm:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
5015
|
+
|
|
5016
|
+
/* \u2500\u2500 Form-element font reset \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
5017
|
+
input, select, button, textarea { font-family: inherit; }
|
|
5018
|
+
|
|
5019
|
+
/* \u2500\u2500 Primary action button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
5020
|
+
.btn-primary { background: #1f6feb; border-color: #1f6feb; color: #fff; }
|
|
5021
|
+
.btn-primary:hover { background: #388bfd; border-color: #388bfd; color: #fff; }
|
|
5022
|
+
.btn-primary:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
5023
|
+
|
|
5024
|
+
/* \u2500\u2500 Login Setup overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
5025
|
+
.ls-modal { max-width: 500px; }
|
|
5026
|
+
.ls-hd { display: flex; align-items: center; gap: 8px; }
|
|
5027
|
+
.ls-hd-icon { font-size: 15px; }
|
|
5028
|
+
|
|
5029
|
+
.ls-body {
|
|
5030
|
+
padding: 20px; overflow-y: auto; flex: 1;
|
|
5031
|
+
display: flex; flex-direction: column; gap: 20px;
|
|
5032
|
+
scrollbar-width: thin; scrollbar-color: #30363d transparent;
|
|
5033
|
+
}
|
|
5034
|
+
|
|
5035
|
+
.ls-section { display: flex; flex-direction: column; gap: 8px; }
|
|
5036
|
+
.ls-section-label {
|
|
5037
|
+
font-size: 10px; font-weight: 700; text-transform: uppercase;
|
|
5038
|
+
letter-spacing: 0.8px; color: #484f58;
|
|
5039
|
+
}
|
|
5040
|
+
|
|
5041
|
+
.ls-actions { display: flex; gap: 10px; }
|
|
5042
|
+
.ls-action-btn {
|
|
5043
|
+
flex: 1; padding: 14px 12px; border-radius: 8px;
|
|
5044
|
+
background: #0d1117; border: 1px solid #21262d; color: #8b949e;
|
|
5045
|
+
display: flex; flex-direction: column; align-items: center; gap: 6px;
|
|
5046
|
+
transition: background 0.15s, border-color 0.15s, color 0.15s;
|
|
5047
|
+
}
|
|
5048
|
+
.ls-action-btn:hover { background: #161b22; color: #e6edf3; border-color: #388bfd; }
|
|
5049
|
+
.ls-action-icon { font-size: 22px; line-height: 1; }
|
|
5050
|
+
.ls-action-label { font-size: 12px; font-weight: 600; color: #c9d1d9; }
|
|
5051
|
+
.ls-action-btn:hover .ls-action-label { color: #e6edf3; }
|
|
5052
|
+
.ls-action-sub { font-size: 10px; color: #484f58; line-height: 1.4; text-align: center; }
|
|
5053
|
+
|
|
5054
|
+
.ls-file-row {
|
|
5055
|
+
display: flex; align-items: center; gap: 10px;
|
|
5056
|
+
padding: 10px 12px; background: #0d1117;
|
|
5057
|
+
border: 1px solid #21262d; border-radius: 8px;
|
|
5058
|
+
}
|
|
5059
|
+
.ls-file-icon { font-size: 14px; flex-shrink: 0; }
|
|
5060
|
+
.ls-file-name {
|
|
5061
|
+
flex: 1; font-size: 11px; color: #c9d1d9;
|
|
5062
|
+
font-family: 'Cascadia Code','Fira Code','Consolas',monospace;
|
|
5063
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
5064
|
+
min-width: 0;
|
|
5065
|
+
}
|
|
5066
|
+
.ls-btn-rescan {
|
|
5067
|
+
flex-shrink: 0; padding: 4px 10px; font-size: 11px;
|
|
5068
|
+
background: #161b22; border-color: #30363d; color: #8b949e;
|
|
5069
|
+
}
|
|
5070
|
+
.ls-btn-rescan:hover { background: #21262d; color: #e6edf3; }
|
|
5071
|
+
|
|
5072
|
+
.ls-input {
|
|
5073
|
+
width: 100%; padding: 8px 10px; background: #0d1117;
|
|
5074
|
+
border: 1px solid #30363d; border-radius: 6px;
|
|
5075
|
+
color: #c9d1d9; font-size: 12px; outline: none; font-family: inherit;
|
|
5076
|
+
}
|
|
5077
|
+
.ls-input:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }
|
|
5078
|
+
|
|
5079
|
+
.ls-fns {
|
|
5080
|
+
display: flex; flex-wrap: wrap; gap: 6px;
|
|
5081
|
+
padding: 10px; background: #0d1117;
|
|
5082
|
+
border: 1px solid #21262d; border-radius: 6px; min-height: 38px;
|
|
5083
|
+
}
|
|
5084
|
+
.ls-fn-chip {
|
|
5085
|
+
padding: 3px 10px; font-size: 11px; color: #79c0ff;
|
|
5086
|
+
background: rgba(47,129,247,0.1); border: 1px solid rgba(47,129,247,0.2);
|
|
5087
|
+
border-radius: 12px; font-family: 'Cascadia Code','Fira Code','Consolas',monospace;
|
|
5088
|
+
}
|
|
5089
|
+
|
|
5090
|
+
.ls-field-block { display: flex; flex-direction: column; gap: 6px; }
|
|
5091
|
+
.ls-field-block + .ls-field-block { margin-top: 12px; }
|
|
5092
|
+
.ls-label { font-size: 11px; color: #8b949e; }
|
|
5093
|
+
.ls-select {
|
|
5094
|
+
width: 100%; padding: 8px 10px; background: #0d1117;
|
|
5095
|
+
border: 1px solid #30363d; border-radius: 6px;
|
|
5096
|
+
color: #c9d1d9; font-size: 12px; outline: none; cursor: pointer;
|
|
5097
|
+
}
|
|
5098
|
+
.ls-select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }
|
|
5099
|
+
|
|
5100
|
+
.ls-empty-state {
|
|
5101
|
+
display: flex; align-items: center; gap: 10px;
|
|
5102
|
+
padding: 14px; background: #0d1117; border: 1px solid #21262d;
|
|
5103
|
+
border-radius: 8px; font-size: 12px; color: #484f58;
|
|
5104
|
+
}
|
|
5105
|
+
.ls-empty-icon { font-size: 16px; }
|
|
5106
|
+
|
|
5107
|
+
.ls-ft { padding: 14px 20px; }
|
|
4586
5108
|
`;
|
|
4587
5109
|
|
|
4588
5110
|
// src/components/configuration/configuration.template.ts
|
|
@@ -4800,6 +5322,13 @@ function renderConfiguration(state, t) {
|
|
|
4800
5322
|
</div>` : ""}
|
|
4801
5323
|
</div>
|
|
4802
5324
|
|
|
5325
|
+
<!-- Login Setup -->
|
|
5326
|
+
<div class="card card-wide">
|
|
5327
|
+
<div class="card-hd">${t("CONFIG.LOGIN_SETUP_SECTION")}</div>
|
|
5328
|
+
${state.loginSetupConfig ? `<p style="font-size:12px;color:#8b949e;margin:0 0 8px">${escHtml(state.loginSetupConfig.filePath)}</p>` : `<p style="font-size:12px;color:#8b949e;margin:0 0 8px">${t("CONFIG.LOGIN_SETUP_NOT_CONFIGURED")}</p>`}
|
|
5329
|
+
<button id="btn-open-login-setup" class="btn-sm">${t("CONFIG.LOGIN_SETUP_SET_UP_BTN")}</button>
|
|
5330
|
+
</div>
|
|
5331
|
+
|
|
4803
5332
|
<!-- Data -->
|
|
4804
5333
|
<div class="card card-wide">
|
|
4805
5334
|
<div class="card-hd">${t("CONFIG.DATA_SECTION")}</div>
|
|
@@ -4813,7 +5342,93 @@ function renderConfiguration(state, t) {
|
|
|
4813
5342
|
</div>
|
|
4814
5343
|
</div>
|
|
4815
5344
|
|
|
4816
|
-
</div>${renderExportOverlay(state, t)}`;
|
|
5345
|
+
</div>${renderExportOverlay(state, t)}${renderLoginSetupOverlay(state, t)}`;
|
|
5346
|
+
}
|
|
5347
|
+
function renderLoginSetupOverlay(state, t) {
|
|
5348
|
+
if (!state.isLoginSetupOpen) return "";
|
|
5349
|
+
const cfg = state.loginSetupConfig;
|
|
5350
|
+
const path = state.loginSetupDraftPath ?? cfg?.filePath ?? "";
|
|
5351
|
+
const fns = state.loginSetupDraftFunctions ?? cfg?.detectedFunctions ?? [];
|
|
5352
|
+
const beforeFn = state.loginSetupDraftBeforeFn !== void 0 ? state.loginSetupDraftBeforeFn : cfg?.beforeFn ?? null;
|
|
5353
|
+
const beforeEachFn = state.loginSetupDraftBeforeEachFn !== void 0 ? state.loginSetupDraftBeforeEachFn : cfg?.beforeEachFn ?? null;
|
|
5354
|
+
const hasContent = state.loginSetupDraftHasContent ?? !!cfg?.fileContent;
|
|
5355
|
+
const fnOption = (name, selected) => `<option value="${escAttr(name ?? "")}" ${selected === name ? "selected" : ""}>${name ? escHtml(name) : t("CONFIG.LOGIN_SETUP_NONE_OPTION")}</option>`;
|
|
5356
|
+
const fnDropdown = (id, label, selected) => `
|
|
5357
|
+
<div class="ls-field-block">
|
|
5358
|
+
<label class="ls-label" for="${id}">${escHtml(label)}</label>
|
|
5359
|
+
<select id="${id}" class="ls-select">
|
|
5360
|
+
${fnOption(null, selected)}
|
|
5361
|
+
${fns.map((fn) => fnOption(fn, selected)).join("")}
|
|
5362
|
+
</select>
|
|
5363
|
+
</div>`;
|
|
5364
|
+
const functionsSection = hasContent ? fns.length > 0 ? `<div class="ls-section">
|
|
5365
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_FUNCTIONS_DETECTED")}</span>
|
|
5366
|
+
<div class="ls-fns">${fns.map((fn) => `<span class="ls-fn-chip">${escHtml(fn)}</span>`).join("")}</div>
|
|
5367
|
+
</div>
|
|
5368
|
+
<div class="ls-section">
|
|
5369
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_BLOCK_ASSIGN")}</span>
|
|
5370
|
+
${fnDropdown("login-setup-before-fn", t("CONFIG.LOGIN_SETUP_BEFORE_LABEL"), beforeFn)}
|
|
5371
|
+
${fnDropdown("login-setup-before-each-fn", t("CONFIG.LOGIN_SETUP_BEFORE_EACH_LABEL"), beforeEachFn)}
|
|
5372
|
+
</div>` : `<div class="ls-empty-state">
|
|
5373
|
+
<span class="ls-empty-icon">\u{1F50D}</span>
|
|
5374
|
+
<span>${t("CONFIG.LOGIN_SETUP_NO_FUNCTIONS")}</span>
|
|
5375
|
+
</div>` : "";
|
|
5376
|
+
const fileSection = hasContent ? `<div class="ls-section">
|
|
5377
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_FILE_NAME_LABEL")}</span>
|
|
5378
|
+
<div class="ls-file-row">
|
|
5379
|
+
<span class="ls-file-icon">\u{1F4C4}</span>
|
|
5380
|
+
<span class="ls-file-name">${escHtml(path)}</span>
|
|
5381
|
+
<button id="btn-login-setup-rescan" class="ls-btn-rescan">${t("CONFIG.LOGIN_SETUP_RESCAN")}</button>
|
|
5382
|
+
</div>
|
|
5383
|
+
</div>` : `<div class="ls-section">
|
|
5384
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_FILE_NAME_LABEL")}</span>
|
|
5385
|
+
<input id="login-setup-filepath" type="text" class="ls-input"
|
|
5386
|
+
placeholder="${escAttr(t("CONFIG.LOGIN_SETUP_FILE_NAME_PH"))}"
|
|
5387
|
+
value="${escAttr(path)}" />
|
|
5388
|
+
</div>`;
|
|
5389
|
+
return `
|
|
5390
|
+
<div class="export-overlay" id="login-setup-overlay">
|
|
5391
|
+
<div class="export-modal ls-modal">
|
|
5392
|
+
|
|
5393
|
+
<div class="export-hd ls-hd">
|
|
5394
|
+
<span class="ls-hd-icon">\u{1F510}</span>
|
|
5395
|
+
${t("CONFIG.LOGIN_SETUP_TITLE")}
|
|
5396
|
+
</div>
|
|
5397
|
+
|
|
5398
|
+
<div class="ls-body">
|
|
5399
|
+
|
|
5400
|
+
<div class="ls-section">
|
|
5401
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_SOURCE_LABEL")}</span>
|
|
5402
|
+
<div class="ls-actions">
|
|
5403
|
+
<button id="btn-login-setup-create-scaffold" class="ls-action-btn">
|
|
5404
|
+
<span class="ls-action-icon">\u2728</span>
|
|
5405
|
+
<span class="ls-action-label">${t("CONFIG.LOGIN_SETUP_CREATE_SCAFFOLD")}</span>
|
|
5406
|
+
<span class="ls-action-sub">${t("CONFIG.LOGIN_SETUP_CREATE_SUB")}</span>
|
|
5407
|
+
</button>
|
|
5408
|
+
<button id="btn-login-setup-pick-file" class="ls-action-btn">
|
|
5409
|
+
<span class="ls-action-icon">\u{1F4C2}</span>
|
|
5410
|
+
<span class="ls-action-label">${t("CONFIG.LOGIN_SETUP_SELECT_EXISTING")}</span>
|
|
5411
|
+
<span class="ls-action-sub">${t("CONFIG.LOGIN_SETUP_SELECT_SUB")}</span>
|
|
5412
|
+
</button>
|
|
5413
|
+
</div>
|
|
5414
|
+
</div>
|
|
5415
|
+
|
|
5416
|
+
${fileSection}
|
|
5417
|
+
|
|
5418
|
+
${functionsSection}
|
|
5419
|
+
|
|
5420
|
+
</div>
|
|
5421
|
+
|
|
5422
|
+
<div class="export-ft ls-ft">
|
|
5423
|
+
<button id="btn-login-setup-clear" class="btn-danger">${t("CONFIG.LOGIN_SETUP_CLEAR_BTN")}</button>
|
|
5424
|
+
<span class="export-ft-actions">
|
|
5425
|
+
<button id="btn-login-setup-cancel">${t("CONFIG.LOGIN_SETUP_CANCEL_BTN")}</button>
|
|
5426
|
+
<button id="btn-login-setup-save" class="btn-primary">${t("CONFIG.LOGIN_SETUP_SAVE_BTN")}</button>
|
|
5427
|
+
</span>
|
|
5428
|
+
</div>
|
|
5429
|
+
|
|
5430
|
+
</div>
|
|
5431
|
+
</div>`;
|
|
4817
5432
|
}
|
|
4818
5433
|
|
|
4819
5434
|
// src/components/configuration/configuration.ts
|
|
@@ -4834,6 +5449,15 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4834
5449
|
exportSelectedIds = /* @__PURE__ */ new Set();
|
|
4835
5450
|
exportSelectedTags = /* @__PURE__ */ new Set();
|
|
4836
5451
|
issueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };
|
|
5452
|
+
isLoginSetupOpen = false;
|
|
5453
|
+
loginSetupConfig = null;
|
|
5454
|
+
loginSetupDraftPath = "";
|
|
5455
|
+
loginSetupDraftFunctions = [];
|
|
5456
|
+
loginSetupDraftBeforeFn = null;
|
|
5457
|
+
loginSetupDraftBeforeEachFn = null;
|
|
5458
|
+
loginSetupDraftHasContent = false;
|
|
5459
|
+
loginSetupDraftHandle = null;
|
|
5460
|
+
loginSetupDraftContent = "";
|
|
4837
5461
|
filesystemGranted = false;
|
|
4838
5462
|
cypressFolderName = null;
|
|
4839
5463
|
constructor() {
|
|
@@ -4875,6 +5499,7 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4875
5499
|
provider: config?.["issueTrackerProvider"] ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,
|
|
4876
5500
|
baseUrl: config?.["issueTrackerBaseUrl"] ?? ""
|
|
4877
5501
|
};
|
|
5502
|
+
this.loginSetupConfig = await this.persistence.getLoginSetup();
|
|
4878
5503
|
this.render();
|
|
4879
5504
|
}
|
|
4880
5505
|
async onLanguageChange(lang) {
|
|
@@ -4940,6 +5565,85 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4940
5565
|
await this.persistence.setConfig({ issueTrackerBaseUrl: baseUrl });
|
|
4941
5566
|
this.dispatchEvent(new CustomEvent("issuetrackerchange", { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));
|
|
4942
5567
|
}
|
|
5568
|
+
openLoginSetupPanel() {
|
|
5569
|
+
this.isLoginSetupOpen = true;
|
|
5570
|
+
const cfg = this.loginSetupConfig;
|
|
5571
|
+
this.loginSetupDraftHandle = null;
|
|
5572
|
+
this.loginSetupDraftContent = cfg?.fileContent ?? "";
|
|
5573
|
+
this.loginSetupDraftPath = cfg?.filePath ?? "";
|
|
5574
|
+
this.loginSetupDraftFunctions = cfg?.detectedFunctions ?? [];
|
|
5575
|
+
this.loginSetupDraftBeforeFn = cfg?.beforeFn ?? null;
|
|
5576
|
+
this.loginSetupDraftBeforeEachFn = cfg?.beforeEachFn ?? null;
|
|
5577
|
+
this.loginSetupDraftHasContent = !!cfg?.fileContent;
|
|
5578
|
+
this.render();
|
|
5579
|
+
}
|
|
5580
|
+
closeLoginSetupPanel() {
|
|
5581
|
+
this.isLoginSetupOpen = false;
|
|
5582
|
+
this.render();
|
|
5583
|
+
}
|
|
5584
|
+
async saveLoginSetupConfig(config) {
|
|
5585
|
+
await this.persistence.saveLoginSetup(config);
|
|
5586
|
+
this.loginSetupConfig = config;
|
|
5587
|
+
this.isLoginSetupOpen = false;
|
|
5588
|
+
this.render();
|
|
5589
|
+
}
|
|
5590
|
+
async clearLoginSetupConfig() {
|
|
5591
|
+
await this.persistence.clearLoginSetup();
|
|
5592
|
+
this.loginSetupConfig = null;
|
|
5593
|
+
this.render();
|
|
5594
|
+
}
|
|
5595
|
+
async loginSetupPickFile() {
|
|
5596
|
+
const currentPath = this.shadow.getElementById("login-setup-filepath")?.value.trim() ?? "";
|
|
5597
|
+
try {
|
|
5598
|
+
const [handle] = await window.showOpenFilePicker({
|
|
5599
|
+
types: [{ description: "TypeScript files", accept: { "text/plain": [".ts"] } }],
|
|
5600
|
+
multiple: false
|
|
5601
|
+
});
|
|
5602
|
+
this.loginSetupDraftHandle = handle;
|
|
5603
|
+
const file = await handle.getFile();
|
|
5604
|
+
this.loginSetupDraftContent = await file.text();
|
|
5605
|
+
this.loginSetupDraftHasContent = true;
|
|
5606
|
+
this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;
|
|
5607
|
+
this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);
|
|
5608
|
+
this.render();
|
|
5609
|
+
} catch (e) {
|
|
5610
|
+
if (e?.name !== "AbortError") showToast(this.t("CONFIG.FOLDER_ERROR_TOAST"), false);
|
|
5611
|
+
}
|
|
5612
|
+
}
|
|
5613
|
+
async loginSetupCreateScaffold() {
|
|
5614
|
+
const currentPath = this.shadow.getElementById("login-setup-filepath")?.value.trim() ?? "";
|
|
5615
|
+
try {
|
|
5616
|
+
const handle = await window.showSaveFilePicker({
|
|
5617
|
+
suggestedName: "login.service.ts",
|
|
5618
|
+
types: [{ description: "TypeScript files", accept: { "text/plain": [".ts"] } }]
|
|
5619
|
+
});
|
|
5620
|
+
const content = buildLoginScaffold();
|
|
5621
|
+
const writable = await handle.createWritable();
|
|
5622
|
+
await writable.write(content);
|
|
5623
|
+
await writable.close();
|
|
5624
|
+
this.loginSetupDraftHandle = handle;
|
|
5625
|
+
this.loginSetupDraftContent = content;
|
|
5626
|
+
this.loginSetupDraftHasContent = true;
|
|
5627
|
+
this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;
|
|
5628
|
+
this.loginSetupDraftFunctions = extractExportedFunctions(content);
|
|
5629
|
+
this.render();
|
|
5630
|
+
} catch (e) {
|
|
5631
|
+
if (e?.name !== "AbortError") showToast(this.t("CONFIG.FOLDER_ERROR_TOAST"), false);
|
|
5632
|
+
}
|
|
5633
|
+
}
|
|
5634
|
+
async loginSetupRescan() {
|
|
5635
|
+
const currentPath = this.shadow.getElementById("login-setup-filepath")?.value.trim();
|
|
5636
|
+
if (currentPath !== void 0) this.loginSetupDraftPath = currentPath;
|
|
5637
|
+
try {
|
|
5638
|
+
if (this.loginSetupDraftHandle) {
|
|
5639
|
+
const file = await this.loginSetupDraftHandle.getFile();
|
|
5640
|
+
this.loginSetupDraftContent = await file.text();
|
|
5641
|
+
}
|
|
5642
|
+
this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);
|
|
5643
|
+
this.render();
|
|
5644
|
+
} catch {
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
4943
5647
|
async changeFolder() {
|
|
4944
5648
|
try {
|
|
4945
5649
|
await this.persistence.requestDirectoryPermissions();
|
|
@@ -5042,7 +5746,14 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5042
5746
|
exportTests: this.exportTests,
|
|
5043
5747
|
exportSelectedIds: this.exportSelectedIds,
|
|
5044
5748
|
exportSelectedTags: this.exportSelectedTags,
|
|
5045
|
-
issueTrackerConfig: this.issueTrackerConfig
|
|
5749
|
+
issueTrackerConfig: this.issueTrackerConfig,
|
|
5750
|
+
isLoginSetupOpen: this.isLoginSetupOpen,
|
|
5751
|
+
loginSetupConfig: this.loginSetupConfig,
|
|
5752
|
+
loginSetupDraftPath: this.loginSetupDraftPath,
|
|
5753
|
+
loginSetupDraftFunctions: this.loginSetupDraftFunctions,
|
|
5754
|
+
loginSetupDraftBeforeFn: this.loginSetupDraftBeforeFn,
|
|
5755
|
+
loginSetupDraftBeforeEachFn: this.loginSetupDraftBeforeEachFn,
|
|
5756
|
+
loginSetupDraftHasContent: this.loginSetupDraftHasContent
|
|
5046
5757
|
}, this.t.bind(this))}`;
|
|
5047
5758
|
;
|
|
5048
5759
|
this.shadow.getElementById("lang-select").addEventListener(
|
|
@@ -5101,24 +5812,48 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5101
5812
|
this.shadow.querySelectorAll("[data-export-tag]").forEach(
|
|
5102
5813
|
(el) => el.addEventListener("click", () => this.toggleExportTag(el.dataset["exportTag"] ?? ""))
|
|
5103
5814
|
);
|
|
5815
|
+
this.shadow.getElementById("btn-open-login-setup")?.addEventListener("click", () => this.openLoginSetupPanel());
|
|
5816
|
+
this.shadow.getElementById("btn-login-setup-cancel")?.addEventListener("click", () => this.closeLoginSetupPanel());
|
|
5817
|
+
this.shadow.getElementById("btn-login-setup-pick-file")?.addEventListener("click", () => this.loginSetupPickFile());
|
|
5818
|
+
this.shadow.getElementById("btn-login-setup-create-scaffold")?.addEventListener("click", () => this.loginSetupCreateScaffold());
|
|
5819
|
+
this.shadow.getElementById("btn-login-setup-rescan")?.addEventListener("click", () => this.loginSetupRescan());
|
|
5820
|
+
this.shadow.getElementById("btn-login-setup-clear")?.addEventListener("click", () => this.clearLoginSetupConfig());
|
|
5821
|
+
this.shadow.getElementById("btn-login-setup-save")?.addEventListener("click", async () => {
|
|
5822
|
+
const pathEl = this.shadow.getElementById("login-setup-filepath");
|
|
5823
|
+
const beforeEl = this.shadow.getElementById("login-setup-before-fn");
|
|
5824
|
+
const beforeEachEl = this.shadow.getElementById("login-setup-before-each-fn");
|
|
5825
|
+
await this.saveLoginSetupConfig({
|
|
5826
|
+
enabled: true,
|
|
5827
|
+
filePath: pathEl?.value.trim() ?? this.loginSetupDraftPath,
|
|
5828
|
+
fileContent: this.loginSetupDraftContent,
|
|
5829
|
+
detectedFunctions: this.loginSetupDraftFunctions,
|
|
5830
|
+
beforeFn: beforeEl?.value || null,
|
|
5831
|
+
beforeEachFn: beforeEachEl?.value || null
|
|
5832
|
+
});
|
|
5833
|
+
});
|
|
5834
|
+
;
|
|
5104
5835
|
this.shadow.getElementById("file-input").addEventListener("change", async (e) => {
|
|
5105
5836
|
const file = e.target.files?.[0];
|
|
5106
5837
|
if (!file) return;
|
|
5107
5838
|
try {
|
|
5108
5839
|
await this.importAllData(file);
|
|
5109
|
-
|
|
5840
|
+
showToast(this.t("CONFIG.IMPORT_SUCCESS"));
|
|
5110
5841
|
} catch (err) {
|
|
5111
|
-
|
|
5842
|
+
showToast(err.message ?? this.t("CONFIG.IMPORT_ERROR"), false);
|
|
5112
5843
|
}
|
|
5113
5844
|
const target = e.target;
|
|
5114
5845
|
if (target) target.value = "";
|
|
5115
5846
|
});
|
|
5116
5847
|
}
|
|
5117
5848
|
};
|
|
5118
|
-
if (!customElements.get("e2e-configuration")) {
|
|
5119
|
-
customElements.define("e2e-configuration", ConfigurationElement);
|
|
5849
|
+
if (!customElements.get("lib-e2e-configuration")) {
|
|
5850
|
+
customElements.define("lib-e2e-configuration", ConfigurationElement);
|
|
5120
5851
|
}
|
|
5121
5852
|
|
|
5853
|
+
// src/components/advanced-test-editor/advanced-test-editor.ts
|
|
5854
|
+
var import_sweetalert2 = __toESM(require("sweetalert2"), 1);
|
|
5855
|
+
init_code_format_utils();
|
|
5856
|
+
|
|
5122
5857
|
// src/components/advanced-test-editor/advanced-test-editor.styles.ts
|
|
5123
5858
|
var ADVANCED_TEST_EDITOR_STYLES = `
|
|
5124
5859
|
:host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }
|
|
@@ -5377,6 +6112,7 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
5377
6112
|
isCreatingFolder = false;
|
|
5378
6113
|
collapsedDirs = /* @__PURE__ */ new Set();
|
|
5379
6114
|
sidebarWidth = 220;
|
|
6115
|
+
loginSetupConfig = null;
|
|
5380
6116
|
hasPermission = false;
|
|
5381
6117
|
needsReauth = false;
|
|
5382
6118
|
_dirHandle = null;
|
|
@@ -5437,20 +6173,51 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
5437
6173
|
const name = rawName.trim().replace(/\.cy\.ts$/, "");
|
|
5438
6174
|
if (!name) return;
|
|
5439
6175
|
const fileName = `${name}.cy.ts`;
|
|
5440
|
-
const
|
|
6176
|
+
const cfg = this.loginSetupConfig;
|
|
6177
|
+
if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {
|
|
6178
|
+
const e2eName = this._e2eHandle.name ?? "e2e";
|
|
6179
|
+
const fromPath = `cypress/${e2eName}/${fileName}`;
|
|
6180
|
+
const importPath = buildLoginImportPath(fromPath, cfg.filePath);
|
|
6181
|
+
const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(
|
|
6182
|
+
importPath,
|
|
6183
|
+
cfg.beforeFn,
|
|
6184
|
+
cfg.beforeEachFn
|
|
6185
|
+
);
|
|
6186
|
+
const header = importLine ? `${importLine}
|
|
5441
6187
|
|
|
6188
|
+
` : "";
|
|
6189
|
+
const inner = [beforeBlock, beforeEachBlock].filter(Boolean).join("");
|
|
6190
|
+
const template = `${header}describe('${escapeSingleQuotes(name)}', () => {
|
|
6191
|
+
${inner}
|
|
5442
6192
|
it('should ', () => {
|
|
5443
6193
|
|
|
5444
6194
|
});
|
|
5445
6195
|
|
|
5446
6196
|
});
|
|
5447
6197
|
`;
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
6198
|
+
try {
|
|
6199
|
+
const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });
|
|
6200
|
+
const writable = await fileHandle.createWritable();
|
|
6201
|
+
await writable.write(template);
|
|
6202
|
+
await writable.close();
|
|
6203
|
+
} catch {
|
|
6204
|
+
}
|
|
6205
|
+
} else {
|
|
6206
|
+
const template = `describe('${escapeSingleQuotes(name)}', () => {
|
|
6207
|
+
|
|
6208
|
+
it('should ', () => {
|
|
6209
|
+
|
|
6210
|
+
});
|
|
6211
|
+
|
|
6212
|
+
});
|
|
6213
|
+
`;
|
|
6214
|
+
try {
|
|
6215
|
+
const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });
|
|
6216
|
+
const writable = await fileHandle.createWritable();
|
|
6217
|
+
await writable.write(template);
|
|
6218
|
+
await writable.close();
|
|
6219
|
+
} catch {
|
|
6220
|
+
}
|
|
5454
6221
|
}
|
|
5455
6222
|
this.isCreatingFile = false;
|
|
5456
6223
|
await this.getFoldersData();
|
|
@@ -5478,6 +6245,30 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
5478
6245
|
const comment = this.testNotes ? this.transformationService.buildBlockComment(this.testNotes) + "\n" : "";
|
|
5479
6246
|
content = this.transformationService.insertItBlock(content, comment + this.testItBlock);
|
|
5480
6247
|
if (!content) return;
|
|
6248
|
+
const cfg = this.loginSetupConfig;
|
|
6249
|
+
if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {
|
|
6250
|
+
const fns = [cfg.beforeFn, cfg.beforeEachFn].filter(Boolean);
|
|
6251
|
+
if (!hasLoginBlocks(content, fns)) {
|
|
6252
|
+
const e2eName = this._e2eHandle?.name ?? "e2e";
|
|
6253
|
+
const fileName = this.selectedFile?.name ?? "";
|
|
6254
|
+
const fromPath = `cypress/${e2eName}/${fileName}`;
|
|
6255
|
+
const importPath = buildLoginImportPath(fromPath, cfg.filePath);
|
|
6256
|
+
const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(importPath, cfg.beforeFn, cfg.beforeEachFn);
|
|
6257
|
+
const result = await import_sweetalert2.default.fire({
|
|
6258
|
+
title: this.t("CONFIG.LOGIN_SETUP_INJECT_TITLE"),
|
|
6259
|
+
html: `<div style="padding:10px 18px 14px;color:#8b949e;font-size:13px;line-height:1.6;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif">${this.t("CONFIG.LOGIN_SETUP_INJECT_TEXT")}</div>`,
|
|
6260
|
+
icon: "question",
|
|
6261
|
+
showCancelButton: true,
|
|
6262
|
+
confirmButtonText: this.t("CONFIG.LOGIN_SETUP_INJECT_CONFIRM"),
|
|
6263
|
+
cancelButtonText: this.t("CONFIG.LOGIN_SETUP_CANCEL_BTN"),
|
|
6264
|
+
confirmButtonColor: "#1f6feb",
|
|
6265
|
+
width: 460
|
|
6266
|
+
});
|
|
6267
|
+
if (result.isConfirmed) {
|
|
6268
|
+
content = injectLoginBlocksIntoExisting(content, importLine, beforeBlock, beforeEachBlock);
|
|
6269
|
+
}
|
|
6270
|
+
}
|
|
6271
|
+
}
|
|
5481
6272
|
const writable = await this.selectedFileHandle.createWritable();
|
|
5482
6273
|
await writable.write(content);
|
|
5483
6274
|
await writable.close();
|
|
@@ -5672,8 +6463,8 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
5672
6463
|
});
|
|
5673
6464
|
}
|
|
5674
6465
|
};
|
|
5675
|
-
if (!customElements.get("advanced-test-editor")) {
|
|
5676
|
-
customElements.define("advanced-test-editor", AdvancedTestEditorElement);
|
|
6466
|
+
if (!customElements.get("lib-e2e-advanced-test-editor")) {
|
|
6467
|
+
customElements.define("lib-e2e-advanced-test-editor", AdvancedTestEditorElement);
|
|
5677
6468
|
}
|
|
5678
6469
|
|
|
5679
6470
|
// src/components/file-preview/file-preview.styles.ts
|
|
@@ -6039,8 +6830,8 @@ var FilePreviewElement = class extends HTMLElement {
|
|
|
6039
6830
|
});
|
|
6040
6831
|
}
|
|
6041
6832
|
};
|
|
6042
|
-
if (!customElements.get("file-preview")) {
|
|
6043
|
-
customElements.define("file-preview", FilePreviewElement);
|
|
6833
|
+
if (!customElements.get("lib-e2e-file-preview")) {
|
|
6834
|
+
customElements.define("lib-e2e-file-preview", FilePreviewElement);
|
|
6044
6835
|
}
|
|
6045
6836
|
|
|
6046
6837
|
// src/components/help-panel/help-panel.styles.ts
|
|
@@ -6136,12 +6927,12 @@ var REFERENCE_SECTIONS = [
|
|
|
6136
6927
|
{ title: "HELP.SEC_PANELS", items: ["HELP.PANEL_TESTS", "HELP.PANEL_COMMANDS", "HELP.PANEL_CONFIG", "HELP.PANEL_FILES"] },
|
|
6137
6928
|
{ title: "HELP.SEC_SELECTOR", items: ["HELP.SELECTOR_1", "HELP.SELECTOR_2"] },
|
|
6138
6929
|
{ title: "HELP.SEC_DATA", items: ["HELP.DATA_1", "HELP.DATA_2"] },
|
|
6139
|
-
{ title: "HELP.SEC_ADVANCED", items: ["HELP.ADV_INVISIBLE", "HELP.ADV_RUNNER", "HELP.ADV_CROSSAPP", "HELP.ADV_DRAG"] }
|
|
6930
|
+
{ title: "HELP.SEC_ADVANCED", items: ["HELP.ADV_INVISIBLE", "HELP.ADV_RUNNER", "HELP.ADV_CROSSAPP", "HELP.ADV_DRAG", "HELP.ADV_LOGIN"] }
|
|
6140
6931
|
];
|
|
6141
6932
|
var GUIDE_SECTIONS = [
|
|
6142
6933
|
{ 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"] },
|
|
6143
|
-
{ 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"] },
|
|
6144
|
-
{ 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"
|
|
6934
|
+
{ 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", "HELP.G_COV_7"] },
|
|
6935
|
+
{ 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"] }
|
|
6145
6936
|
];
|
|
6146
6937
|
function sectionsHtml(sections, t) {
|
|
6147
6938
|
return sections.map(
|
|
@@ -6188,12 +6979,12 @@ var HelpPanelElement = class extends HTMLElement {
|
|
|
6188
6979
|
});
|
|
6189
6980
|
}
|
|
6190
6981
|
};
|
|
6191
|
-
if (!customElements.get("help-panel")) {
|
|
6192
|
-
customElements.define("help-panel", HelpPanelElement);
|
|
6982
|
+
if (!customElements.get("lib-e2e-help-panel")) {
|
|
6983
|
+
customElements.define("lib-e2e-help-panel", HelpPanelElement);
|
|
6193
6984
|
}
|
|
6194
6985
|
|
|
6195
6986
|
// src/components/lib-e2e-recorder/lib-e2e-recorder.ts
|
|
6196
|
-
var
|
|
6987
|
+
var import_sweetalert22 = __toESM(require("sweetalert2"), 1);
|
|
6197
6988
|
|
|
6198
6989
|
// src/components/lib-e2e-recorder/lib-e2e-recorder.styles.ts
|
|
6199
6990
|
var DIRECTIONS = ["up-left", "up-right", "down-left", "down-right"];
|
|
@@ -6394,6 +7185,140 @@ function renderRecorderWidget(rec, paused, t) {
|
|
|
6394
7185
|
<div class="rec-badge">${paused ? t("RECORDER.BADGE_PAUSED") : t("RECORDER.BADGE_REC")}</div>`;
|
|
6395
7186
|
}
|
|
6396
7187
|
|
|
7188
|
+
// src/components/lib-e2e-recorder/assertion-builder.ts
|
|
7189
|
+
init_code_format_utils();
|
|
7190
|
+
var NO_VALUE_ASSERTIONS = /* @__PURE__ */ new Set(["be.visible", "not.exist", "be.disabled", "be.checked"]);
|
|
7191
|
+
function injectAssertionBuilder(container, t, onAddCommand) {
|
|
7192
|
+
container.insertAdjacentHTML("beforeend", `
|
|
7193
|
+
<div id="assertion-builder"
|
|
7194
|
+
style="padding:10px 12px;border-top:1px solid #21262d;background:#0d1117">
|
|
7195
|
+
<div style="font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px">
|
|
7196
|
+
${t("RECORDER.ASSERTION_SECTION")}
|
|
7197
|
+
</div>
|
|
7198
|
+
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end">
|
|
7199
|
+
<input id="assert-selector" type="text"
|
|
7200
|
+
placeholder="${t("RECORDER.ASSERT_SELECTOR_PH").replace(/"/g, """)}"
|
|
7201
|
+
style="flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
7202
|
+
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;
|
|
7203
|
+
font-family:'Cascadia Code','Fira Code',monospace"/>
|
|
7204
|
+
<select id="assert-type"
|
|
7205
|
+
style="padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;
|
|
7206
|
+
color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0">
|
|
7207
|
+
<option value="be.visible">be.visible</option>
|
|
7208
|
+
<option value="not.exist">not.exist</option>
|
|
7209
|
+
<option value="be.disabled">be.disabled</option>
|
|
7210
|
+
<option value="be.checked">be.checked</option>
|
|
7211
|
+
<option value="contain.text">contain.text</option>
|
|
7212
|
+
<option value="have.value">have.value</option>
|
|
7213
|
+
<option value="have.length">have.length</option>
|
|
7214
|
+
<option value="have.class">have.class</option>
|
|
7215
|
+
<option value="have.attr">have.attr</option>
|
|
7216
|
+
</select>
|
|
7217
|
+
<input id="assert-value" type="text" placeholder="${t("RECORDER.ASSERT_VALUE_PH")}"
|
|
7218
|
+
style="flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
7219
|
+
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none"/>
|
|
7220
|
+
<button id="btn-add-assertion"
|
|
7221
|
+
style="padding:5px 12px;border:none;border-radius:5px;cursor:pointer;
|
|
7222
|
+
font-size:11px;font-weight:500;background:#2f81f7;color:#fff;
|
|
7223
|
+
white-space:nowrap;flex-shrink:0">
|
|
7224
|
+
${t("RECORDER.ASSERT_ADD_BTN")}
|
|
7225
|
+
</button>
|
|
7226
|
+
</div>
|
|
7227
|
+
</div>`);
|
|
7228
|
+
document.getElementById("btn-add-assertion")?.addEventListener("click", () => {
|
|
7229
|
+
const sel = document.getElementById("assert-selector").value.trim();
|
|
7230
|
+
const type = document.getElementById("assert-type").value;
|
|
7231
|
+
const val = document.getElementById("assert-value").value.trim();
|
|
7232
|
+
if (!sel) return;
|
|
7233
|
+
const s = escapeSingleQuotes(sel);
|
|
7234
|
+
const v = escapeSingleQuotes(val);
|
|
7235
|
+
const cmd = NO_VALUE_ASSERTIONS.has(type) || !val ? `cy.get('${s}').should('${type}')` : `cy.get('${s}').should('${type}', '${v}')`;
|
|
7236
|
+
onAddCommand(cmd);
|
|
7237
|
+
document.getElementById("assert-selector").value = "";
|
|
7238
|
+
document.getElementById("assert-value").value = "";
|
|
7239
|
+
});
|
|
7240
|
+
}
|
|
7241
|
+
|
|
7242
|
+
// src/components/lib-e2e-recorder/filesystem-setup.ts
|
|
7243
|
+
function mountFilesystemSetupContent(container, t, onSkip, onSelect) {
|
|
7244
|
+
container.innerHTML = `
|
|
7245
|
+
<div style="padding:16px 20px 20px;color:#8b949e;font-size:13px;line-height:1.7">
|
|
7246
|
+
<p>${t("RECORDER.FS_INTRO_HTML")}</p>
|
|
7247
|
+
<p style="margin-top:10px;margin-bottom:6px;font-size:11px;color:#8b949e">
|
|
7248
|
+
${t("RECORDER.FS_STRUCTURE_HINT_HTML")}
|
|
7249
|
+
</p>
|
|
7250
|
+
<pre style="margin:0;padding:10px 14px;background:#0d1117;border:1px solid #21262d;
|
|
7251
|
+
border-radius:8px;font-size:11px;color:#c9d1d9;line-height:1.8;
|
|
7252
|
+
font-family:'Cascadia Code','Fira Code','Consolas',monospace">
|
|
7253
|
+
cypress/ <span style="color:#484f58">${t("RECORDER.FS_TREE_PICK_HINT")}</span>
|
|
7254
|
+
\u2514\u2500\u2500 e2e/ <span style="color:#484f58">${t("RECORDER.FS_TREE_READ_HINT")}</span>
|
|
7255
|
+
\u2514\u2500\u2500 *.cy.ts</pre>
|
|
7256
|
+
<p style="margin-top:8px;font-size:11px;color:#484f58">
|
|
7257
|
+
${t("RECORDER.FS_PERMISSION_NOTE")}
|
|
7258
|
+
</p>
|
|
7259
|
+
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:20px">
|
|
7260
|
+
<button id="fs-skip"
|
|
7261
|
+
style="padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;
|
|
7262
|
+
font-size:12px;font-weight:500;background:transparent;color:#8b949e">
|
|
7263
|
+
${t("RECORDER.FS_LATER_BTN")}
|
|
7264
|
+
</button>
|
|
7265
|
+
<button id="fs-select"
|
|
7266
|
+
style="padding:7px 16px;border:none;border-radius:6px;cursor:pointer;
|
|
7267
|
+
font-size:12px;font-weight:500;background:#2f81f7;color:#fff">
|
|
7268
|
+
${t("RECORDER.FS_SELECT_BTN")}
|
|
7269
|
+
</button>
|
|
7270
|
+
</div>
|
|
7271
|
+
</div>`;
|
|
7272
|
+
document.getElementById("fs-skip")?.addEventListener("click", () => {
|
|
7273
|
+
void onSkip();
|
|
7274
|
+
});
|
|
7275
|
+
document.getElementById("fs-select")?.addEventListener("click", () => {
|
|
7276
|
+
void onSelect();
|
|
7277
|
+
});
|
|
7278
|
+
}
|
|
7279
|
+
|
|
7280
|
+
// src/utils/swal-mount.utils.ts
|
|
7281
|
+
function mountComponentInSwal(tagName, container, props, events) {
|
|
7282
|
+
const el = document.createElement(tagName);
|
|
7283
|
+
Object.assign(el, props);
|
|
7284
|
+
container.appendChild(el);
|
|
7285
|
+
for (const { name, handler } of events ?? []) {
|
|
7286
|
+
el.addEventListener(name, handler);
|
|
7287
|
+
}
|
|
7288
|
+
return el;
|
|
7289
|
+
}
|
|
7290
|
+
|
|
7291
|
+
// src/utils/widget-position.utils.ts
|
|
7292
|
+
var TOGGLE_MARGIN = 30;
|
|
7293
|
+
var DRAG_THRESHOLD = 5;
|
|
7294
|
+
var DEFAULT_EDGE_OFFSET = 46;
|
|
7295
|
+
function boxOffsetForDirection(dir) {
|
|
7296
|
+
return {
|
|
7297
|
+
x: dir.endsWith("left") ? 144 : 46,
|
|
7298
|
+
y: dir.startsWith("up") ? 144 : 46
|
|
7299
|
+
};
|
|
7300
|
+
}
|
|
7301
|
+
function clampTogglePosition(x, y, vw, vh, margin = TOGGLE_MARGIN) {
|
|
7302
|
+
const maxX = Math.max(margin, vw - margin);
|
|
7303
|
+
const maxY = Math.max(margin, vh - margin);
|
|
7304
|
+
return {
|
|
7305
|
+
x: Math.min(Math.max(x, margin), maxX),
|
|
7306
|
+
y: Math.min(Math.max(y, margin), maxY)
|
|
7307
|
+
};
|
|
7308
|
+
}
|
|
7309
|
+
function resolveExpandDirection(x, y, vw, vh) {
|
|
7310
|
+
const vertical = y < vh / 2 ? "down" : "up";
|
|
7311
|
+
const horizontal = x < vw / 2 ? "right" : "left";
|
|
7312
|
+
return `${vertical}-${horizontal}`;
|
|
7313
|
+
}
|
|
7314
|
+
function defaultTogglePosition(vw, vh) {
|
|
7315
|
+
return { x: vw - DEFAULT_EDGE_OFFSET, y: vh - DEFAULT_EDGE_OFFSET };
|
|
7316
|
+
}
|
|
7317
|
+
function boxTopLeftFor(toggleCentre, dir) {
|
|
7318
|
+
const off = boxOffsetForDirection(dir);
|
|
7319
|
+
return { x: toggleCentre.x - off.x, y: toggleCentre.y - off.y };
|
|
7320
|
+
}
|
|
7321
|
+
|
|
6397
7322
|
// src/utils/fixture-convert.utils.ts
|
|
6398
7323
|
function toFixtureInterceptors(interceptors, fixtures) {
|
|
6399
7324
|
const fixtureNames = new Set(fixtures.map((f) => f.name));
|
|
@@ -6513,6 +7438,10 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6513
7438
|
this.recording.destroy();
|
|
6514
7439
|
this._needsRecordingRebuild = true;
|
|
6515
7440
|
}
|
|
7441
|
+
// HttpMonitor reads extendedHttpCommands and fixtureMode synchronously inside
|
|
7442
|
+
// fetch/XHR interception handlers, so they must live in localStorage (sync).
|
|
7443
|
+
// IndexedDB is the persistent source of truth; this method mirrors it into
|
|
7444
|
+
// localStorage on every mount so the sync cache is always fresh.
|
|
6516
7445
|
async initHttpConfig() {
|
|
6517
7446
|
const config = await this.persistence.getConfig("extendedHttpCommands");
|
|
6518
7447
|
if (config === null) {
|
|
@@ -6560,9 +7489,9 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6560
7489
|
}
|
|
6561
7490
|
showSelectorPicker(target) {
|
|
6562
7491
|
Promise.resolve().then(() => (init_selector_picker(), selector_picker_exports)).then(() => {
|
|
6563
|
-
const existing = document.querySelector("selector-picker");
|
|
7492
|
+
const existing = document.querySelector("lib-e2e-selector-picker");
|
|
6564
7493
|
if (existing) existing.remove();
|
|
6565
|
-
const picker = document.createElement("selector-picker");
|
|
7494
|
+
const picker = document.createElement("lib-e2e-selector-picker");
|
|
6566
7495
|
picker.targetElement = target;
|
|
6567
7496
|
picker.recording = this.recording;
|
|
6568
7497
|
picker.translation = this.translation;
|
|
@@ -6624,7 +7553,7 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6624
7553
|
}
|
|
6625
7554
|
async promptResumeOrDiscard(session) {
|
|
6626
7555
|
const t = this.translation.translate.bind(this.translation);
|
|
6627
|
-
const result = await
|
|
7556
|
+
const result = await import_sweetalert22.default.fire({
|
|
6628
7557
|
title: t("RECORDER.SESSION_RESUME_TITLE"),
|
|
6629
7558
|
html: `<div style="padding:8px 4px;color:#8b949e;font-size:13px;line-height:1.6"><p>${t("RECORDER.SESSION_RESUME_TEXT")}</p><p style="margin-top:6px;color:#c9d1d9"><b>${session.commands.length}</b> ${t("RECORDER.SESSION_RESUME_COUNT")}</p></div>`,
|
|
6630
7559
|
showCancelButton: true,
|
|
@@ -6843,8 +7772,9 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6843
7772
|
this.showFilesystemSetupDialog();
|
|
6844
7773
|
}
|
|
6845
7774
|
showFilesystemSetupDialog() {
|
|
6846
|
-
|
|
6847
|
-
|
|
7775
|
+
const t = this.translation.translate.bind(this.translation);
|
|
7776
|
+
import_sweetalert22.default.fire({
|
|
7777
|
+
title: t("RECORDER.FS_TITLE"),
|
|
6848
7778
|
html: '<div id="fs-setup-content"></div>',
|
|
6849
7779
|
showCloseButton: true,
|
|
6850
7780
|
showConfirmButton: false,
|
|
@@ -6853,277 +7783,171 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6853
7783
|
setSwal2DataCyAttribute();
|
|
6854
7784
|
const container = document.getElementById("fs-setup-content");
|
|
6855
7785
|
if (!container) return;
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
<button id="fs-skip"
|
|
6873
|
-
style="padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;
|
|
6874
|
-
font-size:12px;font-weight:500;background:transparent;color:#8b949e">
|
|
6875
|
-
${this.translation.translate("RECORDER.FS_LATER_BTN")}
|
|
6876
|
-
</button>
|
|
6877
|
-
<button id="fs-select"
|
|
6878
|
-
style="padding:7px 16px;border:none;border-radius:6px;cursor:pointer;
|
|
6879
|
-
font-size:12px;font-weight:500;background:#2f81f7;color:#fff">
|
|
6880
|
-
${this.translation.translate("RECORDER.FS_SELECT_BTN")}
|
|
6881
|
-
</button>
|
|
6882
|
-
</div>
|
|
6883
|
-
</div>`;
|
|
6884
|
-
document.getElementById("fs-skip")?.addEventListener("click", async () => {
|
|
6885
|
-
await this.persistence.setConfigKey("allowReadWriteFiles", "false");
|
|
6886
|
-
import_sweetalert2.default.close();
|
|
6887
|
-
});
|
|
6888
|
-
document.getElementById("fs-select")?.addEventListener("click", async () => {
|
|
6889
|
-
try {
|
|
6890
|
-
await this.persistence.requestDirectoryPermissions();
|
|
6891
|
-
import_sweetalert2.default.close();
|
|
6892
|
-
showToast(this.translation.translate("RECORDER.FS_SUCCESS_TOAST"));
|
|
6893
|
-
} catch (e) {
|
|
6894
|
-
if (e?.name !== "AbortError") {
|
|
6895
|
-
showToast(this.translation.translate("RECORDER.FS_ERROR_TOAST"), false);
|
|
7786
|
+
mountFilesystemSetupContent(
|
|
7787
|
+
container,
|
|
7788
|
+
t,
|
|
7789
|
+
async () => {
|
|
7790
|
+
await this.persistence.setConfigKey("allowReadWriteFiles", "false");
|
|
7791
|
+
import_sweetalert22.default.close();
|
|
7792
|
+
},
|
|
7793
|
+
async () => {
|
|
7794
|
+
try {
|
|
7795
|
+
await this.persistence.requestDirectoryPermissions();
|
|
7796
|
+
import_sweetalert22.default.close();
|
|
7797
|
+
showToast(t("RECORDER.FS_SUCCESS_TOAST"));
|
|
7798
|
+
} catch (e) {
|
|
7799
|
+
if (e?.name !== "AbortError") {
|
|
7800
|
+
showToast(t("RECORDER.FS_ERROR_TOAST"), false);
|
|
7801
|
+
}
|
|
6896
7802
|
}
|
|
6897
7803
|
}
|
|
6898
|
-
|
|
7804
|
+
);
|
|
6899
7805
|
}
|
|
6900
7806
|
});
|
|
6901
7807
|
}
|
|
6902
7808
|
// ── dialogs ──────────────────────────────────────────────────────────────
|
|
6903
7809
|
showCommandsDialog() {
|
|
6904
|
-
this.
|
|
6905
|
-
|
|
7810
|
+
this.openSwalDialog(
|
|
7811
|
+
"isCommandsDialogOpen",
|
|
7812
|
+
"commands-modal-content",
|
|
7813
|
+
{
|
|
6906
7814
|
title: this.translation.translate("MAIN_FRAME.DIALOG_COMMANDS"),
|
|
6907
7815
|
html: '<div id="commands-modal-content" style="min-height:250px;padding:0"></div>',
|
|
6908
7816
|
showCloseButton: true,
|
|
6909
|
-
showConfirmButton: false,
|
|
6910
7817
|
allowOutsideClick: false,
|
|
6911
7818
|
backdrop: false,
|
|
6912
|
-
width: 640
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
7819
|
+
width: 640
|
|
7820
|
+
},
|
|
7821
|
+
(container) => {
|
|
7822
|
+
const child = mountComponentInSwal("lib-e2e-test-previsualizer", container, {
|
|
7823
|
+
translation: this.translation,
|
|
7824
|
+
commands: this.cypressCommands,
|
|
7825
|
+
interceptors: this.interceptors,
|
|
7826
|
+
editable: true
|
|
7827
|
+
}, [
|
|
7828
|
+
{ name: "deletecommand", handler: (e) => this.recording.removeCommand(e.detail) },
|
|
7829
|
+
{ name: "movecommand", handler: (e) => this.recording.moveCommand(e.detail.from, e.detail.to) },
|
|
7830
|
+
{ name: "deleteinterceptor", handler: (e) => this.recording.removeInterceptor(e.detail) }
|
|
7831
|
+
]);
|
|
7832
|
+
this._previsualizerRef = child;
|
|
7833
|
+
injectAssertionBuilder(container, this.translation.translate.bind(this.translation), (cmd) => this.recording.appendCommand(cmd));
|
|
7834
|
+
},
|
|
7835
|
+
{
|
|
7836
|
+
// Make the container click-through so the page underneath remains interactive
|
|
7837
|
+
onDidOpenPreamble: () => {
|
|
6917
7838
|
const swalContainer = document.querySelector(".swal2-container");
|
|
6918
7839
|
if (swalContainer) {
|
|
6919
7840
|
swalContainer.style.pointerEvents = "none";
|
|
6920
7841
|
const popup = swalContainer.querySelector(".swal2-popup");
|
|
6921
7842
|
if (popup) popup.style.pointerEvents = "all";
|
|
6922
7843
|
}
|
|
6923
|
-
const container = document.getElementById("commands-modal-content");
|
|
6924
|
-
if (!container) return;
|
|
6925
|
-
const child = document.createElement("test-previsualizer");
|
|
6926
|
-
child.translation = this.translation;
|
|
6927
|
-
child.commands = this.cypressCommands;
|
|
6928
|
-
child.interceptors = this.interceptors;
|
|
6929
|
-
child.editable = true;
|
|
6930
|
-
container.appendChild(child);
|
|
6931
|
-
this._previsualizerRef = child;
|
|
6932
|
-
child.addEventListener("deletecommand", (e) => {
|
|
6933
|
-
this.recording.removeCommand(e.detail);
|
|
6934
|
-
});
|
|
6935
|
-
child.addEventListener("movecommand", (e) => {
|
|
6936
|
-
this.recording.moveCommand(e.detail.from, e.detail.to);
|
|
6937
|
-
});
|
|
6938
|
-
child.addEventListener("deleteinterceptor", (e) => {
|
|
6939
|
-
this.recording.removeInterceptor(e.detail);
|
|
6940
|
-
});
|
|
6941
|
-
const assertionHtml = `
|
|
6942
|
-
<div id="assertion-builder"
|
|
6943
|
-
style="padding:10px 12px;border-top:1px solid #21262d;background:#0d1117">
|
|
6944
|
-
<div style="font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px">
|
|
6945
|
-
${this.translation.translate("RECORDER.ASSERTION_SECTION")}
|
|
6946
|
-
</div>
|
|
6947
|
-
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end">
|
|
6948
|
-
<input id="assert-selector" type="text"
|
|
6949
|
-
placeholder="${this.translation.translate("RECORDER.ASSERT_SELECTOR_PH").replace(/"/g, """)}"
|
|
6950
|
-
style="flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
6951
|
-
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;
|
|
6952
|
-
font-family:'Cascadia Code','Fira Code',monospace"/>
|
|
6953
|
-
<select id="assert-type"
|
|
6954
|
-
style="padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;
|
|
6955
|
-
color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0">
|
|
6956
|
-
<option value="be.visible">be.visible</option>
|
|
6957
|
-
<option value="not.exist">not.exist</option>
|
|
6958
|
-
<option value="be.disabled">be.disabled</option>
|
|
6959
|
-
<option value="be.checked">be.checked</option>
|
|
6960
|
-
<option value="contain.text">contain.text</option>
|
|
6961
|
-
<option value="have.value">have.value</option>
|
|
6962
|
-
<option value="have.length">have.length</option>
|
|
6963
|
-
<option value="have.class">have.class</option>
|
|
6964
|
-
<option value="have.attr">have.attr</option>
|
|
6965
|
-
</select>
|
|
6966
|
-
<input id="assert-value" type="text" placeholder="${this.translation.translate("RECORDER.ASSERT_VALUE_PH")}"
|
|
6967
|
-
style="flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
6968
|
-
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none"/>
|
|
6969
|
-
<button id="btn-add-assertion"
|
|
6970
|
-
style="padding:5px 12px;border:none;border-radius:5px;cursor:pointer;
|
|
6971
|
-
font-size:11px;font-weight:500;background:#2f81f7;color:#fff;
|
|
6972
|
-
white-space:nowrap;flex-shrink:0">
|
|
6973
|
-
${this.translation.translate("RECORDER.ASSERT_ADD_BTN")}
|
|
6974
|
-
</button>
|
|
6975
|
-
</div>
|
|
6976
|
-
</div>`;
|
|
6977
|
-
container.insertAdjacentHTML("beforeend", assertionHtml);
|
|
6978
|
-
const NO_VALUE_ASSERTIONS = /* @__PURE__ */ new Set(["be.visible", "not.exist", "be.disabled", "be.checked"]);
|
|
6979
|
-
document.getElementById("btn-add-assertion")?.addEventListener("click", () => {
|
|
6980
|
-
const sel = document.getElementById("assert-selector").value.trim();
|
|
6981
|
-
const type = document.getElementById("assert-type").value;
|
|
6982
|
-
const val = document.getElementById("assert-value").value.trim();
|
|
6983
|
-
if (!sel) return;
|
|
6984
|
-
const s = escapeSingleQuotes(sel);
|
|
6985
|
-
const v = escapeSingleQuotes(val);
|
|
6986
|
-
const cmd = NO_VALUE_ASSERTIONS.has(type) || !val ? `cy.get('${s}').should('${type}')` : `cy.get('${s}').should('${type}', '${v}')`;
|
|
6987
|
-
this.recording.appendCommand(cmd);
|
|
6988
|
-
document.getElementById("assert-selector").value = "";
|
|
6989
|
-
document.getElementById("assert-value").value = "";
|
|
6990
|
-
});
|
|
6991
7844
|
},
|
|
6992
|
-
|
|
6993
|
-
this.isCommandsDialogOpen = false;
|
|
7845
|
+
onWillClose: () => {
|
|
6994
7846
|
this._previsualizerRef = null;
|
|
6995
7847
|
}
|
|
6996
|
-
}
|
|
6997
|
-
|
|
6998
|
-
});
|
|
7848
|
+
}
|
|
7849
|
+
);
|
|
6999
7850
|
}
|
|
7000
7851
|
showSavedTestsDialog() {
|
|
7001
|
-
this.
|
|
7002
|
-
|
|
7852
|
+
this.openSwalDialog(
|
|
7853
|
+
"isSavedTestsDialogOpen",
|
|
7854
|
+
"saved-tests-modal-content",
|
|
7855
|
+
{
|
|
7003
7856
|
title: this.translation.translate("MAIN_FRAME.DIALOG_SAVED_TESTS"),
|
|
7004
7857
|
html: '<div id="saved-tests-modal-content" style="min-height:250px;padding:0"></div>',
|
|
7005
7858
|
showCloseButton: true,
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
child.translation = this.translation;
|
|
7017
|
-
child.issueTrackerConfig = this.issueTrackerConfig;
|
|
7018
|
-
container.appendChild(child);
|
|
7019
|
-
},
|
|
7020
|
-
willClose: () => {
|
|
7021
|
-
this.isSavedTestsDialogOpen = false;
|
|
7022
|
-
}
|
|
7023
|
-
});
|
|
7024
|
-
this.resizePopup();
|
|
7025
|
-
});
|
|
7859
|
+
width: 680
|
|
7860
|
+
},
|
|
7861
|
+
(container) => {
|
|
7862
|
+
mountComponentInSwal("lib-e2e-test-editor", container, {
|
|
7863
|
+
persistence: this.persistence,
|
|
7864
|
+
translation: this.translation,
|
|
7865
|
+
issueTrackerConfig: this.issueTrackerConfig
|
|
7866
|
+
});
|
|
7867
|
+
}
|
|
7868
|
+
);
|
|
7026
7869
|
}
|
|
7027
7870
|
showSaveTestDialog() {
|
|
7028
|
-
this.
|
|
7029
|
-
|
|
7871
|
+
this.openSwalDialog(
|
|
7872
|
+
"isSaveTestDialogOpen",
|
|
7873
|
+
"save-test-modal-content",
|
|
7874
|
+
{
|
|
7030
7875
|
title: this.translation.translate("MAIN_FRAME.DIALOG_SAVE"),
|
|
7031
7876
|
html: '<div id="save-test-modal-content" style="padding:0"></div>',
|
|
7032
|
-
showCloseButton:
|
|
7033
|
-
showConfirmButton: false,
|
|
7877
|
+
showCloseButton: false,
|
|
7034
7878
|
allowOutsideClick: false,
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
child.issueTrackerConfig = this.issueTrackerConfig;
|
|
7044
|
-
container.appendChild(child);
|
|
7045
|
-
child.addEventListener("savetest", (e) => {
|
|
7879
|
+
allowEscapeKey: false
|
|
7880
|
+
},
|
|
7881
|
+
(container) => {
|
|
7882
|
+
mountComponentInSwal("lib-e2e-save-test", container, {
|
|
7883
|
+
translation: this.translation,
|
|
7884
|
+
issueTrackerConfig: this.issueTrackerConfig
|
|
7885
|
+
}, [
|
|
7886
|
+
{ name: "savetest", handler: (e) => {
|
|
7046
7887
|
const { description, notes, tags, ticketId } = e.detail ?? {};
|
|
7047
7888
|
this.onSaveTest(description ?? null, tags ?? [], notes ?? "", ticketId ?? "");
|
|
7048
|
-
|
|
7049
|
-
}
|
|
7050
|
-
|
|
7889
|
+
import_sweetalert22.default.close();
|
|
7890
|
+
} },
|
|
7891
|
+
{ name: "saveandexport", handler: (e) => {
|
|
7051
7892
|
const { description, notes, tags, ticketId } = e.detail ?? {};
|
|
7052
7893
|
this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? "", ticketId ?? "");
|
|
7053
|
-
|
|
7054
|
-
}
|
|
7055
|
-
|
|
7056
|
-
|
|
7057
|
-
|
|
7058
|
-
|
|
7059
|
-
});
|
|
7060
|
-
});
|
|
7894
|
+
import_sweetalert22.default.close();
|
|
7895
|
+
} }
|
|
7896
|
+
]);
|
|
7897
|
+
},
|
|
7898
|
+
{ skipResize: true }
|
|
7899
|
+
);
|
|
7061
7900
|
}
|
|
7062
7901
|
showSettingsDialog() {
|
|
7063
|
-
this.
|
|
7064
|
-
|
|
7902
|
+
this.openSwalDialog(
|
|
7903
|
+
"isSettingsDialogOpen",
|
|
7904
|
+
"settings-modal-content",
|
|
7905
|
+
{
|
|
7065
7906
|
title: this.translation.translate("MAIN_FRAME.SETTINGS"),
|
|
7066
7907
|
html: '<div id="settings-modal-content" style="padding:0"></div>',
|
|
7067
7908
|
showCloseButton: true,
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7075
|
-
|
|
7076
|
-
const child = document.createElement("e2e-configuration");
|
|
7077
|
-
child.persistence = this.persistence;
|
|
7078
|
-
child.translation = this.translation;
|
|
7079
|
-
container.appendChild(child);
|
|
7080
|
-
child.addEventListener("smartselectorchange", (e) => {
|
|
7909
|
+
width: 520
|
|
7910
|
+
},
|
|
7911
|
+
(container) => {
|
|
7912
|
+
mountComponentInSwal("lib-e2e-configuration", container, {
|
|
7913
|
+
persistence: this.persistence,
|
|
7914
|
+
translation: this.translation
|
|
7915
|
+
}, [
|
|
7916
|
+
{ name: "smartselectorchange", handler: (e) => {
|
|
7081
7917
|
this.smartSelectorEnabled = e.detail;
|
|
7082
|
-
}
|
|
7083
|
-
|
|
7918
|
+
} },
|
|
7919
|
+
{ name: "starthiddenchange", handler: (e) => {
|
|
7084
7920
|
this.isVisible = !e.detail;
|
|
7085
7921
|
this.style.display = this.isVisible ? "" : "none";
|
|
7086
|
-
}
|
|
7087
|
-
|
|
7088
|
-
|
|
7922
|
+
} },
|
|
7923
|
+
{ name: "resetwidgetposition", handler: () => this.resetWidgetPosition() },
|
|
7924
|
+
{ name: "issuetrackerchange", handler: (e) => {
|
|
7089
7925
|
this.issueTrackerConfig = e.detail;
|
|
7090
|
-
}
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
}
|
|
7095
|
-
});
|
|
7096
|
-
this.resizePopup();
|
|
7097
|
-
});
|
|
7926
|
+
} }
|
|
7927
|
+
]);
|
|
7928
|
+
}
|
|
7929
|
+
);
|
|
7098
7930
|
}
|
|
7099
7931
|
showHelpDialog() {
|
|
7100
|
-
this.
|
|
7101
|
-
|
|
7932
|
+
this.openSwalDialog(
|
|
7933
|
+
"isHelpDialogOpen",
|
|
7934
|
+
"help-modal-content",
|
|
7935
|
+
{
|
|
7102
7936
|
title: this.translation.translate("HELP.TITLE"),
|
|
7103
7937
|
html: '<div id="help-modal-content" style="padding:0"></div>',
|
|
7104
7938
|
showCloseButton: true,
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
const child = document.createElement("help-panel");
|
|
7114
|
-
child.translation = this.translation;
|
|
7115
|
-
container.appendChild(child);
|
|
7116
|
-
},
|
|
7117
|
-
willClose: () => {
|
|
7118
|
-
this.isHelpDialogOpen = false;
|
|
7119
|
-
}
|
|
7120
|
-
});
|
|
7121
|
-
this.resizePopup();
|
|
7122
|
-
});
|
|
7939
|
+
width: 560
|
|
7940
|
+
},
|
|
7941
|
+
(container) => {
|
|
7942
|
+
mountComponentInSwal("lib-e2e-help-panel", container, {
|
|
7943
|
+
translation: this.translation
|
|
7944
|
+
});
|
|
7945
|
+
}
|
|
7946
|
+
);
|
|
7123
7947
|
}
|
|
7124
7948
|
showAdvancedEditorDialog(testId) {
|
|
7125
7949
|
this.toggleModal("isAdvancedEditorDialogOpen", () => {
|
|
7126
|
-
|
|
7950
|
+
import_sweetalert22.default.fire({
|
|
7127
7951
|
title: this.translation.translate("MAIN_FRAME.SHOW_ADVANCED_EDITOR"),
|
|
7128
7952
|
html: '<div id="advanced-editor-modal-content" style="flex:1;min-height:0;display:flex;flex-direction:column;padding:0"></div>',
|
|
7129
7953
|
showCloseButton: true,
|
|
@@ -7134,42 +7958,33 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7134
7958
|
didOpen: () => {
|
|
7135
7959
|
makeSwalDraggable();
|
|
7136
7960
|
setSwal2DataCyAttribute();
|
|
7137
|
-
|
|
7138
|
-
if (popup) {
|
|
7139
|
-
popup.style.height = "600px";
|
|
7140
|
-
const htmlContainer = popup.querySelector(".swal2-html-container");
|
|
7141
|
-
if (htmlContainer) {
|
|
7142
|
-
htmlContainer.style.flex = "1";
|
|
7143
|
-
htmlContainer.style.minHeight = "0";
|
|
7144
|
-
htmlContainer.style.overflow = "hidden";
|
|
7145
|
-
htmlContainer.style.padding = "0";
|
|
7146
|
-
htmlContainer.style.margin = "0";
|
|
7147
|
-
htmlContainer.style.display = "flex";
|
|
7148
|
-
htmlContainer.style.flexDirection = "column";
|
|
7149
|
-
}
|
|
7150
|
-
}
|
|
7961
|
+
ensurePopupDimensions(import_sweetalert22.default.getPopup(), 600);
|
|
7151
7962
|
const container = document.getElementById("advanced-editor-modal-content");
|
|
7152
7963
|
if (!container) return;
|
|
7153
|
-
const child =
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7964
|
+
const child = mountComponentInSwal("lib-e2e-advanced-test-editor", container, {
|
|
7965
|
+
persistence: this.persistence,
|
|
7966
|
+
translation: this.translation,
|
|
7967
|
+
...testId !== void 0 ? { testId } : {}
|
|
7968
|
+
}, [
|
|
7969
|
+
{ name: "selectorstrategychange", handler: (e) => {
|
|
7970
|
+
this.recording.selectorStrategy = e.detail;
|
|
7971
|
+
} },
|
|
7972
|
+
{ name: "closemodal", handler: () => import_sweetalert22.default.close() },
|
|
7973
|
+
{ name: "openfileeditor", handler: (e) => {
|
|
7974
|
+
import_sweetalert22.default.close();
|
|
7975
|
+
setTimeout(() => this.showFileEditorDialog(
|
|
7976
|
+
e.detail.handle,
|
|
7977
|
+
e.detail.content,
|
|
7978
|
+
e.detail.fileName,
|
|
7979
|
+
e.detail.testId,
|
|
7980
|
+
e.detail.itBlock,
|
|
7981
|
+
e.detail.interceptorsBlock,
|
|
7982
|
+
e.detail.notes
|
|
7983
|
+
), 150);
|
|
7984
|
+
} }
|
|
7985
|
+
]);
|
|
7986
|
+
void this.persistence.getLoginSetup().then((cfg) => {
|
|
7987
|
+
child.loginSetupConfig = cfg;
|
|
7173
7988
|
});
|
|
7174
7989
|
},
|
|
7175
7990
|
willClose: () => {
|
|
@@ -7177,13 +7992,13 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7177
7992
|
}
|
|
7178
7993
|
});
|
|
7179
7994
|
setTimeout(() => {
|
|
7180
|
-
const popup =
|
|
7995
|
+
const popup = import_sweetalert22.default.getPopup();
|
|
7181
7996
|
if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 0 });
|
|
7182
7997
|
}, 0);
|
|
7183
7998
|
});
|
|
7184
7999
|
}
|
|
7185
8000
|
showFileEditorDialog(handle, content, fileName, testId, itBlock = "", interceptorsBlock = "", notes = "") {
|
|
7186
|
-
|
|
8001
|
+
import_sweetalert22.default.fire({
|
|
7187
8002
|
title: this.translation.translate("RECORDER.FILE_EDITOR_TITLE"),
|
|
7188
8003
|
html: '<div id="file-editor-modal-content" style="flex:1;min-height:0;display:flex;flex-direction:column;padding:0"></div>',
|
|
7189
8004
|
showCloseButton: false,
|
|
@@ -7194,47 +8009,35 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7194
8009
|
didOpen: () => {
|
|
7195
8010
|
makeSwalDraggable();
|
|
7196
8011
|
setSwal2DataCyAttribute();
|
|
7197
|
-
|
|
7198
|
-
if (popup) {
|
|
7199
|
-
popup.style.height = "640px";
|
|
7200
|
-
const htmlContainer = popup.querySelector(".swal2-html-container");
|
|
7201
|
-
if (htmlContainer) {
|
|
7202
|
-
htmlContainer.style.flex = "1";
|
|
7203
|
-
htmlContainer.style.minHeight = "0";
|
|
7204
|
-
htmlContainer.style.overflow = "hidden";
|
|
7205
|
-
htmlContainer.style.padding = "0";
|
|
7206
|
-
htmlContainer.style.margin = "0";
|
|
7207
|
-
htmlContainer.style.display = "flex";
|
|
7208
|
-
htmlContainer.style.flexDirection = "column";
|
|
7209
|
-
}
|
|
7210
|
-
}
|
|
8012
|
+
ensurePopupDimensions(import_sweetalert22.default.getPopup(), 640);
|
|
7211
8013
|
const container = document.getElementById("file-editor-modal-content");
|
|
7212
8014
|
if (!container) return;
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
8015
|
+
mountComponentInSwal("lib-e2e-file-preview", container, {
|
|
8016
|
+
translation: this.translation,
|
|
8017
|
+
fileContent: content,
|
|
8018
|
+
fileName,
|
|
8019
|
+
closeLabel: this.translation.translate("FILE_PREVIEW.BACK_TO_EDITOR"),
|
|
8020
|
+
itBlock,
|
|
8021
|
+
interceptorsBlock,
|
|
8022
|
+
notes
|
|
8023
|
+
}, [
|
|
8024
|
+
{ name: "close", handler: () => {
|
|
8025
|
+
import_sweetalert22.default.close();
|
|
8026
|
+
setTimeout(() => this.showAdvancedEditorDialog(testId), 150);
|
|
8027
|
+
} },
|
|
8028
|
+
{ name: "save", handler: async (e) => {
|
|
8029
|
+
try {
|
|
8030
|
+
const writable = await handle.createWritable();
|
|
8031
|
+
await writable.write(e.detail);
|
|
8032
|
+
await writable.close();
|
|
8033
|
+
showToast(this.translation.translate("RECORDER.FILE_SAVED_TOAST"));
|
|
8034
|
+
} catch {
|
|
8035
|
+
showToast(this.translation.translate("RECORDER.FILE_SAVE_ERROR_TOAST"), false);
|
|
8036
|
+
}
|
|
8037
|
+
import_sweetalert22.default.close();
|
|
8038
|
+
setTimeout(() => this.showAdvancedEditorDialog(testId), 150);
|
|
8039
|
+
} }
|
|
8040
|
+
]);
|
|
7238
8041
|
}
|
|
7239
8042
|
});
|
|
7240
8043
|
this.resizePopup();
|
|
@@ -7243,6 +8046,14 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7243
8046
|
async onSaveTest(description, tags = [], notes = "", ticketId = "") {
|
|
7244
8047
|
if (!description) return;
|
|
7245
8048
|
await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes, ticketId || void 0);
|
|
8049
|
+
const uploadedFiles = this.recording.getUploadedFilesSnapshot();
|
|
8050
|
+
if (uploadedFiles.length > 0) {
|
|
8051
|
+
const filenames = uploadedFiles.map((f) => f.filename).join(", ");
|
|
8052
|
+
showToast(
|
|
8053
|
+
this.translation.translate("RECORDER.FILE_UPLOAD_MANUAL_TOAST").replace("{files}", filenames),
|
|
8054
|
+
false
|
|
8055
|
+
);
|
|
8056
|
+
}
|
|
7246
8057
|
this.recording.clearCommands();
|
|
7247
8058
|
this.clearRecordingHistory();
|
|
7248
8059
|
this.cypressCommands = [];
|
|
@@ -7264,6 +8075,29 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7264
8075
|
showToast(this.translation.translate("RECORDER.FIXTURES_NO_FOLDER_TOAST"), false);
|
|
7265
8076
|
}
|
|
7266
8077
|
}
|
|
8078
|
+
const uploadedFiles = this.recording.getUploadedFilesSnapshot();
|
|
8079
|
+
if (uploadedFiles.length > 0) {
|
|
8080
|
+
const filenames = uploadedFiles.map((f) => f.filename).join(", ");
|
|
8081
|
+
const hasAccess = await this.persistence.hasDirectoryAccess();
|
|
8082
|
+
if (hasAccess) {
|
|
8083
|
+
try {
|
|
8084
|
+
for (const uf of uploadedFiles) {
|
|
8085
|
+
await this.persistence.writeUploadedFile(uf.filename, uf.bytes);
|
|
8086
|
+
}
|
|
8087
|
+
showToast(this.translation.translate("RECORDER.FILE_UPLOAD_COPIED_TOAST").replace("{files}", filenames));
|
|
8088
|
+
} catch {
|
|
8089
|
+
showToast(
|
|
8090
|
+
this.translation.translate("RECORDER.FILE_UPLOAD_COPY_ERROR_TOAST").replace("{files}", filenames),
|
|
8091
|
+
false
|
|
8092
|
+
);
|
|
8093
|
+
}
|
|
8094
|
+
} else {
|
|
8095
|
+
showToast(
|
|
8096
|
+
this.translation.translate("RECORDER.FILE_UPLOAD_MANUAL_TOAST").replace("{files}", filenames),
|
|
8097
|
+
false
|
|
8098
|
+
);
|
|
8099
|
+
}
|
|
8100
|
+
}
|
|
7267
8101
|
const id = await this.persistence.insertTest(description, finalCommands, finalInterceptors, tags, notes, ticketId || void 0);
|
|
7268
8102
|
this.recording.clearCommands();
|
|
7269
8103
|
this.clearRecordingHistory();
|
|
@@ -7274,7 +8108,7 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7274
8108
|
// ── helpers ───────────────────────────────────────────────────────────────
|
|
7275
8109
|
toggleModal(flag, openFn) {
|
|
7276
8110
|
if (this[flag]) {
|
|
7277
|
-
|
|
8111
|
+
import_sweetalert22.default.close();
|
|
7278
8112
|
this[flag] = false;
|
|
7279
8113
|
return;
|
|
7280
8114
|
}
|
|
@@ -7283,10 +8117,32 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7283
8117
|
}
|
|
7284
8118
|
resizePopup() {
|
|
7285
8119
|
setTimeout(() => {
|
|
7286
|
-
const popup =
|
|
8120
|
+
const popup = import_sweetalert22.default.getPopup();
|
|
7287
8121
|
if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 200 });
|
|
7288
8122
|
}, 0);
|
|
7289
8123
|
}
|
|
8124
|
+
openSwalDialog(flag, contentId, swalOptions, onMount, extra) {
|
|
8125
|
+
this.toggleModal(flag, () => {
|
|
8126
|
+
import_sweetalert22.default.fire({
|
|
8127
|
+
showConfirmButton: false,
|
|
8128
|
+
color: "#e6edf3",
|
|
8129
|
+
...swalOptions,
|
|
8130
|
+
didOpen: () => {
|
|
8131
|
+
makeSwalDraggable();
|
|
8132
|
+
setSwal2DataCyAttribute();
|
|
8133
|
+
extra?.onDidOpenPreamble?.();
|
|
8134
|
+
const container = document.getElementById(contentId);
|
|
8135
|
+
if (!container) return;
|
|
8136
|
+
onMount(container);
|
|
8137
|
+
},
|
|
8138
|
+
willClose: () => {
|
|
8139
|
+
this[flag] = false;
|
|
8140
|
+
extra?.onWillClose?.();
|
|
8141
|
+
}
|
|
8142
|
+
});
|
|
8143
|
+
if (!extra?.skipResize) this.resizePopup();
|
|
8144
|
+
});
|
|
8145
|
+
}
|
|
7290
8146
|
render() {
|
|
7291
8147
|
const rec = this.isRecording;
|
|
7292
8148
|
const paused = this.isPaused;
|
|
@@ -7315,17 +8171,14 @@ if (!customElements.get("lib-e2e-recorder")) {
|
|
|
7315
8171
|
}
|
|
7316
8172
|
|
|
7317
8173
|
// src/index.ts
|
|
7318
|
-
var VERSION = "0.
|
|
8174
|
+
var VERSION = "1.0.0";
|
|
7319
8175
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7320
8176
|
0 && (module.exports = {
|
|
7321
|
-
ACTIVE_SESSION_BREADCRUMB_KEY,
|
|
7322
8177
|
AdvancedTestEditorElement,
|
|
7323
8178
|
AdvancedTestTransformationService,
|
|
7324
8179
|
ConfigurationElement,
|
|
7325
8180
|
DB_SCHEMA,
|
|
7326
8181
|
DB_STORE_NAMES,
|
|
7327
|
-
DEFAULT_RESUME_TTL_MINUTES,
|
|
7328
|
-
DRAG_THRESHOLD,
|
|
7329
8182
|
FilePreviewElement,
|
|
7330
8183
|
HelpPanelElement,
|
|
7331
8184
|
HttpMonitor,
|
|
@@ -7334,24 +8187,16 @@ var VERSION = "0.9.0";
|
|
|
7334
8187
|
LOCALE_BY_LANG,
|
|
7335
8188
|
LibE2eRecorderElement,
|
|
7336
8189
|
PersistenceService,
|
|
7337
|
-
RESUME_TTL_CONFIG_KEY,
|
|
7338
8190
|
RecordingService,
|
|
7339
8191
|
SCROLLBAR_STYLES,
|
|
7340
8192
|
SUPPORTED_LANGS,
|
|
7341
8193
|
SaveTestElement,
|
|
7342
8194
|
SelectorPickerElement,
|
|
7343
|
-
Subject,
|
|
7344
|
-
TOGGLE_MARGIN,
|
|
7345
8195
|
TestEditorElement,
|
|
7346
8196
|
TestPrevisualizerElement,
|
|
7347
8197
|
TransformationService,
|
|
7348
8198
|
TranslationService,
|
|
7349
8199
|
VERSION,
|
|
7350
|
-
advancedTestTransformationService,
|
|
7351
|
-
boxOffsetForDirection,
|
|
7352
|
-
boxTopLeftFor,
|
|
7353
|
-
clampTogglePosition,
|
|
7354
|
-
defaultTogglePosition,
|
|
7355
8200
|
generateAlias,
|
|
7356
8201
|
inferAssertionCommand,
|
|
7357
8202
|
injectStyles,
|
|
@@ -7360,13 +8205,7 @@ var VERSION = "0.9.0";
|
|
|
7360
8205
|
localeForLang,
|
|
7361
8206
|
makeModalResizable,
|
|
7362
8207
|
makeSwalDraggable,
|
|
7363
|
-
makeSwalDraggableByContentId,
|
|
7364
|
-
persistenceService,
|
|
7365
|
-
resolveExpandDirection,
|
|
7366
8208
|
selectTestsForExport,
|
|
7367
|
-
|
|
7368
|
-
showToast,
|
|
7369
|
-
transformationService,
|
|
7370
|
-
translationService
|
|
8209
|
+
showToast
|
|
7371
8210
|
});
|
|
7372
8211
|
//# sourceMappingURL=index.cjs.map
|