lib-e2e-cypress-for-dummys-ts 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -34
- package/dist/{chunk-FDMUIHDZ.js → chunk-VT2GLZ62.js} +40 -7
- package/dist/chunk-VT2GLZ62.js.map +1 -0
- package/dist/index.cjs +1691 -1215
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -157
- package/dist/index.d.ts +65 -157
- package/dist/index.js +1653 -1211
- package/dist/index.js.map +1 -1
- package/dist/runner.js +18 -2
- package/dist/selector-picker-ZEZ2G5K6.js +7 -0
- package/package.json +74 -81
- package/dist/chunk-FDMUIHDZ.js.map +0 -1
- package/dist/selector-picker-NKYFFFGK.js +0 -7
- /package/dist/{selector-picker-NKYFFFGK.js.map → selector-picker-ZEZ2G5K6.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
|
});
|
|
@@ -463,20 +500,15 @@ __export(index_exports, {
|
|
|
463
500
|
ACTIVE_SESSION_BREADCRUMB_KEY: () => ACTIVE_SESSION_BREADCRUMB_KEY,
|
|
464
501
|
AdvancedTestEditorElement: () => AdvancedTestEditorElement,
|
|
465
502
|
AdvancedTestTransformationService: () => AdvancedTestTransformationService,
|
|
466
|
-
CHAIN_METHODS: () => CHAIN_METHODS,
|
|
467
|
-
CYPRESS_COMPLETIONS: () => CYPRESS_COMPLETIONS,
|
|
468
|
-
CY_METHODS: () => CY_METHODS,
|
|
469
503
|
ConfigurationElement: () => ConfigurationElement,
|
|
470
504
|
DB_SCHEMA: () => DB_SCHEMA,
|
|
471
505
|
DB_STORE_NAMES: () => DB_STORE_NAMES,
|
|
472
|
-
DEFAULT_ISSUE_TRACKER_PROVIDER_ID: () => DEFAULT_ISSUE_TRACKER_PROVIDER_ID,
|
|
473
506
|
DEFAULT_RESUME_TTL_MINUTES: () => DEFAULT_RESUME_TTL_MINUTES,
|
|
474
507
|
DRAG_THRESHOLD: () => DRAG_THRESHOLD,
|
|
475
508
|
FilePreviewElement: () => FilePreviewElement,
|
|
476
509
|
HelpPanelElement: () => HelpPanelElement,
|
|
477
510
|
HttpMonitor: () => HttpMonitor,
|
|
478
511
|
INPUT_TYPES: () => INPUT_TYPES,
|
|
479
|
-
ISSUE_TRACKER_PROVIDERS: () => ISSUE_TRACKER_PROVIDERS,
|
|
480
512
|
LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES: () => LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,
|
|
481
513
|
LOCALE_BY_LANG: () => LOCALE_BY_LANG,
|
|
482
514
|
LibE2eRecorderElement: () => LibE2eRecorderElement,
|
|
@@ -487,25 +519,19 @@ __export(index_exports, {
|
|
|
487
519
|
SUPPORTED_LANGS: () => SUPPORTED_LANGS,
|
|
488
520
|
SaveTestElement: () => SaveTestElement,
|
|
489
521
|
SelectorPickerElement: () => SelectorPickerElement,
|
|
490
|
-
Subject: () => Subject,
|
|
491
522
|
TOGGLE_MARGIN: () => TOGGLE_MARGIN,
|
|
492
|
-
TOP_LEVEL: () => TOP_LEVEL,
|
|
493
523
|
TestEditorElement: () => TestEditorElement,
|
|
494
524
|
TestPrevisualizerElement: () => TestPrevisualizerElement,
|
|
495
525
|
TransformationService: () => TransformationService,
|
|
496
526
|
TranslationService: () => TranslationService,
|
|
497
527
|
VERSION: () => VERSION,
|
|
528
|
+
_resetHttpMonitorState: () => _resetHttpMonitorState,
|
|
498
529
|
advancedTestTransformationService: () => advancedTestTransformationService,
|
|
499
530
|
boxOffsetForDirection: () => boxOffsetForDirection,
|
|
500
531
|
boxTopLeftFor: () => boxTopLeftFor,
|
|
501
|
-
buildTicketComment: () => buildTicketComment,
|
|
502
|
-
buildTicketUrl: () => buildTicketUrl,
|
|
503
532
|
clampTogglePosition: () => clampTogglePosition,
|
|
504
|
-
createCodeEditor: () => createCodeEditor,
|
|
505
533
|
defaultTogglePosition: () => defaultTogglePosition,
|
|
506
|
-
|
|
507
|
-
filterCypressCompletions: () => filterCypressCompletions,
|
|
508
|
-
findIssueTrackerProvider: () => findIssueTrackerProvider,
|
|
534
|
+
ensurePopupDimensions: () => ensurePopupDimensions,
|
|
509
535
|
generateAlias: () => generateAlias,
|
|
510
536
|
inferAssertionCommand: () => inferAssertionCommand,
|
|
511
537
|
injectStyles: () => injectStyles,
|
|
@@ -515,9 +541,7 @@ __export(index_exports, {
|
|
|
515
541
|
makeModalResizable: () => makeModalResizable,
|
|
516
542
|
makeSwalDraggable: () => makeSwalDraggable,
|
|
517
543
|
makeSwalDraggableByContentId: () => makeSwalDraggableByContentId,
|
|
518
|
-
persistenceService: () => persistenceService,
|
|
519
544
|
resolveExpandDirection: () => resolveExpandDirection,
|
|
520
|
-
resolveTicketUrl: () => resolveTicketUrl,
|
|
521
545
|
selectTestsForExport: () => selectTestsForExport,
|
|
522
546
|
setSwal2DataCyAttribute: () => setSwal2DataCyAttribute,
|
|
523
547
|
showToast: () => showToast,
|
|
@@ -616,64 +640,6 @@ var ACTIVE_SESSION_BREADCRUMB_KEY = "e2e-active-session";
|
|
|
616
640
|
var RESUME_TTL_CONFIG_KEY = "resumeRecencyTtlMinutes";
|
|
617
641
|
var DEFAULT_RESUME_TTL_MINUTES = 30;
|
|
618
642
|
|
|
619
|
-
// src/models/issue-tracker.model.ts
|
|
620
|
-
var ISSUE_TRACKER_PROVIDERS = [
|
|
621
|
-
{
|
|
622
|
-
id: "jira",
|
|
623
|
-
labelKey: "CONFIG.ISSUE_TRACKER_PROVIDER_JIRA",
|
|
624
|
-
urlTemplate: "{baseUrl}/browse/{id}",
|
|
625
|
-
fields: [
|
|
626
|
-
{ key: "baseUrl", labelKey: "CONFIG.ISSUE_TRACKER_FIELD_BASEURL", placeholderKey: "CONFIG.ISSUE_TRACKER_PH_JIRA_BASEURL" }
|
|
627
|
-
],
|
|
628
|
-
idPattern: "^[A-Za-z][A-Za-z0-9_]+-\\d+$",
|
|
629
|
-
idPlaceholderKey: "SAVE_TEST.TICKET_PH_JIRA"
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
id: "azure-devops",
|
|
633
|
-
labelKey: "CONFIG.ISSUE_TRACKER_PROVIDER_AZURE",
|
|
634
|
-
urlTemplate: "https://dev.azure.com/{org}/{project}/_workitems/edit/{id}",
|
|
635
|
-
fields: [
|
|
636
|
-
{ key: "org", labelKey: "CONFIG.ISSUE_TRACKER_FIELD_ORG", placeholderKey: "CONFIG.ISSUE_TRACKER_PH_AZURE_ORG" },
|
|
637
|
-
{ key: "project", labelKey: "CONFIG.ISSUE_TRACKER_FIELD_PROJECT", placeholderKey: "CONFIG.ISSUE_TRACKER_PH_AZURE_PROJECT" }
|
|
638
|
-
],
|
|
639
|
-
idPattern: "^\\d+$",
|
|
640
|
-
idPlaceholderKey: "SAVE_TEST.TICKET_PH_AZURE"
|
|
641
|
-
},
|
|
642
|
-
{
|
|
643
|
-
id: "github",
|
|
644
|
-
labelKey: "CONFIG.ISSUE_TRACKER_PROVIDER_GITHUB",
|
|
645
|
-
urlTemplate: "https://github.com/{owner}/{repo}/issues/{id}",
|
|
646
|
-
fields: [
|
|
647
|
-
{ key: "owner", labelKey: "CONFIG.ISSUE_TRACKER_FIELD_OWNER", placeholderKey: "CONFIG.ISSUE_TRACKER_PH_GITHUB_OWNER" },
|
|
648
|
-
{ key: "repo", labelKey: "CONFIG.ISSUE_TRACKER_FIELD_REPO", placeholderKey: "CONFIG.ISSUE_TRACKER_PH_GITHUB_REPO" }
|
|
649
|
-
],
|
|
650
|
-
idPattern: "^\\d+$",
|
|
651
|
-
idPlaceholderKey: "SAVE_TEST.TICKET_PH_GITHUB"
|
|
652
|
-
},
|
|
653
|
-
{
|
|
654
|
-
id: "trello",
|
|
655
|
-
labelKey: "CONFIG.ISSUE_TRACKER_PROVIDER_TRELLO",
|
|
656
|
-
urlTemplate: "https://trello.com/c/{id}",
|
|
657
|
-
fields: [],
|
|
658
|
-
idPattern: "^[A-Za-z0-9]+$",
|
|
659
|
-
idPlaceholderKey: "SAVE_TEST.TICKET_PH_TRELLO"
|
|
660
|
-
},
|
|
661
|
-
{
|
|
662
|
-
id: "custom",
|
|
663
|
-
labelKey: "CONFIG.ISSUE_TRACKER_PROVIDER_CUSTOM",
|
|
664
|
-
urlTemplate: "{template}",
|
|
665
|
-
fields: [
|
|
666
|
-
{ key: "template", labelKey: "CONFIG.ISSUE_TRACKER_FIELD_TEMPLATE", placeholderKey: "CONFIG.ISSUE_TRACKER_PH_CUSTOM_TEMPLATE" }
|
|
667
|
-
],
|
|
668
|
-
idPattern: ".*",
|
|
669
|
-
idPlaceholderKey: "SAVE_TEST.TICKET_PH_CUSTOM"
|
|
670
|
-
}
|
|
671
|
-
];
|
|
672
|
-
var DEFAULT_ISSUE_TRACKER_PROVIDER_ID = "custom";
|
|
673
|
-
function findIssueTrackerProvider(id) {
|
|
674
|
-
return ISSUE_TRACKER_PROVIDERS.find((p) => p.id === id);
|
|
675
|
-
}
|
|
676
|
-
|
|
677
643
|
// src/utils/subject.ts
|
|
678
644
|
var Subject = class {
|
|
679
645
|
_value;
|
|
@@ -719,13 +685,12 @@ var I18N_ES = {
|
|
|
719
685
|
REMOVE_TAG_TITLE: "Quitar",
|
|
720
686
|
NOTES_LABEL: "Descripci\xF3n / Notas (opcional):",
|
|
721
687
|
NOTES_PLACEHOLDER: "Qu\xE9 valida este test, condiciones previas, etc.",
|
|
722
|
-
TICKET_LABEL: "Ticket (opcional):",
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
TICKET_INVALID: "El id del ticket no coincide con el formato esperado del gestor seleccionado."
|
|
688
|
+
TICKET_LABEL: "Ticket / Issue (opcional):",
|
|
689
|
+
TICKET_PLACEHOLDER: "Ej: PROJ-123, #42",
|
|
690
|
+
TICKET_WARN: "ID no v\xE1lido para el proveedor configurado (se guardar\xE1 igualmente)",
|
|
691
|
+
CONFIRM_DISCARD: "\xBFSeguro que quieres descartar el test grabado? Se perder\xE1n todos los pasos registrados.",
|
|
692
|
+
CONFIRM_DISCARD_BTN: "S\xED, descartar",
|
|
693
|
+
BACK_BTN: "Volver"
|
|
729
694
|
},
|
|
730
695
|
TEST_EDITOR: {
|
|
731
696
|
NO_TAGS: "Sin etiquetas",
|
|
@@ -741,7 +706,9 @@ var I18N_ES = {
|
|
|
741
706
|
NO_TESTS: "No hay tests guardados",
|
|
742
707
|
DELETE_TITLE: "Eliminar",
|
|
743
708
|
GROUP_BY_TICKET: "\u{1F3AB} Agrupar por ticket",
|
|
744
|
-
|
|
709
|
+
UNGROUP_TICKET: "\u{1F3AB} Desagrupar",
|
|
710
|
+
NO_TICKET: "Sin ticket",
|
|
711
|
+
TICKET_LINK_TITLE: "Abrir ticket"
|
|
745
712
|
},
|
|
746
713
|
CONFIG: {
|
|
747
714
|
LANG_SECTION: "\u{1F310} Idioma",
|
|
@@ -800,26 +767,35 @@ var I18N_ES = {
|
|
|
800
767
|
WIDGET_POSITION_HINT: "Arrastra el bot\xF3n de grabar para moverlo donde no estorbe. Se recuerda su posici\xF3n.",
|
|
801
768
|
WIDGET_POSITION_RESET_BTN: "\u21BA Restablecer posici\xF3n",
|
|
802
769
|
WIDGET_POSITION_RESET_DONE: "\u2713 Posici\xF3n restablecida",
|
|
803
|
-
ISSUE_TRACKER_SECTION: "\u{1F3AB}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
770
|
+
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue tracker",
|
|
771
|
+
ISSUE_TRACKER_TITLE: "Vincular tests a tickets",
|
|
772
|
+
ISSUE_TRACKER_SUB: "A\xF1ade un ID de ticket al guardar y genera un enlace clickable en el listado.",
|
|
773
|
+
ISSUE_TRACKER_PROVIDER: "Proveedor",
|
|
774
|
+
ISSUE_TRACKER_BASE_URL: "URL base",
|
|
775
|
+
ISSUE_TRACKER_BASE_URL_PH: "Ej: https://miproyecto.atlassian.net",
|
|
776
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
777
|
+
LOGIN_SETUP_NOT_CONFIGURED: "No configurado",
|
|
778
|
+
LOGIN_SETUP_SET_UP_BTN: "Configurar",
|
|
779
|
+
LOGIN_SETUP_TITLE: "Configuraci\xF3n de login",
|
|
780
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Crear scaffold",
|
|
781
|
+
LOGIN_SETUP_SELECT_EXISTING: "Seleccionar fichero existente",
|
|
782
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Nombre del fichero",
|
|
783
|
+
LOGIN_SETUP_FILE_NAME_PH: "Ej: cypress/common-services/login.service.ts",
|
|
784
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-escanear",
|
|
785
|
+
LOGIN_SETUP_NO_FUNCTIONS: "No se encontraron funciones exportadas. Rellena el scaffold y re-escanea.",
|
|
786
|
+
LOGIN_SETUP_BEFORE_LABEL: "Funci\xF3n before() (una vez por suite)",
|
|
787
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "Funci\xF3n beforeEach() (antes de cada test)",
|
|
788
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Ninguna \u2014",
|
|
789
|
+
LOGIN_SETUP_SUMMARY: "Fichero: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
790
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Guardar",
|
|
791
|
+
LOGIN_SETUP_CLEAR_BTN: "Eliminar configuraci\xF3n",
|
|
792
|
+
LOGIN_SETUP_CANCEL_BTN: "Cancelar",
|
|
793
|
+
LOGIN_SETUP_SOURCE_LABEL: "Origen del fichero de login",
|
|
794
|
+
LOGIN_SETUP_CREATE_SUB: "Genera un scaffold con funciones de ejemplo",
|
|
795
|
+
LOGIN_SETUP_SELECT_SUB: "Apunta a un servicio de login existente",
|
|
796
|
+
LOGIN_SETUP_INJECT_TITLE: "\xBFA\xF1adir bloques de login?",
|
|
797
|
+
LOGIN_SETUP_INJECT_TEXT: "Este fichero no tiene los bloques de login configurados. \xBFQuieres a\xF1adir el import y los bloques before/beforeEach ahora?",
|
|
798
|
+
LOGIN_SETUP_INJECT_CONFIRM: "S\xED, a\xF1adir"
|
|
823
799
|
},
|
|
824
800
|
SELECTOR_PICKER: {
|
|
825
801
|
TITLE: "Selecciona un elemento del DOM",
|
|
@@ -910,6 +886,9 @@ var I18N_ES = {
|
|
|
910
886
|
FILE_SAVE_ERROR_TOAST: "Error al guardar el archivo",
|
|
911
887
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures escritos en cypress/fixtures",
|
|
912
888
|
FIXTURES_NO_FOLDER_TOAST: "No se pudieron escribir los fixtures (configura la carpeta Cypress)",
|
|
889
|
+
FILE_UPLOAD_MANUAL_TOAST: "A\xF1ade {files} a cypress/fixtures/ antes de ejecutar el test.",
|
|
890
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copiado/s a cypress/fixtures/.",
|
|
891
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "No se pudo copiar {files} a cypress/fixtures/. A\xF1\xE1delo manualmente.",
|
|
913
892
|
BTN_CONFIG: "Config",
|
|
914
893
|
BTN_FILES: "Ficheros",
|
|
915
894
|
BTN_COMMANDS: "Comandos",
|
|
@@ -957,7 +936,7 @@ var I18N_ES = {
|
|
|
957
936
|
SEC_PANELS: "\u{1F5C2} Paneles",
|
|
958
937
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 guardados: filtrar por tag, copiar, combinar, exportar.",
|
|
959
938
|
PANEL_COMMANDS: "\u2328\uFE0F Comandos \u2014 de la grabaci\xF3n actual: reordenar, borrar, a\xF1adir aserciones.",
|
|
960
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 idioma, selector, HTTP, carpeta Cypress, datos, visibilidad, posici\xF3n.",
|
|
939
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 idioma, selector, HTTP, carpeta Cypress, login setup, datos, visibilidad, posici\xF3n.",
|
|
961
940
|
PANEL_FILES: "\u{1F4C1} Ficheros \u2014 inserta tests en tus .cy.ts y lanza el runner.",
|
|
962
941
|
SEC_SELECTOR: "\u{1F50E} Selectores",
|
|
963
942
|
SELECTOR_1: "Elige el atributo preferido (data-cy, data-testid, aria-label, id) en Config.",
|
|
@@ -970,6 +949,7 @@ var I18N_ES = {
|
|
|
970
949
|
ADV_RUNNER: "Runner local: npx lib-e2e-cypress-runner para lanzar un spec headless desde el editor.",
|
|
971
950
|
ADV_CROSSAPP: "Cross-app: la grabaci\xF3n sobrevive al cambiar de micro-frontend (mismo origen).",
|
|
972
951
|
ADV_DRAG: "Arrastra el bot\xF3n \u23FA para mover el widget; recuerda su posici\xF3n.",
|
|
952
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
973
953
|
CLOSE: "Cerrar",
|
|
974
954
|
TAB_REFERENCE: "Referencia r\xE1pida",
|
|
975
955
|
TAB_GUIDE: "Gu\xEDa de uso",
|
|
@@ -987,13 +967,13 @@ var I18N_ES = {
|
|
|
987
967
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
988
968
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
989
969
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
970
|
+
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.",
|
|
990
971
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
991
972
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
992
973
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
993
974
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
994
975
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
995
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
996
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
976
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
997
977
|
}
|
|
998
978
|
};
|
|
999
979
|
|
|
@@ -1022,13 +1002,12 @@ var I18N_EN = {
|
|
|
1022
1002
|
REMOVE_TAG_TITLE: "Remove",
|
|
1023
1003
|
NOTES_LABEL: "Description / Notes (optional):",
|
|
1024
1004
|
NOTES_PLACEHOLDER: "What this test validates, preconditions, etc.",
|
|
1025
|
-
TICKET_LABEL: "Ticket (optional):",
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
TICKET_INVALID: "The ticket id does not match the expected format for the selected tracker."
|
|
1005
|
+
TICKET_LABEL: "Ticket / Issue (optional):",
|
|
1006
|
+
TICKET_PLACEHOLDER: "E.g.: PROJ-123, #42",
|
|
1007
|
+
TICKET_WARN: "Invalid ID for the configured provider (will be saved anyway)",
|
|
1008
|
+
CONFIRM_DISCARD: "Are you sure you want to discard this recording? All recorded steps will be lost.",
|
|
1009
|
+
CONFIRM_DISCARD_BTN: "Yes, discard",
|
|
1010
|
+
BACK_BTN: "Go back"
|
|
1032
1011
|
},
|
|
1033
1012
|
TEST_EDITOR: {
|
|
1034
1013
|
NO_TAGS: "No tags",
|
|
@@ -1044,7 +1023,9 @@ var I18N_EN = {
|
|
|
1044
1023
|
NO_TESTS: "No saved tests",
|
|
1045
1024
|
DELETE_TITLE: "Delete",
|
|
1046
1025
|
GROUP_BY_TICKET: "\u{1F3AB} Group by ticket",
|
|
1047
|
-
|
|
1026
|
+
UNGROUP_TICKET: "\u{1F3AB} Ungroup",
|
|
1027
|
+
NO_TICKET: "No ticket",
|
|
1028
|
+
TICKET_LINK_TITLE: "Open ticket"
|
|
1048
1029
|
},
|
|
1049
1030
|
CONFIG: {
|
|
1050
1031
|
LANG_SECTION: "\u{1F310} Language",
|
|
@@ -1104,25 +1085,34 @@ var I18N_EN = {
|
|
|
1104
1085
|
WIDGET_POSITION_RESET_BTN: "\u21BA Reset position",
|
|
1105
1086
|
WIDGET_POSITION_RESET_DONE: "\u2713 Position reset",
|
|
1106
1087
|
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue tracker",
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1088
|
+
ISSUE_TRACKER_TITLE: "Link tests to tickets",
|
|
1089
|
+
ISSUE_TRACKER_SUB: "Add a ticket ID when saving and generate a clickable link in the test list.",
|
|
1090
|
+
ISSUE_TRACKER_PROVIDER: "Provider",
|
|
1091
|
+
ISSUE_TRACKER_BASE_URL: "Base URL",
|
|
1092
|
+
ISSUE_TRACKER_BASE_URL_PH: "E.g.: https://myproject.atlassian.net",
|
|
1093
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
1094
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Not configured",
|
|
1095
|
+
LOGIN_SETUP_SET_UP_BTN: "Set up",
|
|
1096
|
+
LOGIN_SETUP_TITLE: "Login setup",
|
|
1097
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Create scaffold",
|
|
1098
|
+
LOGIN_SETUP_SELECT_EXISTING: "Select existing file",
|
|
1099
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "File name",
|
|
1100
|
+
LOGIN_SETUP_FILE_NAME_PH: "E.g.: cypress/common-services/login.service.ts",
|
|
1101
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-scan",
|
|
1102
|
+
LOGIN_SETUP_NO_FUNCTIONS: "No exported functions found. Fill in the scaffold and re-scan.",
|
|
1103
|
+
LOGIN_SETUP_BEFORE_LABEL: "before() function (once per suite)",
|
|
1104
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "beforeEach() function (before every test)",
|
|
1105
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 None \u2014",
|
|
1106
|
+
LOGIN_SETUP_SUMMARY: "File: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
1107
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Save",
|
|
1108
|
+
LOGIN_SETUP_CLEAR_BTN: "Remove configuration",
|
|
1109
|
+
LOGIN_SETUP_CANCEL_BTN: "Cancel",
|
|
1110
|
+
LOGIN_SETUP_SOURCE_LABEL: "Login file source",
|
|
1111
|
+
LOGIN_SETUP_CREATE_SUB: "Generate a scaffold with sample functions",
|
|
1112
|
+
LOGIN_SETUP_SELECT_SUB: "Point to an existing login service file",
|
|
1113
|
+
LOGIN_SETUP_INJECT_TITLE: "Add login blocks?",
|
|
1114
|
+
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?",
|
|
1115
|
+
LOGIN_SETUP_INJECT_CONFIRM: "Yes, add them"
|
|
1126
1116
|
},
|
|
1127
1117
|
SELECTOR_PICKER: {
|
|
1128
1118
|
TITLE: "Select a DOM element",
|
|
@@ -1213,6 +1203,9 @@ var I18N_EN = {
|
|
|
1213
1203
|
FILE_SAVE_ERROR_TOAST: "Error saving the file",
|
|
1214
1204
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures written to cypress/fixtures",
|
|
1215
1205
|
FIXTURES_NO_FOLDER_TOAST: "Could not write fixtures (configure the Cypress folder)",
|
|
1206
|
+
FILE_UPLOAD_MANUAL_TOAST: "Add {files} to cypress/fixtures/ before running the test.",
|
|
1207
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copied to cypress/fixtures/.",
|
|
1208
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "Could not copy {files} to cypress/fixtures/. Add it manually.",
|
|
1216
1209
|
BTN_CONFIG: "Config",
|
|
1217
1210
|
BTN_FILES: "Files",
|
|
1218
1211
|
BTN_COMMANDS: "Commands",
|
|
@@ -1260,7 +1253,7 @@ var I18N_EN = {
|
|
|
1260
1253
|
SEC_PANELS: "\u{1F5C2} Panels",
|
|
1261
1254
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 saved tests: filter by tag, copy, combine, export.",
|
|
1262
1255
|
PANEL_COMMANDS: "\u2328\uFE0F Commands \u2014 current recording: reorder, delete, add assertions.",
|
|
1263
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 language, selector, HTTP, Cypress folder, data, visibility, position.",
|
|
1256
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 language, selector, HTTP, Cypress folder, login setup, data, visibility, position.",
|
|
1264
1257
|
PANEL_FILES: "\u{1F4C1} Files \u2014 insert tests into your .cy.ts and launch the runner.",
|
|
1265
1258
|
SEC_SELECTOR: "\u{1F50E} Selectors",
|
|
1266
1259
|
SELECTOR_1: "Choose the preferred attribute (data-cy, data-testid, aria-label, id) in Config.",
|
|
@@ -1273,6 +1266,7 @@ var I18N_EN = {
|
|
|
1273
1266
|
ADV_RUNNER: "Local runner: npx lib-e2e-cypress-runner to run a spec headless from the editor.",
|
|
1274
1267
|
ADV_CROSSAPP: "Cross-app: the recording survives switching micro-frontend (same origin).",
|
|
1275
1268
|
ADV_DRAG: "Drag the \u23FA button to move the widget; its position is remembered.",
|
|
1269
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): point to your login service; the recorder automatically injects before()/beforeEach() blocks into each new test.",
|
|
1276
1270
|
CLOSE: "Close",
|
|
1277
1271
|
TAB_REFERENCE: "Quick reference",
|
|
1278
1272
|
TAB_GUIDE: "Usage guide",
|
|
@@ -1290,13 +1284,13 @@ var I18N_EN = {
|
|
|
1290
1284
|
G_COV_4: "Reliable selector (data-cy/testid/aria/id) and a picker when none is obvious.",
|
|
1291
1285
|
G_COV_5: "Automatic assertions (Alt+click) and the manual builder.",
|
|
1292
1286
|
G_COV_6: "Continuity when switching micro-frontend (same origin), invisible mode and i18n.",
|
|
1287
|
+
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.",
|
|
1293
1288
|
G_SEC_NOTCOVERED: "\u{1F6AB} What it does NOT cover (yet)",
|
|
1294
1289
|
G_NC_1: "Different origins / subdomains (same origin only).",
|
|
1295
1290
|
G_NC_2: "File upload (selectFile), drag & drop, and hover.",
|
|
1296
1291
|
G_NC_3: "The Tab key (Cypress can't .type() it).",
|
|
1297
1292
|
G_NC_4: "DELETE requests (intentionally ignored).",
|
|
1298
|
-
G_NC_5: "Third-party iframes and Shadow DOM may not be captured."
|
|
1299
|
-
G_NC_6: "Programmatic login generation (on the roadmap)."
|
|
1293
|
+
G_NC_5: "Third-party iframes and Shadow DOM may not be captured."
|
|
1300
1294
|
}
|
|
1301
1295
|
};
|
|
1302
1296
|
|
|
@@ -1325,13 +1319,13 @@ var I18N_FR = {
|
|
|
1325
1319
|
REMOVE_TAG_TITLE: "Retirer",
|
|
1326
1320
|
NOTES_LABEL: "Description / Notes (optionnel) :",
|
|
1327
1321
|
NOTES_PLACEHOLDER: "Ce que ce test valide, conditions pr\xE9alables, etc.",
|
|
1328
|
-
TICKET_LABEL: "Ticket (optionnel) :",
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1322
|
+
TICKET_LABEL: "Ticket / Issue (optionnel) :",
|
|
1323
|
+
TICKET_PLACEHOLDER: "Ex : PROJ-123, #42",
|
|
1324
|
+
TICKET_WARN: "ID non valide pour le fournisseur configur\xE9 (sera enregistr\xE9 quand m\xEAme)",
|
|
1325
|
+
// TODO: translate
|
|
1326
|
+
CONFIRM_DISCARD: "\xCAtes-vous s\xFBr de vouloir abandonner cet enregistrement ? Toutes les \xE9tapes enregistr\xE9es seront perdues.",
|
|
1327
|
+
CONFIRM_DISCARD_BTN: "Oui, abandonner",
|
|
1328
|
+
BACK_BTN: "Retour"
|
|
1335
1329
|
},
|
|
1336
1330
|
TEST_EDITOR: {
|
|
1337
1331
|
NO_TAGS: "Sans \xE9tiquettes",
|
|
@@ -1347,7 +1341,9 @@ var I18N_FR = {
|
|
|
1347
1341
|
NO_TESTS: "Aucun test enregistr\xE9",
|
|
1348
1342
|
DELETE_TITLE: "Supprimer",
|
|
1349
1343
|
GROUP_BY_TICKET: "\u{1F3AB} Grouper par ticket",
|
|
1350
|
-
|
|
1344
|
+
UNGROUP_TICKET: "\u{1F3AB} D\xE9grouper",
|
|
1345
|
+
NO_TICKET: "Sans ticket",
|
|
1346
|
+
TICKET_LINK_TITLE: "Ouvrir le ticket"
|
|
1351
1347
|
},
|
|
1352
1348
|
CONFIG: {
|
|
1353
1349
|
LANG_SECTION: "\u{1F310} Langue",
|
|
@@ -1407,25 +1403,34 @@ var I18N_FR = {
|
|
|
1407
1403
|
WIDGET_POSITION_RESET_BTN: "\u21BA R\xE9initialiser la position",
|
|
1408
1404
|
WIDGET_POSITION_RESET_DONE: "\u2713 Position r\xE9initialis\xE9e",
|
|
1409
1405
|
ISSUE_TRACKER_SECTION: "\u{1F3AB} Gestionnaire de tickets",
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1406
|
+
ISSUE_TRACKER_TITLE: "Lier les tests aux tickets",
|
|
1407
|
+
ISSUE_TRACKER_SUB: "Ajoutez un ID de ticket lors de l'enregistrement et g\xE9n\xE9rez un lien cliquable.",
|
|
1408
|
+
ISSUE_TRACKER_PROVIDER: "Fournisseur",
|
|
1409
|
+
ISSUE_TRACKER_BASE_URL: "URL de base",
|
|
1410
|
+
ISSUE_TRACKER_BASE_URL_PH: "Ex : https://monprojet.atlassian.net",
|
|
1411
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
1412
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Non configur\xE9",
|
|
1413
|
+
LOGIN_SETUP_SET_UP_BTN: "Configurer",
|
|
1414
|
+
LOGIN_SETUP_TITLE: "Configuration du login",
|
|
1415
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Cr\xE9er un scaffold",
|
|
1416
|
+
LOGIN_SETUP_SELECT_EXISTING: "S\xE9lectionner un fichier existant",
|
|
1417
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Nom du fichier",
|
|
1418
|
+
LOGIN_SETUP_FILE_NAME_PH: "Ex : cypress/common-services/login.service.ts",
|
|
1419
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-scanner",
|
|
1420
|
+
LOGIN_SETUP_NO_FUNCTIONS: "Aucune fonction export\xE9e trouv\xE9e. Remplissez le scaffold et re-scannez.",
|
|
1421
|
+
LOGIN_SETUP_BEFORE_LABEL: "Fonction before() (une fois par suite)",
|
|
1422
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "Fonction beforeEach() (avant chaque test)",
|
|
1423
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Aucune \u2014",
|
|
1424
|
+
LOGIN_SETUP_SUMMARY: "Fichier : {file} \xB7 before : {before} \xB7 beforeEach : {beforeEach}",
|
|
1425
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Enregistrer",
|
|
1426
|
+
LOGIN_SETUP_CLEAR_BTN: "Supprimer la configuration",
|
|
1427
|
+
LOGIN_SETUP_CANCEL_BTN: "Annuler",
|
|
1428
|
+
LOGIN_SETUP_SOURCE_LABEL: "Source du fichier de login",
|
|
1429
|
+
LOGIN_SETUP_CREATE_SUB: "G\xE9n\xE9rer un scaffold avec des fonctions exemples",
|
|
1430
|
+
LOGIN_SETUP_SELECT_SUB: "Pointer vers un fichier de service de login existant",
|
|
1431
|
+
LOGIN_SETUP_INJECT_TITLE: "Ajouter les blocs de login ?",
|
|
1432
|
+
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 ?",
|
|
1433
|
+
LOGIN_SETUP_INJECT_CONFIRM: "Oui, ajouter"
|
|
1429
1434
|
},
|
|
1430
1435
|
SELECTOR_PICKER: {
|
|
1431
1436
|
TITLE: "S\xE9lectionnez un \xE9l\xE9ment du DOM",
|
|
@@ -1516,6 +1521,12 @@ var I18N_FR = {
|
|
|
1516
1521
|
FILE_SAVE_ERROR_TOAST: "Erreur lors de l'enregistrement",
|
|
1517
1522
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures \xE9crites dans cypress/fixtures",
|
|
1518
1523
|
FIXTURES_NO_FOLDER_TOAST: "Impossible d'\xE9crire les fixtures (configure le dossier Cypress)",
|
|
1524
|
+
FILE_UPLOAD_MANUAL_TOAST: "Ajoutez {files} \xE0 cypress/fixtures/ avant d'ex\xE9cuter le test.",
|
|
1525
|
+
// TODO: translate
|
|
1526
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copi\xE9(s) dans cypress/fixtures/.",
|
|
1527
|
+
// TODO: translate
|
|
1528
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "Impossible de copier {files} vers cypress/fixtures/. Ajoutez-le manuellement.",
|
|
1529
|
+
// TODO: translate
|
|
1519
1530
|
BTN_CONFIG: "Config",
|
|
1520
1531
|
BTN_FILES: "Fichiers",
|
|
1521
1532
|
BTN_COMMANDS: "Commandes",
|
|
@@ -1563,7 +1574,7 @@ var I18N_FR = {
|
|
|
1563
1574
|
SEC_PANELS: "\u{1F5C2} Panneaux",
|
|
1564
1575
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 enregistr\xE9s : filtrer par tag, copier, combiner, exporter.",
|
|
1565
1576
|
PANEL_COMMANDS: "\u2328\uFE0F Commandes \u2014 enregistrement en cours : r\xE9ordonner, supprimer, ajouter des assertions.",
|
|
1566
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 langue, s\xE9lecteur, HTTP, dossier Cypress, donn\xE9es, visibilit\xE9, position.",
|
|
1577
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 langue, s\xE9lecteur, HTTP, dossier Cypress, login setup, donn\xE9es, visibilit\xE9, position.",
|
|
1567
1578
|
PANEL_FILES: "\u{1F4C1} Fichiers \u2014 ins\xE8re des tests dans tes .cy.ts et lance le runner.",
|
|
1568
1579
|
SEC_SELECTOR: "\u{1F50E} S\xE9lecteurs",
|
|
1569
1580
|
SELECTOR_1: "Choisis l'attribut pr\xE9f\xE9r\xE9 (data-cy, data-testid, aria-label, id) dans Config.",
|
|
@@ -1576,6 +1587,8 @@ var I18N_FR = {
|
|
|
1576
1587
|
ADV_RUNNER: "Runner local : npx lib-e2e-cypress-runner pour lancer un spec headless depuis l'\xE9diteur.",
|
|
1577
1588
|
ADV_CROSSAPP: "Cross-app : l'enregistrement survit au changement de micro-frontend (m\xEAme origine).",
|
|
1578
1589
|
ADV_DRAG: "Fais glisser le bouton \u23FA pour d\xE9placer le widget ; sa position est m\xE9moris\xE9e.",
|
|
1590
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
1591
|
+
// TODO: translate (fr)
|
|
1579
1592
|
CLOSE: "Fermer",
|
|
1580
1593
|
TAB_REFERENCE: "R\xE9f\xE9rence rapide",
|
|
1581
1594
|
TAB_GUIDE: "Guide d'utilisation",
|
|
@@ -1594,13 +1607,14 @@ var I18N_FR = {
|
|
|
1594
1607
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
1595
1608
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
1596
1609
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
1610
|
+
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.",
|
|
1611
|
+
// TODO: translate (fr)
|
|
1597
1612
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
1598
1613
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
1599
1614
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
1600
1615
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
1601
1616
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
1602
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1603
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
1617
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1604
1618
|
}
|
|
1605
1619
|
};
|
|
1606
1620
|
|
|
@@ -1629,13 +1643,13 @@ var I18N_IT = {
|
|
|
1629
1643
|
REMOVE_TAG_TITLE: "Rimuovi",
|
|
1630
1644
|
NOTES_LABEL: "Descrizione / Note (opzionale):",
|
|
1631
1645
|
NOTES_PLACEHOLDER: "Cosa valida questo test, condizioni preliminari, ecc.",
|
|
1632
|
-
TICKET_LABEL: "Ticket (opzionale):",
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1646
|
+
TICKET_LABEL: "Ticket / Issue (opzionale):",
|
|
1647
|
+
TICKET_PLACEHOLDER: "Es: PROJ-123, #42",
|
|
1648
|
+
TICKET_WARN: "ID non valido per il provider configurato (verr\xE0 salvato comunque)",
|
|
1649
|
+
// TODO: translate
|
|
1650
|
+
CONFIRM_DISCARD: "Sei sicuro di voler scartare questa registrazione? Tutti i passi registrati andranno persi.",
|
|
1651
|
+
CONFIRM_DISCARD_BTN: "S\xEC, scarta",
|
|
1652
|
+
BACK_BTN: "Indietro"
|
|
1639
1653
|
},
|
|
1640
1654
|
TEST_EDITOR: {
|
|
1641
1655
|
NO_TAGS: "Nessuna etichetta",
|
|
@@ -1651,7 +1665,9 @@ var I18N_IT = {
|
|
|
1651
1665
|
NO_TESTS: "Nessun test salvato",
|
|
1652
1666
|
DELETE_TITLE: "Elimina",
|
|
1653
1667
|
GROUP_BY_TICKET: "\u{1F3AB} Raggruppa per ticket",
|
|
1654
|
-
|
|
1668
|
+
UNGROUP_TICKET: "\u{1F3AB} Separa",
|
|
1669
|
+
NO_TICKET: "Senza ticket",
|
|
1670
|
+
TICKET_LINK_TITLE: "Apri ticket"
|
|
1655
1671
|
},
|
|
1656
1672
|
CONFIG: {
|
|
1657
1673
|
LANG_SECTION: "\u{1F310} Lingua",
|
|
@@ -1710,26 +1726,35 @@ var I18N_IT = {
|
|
|
1710
1726
|
WIDGET_POSITION_HINT: "Trascina il pulsante di registrazione per spostarlo. La posizione viene ricordata.",
|
|
1711
1727
|
WIDGET_POSITION_RESET_BTN: "\u21BA Reimposta posizione",
|
|
1712
1728
|
WIDGET_POSITION_RESET_DONE: "\u2713 Posizione reimpostata",
|
|
1713
|
-
ISSUE_TRACKER_SECTION: "\u{1F3AB}
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1729
|
+
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue tracker",
|
|
1730
|
+
ISSUE_TRACKER_TITLE: "Collega i test ai ticket",
|
|
1731
|
+
ISSUE_TRACKER_SUB: "Aggiungi un ID ticket al salvataggio e genera un link cliccabile nell'elenco.",
|
|
1732
|
+
ISSUE_TRACKER_PROVIDER: "Provider",
|
|
1733
|
+
ISSUE_TRACKER_BASE_URL: "URL base",
|
|
1734
|
+
ISSUE_TRACKER_BASE_URL_PH: "Es: https://mioprogetto.atlassian.net",
|
|
1735
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
1736
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Non configurato",
|
|
1737
|
+
LOGIN_SETUP_SET_UP_BTN: "Configura",
|
|
1738
|
+
LOGIN_SETUP_TITLE: "Configurazione del login",
|
|
1739
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Crea scaffold",
|
|
1740
|
+
LOGIN_SETUP_SELECT_EXISTING: "Seleziona file esistente",
|
|
1741
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Nome del file",
|
|
1742
|
+
LOGIN_SETUP_FILE_NAME_PH: "Es: cypress/common-services/login.service.ts",
|
|
1743
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Re-scansiona",
|
|
1744
|
+
LOGIN_SETUP_NO_FUNCTIONS: "Nessuna funzione esportata trovata. Compila lo scaffold e ri-scansiona.",
|
|
1745
|
+
LOGIN_SETUP_BEFORE_LABEL: "Funzione before() (una volta per suite)",
|
|
1746
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "Funzione beforeEach() (prima di ogni test)",
|
|
1747
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Nessuna \u2014",
|
|
1748
|
+
LOGIN_SETUP_SUMMARY: "File: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
1749
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Salva",
|
|
1750
|
+
LOGIN_SETUP_CLEAR_BTN: "Rimuovi configurazione",
|
|
1751
|
+
LOGIN_SETUP_CANCEL_BTN: "Annulla",
|
|
1752
|
+
LOGIN_SETUP_SOURCE_LABEL: "Sorgente del file di login",
|
|
1753
|
+
LOGIN_SETUP_CREATE_SUB: "Genera uno scaffold con funzioni di esempio",
|
|
1754
|
+
LOGIN_SETUP_SELECT_SUB: "Punta a un file di servizio di login esistente",
|
|
1755
|
+
LOGIN_SETUP_INJECT_TITLE: "Aggiungere i blocchi di login?",
|
|
1756
|
+
LOGIN_SETUP_INJECT_TEXT: "Questo file non contiene i blocchi di login configurati. Vuoi aggiungere l'import e i blocchi before/beforeEach ora?",
|
|
1757
|
+
LOGIN_SETUP_INJECT_CONFIRM: "S\xEC, aggiungi"
|
|
1733
1758
|
},
|
|
1734
1759
|
SELECTOR_PICKER: {
|
|
1735
1760
|
TITLE: "Seleziona un elemento DOM",
|
|
@@ -1820,6 +1845,12 @@ var I18N_IT = {
|
|
|
1820
1845
|
FILE_SAVE_ERROR_TOAST: "Errore durante il salvataggio",
|
|
1821
1846
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixture scritte in cypress/fixtures",
|
|
1822
1847
|
FIXTURES_NO_FOLDER_TOAST: "Impossibile scrivere le fixture (configura la cartella Cypress)",
|
|
1848
|
+
FILE_UPLOAD_MANUAL_TOAST: "Aggiungi {files} a cypress/fixtures/ prima di eseguire il test.",
|
|
1849
|
+
// TODO: translate
|
|
1850
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} copiato/i in cypress/fixtures/.",
|
|
1851
|
+
// TODO: translate
|
|
1852
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "Impossibile copiare {files} in cypress/fixtures/. Aggiungilo manualmente.",
|
|
1853
|
+
// TODO: translate
|
|
1823
1854
|
BTN_CONFIG: "Config",
|
|
1824
1855
|
BTN_FILES: "File",
|
|
1825
1856
|
BTN_COMMANDS: "Comandi",
|
|
@@ -1867,7 +1898,7 @@ var I18N_IT = {
|
|
|
1867
1898
|
SEC_PANELS: "\u{1F5C2} Pannelli",
|
|
1868
1899
|
PANEL_TESTS: "\u{1F4CB} Test \u2014 salvati: filtra per tag, copia, combina, esporta.",
|
|
1869
1900
|
PANEL_COMMANDS: "\u2328\uFE0F Comandi \u2014 registrazione corrente: riordina, elimina, aggiungi asserzioni.",
|
|
1870
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 lingua, selettore, HTTP, cartella Cypress, dati, visibilit\xE0, posizione.",
|
|
1901
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 lingua, selettore, HTTP, cartella Cypress, login setup, dati, visibilit\xE0, posizione.",
|
|
1871
1902
|
PANEL_FILES: "\u{1F4C1} File \u2014 inserisci test nei tuoi .cy.ts e avvia il runner.",
|
|
1872
1903
|
SEC_SELECTOR: "\u{1F50E} Selettori",
|
|
1873
1904
|
SELECTOR_1: "Scegli l'attributo preferito (data-cy, data-testid, aria-label, id) in Config.",
|
|
@@ -1880,6 +1911,8 @@ var I18N_IT = {
|
|
|
1880
1911
|
ADV_RUNNER: "Runner locale: npx lib-e2e-cypress-runner per eseguire uno spec headless dall'editor.",
|
|
1881
1912
|
ADV_CROSSAPP: "Cross-app: la registrazione sopravvive al cambio di micro-frontend (stessa origine).",
|
|
1882
1913
|
ADV_DRAG: "Trascina il pulsante \u23FA per spostare il widget; la posizione viene ricordata.",
|
|
1914
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
1915
|
+
// TODO: translate (it)
|
|
1883
1916
|
CLOSE: "Chiudi",
|
|
1884
1917
|
TAB_REFERENCE: "Riferimento rapido",
|
|
1885
1918
|
TAB_GUIDE: "Guida all'uso",
|
|
@@ -1898,13 +1931,14 @@ var I18N_IT = {
|
|
|
1898
1931
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
1899
1932
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
1900
1933
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
1934
|
+
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.",
|
|
1935
|
+
// TODO: translate (it)
|
|
1901
1936
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
1902
1937
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
1903
1938
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
1904
1939
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
1905
1940
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
1906
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1907
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
1941
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
1908
1942
|
}
|
|
1909
1943
|
};
|
|
1910
1944
|
|
|
@@ -1933,13 +1967,13 @@ var I18N_DE = {
|
|
|
1933
1967
|
REMOVE_TAG_TITLE: "Entfernen",
|
|
1934
1968
|
NOTES_LABEL: "Beschreibung / Notizen (optional):",
|
|
1935
1969
|
NOTES_PLACEHOLDER: "Was dieser Test validiert, Voraussetzungen usw.",
|
|
1936
|
-
TICKET_LABEL: "Ticket (optional):",
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1970
|
+
TICKET_LABEL: "Ticket / Issue (optional):",
|
|
1971
|
+
TICKET_PLACEHOLDER: "Z. B.: PROJ-123, #42",
|
|
1972
|
+
TICKET_WARN: "Ung\xFCltige ID f\xFCr den konfigurierten Anbieter (wird trotzdem gespeichert)",
|
|
1973
|
+
// TODO: translate
|
|
1974
|
+
CONFIRM_DISCARD: "Sind Sie sicher, dass Sie diese Aufzeichnung verwerfen m\xF6chten? Alle aufgezeichneten Schritte gehen verloren.",
|
|
1975
|
+
CONFIRM_DISCARD_BTN: "Ja, verwerfen",
|
|
1976
|
+
BACK_BTN: "Zur\xFCck"
|
|
1943
1977
|
},
|
|
1944
1978
|
TEST_EDITOR: {
|
|
1945
1979
|
NO_TAGS: "Keine Tags",
|
|
@@ -1955,7 +1989,9 @@ var I18N_DE = {
|
|
|
1955
1989
|
NO_TESTS: "Keine gespeicherten Tests",
|
|
1956
1990
|
DELETE_TITLE: "L\xF6schen",
|
|
1957
1991
|
GROUP_BY_TICKET: "\u{1F3AB} Nach Ticket gruppieren",
|
|
1958
|
-
|
|
1992
|
+
UNGROUP_TICKET: "\u{1F3AB} Gruppierung aufheben",
|
|
1993
|
+
NO_TICKET: "Kein Ticket",
|
|
1994
|
+
TICKET_LINK_TITLE: "Ticket \xF6ffnen"
|
|
1959
1995
|
},
|
|
1960
1996
|
CONFIG: {
|
|
1961
1997
|
LANG_SECTION: "\u{1F310} Sprache",
|
|
@@ -2015,25 +2051,34 @@ var I18N_DE = {
|
|
|
2015
2051
|
WIDGET_POSITION_RESET_BTN: "\u21BA Position zur\xFCcksetzen",
|
|
2016
2052
|
WIDGET_POSITION_RESET_DONE: "\u2713 Position zur\xFCckgesetzt",
|
|
2017
2053
|
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue-Tracker",
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2054
|
+
ISSUE_TRACKER_TITLE: "Tests mit Tickets verkn\xFCpfen",
|
|
2055
|
+
ISSUE_TRACKER_SUB: "F\xFCge beim Speichern eine Ticket-ID hinzu und erstelle einen klickbaren Link.",
|
|
2056
|
+
ISSUE_TRACKER_PROVIDER: "Anbieter",
|
|
2057
|
+
ISSUE_TRACKER_BASE_URL: "Basis-URL",
|
|
2058
|
+
ISSUE_TRACKER_BASE_URL_PH: "Z. B.: https://meinprojekt.atlassian.net",
|
|
2059
|
+
LOGIN_SETUP_SECTION: "\u{1F510} Login setup",
|
|
2060
|
+
LOGIN_SETUP_NOT_CONFIGURED: "Nicht konfiguriert",
|
|
2061
|
+
LOGIN_SETUP_SET_UP_BTN: "Einrichten",
|
|
2062
|
+
LOGIN_SETUP_TITLE: "Login-Konfiguration",
|
|
2063
|
+
LOGIN_SETUP_CREATE_SCAFFOLD: "Scaffold erstellen",
|
|
2064
|
+
LOGIN_SETUP_SELECT_EXISTING: "Vorhandene Datei ausw\xE4hlen",
|
|
2065
|
+
LOGIN_SETUP_FILE_NAME_LABEL: "Dateiname",
|
|
2066
|
+
LOGIN_SETUP_FILE_NAME_PH: "Z. B.: cypress/common-services/login.service.ts",
|
|
2067
|
+
LOGIN_SETUP_RESCAN: "\u{1F504} Erneut scannen",
|
|
2068
|
+
LOGIN_SETUP_NO_FUNCTIONS: "Keine exportierten Funktionen gefunden. Scaffold ausf\xFCllen und erneut scannen.",
|
|
2069
|
+
LOGIN_SETUP_BEFORE_LABEL: "before()-Funktion (einmal pro Suite)",
|
|
2070
|
+
LOGIN_SETUP_BEFORE_EACH_LABEL: "beforeEach()-Funktion (vor jedem Test)",
|
|
2071
|
+
LOGIN_SETUP_NONE_OPTION: "\u2014 Keine \u2014",
|
|
2072
|
+
LOGIN_SETUP_SUMMARY: "Datei: {file} \xB7 before: {before} \xB7 beforeEach: {beforeEach}",
|
|
2073
|
+
LOGIN_SETUP_SAVE_BTN: "\u{1F4BE} Speichern",
|
|
2074
|
+
LOGIN_SETUP_CLEAR_BTN: "Konfiguration entfernen",
|
|
2075
|
+
LOGIN_SETUP_CANCEL_BTN: "Abbrechen",
|
|
2076
|
+
LOGIN_SETUP_SOURCE_LABEL: "Quelle der Login-Datei",
|
|
2077
|
+
LOGIN_SETUP_CREATE_SUB: "Scaffold mit Beispielfunktionen erstellen",
|
|
2078
|
+
LOGIN_SETUP_SELECT_SUB: "Auf eine vorhandene Login-Service-Datei verweisen",
|
|
2079
|
+
LOGIN_SETUP_INJECT_TITLE: "Login-Bl\xF6cke hinzuf\xFCgen?",
|
|
2080
|
+
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?",
|
|
2081
|
+
LOGIN_SETUP_INJECT_CONFIRM: "Ja, hinzuf\xFCgen"
|
|
2037
2082
|
},
|
|
2038
2083
|
SELECTOR_PICKER: {
|
|
2039
2084
|
TITLE: "DOM-Element ausw\xE4hlen",
|
|
@@ -2124,6 +2169,12 @@ var I18N_DE = {
|
|
|
2124
2169
|
FILE_SAVE_ERROR_TOAST: "Fehler beim Speichern",
|
|
2125
2170
|
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures in cypress/fixtures geschrieben",
|
|
2126
2171
|
FIXTURES_NO_FOLDER_TOAST: "Fixtures konnten nicht geschrieben werden (Cypress-Ordner konfigurieren)",
|
|
2172
|
+
FILE_UPLOAD_MANUAL_TOAST: "F\xFCge {files} zu cypress/fixtures/ hinzu, bevor du den Test ausf\xFChrst.",
|
|
2173
|
+
// TODO: translate
|
|
2174
|
+
FILE_UPLOAD_COPIED_TOAST: "{files} nach cypress/fixtures/ kopiert.",
|
|
2175
|
+
// TODO: translate
|
|
2176
|
+
FILE_UPLOAD_COPY_ERROR_TOAST: "{files} konnte nicht nach cypress/fixtures/ kopiert werden. F\xFCge es manuell hinzu.",
|
|
2177
|
+
// TODO: translate
|
|
2127
2178
|
BTN_CONFIG: "Config",
|
|
2128
2179
|
BTN_FILES: "Dateien",
|
|
2129
2180
|
BTN_COMMANDS: "Befehle",
|
|
@@ -2171,7 +2222,7 @@ var I18N_DE = {
|
|
|
2171
2222
|
SEC_PANELS: "\u{1F5C2} Panels",
|
|
2172
2223
|
PANEL_TESTS: "\u{1F4CB} Tests \u2014 gespeichert: nach Tag filtern, kopieren, kombinieren, exportieren.",
|
|
2173
2224
|
PANEL_COMMANDS: "\u2328\uFE0F Befehle \u2014 aktuelle Aufzeichnung: umsortieren, l\xF6schen, Assertions hinzuf\xFCgen.",
|
|
2174
|
-
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 Sprache, Selektor, HTTP, Cypress-Ordner, Daten, Sichtbarkeit, Position.",
|
|
2225
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 Sprache, Selektor, HTTP, Cypress-Ordner, Login-Setup, Daten, Sichtbarkeit, Position.",
|
|
2175
2226
|
PANEL_FILES: "\u{1F4C1} Dateien \u2014 Tests in deine .cy.ts einf\xFCgen und den Runner starten.",
|
|
2176
2227
|
SEC_SELECTOR: "\u{1F50E} Selektoren",
|
|
2177
2228
|
SELECTOR_1: "W\xE4hle das bevorzugte Attribut (data-cy, data-testid, aria-label, id) unter Config.",
|
|
@@ -2184,6 +2235,8 @@ var I18N_DE = {
|
|
|
2184
2235
|
ADV_RUNNER: "Lokaler Runner: npx lib-e2e-cypress-runner, um einen Spec headless aus dem Editor zu starten.",
|
|
2185
2236
|
ADV_CROSSAPP: "Cross-App: die Aufzeichnung \xFCbersteht den Wechsel des Micro-Frontends (gleicher Origin).",
|
|
2186
2237
|
ADV_DRAG: "Ziehe den \u23FA-Button, um das Widget zu verschieben; die Position wird gemerkt.",
|
|
2238
|
+
ADV_LOGIN: "Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() autom\xE1ticamente en cada test nuevo.",
|
|
2239
|
+
// TODO: translate (de)
|
|
2187
2240
|
CLOSE: "Schlie\xDFen",
|
|
2188
2241
|
TAB_REFERENCE: "Kurzreferenz",
|
|
2189
2242
|
TAB_GUIDE: "Nutzungsleitfaden",
|
|
@@ -2202,13 +2255,14 @@ var I18N_DE = {
|
|
|
2202
2255
|
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
2203
2256
|
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
2204
2257
|
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
2258
|
+
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.",
|
|
2259
|
+
// TODO: translate (de)
|
|
2205
2260
|
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
2206
2261
|
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
2207
2262
|
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
2208
2263
|
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
2209
2264
|
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
2210
|
-
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
2211
|
-
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
2265
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse."
|
|
2212
2266
|
}
|
|
2213
2267
|
};
|
|
2214
2268
|
|
|
@@ -2251,34 +2305,8 @@ var TranslationService = class {
|
|
|
2251
2305
|
};
|
|
2252
2306
|
var translationService = new TranslationService();
|
|
2253
2307
|
|
|
2254
|
-
// src/utils/code-format.utils.ts
|
|
2255
|
-
function gcd(a, b) {
|
|
2256
|
-
while (b) {
|
|
2257
|
-
const t = b;
|
|
2258
|
-
b = a % b;
|
|
2259
|
-
a = t;
|
|
2260
|
-
}
|
|
2261
|
-
return a;
|
|
2262
|
-
}
|
|
2263
|
-
function escapeSingleQuotes(value) {
|
|
2264
|
-
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
2265
|
-
}
|
|
2266
|
-
function normalizeBlock(code, baseIndent) {
|
|
2267
|
-
const lines = code.split("\n").map((l) => l.trimEnd());
|
|
2268
|
-
const nonEmpty = lines.filter((l) => l.trim().length > 0);
|
|
2269
|
-
if (!nonEmpty.length) return "";
|
|
2270
|
-
const indents = nonEmpty.map((l) => l.length - l.trimStart().length);
|
|
2271
|
-
const minIndent = Math.min(...indents);
|
|
2272
|
-
const relIndents = [...new Set(indents.map((n) => n - minIndent).filter((n) => n > 0))];
|
|
2273
|
-
const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;
|
|
2274
|
-
return lines.map((l) => {
|
|
2275
|
-
if (!l.trim()) return "";
|
|
2276
|
-
const level = Math.round((l.length - l.trimStart().length - minIndent) / step);
|
|
2277
|
-
return baseIndent + " ".repeat(level) + l.trimStart();
|
|
2278
|
-
}).join("\n");
|
|
2279
|
-
}
|
|
2280
|
-
|
|
2281
2308
|
// src/services/transformation.service.ts
|
|
2309
|
+
init_code_format_utils();
|
|
2282
2310
|
var TransformationService = class {
|
|
2283
2311
|
toLang(lang) {
|
|
2284
2312
|
return isLang(lang) ? lang : "en";
|
|
@@ -2343,6 +2371,7 @@ var advancedTestTransformationService = new AdvancedTestTransformationService();
|
|
|
2343
2371
|
init_selector_quality_utils();
|
|
2344
2372
|
|
|
2345
2373
|
// src/utils/assertion.utils.ts
|
|
2374
|
+
init_code_format_utils();
|
|
2346
2375
|
var MAX_TEXT_LENGTH = 60;
|
|
2347
2376
|
function inferAssertionCommand(el, selector) {
|
|
2348
2377
|
const should = (body) => `cy.get('${selector}').should(${body})`;
|
|
@@ -2367,6 +2396,7 @@ function inferAssertionCommand(el, selector) {
|
|
|
2367
2396
|
}
|
|
2368
2397
|
|
|
2369
2398
|
// src/services/recording.service.ts
|
|
2399
|
+
init_code_format_utils();
|
|
2370
2400
|
var OWN_SELECTOR = '[data-cy="lib-e2e-cypress-for-dummys"]';
|
|
2371
2401
|
function createSessionId() {
|
|
2372
2402
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
@@ -2382,6 +2412,7 @@ var RecordingService = class {
|
|
|
2382
2412
|
selectorNotFound$ = new Subject(null);
|
|
2383
2413
|
inputDebounceTimers = /* @__PURE__ */ new Map();
|
|
2384
2414
|
fixtures = /* @__PURE__ */ new Map();
|
|
2415
|
+
uploadedFiles = /* @__PURE__ */ new Map();
|
|
2385
2416
|
abort = new AbortController();
|
|
2386
2417
|
selectorStrategy = "data-cy";
|
|
2387
2418
|
/** Stable id of the current live session (null when none has started). */
|
|
@@ -2402,12 +2433,13 @@ var RecordingService = class {
|
|
|
2402
2433
|
}
|
|
2403
2434
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
2404
2435
|
startRecording() {
|
|
2436
|
+
this.clearCommands();
|
|
2405
2437
|
this.sessionId = createSessionId();
|
|
2406
2438
|
this.startedAt = Date.now();
|
|
2407
2439
|
this.isPaused$.next(false);
|
|
2408
2440
|
this.isRecording$.next(true);
|
|
2409
2441
|
this.addCommand(`cy.viewport(1900, 1200)`);
|
|
2410
|
-
this.addCommand(`cy.visit('${window.location.pathname}')`);
|
|
2442
|
+
this.addCommand(`cy.visit('${escapeSingleQuotes(window.location.pathname)}')`);
|
|
2411
2443
|
this.addCommand(`cy.get('[data-cy="lib-e2e-cypress-for-dummys"]').invoke('hide');`);
|
|
2412
2444
|
}
|
|
2413
2445
|
/**
|
|
@@ -2505,10 +2537,20 @@ var RecordingService = class {
|
|
|
2505
2537
|
getFixturesSnapshot() {
|
|
2506
2538
|
return [...this.fixtures.entries()].map(([name, content]) => ({ name, content }));
|
|
2507
2539
|
}
|
|
2540
|
+
addUploadedFile(filename, bytes) {
|
|
2541
|
+
this.uploadedFiles.set(filename, bytes);
|
|
2542
|
+
}
|
|
2543
|
+
getUploadedFilesSnapshot() {
|
|
2544
|
+
return [...this.uploadedFiles.entries()].map(([filename, bytes]) => ({ filename, bytes }));
|
|
2545
|
+
}
|
|
2546
|
+
clearUploadedFiles() {
|
|
2547
|
+
this.uploadedFiles.clear();
|
|
2548
|
+
}
|
|
2508
2549
|
clearCommands() {
|
|
2509
2550
|
this.commands$.next([]);
|
|
2510
2551
|
this.interceptors$.next([]);
|
|
2511
2552
|
this.fixtures.clear();
|
|
2553
|
+
this.uploadedFiles.clear();
|
|
2512
2554
|
}
|
|
2513
2555
|
clearInterceptors() {
|
|
2514
2556
|
this.interceptors$.next([]);
|
|
@@ -2628,7 +2670,8 @@ var RecordingService = class {
|
|
|
2628
2670
|
if (e.altKey) return;
|
|
2629
2671
|
const selector = this.resolveSelectorFor(e.target);
|
|
2630
2672
|
if (!selector) return;
|
|
2631
|
-
const
|
|
2673
|
+
const safeSelector = escapeSingleQuotes(selector);
|
|
2674
|
+
const clickCmd = `cy.get('${safeSelector}').click()`;
|
|
2632
2675
|
let cmds = this.commands$.getValue();
|
|
2633
2676
|
let removed = 0;
|
|
2634
2677
|
while (removed < 2 && cmds.length > 0 && cmds[cmds.length - 1] === clickCmd) {
|
|
@@ -2636,7 +2679,7 @@ var RecordingService = class {
|
|
|
2636
2679
|
removed++;
|
|
2637
2680
|
}
|
|
2638
2681
|
if (removed > 0) this.commands$.next(cmds);
|
|
2639
|
-
this.addCommand(`cy.get('${
|
|
2682
|
+
this.addCommand(`cy.get('${safeSelector}').dblclick()`);
|
|
2640
2683
|
},
|
|
2641
2684
|
{ signal: this.abort.signal }
|
|
2642
2685
|
);
|
|
@@ -2648,7 +2691,7 @@ var RecordingService = class {
|
|
|
2648
2691
|
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2649
2692
|
const selector = this.resolveSelectorFor(e.target);
|
|
2650
2693
|
if (!selector) return;
|
|
2651
|
-
this.addCommand(`cy.get('${selector}').rightclick()`);
|
|
2694
|
+
this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').rightclick()`);
|
|
2652
2695
|
},
|
|
2653
2696
|
{ signal: this.abort.signal }
|
|
2654
2697
|
);
|
|
@@ -2668,7 +2711,7 @@ var RecordingService = class {
|
|
|
2668
2711
|
if (!selector) return;
|
|
2669
2712
|
this.flushInputDebounce(target);
|
|
2670
2713
|
const token = key === "Enter" ? "{enter}" : "{esc}";
|
|
2671
|
-
this.addCommand(`cy.get('${selector}').type('${token}')`);
|
|
2714
|
+
this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').type('${token}')`);
|
|
2672
2715
|
},
|
|
2673
2716
|
{ signal: this.abort.signal }
|
|
2674
2717
|
);
|
|
@@ -2692,19 +2735,52 @@ var RecordingService = class {
|
|
|
2692
2735
|
if (!this.isRecording$.getValue()) return;
|
|
2693
2736
|
const target = e.target;
|
|
2694
2737
|
if (!target || this.isOwnElement(target)) return;
|
|
2695
|
-
|
|
2738
|
+
const tag = target.tagName.toLowerCase();
|
|
2739
|
+
if (tag === "select") {
|
|
2696
2740
|
this.handleSelectEvent(target);
|
|
2741
|
+
} else if (tag === "input") {
|
|
2742
|
+
const type = (target.getAttribute("type") ?? "").toLowerCase();
|
|
2743
|
+
if (type === "file") {
|
|
2744
|
+
void this.handleFileInputChange(target);
|
|
2745
|
+
}
|
|
2697
2746
|
}
|
|
2698
2747
|
},
|
|
2699
2748
|
{ signal: this.abort.signal }
|
|
2700
2749
|
);
|
|
2701
2750
|
}
|
|
2751
|
+
async handleFileInputChange(target) {
|
|
2752
|
+
if (this.isPaused$.getValue()) return;
|
|
2753
|
+
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2754
|
+
if (!container) return;
|
|
2755
|
+
const selector = this.getReliableSelector(container);
|
|
2756
|
+
if (!selector || this.isOwnSelector(selector)) return;
|
|
2757
|
+
const files = Array.from(target.files ?? []);
|
|
2758
|
+
if (!files.length) return;
|
|
2759
|
+
const paths = files.map((f) => `'cypress/fixtures/${escapeSingleQuotes(f.name)}'`);
|
|
2760
|
+
const pathArg = paths.length === 1 ? paths[0] : `[${paths.join(", ")}]`;
|
|
2761
|
+
this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').selectFile(${pathArg})`);
|
|
2762
|
+
for (const file of files) {
|
|
2763
|
+
const bytes = await this.readFileAsArrayBuffer(file);
|
|
2764
|
+
this.addUploadedFile(file.name, bytes);
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
readFileAsArrayBuffer(file) {
|
|
2768
|
+
if (typeof file.arrayBuffer === "function") {
|
|
2769
|
+
return file.arrayBuffer();
|
|
2770
|
+
}
|
|
2771
|
+
return new Promise((resolve, reject) => {
|
|
2772
|
+
const reader = new FileReader();
|
|
2773
|
+
reader.onload = () => resolve(reader.result);
|
|
2774
|
+
reader.onerror = () => reject(reader.error);
|
|
2775
|
+
reader.readAsArrayBuffer(file);
|
|
2776
|
+
});
|
|
2777
|
+
}
|
|
2702
2778
|
listenToRouteChanges() {
|
|
2703
2779
|
let lastUrl = window.location.pathname + window.location.search + window.location.hash;
|
|
2704
2780
|
const addUrlCommand = (newUrl) => {
|
|
2705
2781
|
if (!this.isRecording$.getValue()) return;
|
|
2706
2782
|
if (newUrl === lastUrl) return;
|
|
2707
|
-
this.addCommand(`cy.url().should('include', '${newUrl}')`);
|
|
2783
|
+
this.addCommand(`cy.url().should('include', '${escapeSingleQuotes(newUrl)}')`);
|
|
2708
2784
|
lastUrl = newUrl;
|
|
2709
2785
|
};
|
|
2710
2786
|
const wrapMethod = (type) => {
|
|
@@ -2751,6 +2827,13 @@ var RecordingService = class {
|
|
|
2751
2827
|
}
|
|
2752
2828
|
return;
|
|
2753
2829
|
}
|
|
2830
|
+
if (!this.isInteractiveElement(target)) {
|
|
2831
|
+
const interactive = target.closest(
|
|
2832
|
+
'button,a,input,select,textarea,label,summary,mat-option,[role="button"],[role="link"],[role="menuitem"],[role="option"],[role="tab"]'
|
|
2833
|
+
);
|
|
2834
|
+
if (!interactive) return;
|
|
2835
|
+
target = interactive;
|
|
2836
|
+
}
|
|
2754
2837
|
}
|
|
2755
2838
|
const tag = target.tagName.toLowerCase();
|
|
2756
2839
|
if (tag === "input" || tag === "textarea" || tag === "select") {
|
|
@@ -2783,6 +2866,10 @@ var RecordingService = class {
|
|
|
2783
2866
|
this.handleMatOptionClick(target, selector);
|
|
2784
2867
|
return;
|
|
2785
2868
|
}
|
|
2869
|
+
if (!selector) {
|
|
2870
|
+
this.selectorNotFound$.next({ target, action: "click" });
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2786
2873
|
this.addGenericCommand({
|
|
2787
2874
|
selector,
|
|
2788
2875
|
action: (s) => `cy.get('${s}').click()`
|
|
@@ -2794,7 +2881,8 @@ var RecordingService = class {
|
|
|
2794
2881
|
if (matSelect) dataCy = matSelect.closest("[data-cy]")?.getAttribute("data-cy") ?? null;
|
|
2795
2882
|
if (!dataCy) dataCy = target.closest("[data-cy]")?.getAttribute("data-cy") ?? null;
|
|
2796
2883
|
if (dataCy) {
|
|
2797
|
-
|
|
2884
|
+
const safeSel = escapeSingleQuotes(`[data-cy="${escapeCssAttrValue(dataCy)}"]`);
|
|
2885
|
+
this.addCommand(`cy.get('${safeSel}').click()`);
|
|
2798
2886
|
return;
|
|
2799
2887
|
}
|
|
2800
2888
|
if (selector) {
|
|
@@ -2826,7 +2914,7 @@ var RecordingService = class {
|
|
|
2826
2914
|
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2827
2915
|
if (!container) return;
|
|
2828
2916
|
const selector = this.getReliableSelector(container);
|
|
2829
|
-
const value = target.value
|
|
2917
|
+
const value = escapeSingleQuotes(target.value);
|
|
2830
2918
|
this.addGenericCommand({
|
|
2831
2919
|
selector,
|
|
2832
2920
|
action: (s) => `cy.get('${s}').clear().type('${value}')`
|
|
@@ -2845,7 +2933,7 @@ var RecordingService = class {
|
|
|
2845
2933
|
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2846
2934
|
if (!container) return;
|
|
2847
2935
|
const selector = this.getReliableSelector(container);
|
|
2848
|
-
const value = target.value
|
|
2936
|
+
const value = escapeSingleQuotes(target.value);
|
|
2849
2937
|
this.addGenericCommand({
|
|
2850
2938
|
selector,
|
|
2851
2939
|
action: (s) => `cy.get('${s}').select('${value}')`
|
|
@@ -2854,7 +2942,7 @@ var RecordingService = class {
|
|
|
2854
2942
|
// ── Shared helpers ────────────────────────────────────────────────────────
|
|
2855
2943
|
addGenericCommand(opts) {
|
|
2856
2944
|
if (!opts.selector || this.isOwnSelector(opts.selector)) return;
|
|
2857
|
-
this.addCommand(opts.action(opts.selector));
|
|
2945
|
+
this.addCommand(opts.action(escapeSingleQuotes(opts.selector)));
|
|
2858
2946
|
}
|
|
2859
2947
|
getReliableSelector(el) {
|
|
2860
2948
|
const strategy = this.selectorStrategy;
|
|
@@ -2866,20 +2954,20 @@ var RecordingService = class {
|
|
|
2866
2954
|
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;
|
|
2867
2955
|
switch (strategy) {
|
|
2868
2956
|
case "data-testid":
|
|
2869
|
-
if (dataTestid) return `[data-testid="${dataTestid}"]`;
|
|
2870
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2957
|
+
if (dataTestid) return `[data-testid="${escapeCssAttrValue(dataTestid)}"]`;
|
|
2958
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2871
2959
|
return validId ? `#${validId}` : null;
|
|
2872
2960
|
case "aria-label":
|
|
2873
|
-
if (ariaLabel) return `[aria-label="${ariaLabel}"]`;
|
|
2874
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2961
|
+
if (ariaLabel) return `[aria-label="${escapeCssAttrValue(ariaLabel)}"]`;
|
|
2962
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2875
2963
|
return validId ? `#${validId}` : null;
|
|
2876
2964
|
case "id":
|
|
2877
2965
|
if (validId) return `#${validId}`;
|
|
2878
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2879
|
-
return dataTestid ? `[data-testid="${dataTestid}"]` : null;
|
|
2966
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2967
|
+
return dataTestid ? `[data-testid="${escapeCssAttrValue(dataTestid)}"]` : null;
|
|
2880
2968
|
default:
|
|
2881
|
-
if (dataCy) return `[data-cy="${dataCy}"]`;
|
|
2882
|
-
if (dataDotCy) return `[data.cy="${dataDotCy}"]`;
|
|
2969
|
+
if (dataCy) return `[data-cy="${escapeCssAttrValue(dataCy)}"]`;
|
|
2970
|
+
if (dataDotCy) return `[data.cy="${escapeCssAttrValue(dataDotCy)}"]`;
|
|
2883
2971
|
return validId ? `#${validId}` : null;
|
|
2884
2972
|
}
|
|
2885
2973
|
}
|
|
@@ -2905,44 +2993,41 @@ var RecordingService = class {
|
|
|
2905
2993
|
|
|
2906
2994
|
// src/services/persistence.service.ts
|
|
2907
2995
|
var import_idb = require("idb");
|
|
2996
|
+
init_code_format_utils();
|
|
2997
|
+
|
|
2998
|
+
// src/models/issue-tracker.model.ts
|
|
2999
|
+
var ISSUE_TRACKER_PRESETS = {
|
|
3000
|
+
jira: { id: "jira", label: "Jira", urlPattern: "{baseUrl}/browse/{id}", idPattern: /^[A-Z][A-Z0-9]+-\d+$/ },
|
|
3001
|
+
github: { id: "github", label: "GitHub Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
3002
|
+
gitlab: { id: "gitlab", label: "GitLab Issues", urlPattern: "{baseUrl}/-/issues/{id}", idPattern: /^\d+$/ },
|
|
3003
|
+
azure: { id: "azure", label: "Azure DevOps", urlPattern: "{baseUrl}/_workitems/edit/{id}", idPattern: /^\d+$/ },
|
|
3004
|
+
bitbucket: { id: "bitbucket", label: "Bitbucket Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
3005
|
+
custom: { id: "custom", label: "Custom", urlPattern: "{baseUrl}/{id}", idPattern: /.+/ }
|
|
3006
|
+
};
|
|
3007
|
+
var DEFAULT_ISSUE_TRACKER_CONFIG = {
|
|
3008
|
+
enabled: false,
|
|
3009
|
+
provider: "jira",
|
|
3010
|
+
baseUrl: ""
|
|
3011
|
+
};
|
|
2908
3012
|
|
|
2909
3013
|
// src/utils/ticket.utils.ts
|
|
2910
|
-
function buildTicketUrl(
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
const value = (params?.[field.key] ?? "").trim().replace(/\/+$/, "");
|
|
2916
|
-
if (!value) return null;
|
|
2917
|
-
url = url.split(`{${field.key}}`).join(value);
|
|
2918
|
-
}
|
|
2919
|
-
url = url.split("{id}").join(encodeURIComponent(ticketId));
|
|
2920
|
-
if (url.includes("{") || url.includes("}")) return null;
|
|
2921
|
-
return toSafeHttpUrl(url);
|
|
3014
|
+
function buildTicketUrl(ticketId, config) {
|
|
3015
|
+
if (!config.enabled || !ticketId.trim() || !config.baseUrl.trim()) return null;
|
|
3016
|
+
const preset = ISSUE_TRACKER_PRESETS[config.provider];
|
|
3017
|
+
const base = config.baseUrl.replace(/\/+$/, "");
|
|
3018
|
+
return preset.urlPattern.replace("{baseUrl}", base).replace("{id}", encodeURIComponent(ticketId.trim()));
|
|
2922
3019
|
}
|
|
2923
|
-
function
|
|
2924
|
-
|
|
2925
|
-
if (!id) return null;
|
|
2926
|
-
const provider = findIssueTrackerProvider(providerId);
|
|
2927
|
-
if (!provider) return null;
|
|
2928
|
-
return buildTicketUrl(provider, allParams?.[providerId] ?? {}, id);
|
|
2929
|
-
}
|
|
2930
|
-
function toSafeHttpUrl(candidate) {
|
|
2931
|
-
try {
|
|
2932
|
-
const parsed = new URL(candidate);
|
|
2933
|
-
return parsed.protocol === "http:" || parsed.protocol === "https:" ? parsed.href : null;
|
|
2934
|
-
} catch {
|
|
2935
|
-
return null;
|
|
2936
|
-
}
|
|
3020
|
+
function buildTicketComment(ticketId) {
|
|
3021
|
+
return `// Ticket: ${ticketId.trim()}`;
|
|
2937
3022
|
}
|
|
2938
|
-
function
|
|
2939
|
-
|
|
2940
|
-
return
|
|
3023
|
+
function isValidTicketId(ticketId, provider) {
|
|
3024
|
+
if (!ticketId.trim()) return false;
|
|
3025
|
+
return ISSUE_TRACKER_PRESETS[provider].idPattern.test(ticketId.trim());
|
|
2941
3026
|
}
|
|
2942
3027
|
|
|
2943
3028
|
// src/services/persistence.service.ts
|
|
2944
3029
|
var ACTIVE_SESSION_ID = 1;
|
|
2945
|
-
var PersistenceService = class {
|
|
3030
|
+
var PersistenceService = class _PersistenceService {
|
|
2946
3031
|
// dbName is overridable so tests can use unique names for isolation.
|
|
2947
3032
|
constructor(dbName = DB_SCHEMA.name) {
|
|
2948
3033
|
this.dbName = dbName;
|
|
@@ -2995,28 +3080,13 @@ var PersistenceService = class {
|
|
|
2995
3080
|
if (!record) return null;
|
|
2996
3081
|
const commands = await this.getCommandStrings(testId);
|
|
2997
3082
|
const interceptors = await this.getInterceptorStrings(testId);
|
|
2998
|
-
const ticketComment =
|
|
2999
|
-
const
|
|
3083
|
+
const ticketComment = record.ticketId ? buildTicketComment(record.ticketId) + "\n" : "";
|
|
3084
|
+
const itBlock = `${ticketComment}it('${escapeSingleQuotes(record.name)}', () => {
|
|
3000
3085
|
${commands.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
3001
3086
|
});`;
|
|
3002
|
-
const itBlock = ticketComment ? `${ticketComment}
|
|
3003
|
-
${itBody}` : itBody;
|
|
3004
3087
|
const interceptorsBlock = interceptors.length ? " // Auto-generated Cypress interceptors\n" + interceptors.map((i) => normalizeBlock(i, " ")).join("\n") + "\n" : "";
|
|
3005
3088
|
return { ...record, commands, interceptors, cypressCommands: commands, itBlock, interceptorsBlock };
|
|
3006
3089
|
}
|
|
3007
|
-
/**
|
|
3008
|
-
* Builds the traceability comment for a test record (spec 014), reading the
|
|
3009
|
-
* configured issue-tracker provider/params so the link — when resolvable — is
|
|
3010
|
-
* embedded. Returns `null` when the record has no ticket id.
|
|
3011
|
-
*/
|
|
3012
|
-
async ticketCommentFor(record) {
|
|
3013
|
-
if (!record.ticketId) return null;
|
|
3014
|
-
const config = await this.getGeneralConfig();
|
|
3015
|
-
const providerId = config?.["issueTrackerProviderId"] ?? DEFAULT_ISSUE_TRACKER_PROVIDER_ID;
|
|
3016
|
-
const params = config?.["issueTrackerParams"] ?? {};
|
|
3017
|
-
const url = resolveTicketUrl(providerId, params, record.ticketId);
|
|
3018
|
-
return buildTicketComment(record.ticketId, url);
|
|
3019
|
-
}
|
|
3020
3090
|
async deleteTest(id) {
|
|
3021
3091
|
const db = await this.getDB();
|
|
3022
3092
|
await db.delete("tests", id);
|
|
@@ -3092,6 +3162,30 @@ ${itBody}` : itBody;
|
|
|
3092
3162
|
const records = await db.getAll("configuration");
|
|
3093
3163
|
return records[0] ?? null;
|
|
3094
3164
|
}
|
|
3165
|
+
// ── Login setup config ───────────────────────────────────────────────────
|
|
3166
|
+
static LOGIN_SETUP_KEY = "loginSetupConfig";
|
|
3167
|
+
async saveLoginSetup(config) {
|
|
3168
|
+
await this.setConfigKey(_PersistenceService.LOGIN_SETUP_KEY, JSON.stringify(config));
|
|
3169
|
+
}
|
|
3170
|
+
async getLoginSetup() {
|
|
3171
|
+
const record = await this.getConfig(_PersistenceService.LOGIN_SETUP_KEY);
|
|
3172
|
+
if (!record) return null;
|
|
3173
|
+
const raw = record[_PersistenceService.LOGIN_SETUP_KEY];
|
|
3174
|
+
if (typeof raw !== "string") return null;
|
|
3175
|
+
try {
|
|
3176
|
+
return JSON.parse(raw);
|
|
3177
|
+
} catch {
|
|
3178
|
+
return null;
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
async clearLoginSetup() {
|
|
3182
|
+
const db = await this.getDB();
|
|
3183
|
+
const records = await db.getAll("configuration");
|
|
3184
|
+
if (!records.length) return;
|
|
3185
|
+
const current = { ...records[0] };
|
|
3186
|
+
delete current[_PersistenceService.LOGIN_SETUP_KEY];
|
|
3187
|
+
await db.put("configuration", current);
|
|
3188
|
+
}
|
|
3095
3189
|
// ── Active recording session ──────────────────────────────────────────────
|
|
3096
3190
|
/** Upserts the live recording session (single record, fixed key). */
|
|
3097
3191
|
async saveActiveSession(state) {
|
|
@@ -3134,6 +3228,24 @@ ${itBody}` : itBody;
|
|
|
3134
3228
|
}
|
|
3135
3229
|
await this.bulkInsertWithoutId("interceptors", interceptors);
|
|
3136
3230
|
}
|
|
3231
|
+
async hasDirectoryAccess() {
|
|
3232
|
+
const config = await this.getGeneralConfig();
|
|
3233
|
+
return !!config?.["cypressDirectoryHandle"];
|
|
3234
|
+
}
|
|
3235
|
+
async writeUploadedFile(filename, bytes) {
|
|
3236
|
+
const config = await this.getGeneralConfig();
|
|
3237
|
+
const dirHandle = config?.["cypressDirectoryHandle"];
|
|
3238
|
+
if (!dirHandle) throw new Error("No Cypress folder configured");
|
|
3239
|
+
const perm = dirHandle;
|
|
3240
|
+
let state = await perm.queryPermission({ mode: "readwrite" });
|
|
3241
|
+
if (state !== "granted") state = await perm.requestPermission({ mode: "readwrite" });
|
|
3242
|
+
if (state !== "granted") throw new Error("Write permission denied");
|
|
3243
|
+
const fixturesDir = await dirHandle.getDirectoryHandle("fixtures", { create: true });
|
|
3244
|
+
const fileHandle = await fixturesDir.getFileHandle(filename, { create: true });
|
|
3245
|
+
const writable = await fileHandle.createWritable();
|
|
3246
|
+
await writable.write(bytes);
|
|
3247
|
+
await writable.close();
|
|
3248
|
+
}
|
|
3137
3249
|
async requestDirectoryPermissions() {
|
|
3138
3250
|
if (!("showDirectoryPicker" in window)) {
|
|
3139
3251
|
throw new Error("File System Access API not supported");
|
|
@@ -3176,7 +3288,36 @@ ${itBody}` : itBody;
|
|
|
3176
3288
|
}
|
|
3177
3289
|
}
|
|
3178
3290
|
};
|
|
3179
|
-
|
|
3291
|
+
|
|
3292
|
+
// src/services/http-monitor.ts
|
|
3293
|
+
init_code_format_utils();
|
|
3294
|
+
|
|
3295
|
+
// src/utils/redact.utils.ts
|
|
3296
|
+
var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
3297
|
+
"password",
|
|
3298
|
+
"token",
|
|
3299
|
+
"secret",
|
|
3300
|
+
"authorization",
|
|
3301
|
+
"cookie",
|
|
3302
|
+
"access_token",
|
|
3303
|
+
"refresh_token"
|
|
3304
|
+
]);
|
|
3305
|
+
function isSensitiveKey(key) {
|
|
3306
|
+
return SENSITIVE_KEYS.has(key.toLowerCase());
|
|
3307
|
+
}
|
|
3308
|
+
function redactSensitiveFields(obj) {
|
|
3309
|
+
if (Array.isArray(obj)) {
|
|
3310
|
+
return obj.map(redactSensitiveFields);
|
|
3311
|
+
}
|
|
3312
|
+
if (obj !== null && typeof obj === "object") {
|
|
3313
|
+
const result = {};
|
|
3314
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
3315
|
+
result[key] = isSensitiveKey(key) ? "[REDACTED]" : redactSensitiveFields(value);
|
|
3316
|
+
}
|
|
3317
|
+
return result;
|
|
3318
|
+
}
|
|
3319
|
+
return obj;
|
|
3320
|
+
}
|
|
3180
3321
|
|
|
3181
3322
|
// src/services/http-monitor.ts
|
|
3182
3323
|
var INTERCEPTED_METHODS = ["GET", "POST", "PUT"];
|
|
@@ -3189,8 +3330,12 @@ function generateAlias(method, url) {
|
|
|
3189
3330
|
return `${method.toLowerCase()}-intercepted-request`;
|
|
3190
3331
|
}
|
|
3191
3332
|
}
|
|
3333
|
+
var SAFE_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
3192
3334
|
function buildValidations(base, obj) {
|
|
3193
|
-
return Object.keys(obj).filter((key) => key !== "id" && key !== "uid").map((key) =>
|
|
3335
|
+
return Object.keys(obj).filter((key) => key !== "id" && key !== "uid").map((key) => {
|
|
3336
|
+
const accessor = SAFE_IDENTIFIER.test(key) ? `.${key}` : `['${escapeSingleQuotes(key)}']`;
|
|
3337
|
+
return `expect(${base}${accessor}).to.equal(${JSON.stringify(obj[key])});`;
|
|
3338
|
+
}).join("\n");
|
|
3194
3339
|
}
|
|
3195
3340
|
function buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody) {
|
|
3196
3341
|
if (extendedHttp && method === "GET" && responseBody) {
|
|
@@ -3242,20 +3387,149 @@ function resolveMethod(input, init) {
|
|
|
3242
3387
|
if (input instanceof Request) return input.method.toUpperCase();
|
|
3243
3388
|
return "GET";
|
|
3244
3389
|
}
|
|
3390
|
+
async function _handleFetchInterception(recording, input, init, responseClone) {
|
|
3391
|
+
const method = resolveMethod(input, init);
|
|
3392
|
+
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3393
|
+
const url = resolveUrl(input);
|
|
3394
|
+
const alias = generateAlias(method, url);
|
|
3395
|
+
recording.registerInterceptor(method, url, alias);
|
|
3396
|
+
const extendedHttp = localStorage.getItem("extendedHttpCommands") === "true";
|
|
3397
|
+
const fixtureMode = localStorage.getItem("fixtureMode") === "true";
|
|
3398
|
+
const requestBody = extendedHttp ? parseRequestBody(init) : null;
|
|
3399
|
+
let responseText = null;
|
|
3400
|
+
let responseBody = null;
|
|
3401
|
+
if (extendedHttp || fixtureMode && method === "GET") {
|
|
3402
|
+
try {
|
|
3403
|
+
responseText = await responseClone.text();
|
|
3404
|
+
if (extendedHttp) responseBody = parseJsonObject(responseText);
|
|
3405
|
+
} catch {
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
if (fixtureMode && method === "GET" && responseText !== null) {
|
|
3409
|
+
const pretty = prettyJsonOrNull(responseText);
|
|
3410
|
+
if (pretty !== null) {
|
|
3411
|
+
const redacted = redactSensitiveFields(JSON.parse(pretty));
|
|
3412
|
+
recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
const cmd = buildCyWaitCommand(
|
|
3416
|
+
method,
|
|
3417
|
+
alias,
|
|
3418
|
+
extendedHttp,
|
|
3419
|
+
requestBody ? redactSensitiveFields(requestBody) : null,
|
|
3420
|
+
responseBody ? redactSensitiveFields(responseBody) : null
|
|
3421
|
+
);
|
|
3422
|
+
recording.addCommand(cmd);
|
|
3423
|
+
}
|
|
3424
|
+
function _handleXhrInterception(recording, method, url, requestBody, responseText) {
|
|
3425
|
+
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3426
|
+
const alias = generateAlias(method, url);
|
|
3427
|
+
recording.registerInterceptor(method, url, alias);
|
|
3428
|
+
if (localStorage.getItem("fixtureMode") === "true" && method === "GET") {
|
|
3429
|
+
const pretty = prettyJsonOrNull(responseText);
|
|
3430
|
+
if (pretty !== null) {
|
|
3431
|
+
const redacted = redactSensitiveFields(JSON.parse(pretty));
|
|
3432
|
+
recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
const extendedHttp = localStorage.getItem("extendedHttpCommands") === "true";
|
|
3436
|
+
const responseBody = extendedHttp ? parseJsonObject(responseText) : null;
|
|
3437
|
+
const cmd = buildCyWaitCommand(
|
|
3438
|
+
method,
|
|
3439
|
+
alias,
|
|
3440
|
+
extendedHttp,
|
|
3441
|
+
requestBody ? redactSensitiveFields(requestBody) : null,
|
|
3442
|
+
responseBody ? redactSensitiveFields(responseBody) : null
|
|
3443
|
+
);
|
|
3444
|
+
recording.addCommand(cmd);
|
|
3445
|
+
}
|
|
3446
|
+
var _refCount = 0;
|
|
3447
|
+
var _originalFetch = null;
|
|
3448
|
+
var _originalXHR = null;
|
|
3449
|
+
var _recordings = /* @__PURE__ */ new Set();
|
|
3450
|
+
function _patchFetch() {
|
|
3451
|
+
const orig = window.fetch;
|
|
3452
|
+
_originalFetch = orig;
|
|
3453
|
+
window.fetch = async (input, init) => {
|
|
3454
|
+
const response = await orig(input, init);
|
|
3455
|
+
try {
|
|
3456
|
+
const active = [..._recordings];
|
|
3457
|
+
if (active.length > 0) {
|
|
3458
|
+
await Promise.all(
|
|
3459
|
+
active.map((rec) => _handleFetchInterception(rec, input, init, response.clone()).catch(() => {
|
|
3460
|
+
}))
|
|
3461
|
+
);
|
|
3462
|
+
}
|
|
3463
|
+
} catch {
|
|
3464
|
+
}
|
|
3465
|
+
return response;
|
|
3466
|
+
};
|
|
3467
|
+
}
|
|
3468
|
+
function _restoreFetch() {
|
|
3469
|
+
if (!_originalFetch) return;
|
|
3470
|
+
window.fetch = _originalFetch;
|
|
3471
|
+
_originalFetch = null;
|
|
3472
|
+
}
|
|
3473
|
+
function _patchXhr() {
|
|
3474
|
+
const OrigXHR = window.XMLHttpRequest;
|
|
3475
|
+
_originalXHR = OrigXHR;
|
|
3476
|
+
window.XMLHttpRequest = class extends OrigXHR {
|
|
3477
|
+
_xhrMethod = "GET";
|
|
3478
|
+
_xhrUrl = "";
|
|
3479
|
+
_xhrRequestBody = null;
|
|
3480
|
+
open(method, url, async = true, user, password) {
|
|
3481
|
+
this._xhrMethod = method.toUpperCase();
|
|
3482
|
+
this._xhrUrl = url instanceof URL ? url.href : url;
|
|
3483
|
+
super.open(method, url, async, user, password);
|
|
3484
|
+
}
|
|
3485
|
+
send(body) {
|
|
3486
|
+
if (typeof body === "string") {
|
|
3487
|
+
this._xhrRequestBody = parseJsonObject(body);
|
|
3488
|
+
}
|
|
3489
|
+
this.addEventListener("load", () => {
|
|
3490
|
+
try {
|
|
3491
|
+
for (const rec of _recordings) {
|
|
3492
|
+
_handleXhrInterception(rec, this._xhrMethod, this._xhrUrl, this._xhrRequestBody, this.responseText);
|
|
3493
|
+
}
|
|
3494
|
+
} catch {
|
|
3495
|
+
}
|
|
3496
|
+
});
|
|
3497
|
+
super.send(body);
|
|
3498
|
+
}
|
|
3499
|
+
};
|
|
3500
|
+
}
|
|
3501
|
+
function _restoreXhr() {
|
|
3502
|
+
if (!_originalXHR) return;
|
|
3503
|
+
window.XMLHttpRequest = _originalXHR;
|
|
3504
|
+
_originalXHR = null;
|
|
3505
|
+
}
|
|
3506
|
+
function _resetHttpMonitorState() {
|
|
3507
|
+
_refCount = 0;
|
|
3508
|
+
_originalFetch = null;
|
|
3509
|
+
_originalXHR = null;
|
|
3510
|
+
_recordings.clear();
|
|
3511
|
+
}
|
|
3245
3512
|
var HttpMonitor = class {
|
|
3246
3513
|
constructor(recording) {
|
|
3247
3514
|
this.recording = recording;
|
|
3248
3515
|
}
|
|
3249
3516
|
recording;
|
|
3250
|
-
originalFetch = null;
|
|
3251
|
-
originalXHR = null;
|
|
3252
3517
|
install() {
|
|
3253
|
-
this.
|
|
3254
|
-
|
|
3518
|
+
_recordings.add(this.recording);
|
|
3519
|
+
_refCount++;
|
|
3520
|
+
if (_refCount === 1) {
|
|
3521
|
+
_patchFetch();
|
|
3522
|
+
_patchXhr();
|
|
3523
|
+
}
|
|
3255
3524
|
}
|
|
3256
3525
|
uninstall() {
|
|
3257
|
-
this.
|
|
3258
|
-
|
|
3526
|
+
_recordings.delete(this.recording);
|
|
3527
|
+
if (_refCount <= 0) return;
|
|
3528
|
+
_refCount--;
|
|
3529
|
+
if (_refCount === 0) {
|
|
3530
|
+
_restoreFetch();
|
|
3531
|
+
_restoreXhr();
|
|
3532
|
+
}
|
|
3259
3533
|
}
|
|
3260
3534
|
isExtendedHttpEnabled() {
|
|
3261
3535
|
return localStorage.getItem("extendedHttpCommands") === "true";
|
|
@@ -3263,105 +3537,6 @@ var HttpMonitor = class {
|
|
|
3263
3537
|
isFixtureModeEnabled() {
|
|
3264
3538
|
return localStorage.getItem("fixtureMode") === "true";
|
|
3265
3539
|
}
|
|
3266
|
-
installFetch() {
|
|
3267
|
-
if (this.originalFetch) return;
|
|
3268
|
-
const originalFetch = window.fetch;
|
|
3269
|
-
this.originalFetch = originalFetch;
|
|
3270
|
-
window.fetch = async (input, init) => {
|
|
3271
|
-
const response = await originalFetch(input, init);
|
|
3272
|
-
try {
|
|
3273
|
-
await this.handleFetchInterception(input, init, response.clone());
|
|
3274
|
-
} catch {
|
|
3275
|
-
}
|
|
3276
|
-
return response;
|
|
3277
|
-
};
|
|
3278
|
-
}
|
|
3279
|
-
uninstallFetch() {
|
|
3280
|
-
if (!this.originalFetch) return;
|
|
3281
|
-
window.fetch = this.originalFetch;
|
|
3282
|
-
this.originalFetch = null;
|
|
3283
|
-
}
|
|
3284
|
-
installXhr() {
|
|
3285
|
-
if (this.originalXHR) return;
|
|
3286
|
-
this.originalXHR = window.XMLHttpRequest;
|
|
3287
|
-
const OrigXHR = this.originalXHR;
|
|
3288
|
-
const handleXhrInterception = this.handleXhrInterception.bind(this);
|
|
3289
|
-
window.XMLHttpRequest = class extends OrigXHR {
|
|
3290
|
-
_xhrMethod = "GET";
|
|
3291
|
-
_xhrUrl = "";
|
|
3292
|
-
_xhrRequestBody = null;
|
|
3293
|
-
open(method, url, async = true, user, password) {
|
|
3294
|
-
this._xhrMethod = method.toUpperCase();
|
|
3295
|
-
this._xhrUrl = url instanceof URL ? url.href : url;
|
|
3296
|
-
super.open(method, url, async, user, password);
|
|
3297
|
-
}
|
|
3298
|
-
send(body) {
|
|
3299
|
-
if (typeof body === "string") {
|
|
3300
|
-
this._xhrRequestBody = parseJsonObject(body);
|
|
3301
|
-
}
|
|
3302
|
-
this.addEventListener("load", () => {
|
|
3303
|
-
try {
|
|
3304
|
-
handleXhrInterception(
|
|
3305
|
-
this._xhrMethod,
|
|
3306
|
-
this._xhrUrl,
|
|
3307
|
-
this._xhrRequestBody,
|
|
3308
|
-
this.responseText
|
|
3309
|
-
);
|
|
3310
|
-
} catch {
|
|
3311
|
-
}
|
|
3312
|
-
});
|
|
3313
|
-
super.send(body);
|
|
3314
|
-
}
|
|
3315
|
-
};
|
|
3316
|
-
}
|
|
3317
|
-
uninstallXhr() {
|
|
3318
|
-
if (!this.originalXHR) return;
|
|
3319
|
-
window.XMLHttpRequest = this.originalXHR;
|
|
3320
|
-
this.originalXHR = null;
|
|
3321
|
-
}
|
|
3322
|
-
async handleFetchInterception(input, init, responseClone) {
|
|
3323
|
-
const method = resolveMethod(input, init);
|
|
3324
|
-
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3325
|
-
const url = resolveUrl(input);
|
|
3326
|
-
const alias = generateAlias(method, url);
|
|
3327
|
-
if (this.isFixtureModeEnabled() && method === "GET") {
|
|
3328
|
-
const pretty = prettyJsonOrNull(await responseClone.text());
|
|
3329
|
-
const fixtureFile = `${alias}.json`;
|
|
3330
|
-
if (pretty !== null) this.recording.registerFixture(fixtureFile, pretty);
|
|
3331
|
-
this.recording.registerInterceptor(method, url, alias, pretty !== null ? fixtureFile : void 0);
|
|
3332
|
-
this.recording.addCommand(`cy.wait('@${alias}').then((interception) => { })`);
|
|
3333
|
-
return;
|
|
3334
|
-
}
|
|
3335
|
-
this.recording.registerInterceptor(method, url, alias);
|
|
3336
|
-
const extendedHttp = this.isExtendedHttpEnabled();
|
|
3337
|
-
const requestBody = extendedHttp ? parseRequestBody(init) : null;
|
|
3338
|
-
let responseBody = null;
|
|
3339
|
-
if (extendedHttp) {
|
|
3340
|
-
try {
|
|
3341
|
-
responseBody = parseJsonObject(await responseClone.text());
|
|
3342
|
-
} catch {
|
|
3343
|
-
}
|
|
3344
|
-
}
|
|
3345
|
-
const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);
|
|
3346
|
-
this.recording.addCommand(cmd);
|
|
3347
|
-
}
|
|
3348
|
-
handleXhrInterception(method, url, requestBody, responseText) {
|
|
3349
|
-
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
3350
|
-
const alias = generateAlias(method, url);
|
|
3351
|
-
if (this.isFixtureModeEnabled() && method === "GET") {
|
|
3352
|
-
const pretty = prettyJsonOrNull(responseText);
|
|
3353
|
-
const fixtureFile = `${alias}.json`;
|
|
3354
|
-
if (pretty !== null) this.recording.registerFixture(fixtureFile, pretty);
|
|
3355
|
-
this.recording.registerInterceptor(method, url, alias, pretty !== null ? fixtureFile : void 0);
|
|
3356
|
-
this.recording.addCommand(`cy.wait('@${alias}').then((interception) => { })`);
|
|
3357
|
-
return;
|
|
3358
|
-
}
|
|
3359
|
-
this.recording.registerInterceptor(method, url, alias);
|
|
3360
|
-
const extendedHttp = this.isExtendedHttpEnabled();
|
|
3361
|
-
const responseBody = extendedHttp ? parseJsonObject(responseText) : null;
|
|
3362
|
-
const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);
|
|
3363
|
-
this.recording.addCommand(cmd);
|
|
3364
|
-
}
|
|
3365
3540
|
};
|
|
3366
3541
|
|
|
3367
3542
|
// src/utils/styles.utils.ts
|
|
@@ -3610,6 +3785,19 @@ function setSwal2DataCyAttribute(dataCy = "lib-e2e-cypress-for-dummys") {
|
|
|
3610
3785
|
document.querySelector(".swal2-html-container")?.setAttribute("data-cy", dataCy);
|
|
3611
3786
|
document.querySelector(".swal2-title")?.setAttribute("data-cy", dataCy);
|
|
3612
3787
|
}
|
|
3788
|
+
function ensurePopupDimensions(popup, heightPx) {
|
|
3789
|
+
if (!popup) return;
|
|
3790
|
+
popup.style.height = `${heightPx}px`;
|
|
3791
|
+
const htmlContainer = popup.querySelector(".swal2-html-container");
|
|
3792
|
+
if (!htmlContainer) return;
|
|
3793
|
+
htmlContainer.style.flex = "1";
|
|
3794
|
+
htmlContainer.style.minHeight = "0";
|
|
3795
|
+
htmlContainer.style.overflow = "hidden";
|
|
3796
|
+
htmlContainer.style.padding = "0";
|
|
3797
|
+
htmlContainer.style.margin = "0";
|
|
3798
|
+
htmlContainer.style.display = "flex";
|
|
3799
|
+
htmlContainer.style.flexDirection = "column";
|
|
3800
|
+
}
|
|
3613
3801
|
|
|
3614
3802
|
// src/utils/toast.utils.ts
|
|
3615
3803
|
function showToast(message, isSuccess = true) {
|
|
@@ -3681,177 +3869,6 @@ function boxTopLeftFor(toggleCentre, dir) {
|
|
|
3681
3869
|
return { x: toggleCentre.x - off.x, y: toggleCentre.y - off.y };
|
|
3682
3870
|
}
|
|
3683
3871
|
|
|
3684
|
-
// src/utils/cypress-completions.ts
|
|
3685
|
-
var CY_METHODS = [
|
|
3686
|
-
"visit",
|
|
3687
|
-
"get",
|
|
3688
|
-
"contains",
|
|
3689
|
-
"intercept",
|
|
3690
|
-
"wait",
|
|
3691
|
-
"request",
|
|
3692
|
-
"url",
|
|
3693
|
-
"location",
|
|
3694
|
-
"viewport",
|
|
3695
|
-
"fixture",
|
|
3696
|
-
"wrap",
|
|
3697
|
-
"reload",
|
|
3698
|
-
"go",
|
|
3699
|
-
"window",
|
|
3700
|
-
"document",
|
|
3701
|
-
"session",
|
|
3702
|
-
"clearCookies",
|
|
3703
|
-
"clearLocalStorage",
|
|
3704
|
-
"screenshot",
|
|
3705
|
-
"log"
|
|
3706
|
-
];
|
|
3707
|
-
var CHAIN_METHODS = [
|
|
3708
|
-
"click",
|
|
3709
|
-
"dblclick",
|
|
3710
|
-
"rightclick",
|
|
3711
|
-
"type",
|
|
3712
|
-
"clear",
|
|
3713
|
-
"select",
|
|
3714
|
-
"check",
|
|
3715
|
-
"uncheck",
|
|
3716
|
-
"should",
|
|
3717
|
-
"and",
|
|
3718
|
-
"find",
|
|
3719
|
-
"first",
|
|
3720
|
-
"last",
|
|
3721
|
-
"eq",
|
|
3722
|
-
"then",
|
|
3723
|
-
"its",
|
|
3724
|
-
"invoke",
|
|
3725
|
-
"as",
|
|
3726
|
-
"trigger",
|
|
3727
|
-
"focus",
|
|
3728
|
-
"blur",
|
|
3729
|
-
"scrollIntoView",
|
|
3730
|
-
"within",
|
|
3731
|
-
"parent",
|
|
3732
|
-
"children",
|
|
3733
|
-
"siblings",
|
|
3734
|
-
"contains",
|
|
3735
|
-
"each",
|
|
3736
|
-
"filter",
|
|
3737
|
-
"wait"
|
|
3738
|
-
];
|
|
3739
|
-
var TOP_LEVEL = [
|
|
3740
|
-
"cy",
|
|
3741
|
-
"describe",
|
|
3742
|
-
"it",
|
|
3743
|
-
"context",
|
|
3744
|
-
"beforeEach",
|
|
3745
|
-
"afterEach",
|
|
3746
|
-
"before",
|
|
3747
|
-
"after",
|
|
3748
|
-
"Cypress"
|
|
3749
|
-
];
|
|
3750
|
-
var CYPRESS_COMPLETIONS = [
|
|
3751
|
-
...TOP_LEVEL,
|
|
3752
|
-
...CY_METHODS.map((m) => `cy.${m}`),
|
|
3753
|
-
...CHAIN_METHODS
|
|
3754
|
-
];
|
|
3755
|
-
function filterCompletions(list, prefix) {
|
|
3756
|
-
const p = prefix.toLowerCase();
|
|
3757
|
-
if (!p) return [...list];
|
|
3758
|
-
return list.filter((label) => label.toLowerCase().includes(p));
|
|
3759
|
-
}
|
|
3760
|
-
function filterCypressCompletions(prefix) {
|
|
3761
|
-
return filterCompletions(CYPRESS_COMPLETIONS, prefix);
|
|
3762
|
-
}
|
|
3763
|
-
|
|
3764
|
-
// src/utils/code-editor.ts
|
|
3765
|
-
function toOptions(labels, type) {
|
|
3766
|
-
return labels.map((label) => ({ label, type }));
|
|
3767
|
-
}
|
|
3768
|
-
function cypressCompletionSource(context) {
|
|
3769
|
-
const cyMatch = context.matchBefore(/cy\.\w*$/);
|
|
3770
|
-
if (cyMatch) {
|
|
3771
|
-
return { from: cyMatch.from + 3, options: toOptions(filterCompletions(CY_METHODS, cyMatch.text.slice(3)), "method") };
|
|
3772
|
-
}
|
|
3773
|
-
const chainMatch = context.matchBefore(/\.\w*$/);
|
|
3774
|
-
if (chainMatch) {
|
|
3775
|
-
return { from: chainMatch.from + 1, options: toOptions(filterCompletions(CHAIN_METHODS, chainMatch.text.slice(1)), "method") };
|
|
3776
|
-
}
|
|
3777
|
-
const word = context.matchBefore(/\w*/);
|
|
3778
|
-
if (!word || word.from === word.to && !context.explicit) return null;
|
|
3779
|
-
return { from: word.from, options: toOptions(filterCompletions(TOP_LEVEL, word.text), "keyword") };
|
|
3780
|
-
}
|
|
3781
|
-
async function createCodeEditor(opts) {
|
|
3782
|
-
const [view, state, language, langJs, autocomplete, commands, highlight] = await Promise.all([
|
|
3783
|
-
import("@codemirror/view"),
|
|
3784
|
-
import("@codemirror/state"),
|
|
3785
|
-
import("@codemirror/language"),
|
|
3786
|
-
import("@codemirror/lang-javascript"),
|
|
3787
|
-
import("@codemirror/autocomplete"),
|
|
3788
|
-
import("@codemirror/commands"),
|
|
3789
|
-
import("@lezer/highlight")
|
|
3790
|
-
]);
|
|
3791
|
-
const { EditorView, keymap, lineNumbers, highlightActiveLine, drawSelection } = view;
|
|
3792
|
-
const { EditorState } = state;
|
|
3793
|
-
const { syntaxHighlighting, HighlightStyle, indentOnInput, bracketMatching } = language;
|
|
3794
|
-
const { javascript } = langJs;
|
|
3795
|
-
const { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } = autocomplete;
|
|
3796
|
-
const { history: history2, defaultKeymap, historyKeymap, indentWithTab } = commands;
|
|
3797
|
-
const { tags } = highlight;
|
|
3798
|
-
const darkHighlight = HighlightStyle.define([
|
|
3799
|
-
{ tag: tags.keyword, color: "#ff7b72" },
|
|
3800
|
-
{ tag: tags.string, color: "#a5d6ff" },
|
|
3801
|
-
{ tag: [tags.function(tags.variableName), tags.function(tags.propertyName)], color: "#d2a8ff" },
|
|
3802
|
-
{ tag: tags.number, color: "#79c0ff" },
|
|
3803
|
-
{ tag: [tags.bool, tags.null], color: "#79c0ff" },
|
|
3804
|
-
{ tag: tags.comment, color: "#8b949e", fontStyle: "italic" },
|
|
3805
|
-
{ tag: [tags.propertyName, tags.attributeName], color: "#7ee787" },
|
|
3806
|
-
{ tag: [tags.typeName, tags.className], color: "#ffa657" },
|
|
3807
|
-
{ tag: tags.operator, color: "#ff7b72" },
|
|
3808
|
-
{ tag: [tags.brace, tags.bracket, tags.punctuation], color: "#c9d1d9" }
|
|
3809
|
-
]);
|
|
3810
|
-
const theme = EditorView.theme(
|
|
3811
|
-
{
|
|
3812
|
-
"&": { color: "#c9d1d9", backgroundColor: "#0d1117", height: "100%", fontSize: "13px" },
|
|
3813
|
-
".cm-scroller": { fontFamily: "'Cascadia Code','Fira Code',Consolas,monospace", overflow: "auto" },
|
|
3814
|
-
".cm-gutters": { backgroundColor: "#0d1117", color: "#484f58", border: "none" },
|
|
3815
|
-
".cm-activeLine": { backgroundColor: "rgba(110,118,129,0.10)" },
|
|
3816
|
-
".cm-activeLineGutter": { backgroundColor: "transparent" },
|
|
3817
|
-
"&.cm-focused": { outline: "none" },
|
|
3818
|
-
".cm-tooltip": { background: "#161b22", border: "1px solid #30363d", color: "#c9d1d9", borderRadius: "6px" },
|
|
3819
|
-
".cm-tooltip-autocomplete ul li[aria-selected]": { background: "#1f6feb", color: "#fff" }
|
|
3820
|
-
},
|
|
3821
|
-
{ dark: true }
|
|
3822
|
-
);
|
|
3823
|
-
const editorView = new EditorView({
|
|
3824
|
-
parent: opts.parent,
|
|
3825
|
-
...opts.root ? { root: opts.root } : {},
|
|
3826
|
-
state: EditorState.create({
|
|
3827
|
-
doc: opts.doc,
|
|
3828
|
-
extensions: [
|
|
3829
|
-
lineNumbers(),
|
|
3830
|
-
highlightActiveLine(),
|
|
3831
|
-
drawSelection(),
|
|
3832
|
-
history2(),
|
|
3833
|
-
indentOnInput(),
|
|
3834
|
-
bracketMatching(),
|
|
3835
|
-
closeBrackets(),
|
|
3836
|
-
javascript({ typescript: true }),
|
|
3837
|
-
syntaxHighlighting(darkHighlight),
|
|
3838
|
-
autocompletion({ override: [cypressCompletionSource] }),
|
|
3839
|
-
keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...historyKeymap, ...completionKeymap, indentWithTab]),
|
|
3840
|
-
theme,
|
|
3841
|
-
EditorView.updateListener.of((update) => {
|
|
3842
|
-
if (update.docChanged && opts.onChange) opts.onChange(update.state.doc.toString());
|
|
3843
|
-
})
|
|
3844
|
-
]
|
|
3845
|
-
})
|
|
3846
|
-
});
|
|
3847
|
-
return {
|
|
3848
|
-
getValue: () => editorView.state.doc.toString(),
|
|
3849
|
-
setValue: (value) => editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: value } }),
|
|
3850
|
-
focus: () => editorView.focus(),
|
|
3851
|
-
destroy: () => editorView.destroy()
|
|
3852
|
-
};
|
|
3853
|
-
}
|
|
3854
|
-
|
|
3855
3872
|
// src/index.ts
|
|
3856
3873
|
init_selector_picker();
|
|
3857
3874
|
|
|
@@ -4053,8 +4070,8 @@ var TestPrevisualizerElement = class extends HTMLElement {
|
|
|
4053
4070
|
}
|
|
4054
4071
|
}
|
|
4055
4072
|
};
|
|
4056
|
-
if (!customElements.get("test-previsualizer")) {
|
|
4057
|
-
customElements.define("test-previsualizer", TestPrevisualizerElement);
|
|
4073
|
+
if (!customElements.get("lib-e2e-test-previsualizer")) {
|
|
4074
|
+
customElements.define("lib-e2e-test-previsualizer", TestPrevisualizerElement);
|
|
4058
4075
|
}
|
|
4059
4076
|
|
|
4060
4077
|
// src/components/save-test/save-test.styles.ts
|
|
@@ -4118,10 +4135,21 @@ var SAVE_TEST_STYLES = `
|
|
|
4118
4135
|
transition: color 0.12s; padding: 0; background: none; border: none;
|
|
4119
4136
|
}
|
|
4120
4137
|
.chip-del:hover { color: #f85149; filter: none; }
|
|
4138
|
+
.discard-warn { color: #e6edf3; font-size: 13px; margin-bottom: 20px; line-height: 1.5; }
|
|
4121
4139
|
`;
|
|
4122
4140
|
|
|
4123
4141
|
// src/components/save-test/save-test.template.ts
|
|
4124
4142
|
init_html_utils();
|
|
4143
|
+
function renderSaveTestConfirmDiscard(t) {
|
|
4144
|
+
return `
|
|
4145
|
+
<div class="container">
|
|
4146
|
+
<p class="discard-warn">\u26A0 ${t("SAVE_TEST.CONFIRM_DISCARD")}</p>
|
|
4147
|
+
<div class="btn-row">
|
|
4148
|
+
<button class="btn-danger" id="btn-confirm-discard">${t("SAVE_TEST.CONFIRM_DISCARD_BTN")}</button>
|
|
4149
|
+
<button id="btn-back-discard">${t("SAVE_TEST.BACK_BTN")}</button>
|
|
4150
|
+
</div>
|
|
4151
|
+
</div>`;
|
|
4152
|
+
}
|
|
4125
4153
|
function renderSaveTestAsk(t) {
|
|
4126
4154
|
return `
|
|
4127
4155
|
<div class="container">
|
|
@@ -4132,11 +4160,15 @@ function renderSaveTestAsk(t) {
|
|
|
4132
4160
|
</div>
|
|
4133
4161
|
</div>`;
|
|
4134
4162
|
}
|
|
4135
|
-
function renderSaveTestDesc(description, notes, tags,
|
|
4163
|
+
function renderSaveTestDesc(description, notes, tags, ticketId, issueTrackerEnabled, ticketWarn, t) {
|
|
4136
4164
|
const chipsHtml = tags.map(
|
|
4137
4165
|
(tag) => `<span class="chip">${escHtml(tag)}<button class="chip-del" data-tag="${escAttr(tag)}" title="${t("SAVE_TEST.REMOVE_TAG_TITLE")}">\u2715</button></span>`
|
|
4138
4166
|
).join("");
|
|
4139
|
-
const
|
|
4167
|
+
const ticketHtml = issueTrackerEnabled ? `
|
|
4168
|
+
<span class="tag-label">${t("SAVE_TEST.TICKET_LABEL")}</span>
|
|
4169
|
+
<input id="ticket-input" type="text" placeholder="${escAttr(t("SAVE_TEST.TICKET_PLACEHOLDER"))}"
|
|
4170
|
+
value="${escAttr(ticketId)}" autocomplete="off" />
|
|
4171
|
+
${ticketWarn ? `<span class="ticket-warn">\u26A0 ${t("SAVE_TEST.TICKET_WARN")}</span>` : ""}` : "";
|
|
4140
4172
|
return `
|
|
4141
4173
|
<div class="container">
|
|
4142
4174
|
<p>${t("SAVE_TEST.DESC_LABEL")} (<code>it()</code>):</p>
|
|
@@ -4144,16 +4176,13 @@ function renderSaveTestDesc(description, notes, tags, ticket, t) {
|
|
|
4144
4176
|
value="${escAttr(description)}" autocomplete="off" />
|
|
4145
4177
|
<span class="tag-label">${t("SAVE_TEST.NOTES_LABEL")}</span>
|
|
4146
4178
|
<textarea id="notes-input" rows="3" placeholder="${escAttr(t("SAVE_TEST.NOTES_PLACEHOLDER"))}">${escHtml(notes)}</textarea>
|
|
4147
|
-
<span class="tag-label">${t("SAVE_TEST.TICKET_LABEL")}</span>
|
|
4148
|
-
<input id="ticket-input" type="text" placeholder="${escAttr(t(ticket.placeholderKey))}"
|
|
4149
|
-
value="${escAttr(ticket.id)}" autocomplete="off" />
|
|
4150
|
-
${ticketWarning}
|
|
4151
4179
|
<span class="tag-label">${t("SAVE_TEST.TAGS_LABEL")}</span>
|
|
4152
4180
|
<div class="tag-input-row">
|
|
4153
4181
|
<input id="tag-input" type="text" placeholder="${t("SAVE_TEST.TAGS_PLACEHOLDER")}" autocomplete="off" />
|
|
4154
4182
|
<button class="btn-tag-add" id="btn-add-tag">${t("SAVE_TEST.ADD_TAG")}</button>
|
|
4155
4183
|
</div>
|
|
4156
4184
|
<div class="chips" id="chips-container">${chipsHtml || `<span style="color:#484f58;font-size:11px">${t("SAVE_TEST.NO_TAGS")}</span>`}</div>
|
|
4185
|
+
${ticketHtml}
|
|
4157
4186
|
<div class="btn-row">
|
|
4158
4187
|
<button class="btn-primary" id="btn-confirm">${t("SAVE_TEST.SAVE_BTN")}</button>
|
|
4159
4188
|
<button class="btn-success" id="btn-export">${t("SAVE_TEST.SAVE_AND_EDIT")}</button>
|
|
@@ -4166,12 +4195,12 @@ function renderSaveTestDesc(description, notes, tags, ticket, t) {
|
|
|
4166
4195
|
var SaveTestElement = class extends HTMLElement {
|
|
4167
4196
|
shadow;
|
|
4168
4197
|
_step = "ask";
|
|
4198
|
+
_stepBeforeDiscard = "ask";
|
|
4169
4199
|
description = "";
|
|
4170
4200
|
notes = "";
|
|
4171
4201
|
tags = [];
|
|
4172
4202
|
ticketId = "";
|
|
4173
|
-
|
|
4174
|
-
issueTrackerProviderId = DEFAULT_ISSUE_TRACKER_PROVIDER_ID;
|
|
4203
|
+
issueTrackerConfig = DEFAULT_ISSUE_TRACKER_CONFIG;
|
|
4175
4204
|
translation = translationService;
|
|
4176
4205
|
constructor() {
|
|
4177
4206
|
super();
|
|
@@ -4188,13 +4217,22 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
4188
4217
|
this.render();
|
|
4189
4218
|
}
|
|
4190
4219
|
confirmSave() {
|
|
4191
|
-
this.dispatch("savetest", { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim()
|
|
4220
|
+
this.dispatch("savetest", { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() });
|
|
4192
4221
|
}
|
|
4193
4222
|
confirmSaveAndExport() {
|
|
4194
|
-
this.dispatch("saveandexport", { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim()
|
|
4223
|
+
this.dispatch("saveandexport", { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() });
|
|
4195
4224
|
}
|
|
4196
4225
|
cancel() {
|
|
4197
|
-
this.
|
|
4226
|
+
this._stepBeforeDiscard = this._step === "confirm-discard" ? "ask" : this._step;
|
|
4227
|
+
this._step = "confirm-discard";
|
|
4228
|
+
this.render();
|
|
4229
|
+
}
|
|
4230
|
+
confirmDiscard() {
|
|
4231
|
+
this.dispatch("savetest", { description: null, notes: "", tags: [], ticketId: "" });
|
|
4232
|
+
}
|
|
4233
|
+
backFromDiscard() {
|
|
4234
|
+
this._step = this._stepBeforeDiscard;
|
|
4235
|
+
this.render();
|
|
4198
4236
|
}
|
|
4199
4237
|
restartComponent() {
|
|
4200
4238
|
this._step = "ask";
|
|
@@ -4218,44 +4256,37 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
4218
4256
|
t(key) {
|
|
4219
4257
|
return this.translation.translate(key);
|
|
4220
4258
|
}
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
const trimmed = this.ticketId.trim();
|
|
4225
|
-
let invalid = false;
|
|
4226
|
-
if (trimmed) {
|
|
4227
|
-
try {
|
|
4228
|
-
invalid = !new RegExp(provider.idPattern).test(trimmed);
|
|
4229
|
-
} catch {
|
|
4230
|
-
invalid = false;
|
|
4231
|
-
}
|
|
4232
|
-
}
|
|
4233
|
-
return { id: this.ticketId, placeholderKey: provider.idPlaceholderKey, invalid };
|
|
4259
|
+
get ticketIdWarning() {
|
|
4260
|
+
if (!this.ticketId.trim() || !this.issueTrackerConfig.enabled) return false;
|
|
4261
|
+
return !isValidTicketId(this.ticketId, this.issueTrackerConfig.provider);
|
|
4234
4262
|
}
|
|
4235
4263
|
dispatch(type, detail) {
|
|
4236
4264
|
this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));
|
|
4237
4265
|
}
|
|
4238
4266
|
render() {
|
|
4267
|
+
if (this._step === "confirm-discard") {
|
|
4268
|
+
this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestConfirmDiscard(this.t.bind(this))}`;
|
|
4269
|
+
this.shadow.getElementById("btn-confirm-discard")?.addEventListener("click", () => this.confirmDiscard());
|
|
4270
|
+
this.shadow.getElementById("btn-back-discard")?.addEventListener("click", () => this.backFromDiscard());
|
|
4271
|
+
return;
|
|
4272
|
+
}
|
|
4239
4273
|
if (this._step === "ask") {
|
|
4240
4274
|
this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestAsk(this.t.bind(this))}`;
|
|
4241
4275
|
this.shadow.getElementById("btn-yes")?.addEventListener("click", () => this.askSave());
|
|
4242
4276
|
this.shadow.getElementById("btn-no")?.addEventListener("click", () => this.cancel());
|
|
4243
4277
|
} else {
|
|
4244
|
-
this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.
|
|
4278
|
+
this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.ticketId, this.issueTrackerConfig.enabled, this.ticketIdWarning, this.t.bind(this))}`;
|
|
4245
4279
|
const descInput = this.shadow.getElementById("desc-input");
|
|
4246
4280
|
const notesInput = this.shadow.getElementById("notes-input");
|
|
4247
|
-
const ticketInput = this.shadow.getElementById("ticket-input");
|
|
4248
4281
|
const tagInput = this.shadow.getElementById("tag-input");
|
|
4282
|
+
const ticketInput = this.shadow.getElementById("ticket-input");
|
|
4249
4283
|
descInput.addEventListener("input", () => {
|
|
4250
4284
|
this.description = descInput.value;
|
|
4251
4285
|
});
|
|
4252
4286
|
notesInput.addEventListener("input", () => {
|
|
4253
4287
|
this.notes = notesInput.value;
|
|
4254
4288
|
});
|
|
4255
|
-
ticketInput
|
|
4256
|
-
this.ticketId = ticketInput.value;
|
|
4257
|
-
});
|
|
4258
|
-
ticketInput.addEventListener("change", () => {
|
|
4289
|
+
ticketInput?.addEventListener("input", () => {
|
|
4259
4290
|
this.ticketId = ticketInput.value;
|
|
4260
4291
|
this.render();
|
|
4261
4292
|
});
|
|
@@ -4280,10 +4311,13 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
4280
4311
|
}
|
|
4281
4312
|
}
|
|
4282
4313
|
};
|
|
4283
|
-
if (!customElements.get("save-test")) {
|
|
4284
|
-
customElements.define("save-test", SaveTestElement);
|
|
4314
|
+
if (!customElements.get("lib-e2e-save-test")) {
|
|
4315
|
+
customElements.define("lib-e2e-save-test", SaveTestElement);
|
|
4285
4316
|
}
|
|
4286
4317
|
|
|
4318
|
+
// src/components/test-editor/test-editor.ts
|
|
4319
|
+
init_code_format_utils();
|
|
4320
|
+
|
|
4287
4321
|
// src/components/test-editor/test-editor.styles.ts
|
|
4288
4322
|
var TEST_EDITOR_STYLES = `
|
|
4289
4323
|
:host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }
|
|
@@ -4350,6 +4384,18 @@ var TEST_EDITOR_STYLES = `
|
|
|
4350
4384
|
padding: 1px 7px; border-radius: 20px; font-size: 10px;
|
|
4351
4385
|
background: rgba(47,129,247,0.1); color: #8b949e; border: 1px solid rgba(47,129,247,0.2);
|
|
4352
4386
|
}
|
|
4387
|
+
.ticket-badge, .ticket-link {
|
|
4388
|
+
padding: 1px 7px; border-radius: 20px; font-size: 10px; font-weight: 500;
|
|
4389
|
+
background: rgba(210,153,34,0.12); color: #d29922; border: 1px solid rgba(210,153,34,0.3);
|
|
4390
|
+
white-space: nowrap; flex-shrink: 0;
|
|
4391
|
+
}
|
|
4392
|
+
.ticket-link {
|
|
4393
|
+
text-decoration: none; cursor: pointer;
|
|
4394
|
+
transition: background 0.12s, border-color 0.12s;
|
|
4395
|
+
}
|
|
4396
|
+
.ticket-link::before { content: '\u{1F3AB} '; font-size: 9px; }
|
|
4397
|
+
.ticket-link:hover { background: rgba(210,153,34,0.22); border-color: rgba(210,153,34,0.55); color: #e3b341; }
|
|
4398
|
+
.ticket-badge::before { content: '\u{1F3AB} '; font-size: 9px; }
|
|
4353
4399
|
.btn-icon {
|
|
4354
4400
|
padding: 3px 8px; border: none; border-radius: 6px; cursor: pointer;
|
|
4355
4401
|
font-size: 11px; background: #21262d; color: #8b949e;
|
|
@@ -4381,6 +4427,13 @@ var TEST_EDITOR_STYLES = `
|
|
|
4381
4427
|
.code-preview::-webkit-scrollbar { height: 4px; }
|
|
4382
4428
|
.code-preview::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }
|
|
4383
4429
|
.code-preview-icp { margin-top: 8px; }
|
|
4430
|
+
.ticket-group { margin-bottom: 8px; }
|
|
4431
|
+
.ticket-group-header {
|
|
4432
|
+
padding: 4px 10px; margin-bottom: 4px;
|
|
4433
|
+
font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.7px;
|
|
4434
|
+
color: #d29922; border-left: 3px solid rgba(210,153,34,0.5);
|
|
4435
|
+
background: rgba(210,153,34,0.06); border-radius: 0 4px 4px 0;
|
|
4436
|
+
}
|
|
4384
4437
|
.sh-kw { color: #ff7b72; }
|
|
4385
4438
|
.sh-bi { color: #d2a8ff; }
|
|
4386
4439
|
.sh-str { color: #a5d6ff; }
|
|
@@ -4487,8 +4540,50 @@ function highlightLine(line) {
|
|
|
4487
4540
|
}
|
|
4488
4541
|
|
|
4489
4542
|
// src/components/test-editor/test-editor.template.ts
|
|
4543
|
+
init_code_format_utils();
|
|
4544
|
+
function renderTestRow(test, i, state, t) {
|
|
4545
|
+
const { selectMode, selectedIds, expandedIndex, interceptorsByTest, locale, issueTrackerConfig } = state;
|
|
4546
|
+
const expanded = expandedIndex === i;
|
|
4547
|
+
const date = new Date(test.createdAt).toLocaleString(locale, { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
4548
|
+
const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];
|
|
4549
|
+
const tagsHtml = (test.tags ?? []).length ? `<span class="test-tags">${(test.tags ?? []).map((tag) => `<span class="test-tag">${escHtml(tag)}</span>`).join("")}</span>` : "";
|
|
4550
|
+
const checkbox = selectMode ? `<input type="checkbox" ${selectedIds.has(test.id) ? "checked" : ""} data-select="${test.id}" />` : "";
|
|
4551
|
+
const hasIcps = (test.interceptors ?? []).length > 0;
|
|
4552
|
+
const ticketId = test.ticketId;
|
|
4553
|
+
const ticketComment = ticketId ? buildTicketComment(ticketId) + "\n" : "";
|
|
4554
|
+
const itBlockCode = `${ticketComment}it('${escapeSingleQuotes(test.name)}', () => {
|
|
4555
|
+
${(test.commands ?? []).map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4556
|
+
});`;
|
|
4557
|
+
const icpBlockCode = icps.length ? `beforeEach(() => {
|
|
4558
|
+
// Auto-generated Cypress interceptors
|
|
4559
|
+
${icps.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4560
|
+
});` : "";
|
|
4561
|
+
const notesHtml = expanded && test.notes ? `<p class="test-notes">${escHtml(test.notes)}</p>` : "";
|
|
4562
|
+
const ticketUrl = ticketId ? buildTicketUrl(ticketId, issueTrackerConfig) : null;
|
|
4563
|
+
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>` : "";
|
|
4564
|
+
const body = expanded ? `
|
|
4565
|
+
<div class="row-body">
|
|
4566
|
+
${notesHtml}
|
|
4567
|
+
<pre class="code-preview">${syntaxHighlight(itBlockCode)}</pre>
|
|
4568
|
+
${icpBlockCode ? `<pre class="code-preview code-preview-icp">${syntaxHighlight(icpBlockCode)}</pre>` : ""}
|
|
4569
|
+
</div>` : "";
|
|
4570
|
+
return `
|
|
4571
|
+
<div class="row${selectedIds.has(test.id) ? " selected-row" : ""}">
|
|
4572
|
+
<div class="row-header" data-action="expand" data-idx="${i}">
|
|
4573
|
+
${checkbox}
|
|
4574
|
+
<span class="test-name">${escHtml(test.name)}</span>
|
|
4575
|
+
${tagsHtml}
|
|
4576
|
+
${ticketHtml}
|
|
4577
|
+
<span class="test-date">${date}</span>
|
|
4578
|
+
<button class="btn-icon" data-action="copy-cmds" data-idx="${i}" title="${t("TEST_EDITOR.COPY_CMDS_BTN")}">${t("TEST_EDITOR.COPY_CMDS_BTN")}</button>
|
|
4579
|
+
${hasIcps ? `<button class="btn-icon" data-action="copy-icps" data-idx="${i}" title="${t("TEST_EDITOR.COPY_ICPS_BTN")}">${t("TEST_EDITOR.COPY_ICPS_BTN")}</button>` : ""}
|
|
4580
|
+
<button class="btn-icon btn-del" data-action="delete" data-id="${test.id}" title="${t("TEST_EDITOR.DELETE_TITLE")}">\u{1F5D1}</button>
|
|
4581
|
+
</div>
|
|
4582
|
+
${body}
|
|
4583
|
+
</div>`;
|
|
4584
|
+
}
|
|
4490
4585
|
function renderTestEditor(state, t) {
|
|
4491
|
-
const { tags, visible, selectedVisible, activeTag, selectMode,
|
|
4586
|
+
const { tags, visible, selectedVisible, activeTag, selectMode, describeName, groupByTicket } = state;
|
|
4492
4587
|
const tagFilterHtml = tags.length ? `<div class="tag-filter">
|
|
4493
4588
|
${tags.map((tag) => `<button class="tag-chip${activeTag === tag ? " active" : ""}" data-filter-tag="${escAttr(tag)}">${escHtml(tag)}</button>`).join("")}
|
|
4494
4589
|
</div>` : `<div class="tag-filter" style="color:#484f58;font-size:11px">${t("TEST_EDITOR.NO_TAGS")}</div>`;
|
|
@@ -4497,80 +4592,43 @@ function renderTestEditor(state, t) {
|
|
|
4497
4592
|
<input id="describe-name" type="text" placeholder="${t("TEST_EDITOR.DESCRIBE_PLACEHOLDER")}" value="${escAttr(describeName)}" />
|
|
4498
4593
|
<button class="btn-gen-describe" id="btn-gen-describe">${t("TEST_EDITOR.COPY_DESCRIBE")}</button>
|
|
4499
4594
|
</div>` : "";
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
const date = new Date(test.createdAt).toLocaleString(locale, { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
4503
|
-
const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];
|
|
4504
|
-
const tagsHtml = (test.tags ?? []).length ? `<span class="test-tags">${(test.tags ?? []).map((tag) => `<span class="test-tag">${escHtml(tag)}</span>`).join("")}</span>` : "";
|
|
4505
|
-
const ticketId = (test.ticketId ?? "").trim();
|
|
4506
|
-
const ticketUrl = ticketUrlByTest[test.id] ?? null;
|
|
4507
|
-
const ticketHtml = !ticketId ? "" : ticketUrl ? `<a class="test-ticket" data-ticket-link href="${escAttr(ticketUrl)}" target="_blank" rel="noopener noreferrer" style="color:#58a6ff;font-size:11px;text-decoration:none">\u{1F3AB} ${escHtml(ticketId)}</a>` : `<span class="test-ticket" style="color:#8b949e;font-size:11px">\u{1F3AB} ${escHtml(ticketId)}</span>`;
|
|
4508
|
-
const checkbox = selectMode ? `<input type="checkbox" ${selectedIds.has(test.id) ? "checked" : ""} data-select="${test.id}" />` : "";
|
|
4509
|
-
const hasIcps = (test.interceptors ?? []).length > 0;
|
|
4510
|
-
const ticketComment = ticketId ? `${buildTicketComment(ticketId, ticketUrl)}
|
|
4511
|
-
` : "";
|
|
4512
|
-
const itBlockCode = `${ticketComment}it('${escapeSingleQuotes(test.name)}', () => {
|
|
4513
|
-
${(test.commands ?? []).map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4514
|
-
});`;
|
|
4515
|
-
const icpBlockCode = icps.length ? `beforeEach(() => {
|
|
4516
|
-
// Auto-generated Cypress interceptors
|
|
4517
|
-
${icps.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4518
|
-
});` : "";
|
|
4519
|
-
const notesHtml = expanded && test.notes ? `<p class="test-notes">${escHtml(test.notes)}</p>` : "";
|
|
4520
|
-
const body = expanded ? `
|
|
4521
|
-
<div class="row-body">
|
|
4522
|
-
${notesHtml}
|
|
4523
|
-
<pre class="code-preview">${syntaxHighlight(itBlockCode)}</pre>
|
|
4524
|
-
${icpBlockCode ? `<pre class="code-preview code-preview-icp">${syntaxHighlight(icpBlockCode)}</pre>` : ""}
|
|
4525
|
-
</div>` : "";
|
|
4526
|
-
return `
|
|
4527
|
-
<div class="row${selectedIds.has(test.id) ? " selected-row" : ""}">
|
|
4528
|
-
<div class="row-header" data-action="expand" data-idx="${i}">
|
|
4529
|
-
${checkbox}
|
|
4530
|
-
<span class="test-name">${escHtml(test.name)}</span>
|
|
4531
|
-
${tagsHtml}
|
|
4532
|
-
${ticketHtml}
|
|
4533
|
-
<span class="test-date">${date}</span>
|
|
4534
|
-
<button class="btn-icon" data-action="copy-cmds" data-idx="${i}" title="${t("TEST_EDITOR.COPY_CMDS_BTN")}">${t("TEST_EDITOR.COPY_CMDS_BTN")}</button>
|
|
4535
|
-
${hasIcps ? `<button class="btn-icon" data-action="copy-icps" data-idx="${i}" title="${t("TEST_EDITOR.COPY_ICPS_BTN")}">${t("TEST_EDITOR.COPY_ICPS_BTN")}</button>` : ""}
|
|
4536
|
-
<button class="btn-icon btn-del" data-action="delete" data-id="${test.id}" title="${t("TEST_EDITOR.DELETE_TITLE")}">\u{1F5D1}</button>
|
|
4537
|
-
</div>
|
|
4538
|
-
${body}
|
|
4539
|
-
</div>`;
|
|
4540
|
-
};
|
|
4541
|
-
const indexed = visible.map((test, i) => ({ test, i }));
|
|
4542
|
-
const groupedRows = () => {
|
|
4595
|
+
let rows;
|
|
4596
|
+
if (groupByTicket) {
|
|
4543
4597
|
const groups = /* @__PURE__ */ new Map();
|
|
4544
|
-
for (const
|
|
4545
|
-
const key =
|
|
4546
|
-
const
|
|
4547
|
-
|
|
4548
|
-
|
|
4598
|
+
for (const test of visible) {
|
|
4599
|
+
const key = test.ticketId?.trim() || "";
|
|
4600
|
+
const group = groups.get(key) ?? [];
|
|
4601
|
+
group.push(test);
|
|
4602
|
+
groups.set(key, group);
|
|
4549
4603
|
}
|
|
4550
|
-
const
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
const
|
|
4555
|
-
const header =
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4604
|
+
const sortedKeys = [...groups.keys()].sort(
|
|
4605
|
+
(a, b) => a === "" ? 1 : b === "" ? -1 : a.localeCompare(b)
|
|
4606
|
+
);
|
|
4607
|
+
rows = sortedKeys.map((key) => {
|
|
4608
|
+
const group = groups.get(key);
|
|
4609
|
+
const header = `<div class="ticket-group-header">${key ? escHtml(key) : t("TEST_EDITOR.NO_TICKET")}</div>`;
|
|
4610
|
+
const groupRows = group.map((test) => {
|
|
4611
|
+
const i = visible.indexOf(test);
|
|
4612
|
+
return renderTestRow(test, i, state, t);
|
|
4613
|
+
}).join("");
|
|
4614
|
+
return `<div class="ticket-group">${header}${groupRows}</div>`;
|
|
4560
4615
|
}).join("");
|
|
4561
|
-
}
|
|
4562
|
-
|
|
4616
|
+
} else {
|
|
4617
|
+
rows = visible.map((test, i) => renderTestRow(test, i, state, t)).join("");
|
|
4618
|
+
}
|
|
4563
4619
|
return `
|
|
4564
4620
|
<div class="toolbar">
|
|
4565
4621
|
${tagFilterHtml}
|
|
4566
|
-
<button class="btn-select${groupByTicket ? " active" : ""}" id="btn-group-ticket"
|
|
4622
|
+
<button class="btn-select${groupByTicket ? " active" : ""}" id="btn-group-ticket">
|
|
4623
|
+
${groupByTicket ? t("TEST_EDITOR.UNGROUP_TICKET") : t("TEST_EDITOR.GROUP_BY_TICKET")}
|
|
4624
|
+
</button>
|
|
4567
4625
|
<button class="btn-select${selectMode ? " active" : ""}" id="btn-select-mode">
|
|
4568
4626
|
${selectMode ? t("TEST_EDITOR.CANCEL_SELECT") : t("TEST_EDITOR.MULTI_SELECT")}
|
|
4569
4627
|
</button>
|
|
4570
4628
|
</div>
|
|
4571
4629
|
${describeBarHtml}
|
|
4572
4630
|
<div class="list">
|
|
4573
|
-
${
|
|
4631
|
+
${visible.length ? rows : `<div class="empty">${t("TEST_EDITOR.NO_TESTS")}</div>`}
|
|
4574
4632
|
</div>`;
|
|
4575
4633
|
}
|
|
4576
4634
|
|
|
@@ -4587,8 +4645,7 @@ var TestEditorElement = class extends HTMLElement {
|
|
|
4587
4645
|
selectedIds = /* @__PURE__ */ new Set();
|
|
4588
4646
|
describeName = "";
|
|
4589
4647
|
groupByTicket = false;
|
|
4590
|
-
|
|
4591
|
-
issueTrackerParams = {};
|
|
4648
|
+
issueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };
|
|
4592
4649
|
constructor() {
|
|
4593
4650
|
super();
|
|
4594
4651
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
@@ -4598,17 +4655,7 @@ var TestEditorElement = class extends HTMLElement {
|
|
|
4598
4655
|
this.loadTests();
|
|
4599
4656
|
}
|
|
4600
4657
|
async loadTests() {
|
|
4601
|
-
|
|
4602
|
-
this.persistence.getAllTests(),
|
|
4603
|
-
this.persistence.getGeneralConfig()
|
|
4604
|
-
]);
|
|
4605
|
-
this.tests = tests;
|
|
4606
|
-
this.issueTrackerProviderId = config?.["issueTrackerProviderId"] ?? DEFAULT_ISSUE_TRACKER_PROVIDER_ID;
|
|
4607
|
-
this.issueTrackerParams = config?.["issueTrackerParams"] ?? {};
|
|
4608
|
-
this.render();
|
|
4609
|
-
}
|
|
4610
|
-
toggleGroupByTicket() {
|
|
4611
|
-
this.groupByTicket = !this.groupByTicket;
|
|
4658
|
+
this.tests = await this.persistence.getAllTests();
|
|
4612
4659
|
this.render();
|
|
4613
4660
|
}
|
|
4614
4661
|
async deleteTest(id) {
|
|
@@ -4629,6 +4676,10 @@ var TestEditorElement = class extends HTMLElement {
|
|
|
4629
4676
|
hasInterceptors(testId) {
|
|
4630
4677
|
return Array.isArray(this.interceptorsByTest[testId]) && this.interceptorsByTest[testId].length > 0;
|
|
4631
4678
|
}
|
|
4679
|
+
toggleGroupByTicket() {
|
|
4680
|
+
this.groupByTicket = !this.groupByTicket;
|
|
4681
|
+
this.render();
|
|
4682
|
+
}
|
|
4632
4683
|
toggleSelectMode() {
|
|
4633
4684
|
this.selectMode = !this.selectMode;
|
|
4634
4685
|
if (!this.selectMode) this.selectedIds.clear();
|
|
@@ -4683,12 +4734,6 @@ ${beforeEach}${itBlocks}
|
|
|
4683
4734
|
const tags = this.allTags;
|
|
4684
4735
|
const visible = this.visibleTests;
|
|
4685
4736
|
const selectedVisible = visible.filter((t) => this.selectedIds.has(t.id));
|
|
4686
|
-
const ticketUrlByTest = {};
|
|
4687
|
-
for (const test of visible) {
|
|
4688
|
-
if (test.ticketId) {
|
|
4689
|
-
ticketUrlByTest[test.id] = resolveTicketUrl(this.issueTrackerProviderId, this.issueTrackerParams, test.ticketId);
|
|
4690
|
-
}
|
|
4691
|
-
}
|
|
4692
4737
|
this.shadow.innerHTML = `<style>${TEST_EDITOR_STYLES}</style>${renderTestEditor({
|
|
4693
4738
|
tags,
|
|
4694
4739
|
visible,
|
|
@@ -4699,15 +4744,12 @@ ${beforeEach}${itBlocks}
|
|
|
4699
4744
|
describeName: this.describeName,
|
|
4700
4745
|
expandedIndex: this.expandedIndex,
|
|
4701
4746
|
interceptorsByTest: this.interceptorsByTest,
|
|
4747
|
+
locale: localeForLang(this.translation.getLang()),
|
|
4702
4748
|
groupByTicket: this.groupByTicket,
|
|
4703
|
-
|
|
4704
|
-
locale: localeForLang(this.translation.getLang())
|
|
4749
|
+
issueTrackerConfig: this.issueTrackerConfig
|
|
4705
4750
|
}, this.t.bind(this))}`;
|
|
4706
|
-
this.shadow.getElementById("btn-select-mode")?.addEventListener("click", () => this.toggleSelectMode());
|
|
4707
4751
|
this.shadow.getElementById("btn-group-ticket")?.addEventListener("click", () => this.toggleGroupByTicket());
|
|
4708
|
-
this.shadow.
|
|
4709
|
-
(el) => el.addEventListener("click", (ev) => ev.stopPropagation())
|
|
4710
|
-
);
|
|
4752
|
+
this.shadow.getElementById("btn-select-mode")?.addEventListener("click", () => this.toggleSelectMode());
|
|
4711
4753
|
this.shadow.querySelectorAll("[data-filter-tag]").forEach((el) => {
|
|
4712
4754
|
el.addEventListener("click", () => {
|
|
4713
4755
|
const tag = el.dataset["filterTag"] ?? "";
|
|
@@ -4765,32 +4807,99 @@ ${beforeEach}${itBlocks}
|
|
|
4765
4807
|
});
|
|
4766
4808
|
}
|
|
4767
4809
|
};
|
|
4768
|
-
if (!customElements.get("test-editor")) {
|
|
4769
|
-
customElements.define("test-editor", TestEditorElement);
|
|
4810
|
+
if (!customElements.get("lib-e2e-test-editor")) {
|
|
4811
|
+
customElements.define("lib-e2e-test-editor", TestEditorElement);
|
|
4812
|
+
}
|
|
4813
|
+
|
|
4814
|
+
// src/utils/login-setup.utils.ts
|
|
4815
|
+
var EXPORT_FN_RE = /^(?!\/\/).*\bexport\s+(?:async\s+)?function\s+(\w+)|^(?!\/\/).*\bexport\s+const\s+(\w+)\s*=\s*(?:async\s*)?\(/gm;
|
|
4816
|
+
function extractExportedFunctions(fileContent) {
|
|
4817
|
+
const names = [];
|
|
4818
|
+
let match;
|
|
4819
|
+
const re = new RegExp(EXPORT_FN_RE.source, EXPORT_FN_RE.flags);
|
|
4820
|
+
while ((match = re.exec(fileContent)) !== null) {
|
|
4821
|
+
const name = match[1] ?? match[2];
|
|
4822
|
+
if (name) names.push(name);
|
|
4823
|
+
}
|
|
4824
|
+
return names;
|
|
4825
|
+
}
|
|
4826
|
+
function buildLoginScaffold() {
|
|
4827
|
+
return [
|
|
4828
|
+
"/**",
|
|
4829
|
+
" * Login service scaffold \u2014 fill in your own auth logic.",
|
|
4830
|
+
" * This file is not committed to source control.",
|
|
4831
|
+
" */",
|
|
4832
|
+
"",
|
|
4833
|
+
"export function fetchAuthToken() {",
|
|
4834
|
+
" // TODO: implement \u2014 retrieve and return your auth token",
|
|
4835
|
+
"}",
|
|
4836
|
+
"",
|
|
4837
|
+
"export function setupRequestInterceptors() {",
|
|
4838
|
+
" // TODO: implement \u2014 configure cy.intercept() or set localStorage/cookies",
|
|
4839
|
+
"}",
|
|
4840
|
+
""
|
|
4841
|
+
].join("\n");
|
|
4842
|
+
}
|
|
4843
|
+
function buildLoginImportPath(fromFilePath, toServiceFilePath) {
|
|
4844
|
+
const fromParts = fromFilePath.replace(/\\/g, "/").split("/");
|
|
4845
|
+
const toParts = toServiceFilePath.replace(/\\/g, "/").split("/");
|
|
4846
|
+
fromParts.pop();
|
|
4847
|
+
let common = 0;
|
|
4848
|
+
while (common < fromParts.length && common < toParts.length - 1 && fromParts[common] === toParts[common]) {
|
|
4849
|
+
common++;
|
|
4850
|
+
}
|
|
4851
|
+
const ups = fromParts.length - common;
|
|
4852
|
+
const downs = toParts.slice(common);
|
|
4853
|
+
const serviceFile = downs[downs.length - 1].replace(/\.ts$/, "");
|
|
4854
|
+
const prefix = ups === 0 ? "." : Array(ups).fill("..").join("/");
|
|
4855
|
+
const middle = downs.slice(0, -1);
|
|
4856
|
+
return [prefix, ...middle, serviceFile].join("/");
|
|
4857
|
+
}
|
|
4858
|
+
function hasLoginBlocks(content, fnNames) {
|
|
4859
|
+
return fnNames.some((fn) => new RegExp(`\\b${fn}\\s*\\(`).test(content));
|
|
4860
|
+
}
|
|
4861
|
+
function injectLoginBlocksIntoExisting(content, importLine, beforeBlock, beforeEachBlock) {
|
|
4862
|
+
let result = content;
|
|
4863
|
+
if (importLine && !content.includes(importLine)) {
|
|
4864
|
+
result = `${importLine}
|
|
4865
|
+
|
|
4866
|
+
${result}`;
|
|
4867
|
+
}
|
|
4868
|
+
const blocks = [beforeBlock, beforeEachBlock].filter(Boolean).join("");
|
|
4869
|
+
if (blocks) {
|
|
4870
|
+
const describeMatch = result.match(/(describe\s*\(.*?{)/s);
|
|
4871
|
+
if (describeMatch) {
|
|
4872
|
+
const insertPos = (describeMatch.index ?? 0) + describeMatch[0].length;
|
|
4873
|
+
result = result.slice(0, insertPos) + "\n" + blocks + result.slice(insertPos);
|
|
4874
|
+
}
|
|
4875
|
+
}
|
|
4876
|
+
return result;
|
|
4877
|
+
}
|
|
4878
|
+
function buildLoginBlocks(importPath, beforeFn, beforeEachFn) {
|
|
4879
|
+
if (!beforeFn && !beforeEachFn) {
|
|
4880
|
+
return { importLine: "", beforeBlock: "", beforeEachBlock: "" };
|
|
4881
|
+
}
|
|
4882
|
+
const fns = [...new Set([beforeFn, beforeEachFn].filter(Boolean))];
|
|
4883
|
+
const importLine = `import { ${fns.join(", ")} } from '${importPath}';`;
|
|
4884
|
+
const beforeBlock = beforeFn ? ` before(() => { ${beforeFn}(); });
|
|
4885
|
+
` : "";
|
|
4886
|
+
const beforeEachBlock = beforeEachFn ? ` beforeEach(() => { ${beforeEachFn}(); });
|
|
4887
|
+
` : "";
|
|
4888
|
+
return { importLine, beforeBlock, beforeEachBlock };
|
|
4770
4889
|
}
|
|
4771
4890
|
|
|
4772
4891
|
// src/components/configuration/configuration.styles.ts
|
|
4773
4892
|
var CONFIGURATION_STYLES = `
|
|
4774
|
-
:host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }
|
|
4893
|
+
:host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; max-height: 70vh; overflow-y: auto; scrollbar-width: thin; scrollbar-color: #30363d transparent; }
|
|
4775
4894
|
* { box-sizing: border-box; }
|
|
4776
4895
|
|
|
4777
4896
|
/* \u2500\u2500 Grid container \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\u2500 */
|
|
4778
|
-
/* The SweetAlert2 host clips overflow (overflow:hidden), so the grid owns its
|
|
4779
|
-
own scroll \u2014 otherwise the last cards fall below the fold with no scrollbar. */
|
|
4780
4897
|
.cfg-grid {
|
|
4781
4898
|
display: grid;
|
|
4782
4899
|
grid-template-columns: 1fr 1fr;
|
|
4783
4900
|
gap: 10px;
|
|
4784
4901
|
padding: 14px;
|
|
4785
|
-
max-height: 72vh;
|
|
4786
|
-
overflow-y: auto;
|
|
4787
|
-
scrollbar-width: thin;
|
|
4788
|
-
scrollbar-color: #30363d transparent;
|
|
4789
4902
|
}
|
|
4790
|
-
.cfg-grid::-webkit-scrollbar { width: 8px; }
|
|
4791
|
-
.cfg-grid::-webkit-scrollbar-thumb { background: #30363d; border-radius: 4px; }
|
|
4792
|
-
.cfg-grid::-webkit-scrollbar-thumb:hover { background: #484f58; }
|
|
4793
|
-
.cfg-grid::-webkit-scrollbar-track { background: transparent; }
|
|
4794
4903
|
|
|
4795
4904
|
/* \u2500\u2500 Cards \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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
4796
4905
|
.card {
|
|
@@ -4937,6 +5046,99 @@ var CONFIGURATION_STYLES = `
|
|
|
4937
5046
|
.btn-export-confirm { background: #238636; border-color: #238636; color: #fff; }
|
|
4938
5047
|
.btn-export-confirm:hover:not(:disabled) { background: #2ea043; border-color: #2ea043; }
|
|
4939
5048
|
.btn-export-confirm:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
5049
|
+
|
|
5050
|
+
/* \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 */
|
|
5051
|
+
input, select, button, textarea { font-family: inherit; }
|
|
5052
|
+
|
|
5053
|
+
/* \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 */
|
|
5054
|
+
.btn-primary { background: #1f6feb; border-color: #1f6feb; color: #fff; }
|
|
5055
|
+
.btn-primary:hover { background: #388bfd; border-color: #388bfd; color: #fff; }
|
|
5056
|
+
.btn-primary:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
5057
|
+
|
|
5058
|
+
/* \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 */
|
|
5059
|
+
.ls-modal { max-width: 500px; }
|
|
5060
|
+
.ls-hd { display: flex; align-items: center; gap: 8px; }
|
|
5061
|
+
.ls-hd-icon { font-size: 15px; }
|
|
5062
|
+
|
|
5063
|
+
.ls-body {
|
|
5064
|
+
padding: 20px; overflow-y: auto; flex: 1;
|
|
5065
|
+
display: flex; flex-direction: column; gap: 20px;
|
|
5066
|
+
scrollbar-width: thin; scrollbar-color: #30363d transparent;
|
|
5067
|
+
}
|
|
5068
|
+
|
|
5069
|
+
.ls-section { display: flex; flex-direction: column; gap: 8px; }
|
|
5070
|
+
.ls-section-label {
|
|
5071
|
+
font-size: 10px; font-weight: 700; text-transform: uppercase;
|
|
5072
|
+
letter-spacing: 0.8px; color: #484f58;
|
|
5073
|
+
}
|
|
5074
|
+
|
|
5075
|
+
.ls-actions { display: flex; gap: 10px; }
|
|
5076
|
+
.ls-action-btn {
|
|
5077
|
+
flex: 1; padding: 14px 12px; border-radius: 8px;
|
|
5078
|
+
background: #0d1117; border: 1px solid #21262d; color: #8b949e;
|
|
5079
|
+
display: flex; flex-direction: column; align-items: center; gap: 6px;
|
|
5080
|
+
transition: background 0.15s, border-color 0.15s, color 0.15s;
|
|
5081
|
+
}
|
|
5082
|
+
.ls-action-btn:hover { background: #161b22; color: #e6edf3; border-color: #388bfd; }
|
|
5083
|
+
.ls-action-icon { font-size: 22px; line-height: 1; }
|
|
5084
|
+
.ls-action-label { font-size: 12px; font-weight: 600; color: #c9d1d9; }
|
|
5085
|
+
.ls-action-btn:hover .ls-action-label { color: #e6edf3; }
|
|
5086
|
+
.ls-action-sub { font-size: 10px; color: #484f58; line-height: 1.4; text-align: center; }
|
|
5087
|
+
|
|
5088
|
+
.ls-file-row {
|
|
5089
|
+
display: flex; align-items: center; gap: 10px;
|
|
5090
|
+
padding: 10px 12px; background: #0d1117;
|
|
5091
|
+
border: 1px solid #21262d; border-radius: 8px;
|
|
5092
|
+
}
|
|
5093
|
+
.ls-file-icon { font-size: 14px; flex-shrink: 0; }
|
|
5094
|
+
.ls-file-name {
|
|
5095
|
+
flex: 1; font-size: 11px; color: #c9d1d9;
|
|
5096
|
+
font-family: 'Cascadia Code','Fira Code','Consolas',monospace;
|
|
5097
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
5098
|
+
min-width: 0;
|
|
5099
|
+
}
|
|
5100
|
+
.ls-btn-rescan {
|
|
5101
|
+
flex-shrink: 0; padding: 4px 10px; font-size: 11px;
|
|
5102
|
+
background: #161b22; border-color: #30363d; color: #8b949e;
|
|
5103
|
+
}
|
|
5104
|
+
.ls-btn-rescan:hover { background: #21262d; color: #e6edf3; }
|
|
5105
|
+
|
|
5106
|
+
.ls-input {
|
|
5107
|
+
width: 100%; padding: 8px 10px; background: #0d1117;
|
|
5108
|
+
border: 1px solid #30363d; border-radius: 6px;
|
|
5109
|
+
color: #c9d1d9; font-size: 12px; outline: none; font-family: inherit;
|
|
5110
|
+
}
|
|
5111
|
+
.ls-input:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }
|
|
5112
|
+
|
|
5113
|
+
.ls-fns {
|
|
5114
|
+
display: flex; flex-wrap: wrap; gap: 6px;
|
|
5115
|
+
padding: 10px; background: #0d1117;
|
|
5116
|
+
border: 1px solid #21262d; border-radius: 6px; min-height: 38px;
|
|
5117
|
+
}
|
|
5118
|
+
.ls-fn-chip {
|
|
5119
|
+
padding: 3px 10px; font-size: 11px; color: #79c0ff;
|
|
5120
|
+
background: rgba(47,129,247,0.1); border: 1px solid rgba(47,129,247,0.2);
|
|
5121
|
+
border-radius: 12px; font-family: 'Cascadia Code','Fira Code','Consolas',monospace;
|
|
5122
|
+
}
|
|
5123
|
+
|
|
5124
|
+
.ls-field-block { display: flex; flex-direction: column; gap: 6px; }
|
|
5125
|
+
.ls-field-block + .ls-field-block { margin-top: 12px; }
|
|
5126
|
+
.ls-label { font-size: 11px; color: #8b949e; }
|
|
5127
|
+
.ls-select {
|
|
5128
|
+
width: 100%; padding: 8px 10px; background: #0d1117;
|
|
5129
|
+
border: 1px solid #30363d; border-radius: 6px;
|
|
5130
|
+
color: #c9d1d9; font-size: 12px; outline: none; cursor: pointer;
|
|
5131
|
+
}
|
|
5132
|
+
.ls-select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }
|
|
5133
|
+
|
|
5134
|
+
.ls-empty-state {
|
|
5135
|
+
display: flex; align-items: center; gap: 10px;
|
|
5136
|
+
padding: 14px; background: #0d1117; border: 1px solid #21262d;
|
|
5137
|
+
border-radius: 8px; font-size: 12px; color: #484f58;
|
|
5138
|
+
}
|
|
5139
|
+
.ls-empty-icon { font-size: 16px; }
|
|
5140
|
+
|
|
5141
|
+
.ls-ft { padding: 14px 20px; }
|
|
4940
5142
|
`;
|
|
4941
5143
|
|
|
4942
5144
|
// src/components/configuration/configuration.template.ts
|
|
@@ -5004,33 +5206,8 @@ function renderExportOverlay(state, t) {
|
|
|
5004
5206
|
</div>
|
|
5005
5207
|
</div>`;
|
|
5006
5208
|
}
|
|
5007
|
-
var TRACKER_INPUT_STYLE = "flex:1;min-width:180px;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none";
|
|
5008
|
-
function renderIssueTrackerCard(state, t) {
|
|
5009
|
-
const { issueTrackerProviderId, issueTrackerParams } = state;
|
|
5010
|
-
const provider = findIssueTrackerProvider(issueTrackerProviderId) ?? ISSUE_TRACKER_PROVIDERS[0];
|
|
5011
|
-
const values = issueTrackerParams[provider.id] ?? {};
|
|
5012
|
-
const options = ISSUE_TRACKER_PROVIDERS.map(
|
|
5013
|
-
(p) => `<option value="${escAttr(p.id)}" ${provider.id === p.id ? "selected" : ""}>${escHtml(t(p.labelKey))}</option>`
|
|
5014
|
-
).join("");
|
|
5015
|
-
const fields = provider.fields.map((f) => `
|
|
5016
|
-
<div class="field-row">
|
|
5017
|
-
<span class="field-label">${escHtml(t(f.labelKey))}</span>
|
|
5018
|
-
<input type="text" data-tracker-field="${escAttr(f.key)}" value="${escAttr(values[f.key] ?? "")}"
|
|
5019
|
-
placeholder="${escAttr(t(f.placeholderKey))}" style="${TRACKER_INPUT_STYLE}" />
|
|
5020
|
-
</div>`).join("");
|
|
5021
|
-
return `
|
|
5022
|
-
<div class="card card-wide">
|
|
5023
|
-
<div class="card-hd">${t("CONFIG.ISSUE_TRACKER_SECTION")}</div>
|
|
5024
|
-
<div class="field-row">
|
|
5025
|
-
<span class="field-label">${t("CONFIG.ISSUE_TRACKER_LABEL")}</span>
|
|
5026
|
-
<select id="issue-tracker-provider">${options}</select>
|
|
5027
|
-
</div>
|
|
5028
|
-
${fields}
|
|
5029
|
-
<div class="check-sub issue-tracker-disclaimer" style="margin-top:8px">${t("CONFIG.ISSUE_TRACKER_DISCLAIMER")}</div>
|
|
5030
|
-
</div>`;
|
|
5031
|
-
}
|
|
5032
5209
|
function renderConfiguration(state, t) {
|
|
5033
|
-
const { selectedLanguage, advancedHttpConfig, fixtureMode, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes } = state;
|
|
5210
|
+
const { selectedLanguage, advancedHttpConfig, fixtureMode, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes, issueTrackerConfig } = state;
|
|
5034
5211
|
const langOptions = LANGS.map(
|
|
5035
5212
|
(l) => `<option value="${l.value}" ${selectedLanguage === l.value ? "selected" : ""}>${l.label}</option>`
|
|
5036
5213
|
).join("");
|
|
@@ -5151,8 +5328,40 @@ function renderConfiguration(state, t) {
|
|
|
5151
5328
|
</div>
|
|
5152
5329
|
</div>
|
|
5153
5330
|
|
|
5154
|
-
<!-- Issue
|
|
5155
|
-
|
|
5331
|
+
<!-- Issue Tracker -->
|
|
5332
|
+
<div class="card card-wide">
|
|
5333
|
+
<div class="card-hd">${t("CONFIG.ISSUE_TRACKER_SECTION")}</div>
|
|
5334
|
+
<label class="check-row">
|
|
5335
|
+
<input type="checkbox" id="issue-tracker-toggle" ${issueTrackerConfig.enabled ? "checked" : ""} />
|
|
5336
|
+
<div>
|
|
5337
|
+
<div class="check-title">${t("CONFIG.ISSUE_TRACKER_TITLE")}</div>
|
|
5338
|
+
<div class="check-sub">${t("CONFIG.ISSUE_TRACKER_SUB")}</div>
|
|
5339
|
+
</div>
|
|
5340
|
+
</label>
|
|
5341
|
+
${issueTrackerConfig.enabled ? `
|
|
5342
|
+
<div class="field-row" style="margin-top:10px">
|
|
5343
|
+
<span class="field-label">${t("CONFIG.ISSUE_TRACKER_PROVIDER")}</span>
|
|
5344
|
+
<select id="issue-tracker-provider">
|
|
5345
|
+
${Object.values(ISSUE_TRACKER_PRESETS).map(
|
|
5346
|
+
(p) => `<option value="${p.id}" ${issueTrackerConfig.provider === p.id ? "selected" : ""}>${escHtml(p.label)}</option>`
|
|
5347
|
+
).join("")}
|
|
5348
|
+
</select>
|
|
5349
|
+
</div>
|
|
5350
|
+
<div class="field-row" style="margin-top:8px">
|
|
5351
|
+
<span class="field-label">${t("CONFIG.ISSUE_TRACKER_BASE_URL")}</span>
|
|
5352
|
+
<input id="issue-tracker-base-url" type="text"
|
|
5353
|
+
placeholder="${escAttr(t("CONFIG.ISSUE_TRACKER_BASE_URL_PH"))}"
|
|
5354
|
+
value="${escAttr(issueTrackerConfig.baseUrl)}"
|
|
5355
|
+
style="flex:1;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none" />
|
|
5356
|
+
</div>` : ""}
|
|
5357
|
+
</div>
|
|
5358
|
+
|
|
5359
|
+
<!-- Login Setup -->
|
|
5360
|
+
<div class="card card-wide">
|
|
5361
|
+
<div class="card-hd">${t("CONFIG.LOGIN_SETUP_SECTION")}</div>
|
|
5362
|
+
${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>`}
|
|
5363
|
+
<button id="btn-open-login-setup" class="btn-sm">${t("CONFIG.LOGIN_SETUP_SET_UP_BTN")}</button>
|
|
5364
|
+
</div>
|
|
5156
5365
|
|
|
5157
5366
|
<!-- Data -->
|
|
5158
5367
|
<div class="card card-wide">
|
|
@@ -5167,7 +5376,93 @@ function renderConfiguration(state, t) {
|
|
|
5167
5376
|
</div>
|
|
5168
5377
|
</div>
|
|
5169
5378
|
|
|
5170
|
-
</div>${renderExportOverlay(state, t)}`;
|
|
5379
|
+
</div>${renderExportOverlay(state, t)}${renderLoginSetupOverlay(state, t)}`;
|
|
5380
|
+
}
|
|
5381
|
+
function renderLoginSetupOverlay(state, t) {
|
|
5382
|
+
if (!state.isLoginSetupOpen) return "";
|
|
5383
|
+
const cfg = state.loginSetupConfig;
|
|
5384
|
+
const path = state.loginSetupDraftPath ?? cfg?.filePath ?? "";
|
|
5385
|
+
const fns = state.loginSetupDraftFunctions ?? cfg?.detectedFunctions ?? [];
|
|
5386
|
+
const beforeFn = state.loginSetupDraftBeforeFn !== void 0 ? state.loginSetupDraftBeforeFn : cfg?.beforeFn ?? null;
|
|
5387
|
+
const beforeEachFn = state.loginSetupDraftBeforeEachFn !== void 0 ? state.loginSetupDraftBeforeEachFn : cfg?.beforeEachFn ?? null;
|
|
5388
|
+
const hasContent = state.loginSetupDraftHasContent ?? !!cfg?.fileContent;
|
|
5389
|
+
const fnOption = (name, selected) => `<option value="${escAttr(name ?? "")}" ${selected === name ? "selected" : ""}>${name ? escHtml(name) : t("CONFIG.LOGIN_SETUP_NONE_OPTION")}</option>`;
|
|
5390
|
+
const fnDropdown = (id, label, selected) => `
|
|
5391
|
+
<div class="ls-field-block">
|
|
5392
|
+
<label class="ls-label" for="${id}">${escHtml(label)}</label>
|
|
5393
|
+
<select id="${id}" class="ls-select">
|
|
5394
|
+
${fnOption(null, selected)}
|
|
5395
|
+
${fns.map((fn) => fnOption(fn, selected)).join("")}
|
|
5396
|
+
</select>
|
|
5397
|
+
</div>`;
|
|
5398
|
+
const functionsSection = hasContent ? fns.length > 0 ? `<div class="ls-section">
|
|
5399
|
+
<span class="ls-section-label">Funciones detectadas</span>
|
|
5400
|
+
<div class="ls-fns">${fns.map((fn) => `<span class="ls-fn-chip">${escHtml(fn)}</span>`).join("")}</div>
|
|
5401
|
+
</div>
|
|
5402
|
+
<div class="ls-section">
|
|
5403
|
+
<span class="ls-section-label">Asignaci\xF3n de bloques</span>
|
|
5404
|
+
${fnDropdown("login-setup-before-fn", t("CONFIG.LOGIN_SETUP_BEFORE_LABEL"), beforeFn)}
|
|
5405
|
+
${fnDropdown("login-setup-before-each-fn", t("CONFIG.LOGIN_SETUP_BEFORE_EACH_LABEL"), beforeEachFn)}
|
|
5406
|
+
</div>` : `<div class="ls-empty-state">
|
|
5407
|
+
<span class="ls-empty-icon">\u{1F50D}</span>
|
|
5408
|
+
<span>${t("CONFIG.LOGIN_SETUP_NO_FUNCTIONS")}</span>
|
|
5409
|
+
</div>` : "";
|
|
5410
|
+
const fileSection = hasContent ? `<div class="ls-section">
|
|
5411
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_FILE_NAME_LABEL")}</span>
|
|
5412
|
+
<div class="ls-file-row">
|
|
5413
|
+
<span class="ls-file-icon">\u{1F4C4}</span>
|
|
5414
|
+
<span class="ls-file-name">${escHtml(path)}</span>
|
|
5415
|
+
<button id="btn-login-setup-rescan" class="ls-btn-rescan">${t("CONFIG.LOGIN_SETUP_RESCAN")}</button>
|
|
5416
|
+
</div>
|
|
5417
|
+
</div>` : `<div class="ls-section">
|
|
5418
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_FILE_NAME_LABEL")}</span>
|
|
5419
|
+
<input id="login-setup-filepath" type="text" class="ls-input"
|
|
5420
|
+
placeholder="${escAttr(t("CONFIG.LOGIN_SETUP_FILE_NAME_PH"))}"
|
|
5421
|
+
value="${escAttr(path)}" />
|
|
5422
|
+
</div>`;
|
|
5423
|
+
return `
|
|
5424
|
+
<div class="export-overlay" id="login-setup-overlay">
|
|
5425
|
+
<div class="export-modal ls-modal">
|
|
5426
|
+
|
|
5427
|
+
<div class="export-hd ls-hd">
|
|
5428
|
+
<span class="ls-hd-icon">\u{1F510}</span>
|
|
5429
|
+
${t("CONFIG.LOGIN_SETUP_TITLE")}
|
|
5430
|
+
</div>
|
|
5431
|
+
|
|
5432
|
+
<div class="ls-body">
|
|
5433
|
+
|
|
5434
|
+
<div class="ls-section">
|
|
5435
|
+
<span class="ls-section-label">${t("CONFIG.LOGIN_SETUP_SOURCE_LABEL")}</span>
|
|
5436
|
+
<div class="ls-actions">
|
|
5437
|
+
<button id="btn-login-setup-create-scaffold" class="ls-action-btn">
|
|
5438
|
+
<span class="ls-action-icon">\u2728</span>
|
|
5439
|
+
<span class="ls-action-label">${t("CONFIG.LOGIN_SETUP_CREATE_SCAFFOLD")}</span>
|
|
5440
|
+
<span class="ls-action-sub">${t("CONFIG.LOGIN_SETUP_CREATE_SUB")}</span>
|
|
5441
|
+
</button>
|
|
5442
|
+
<button id="btn-login-setup-pick-file" class="ls-action-btn">
|
|
5443
|
+
<span class="ls-action-icon">\u{1F4C2}</span>
|
|
5444
|
+
<span class="ls-action-label">${t("CONFIG.LOGIN_SETUP_SELECT_EXISTING")}</span>
|
|
5445
|
+
<span class="ls-action-sub">${t("CONFIG.LOGIN_SETUP_SELECT_SUB")}</span>
|
|
5446
|
+
</button>
|
|
5447
|
+
</div>
|
|
5448
|
+
</div>
|
|
5449
|
+
|
|
5450
|
+
${fileSection}
|
|
5451
|
+
|
|
5452
|
+
${functionsSection}
|
|
5453
|
+
|
|
5454
|
+
</div>
|
|
5455
|
+
|
|
5456
|
+
<div class="export-ft ls-ft">
|
|
5457
|
+
<button id="btn-login-setup-clear" class="btn-danger">${t("CONFIG.LOGIN_SETUP_CLEAR_BTN")}</button>
|
|
5458
|
+
<span class="export-ft-actions">
|
|
5459
|
+
<button id="btn-login-setup-cancel">${t("CONFIG.LOGIN_SETUP_CANCEL_BTN")}</button>
|
|
5460
|
+
<button id="btn-login-setup-save" class="btn-primary">${t("CONFIG.LOGIN_SETUP_SAVE_BTN")}</button>
|
|
5461
|
+
</span>
|
|
5462
|
+
</div>
|
|
5463
|
+
|
|
5464
|
+
</div>
|
|
5465
|
+
</div>`;
|
|
5171
5466
|
}
|
|
5172
5467
|
|
|
5173
5468
|
// src/components/configuration/configuration.ts
|
|
@@ -5182,13 +5477,21 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5182
5477
|
smartSelectorEnabled = true;
|
|
5183
5478
|
startHidden = false;
|
|
5184
5479
|
resumeTtlMinutes = DEFAULT_RESUME_TTL_MINUTES;
|
|
5185
|
-
issueTrackerProviderId = DEFAULT_ISSUE_TRACKER_PROVIDER_ID;
|
|
5186
|
-
issueTrackerParams = {};
|
|
5187
5480
|
isExporting = false;
|
|
5188
5481
|
exportMode = "all";
|
|
5189
5482
|
exportTests = [];
|
|
5190
5483
|
exportSelectedIds = /* @__PURE__ */ new Set();
|
|
5191
5484
|
exportSelectedTags = /* @__PURE__ */ new Set();
|
|
5485
|
+
issueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };
|
|
5486
|
+
isLoginSetupOpen = false;
|
|
5487
|
+
loginSetupConfig = null;
|
|
5488
|
+
loginSetupDraftPath = "";
|
|
5489
|
+
loginSetupDraftFunctions = [];
|
|
5490
|
+
loginSetupDraftBeforeFn = null;
|
|
5491
|
+
loginSetupDraftBeforeEachFn = null;
|
|
5492
|
+
loginSetupDraftHasContent = false;
|
|
5493
|
+
loginSetupDraftHandle = null;
|
|
5494
|
+
loginSetupDraftContent = "";
|
|
5192
5495
|
filesystemGranted = false;
|
|
5193
5496
|
cypressFolderName = null;
|
|
5194
5497
|
constructor() {
|
|
@@ -5225,12 +5528,12 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5225
5528
|
this.filesystemGranted = config?.["allowReadWriteFiles"] === "true";
|
|
5226
5529
|
const handle = config?.["cypressDirectoryHandle"];
|
|
5227
5530
|
this.cypressFolderName = handle?.name ?? null;
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5531
|
+
this.issueTrackerConfig = {
|
|
5532
|
+
enabled: config?.["issueTrackerEnabled"] === "true",
|
|
5533
|
+
provider: config?.["issueTrackerProvider"] ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,
|
|
5534
|
+
baseUrl: config?.["issueTrackerBaseUrl"] ?? ""
|
|
5535
|
+
};
|
|
5536
|
+
this.loginSetupConfig = await this.persistence.getLoginSetup();
|
|
5234
5537
|
this.render();
|
|
5235
5538
|
}
|
|
5236
5539
|
async onLanguageChange(lang) {
|
|
@@ -5263,20 +5566,6 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5263
5566
|
await this.persistence.setConfig({ [RESUME_TTL_CONFIG_KEY]: safe });
|
|
5264
5567
|
this.render();
|
|
5265
5568
|
}
|
|
5266
|
-
/** Selects the issue-tracker provider (link-only, no sync — spec 014). */
|
|
5267
|
-
async onIssueTrackerProviderChange(id) {
|
|
5268
|
-
this.issueTrackerProviderId = id;
|
|
5269
|
-
await this.persistence.setConfig({ issueTrackerProviderId: id });
|
|
5270
|
-
this.render();
|
|
5271
|
-
}
|
|
5272
|
-
/** Stores a provider field value, scoped to the active provider so switching keeps values. */
|
|
5273
|
-
async onIssueTrackerParamChange(fieldKey, value) {
|
|
5274
|
-
const providerId = this.issueTrackerProviderId;
|
|
5275
|
-
const current = { ...this.issueTrackerParams[providerId] ?? {} };
|
|
5276
|
-
current[fieldKey] = value;
|
|
5277
|
-
this.issueTrackerParams = { ...this.issueTrackerParams, [providerId]: current };
|
|
5278
|
-
await this.persistence.setConfig({ issueTrackerParams: this.issueTrackerParams });
|
|
5279
|
-
}
|
|
5280
5569
|
onResetWidgetPosition() {
|
|
5281
5570
|
this.dispatchEvent(new CustomEvent("resetwidgetposition", { bubbles: true, composed: true }));
|
|
5282
5571
|
showToast(this.t("CONFIG.WIDGET_POSITION_RESET_DONE"));
|
|
@@ -5293,6 +5582,102 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5293
5582
|
this.dispatchEvent(new CustomEvent("selectorstrategychange", { detail: strategy, bubbles: true, composed: true }));
|
|
5294
5583
|
this.render();
|
|
5295
5584
|
}
|
|
5585
|
+
async onIssueTrackerEnabledChange(enabled) {
|
|
5586
|
+
this.issueTrackerConfig = { ...this.issueTrackerConfig, enabled };
|
|
5587
|
+
await this.persistence.setConfig({ issueTrackerEnabled: enabled ? "true" : "false" });
|
|
5588
|
+
this.dispatchEvent(new CustomEvent("issuetrackerchange", { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));
|
|
5589
|
+
this.render();
|
|
5590
|
+
}
|
|
5591
|
+
async onIssueTrackerProviderChange(provider) {
|
|
5592
|
+
this.issueTrackerConfig = { ...this.issueTrackerConfig, provider };
|
|
5593
|
+
await this.persistence.setConfig({ issueTrackerProvider: provider });
|
|
5594
|
+
this.dispatchEvent(new CustomEvent("issuetrackerchange", { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));
|
|
5595
|
+
this.render();
|
|
5596
|
+
}
|
|
5597
|
+
async onIssueTrackerBaseUrlChange(baseUrl) {
|
|
5598
|
+
this.issueTrackerConfig = { ...this.issueTrackerConfig, baseUrl };
|
|
5599
|
+
await this.persistence.setConfig({ issueTrackerBaseUrl: baseUrl });
|
|
5600
|
+
this.dispatchEvent(new CustomEvent("issuetrackerchange", { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));
|
|
5601
|
+
}
|
|
5602
|
+
openLoginSetupPanel() {
|
|
5603
|
+
this.isLoginSetupOpen = true;
|
|
5604
|
+
const cfg = this.loginSetupConfig;
|
|
5605
|
+
this.loginSetupDraftHandle = null;
|
|
5606
|
+
this.loginSetupDraftContent = cfg?.fileContent ?? "";
|
|
5607
|
+
this.loginSetupDraftPath = cfg?.filePath ?? "";
|
|
5608
|
+
this.loginSetupDraftFunctions = cfg?.detectedFunctions ?? [];
|
|
5609
|
+
this.loginSetupDraftBeforeFn = cfg?.beforeFn ?? null;
|
|
5610
|
+
this.loginSetupDraftBeforeEachFn = cfg?.beforeEachFn ?? null;
|
|
5611
|
+
this.loginSetupDraftHasContent = !!cfg?.fileContent;
|
|
5612
|
+
this.render();
|
|
5613
|
+
}
|
|
5614
|
+
closeLoginSetupPanel() {
|
|
5615
|
+
this.isLoginSetupOpen = false;
|
|
5616
|
+
this.render();
|
|
5617
|
+
}
|
|
5618
|
+
async saveLoginSetupConfig(config) {
|
|
5619
|
+
await this.persistence.saveLoginSetup(config);
|
|
5620
|
+
this.loginSetupConfig = config;
|
|
5621
|
+
this.isLoginSetupOpen = false;
|
|
5622
|
+
this.render();
|
|
5623
|
+
}
|
|
5624
|
+
async clearLoginSetupConfig() {
|
|
5625
|
+
await this.persistence.clearLoginSetup();
|
|
5626
|
+
this.loginSetupConfig = null;
|
|
5627
|
+
this.render();
|
|
5628
|
+
}
|
|
5629
|
+
async loginSetupPickFile() {
|
|
5630
|
+
const currentPath = this.shadow.getElementById("login-setup-filepath")?.value.trim() ?? "";
|
|
5631
|
+
try {
|
|
5632
|
+
const [handle] = await window.showOpenFilePicker({
|
|
5633
|
+
types: [{ description: "TypeScript files", accept: { "text/plain": [".ts"] } }],
|
|
5634
|
+
multiple: false
|
|
5635
|
+
});
|
|
5636
|
+
this.loginSetupDraftHandle = handle;
|
|
5637
|
+
const file = await handle.getFile();
|
|
5638
|
+
this.loginSetupDraftContent = await file.text();
|
|
5639
|
+
this.loginSetupDraftHasContent = true;
|
|
5640
|
+
this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;
|
|
5641
|
+
this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);
|
|
5642
|
+
this.render();
|
|
5643
|
+
} catch (e) {
|
|
5644
|
+
if (e?.name !== "AbortError") showToast(this.t("CONFIG.FOLDER_ERROR_TOAST"), false);
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
5647
|
+
async loginSetupCreateScaffold() {
|
|
5648
|
+
const currentPath = this.shadow.getElementById("login-setup-filepath")?.value.trim() ?? "";
|
|
5649
|
+
try {
|
|
5650
|
+
const handle = await window.showSaveFilePicker({
|
|
5651
|
+
suggestedName: "login.service.ts",
|
|
5652
|
+
types: [{ description: "TypeScript files", accept: { "text/plain": [".ts"] } }]
|
|
5653
|
+
});
|
|
5654
|
+
const content = buildLoginScaffold();
|
|
5655
|
+
const writable = await handle.createWritable();
|
|
5656
|
+
await writable.write(content);
|
|
5657
|
+
await writable.close();
|
|
5658
|
+
this.loginSetupDraftHandle = handle;
|
|
5659
|
+
this.loginSetupDraftContent = content;
|
|
5660
|
+
this.loginSetupDraftHasContent = true;
|
|
5661
|
+
this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;
|
|
5662
|
+
this.loginSetupDraftFunctions = extractExportedFunctions(content);
|
|
5663
|
+
this.render();
|
|
5664
|
+
} catch (e) {
|
|
5665
|
+
if (e?.name !== "AbortError") showToast(this.t("CONFIG.FOLDER_ERROR_TOAST"), false);
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
async loginSetupRescan() {
|
|
5669
|
+
const currentPath = this.shadow.getElementById("login-setup-filepath")?.value.trim();
|
|
5670
|
+
if (currentPath !== void 0) this.loginSetupDraftPath = currentPath;
|
|
5671
|
+
try {
|
|
5672
|
+
if (this.loginSetupDraftHandle) {
|
|
5673
|
+
const file = await this.loginSetupDraftHandle.getFile();
|
|
5674
|
+
this.loginSetupDraftContent = await file.text();
|
|
5675
|
+
}
|
|
5676
|
+
this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);
|
|
5677
|
+
this.render();
|
|
5678
|
+
} catch {
|
|
5679
|
+
}
|
|
5680
|
+
}
|
|
5296
5681
|
async changeFolder() {
|
|
5297
5682
|
try {
|
|
5298
5683
|
await this.persistence.requestDirectoryPermissions();
|
|
@@ -5390,13 +5775,19 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5390
5775
|
smartSelectorEnabled: this.smartSelectorEnabled,
|
|
5391
5776
|
startHidden: this.startHidden,
|
|
5392
5777
|
resumeTtlMinutes: this.resumeTtlMinutes,
|
|
5393
|
-
issueTrackerProviderId: this.issueTrackerProviderId,
|
|
5394
|
-
issueTrackerParams: this.issueTrackerParams,
|
|
5395
5778
|
isExporting: this.isExporting,
|
|
5396
5779
|
exportMode: this.exportMode,
|
|
5397
5780
|
exportTests: this.exportTests,
|
|
5398
5781
|
exportSelectedIds: this.exportSelectedIds,
|
|
5399
|
-
exportSelectedTags: this.exportSelectedTags
|
|
5782
|
+
exportSelectedTags: this.exportSelectedTags,
|
|
5783
|
+
issueTrackerConfig: this.issueTrackerConfig,
|
|
5784
|
+
isLoginSetupOpen: this.isLoginSetupOpen,
|
|
5785
|
+
loginSetupConfig: this.loginSetupConfig,
|
|
5786
|
+
loginSetupDraftPath: this.loginSetupDraftPath,
|
|
5787
|
+
loginSetupDraftFunctions: this.loginSetupDraftFunctions,
|
|
5788
|
+
loginSetupDraftBeforeFn: this.loginSetupDraftBeforeFn,
|
|
5789
|
+
loginSetupDraftBeforeEachFn: this.loginSetupDraftBeforeEachFn,
|
|
5790
|
+
loginSetupDraftHasContent: this.loginSetupDraftHasContent
|
|
5400
5791
|
}, this.t.bind(this))}`;
|
|
5401
5792
|
;
|
|
5402
5793
|
this.shadow.getElementById("lang-select").addEventListener(
|
|
@@ -5428,15 +5819,18 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5428
5819
|
"change",
|
|
5429
5820
|
(e) => this.onSelectorStrategyChange(e.target.value)
|
|
5430
5821
|
);
|
|
5822
|
+
;
|
|
5823
|
+
this.shadow.getElementById("issue-tracker-toggle")?.addEventListener(
|
|
5824
|
+
"change",
|
|
5825
|
+
(e) => this.onIssueTrackerEnabledChange(e.target.checked)
|
|
5826
|
+
);
|
|
5431
5827
|
this.shadow.getElementById("issue-tracker-provider")?.addEventListener(
|
|
5432
5828
|
"change",
|
|
5433
5829
|
(e) => this.onIssueTrackerProviderChange(e.target.value)
|
|
5434
5830
|
);
|
|
5435
|
-
this.shadow.
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
() => this.onIssueTrackerParamChange(el.dataset["trackerField"] ?? "", el.value)
|
|
5439
|
-
)
|
|
5831
|
+
this.shadow.getElementById("issue-tracker-base-url")?.addEventListener(
|
|
5832
|
+
"change",
|
|
5833
|
+
(e) => this.onIssueTrackerBaseUrlChange(e.target.value)
|
|
5440
5834
|
);
|
|
5441
5835
|
this.shadow.getElementById("btn-change-folder")?.addEventListener("click", () => this.changeFolder());
|
|
5442
5836
|
this.shadow.getElementById("btn-revoke")?.addEventListener("click", () => this.revokeAccess());
|
|
@@ -5452,24 +5846,48 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
5452
5846
|
this.shadow.querySelectorAll("[data-export-tag]").forEach(
|
|
5453
5847
|
(el) => el.addEventListener("click", () => this.toggleExportTag(el.dataset["exportTag"] ?? ""))
|
|
5454
5848
|
);
|
|
5849
|
+
this.shadow.getElementById("btn-open-login-setup")?.addEventListener("click", () => this.openLoginSetupPanel());
|
|
5850
|
+
this.shadow.getElementById("btn-login-setup-cancel")?.addEventListener("click", () => this.closeLoginSetupPanel());
|
|
5851
|
+
this.shadow.getElementById("btn-login-setup-pick-file")?.addEventListener("click", () => this.loginSetupPickFile());
|
|
5852
|
+
this.shadow.getElementById("btn-login-setup-create-scaffold")?.addEventListener("click", () => this.loginSetupCreateScaffold());
|
|
5853
|
+
this.shadow.getElementById("btn-login-setup-rescan")?.addEventListener("click", () => this.loginSetupRescan());
|
|
5854
|
+
this.shadow.getElementById("btn-login-setup-clear")?.addEventListener("click", () => this.clearLoginSetupConfig());
|
|
5855
|
+
this.shadow.getElementById("btn-login-setup-save")?.addEventListener("click", async () => {
|
|
5856
|
+
const pathEl = this.shadow.getElementById("login-setup-filepath");
|
|
5857
|
+
const beforeEl = this.shadow.getElementById("login-setup-before-fn");
|
|
5858
|
+
const beforeEachEl = this.shadow.getElementById("login-setup-before-each-fn");
|
|
5859
|
+
await this.saveLoginSetupConfig({
|
|
5860
|
+
enabled: true,
|
|
5861
|
+
filePath: pathEl?.value.trim() ?? this.loginSetupDraftPath,
|
|
5862
|
+
fileContent: this.loginSetupDraftContent,
|
|
5863
|
+
detectedFunctions: this.loginSetupDraftFunctions,
|
|
5864
|
+
beforeFn: beforeEl?.value || null,
|
|
5865
|
+
beforeEachFn: beforeEachEl?.value || null
|
|
5866
|
+
});
|
|
5867
|
+
});
|
|
5868
|
+
;
|
|
5455
5869
|
this.shadow.getElementById("file-input").addEventListener("change", async (e) => {
|
|
5456
5870
|
const file = e.target.files?.[0];
|
|
5457
5871
|
if (!file) return;
|
|
5458
5872
|
try {
|
|
5459
5873
|
await this.importAllData(file);
|
|
5460
|
-
|
|
5874
|
+
showToast(this.t("CONFIG.IMPORT_SUCCESS"));
|
|
5461
5875
|
} catch (err) {
|
|
5462
|
-
|
|
5876
|
+
showToast(err.message ?? this.t("CONFIG.IMPORT_ERROR"), false);
|
|
5463
5877
|
}
|
|
5464
5878
|
const target = e.target;
|
|
5465
5879
|
if (target) target.value = "";
|
|
5466
5880
|
});
|
|
5467
5881
|
}
|
|
5468
5882
|
};
|
|
5469
|
-
if (!customElements.get("e2e-configuration")) {
|
|
5470
|
-
customElements.define("e2e-configuration", ConfigurationElement);
|
|
5883
|
+
if (!customElements.get("lib-e2e-configuration")) {
|
|
5884
|
+
customElements.define("lib-e2e-configuration", ConfigurationElement);
|
|
5471
5885
|
}
|
|
5472
5886
|
|
|
5887
|
+
// src/components/advanced-test-editor/advanced-test-editor.ts
|
|
5888
|
+
var import_sweetalert2 = __toESM(require("sweetalert2"), 1);
|
|
5889
|
+
init_code_format_utils();
|
|
5890
|
+
|
|
5473
5891
|
// src/components/advanced-test-editor/advanced-test-editor.styles.ts
|
|
5474
5892
|
var ADVANCED_TEST_EDITOR_STYLES = `
|
|
5475
5893
|
:host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }
|
|
@@ -5728,6 +6146,7 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
5728
6146
|
isCreatingFolder = false;
|
|
5729
6147
|
collapsedDirs = /* @__PURE__ */ new Set();
|
|
5730
6148
|
sidebarWidth = 220;
|
|
6149
|
+
loginSetupConfig = null;
|
|
5731
6150
|
hasPermission = false;
|
|
5732
6151
|
needsReauth = false;
|
|
5733
6152
|
_dirHandle = null;
|
|
@@ -5788,20 +6207,51 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
5788
6207
|
const name = rawName.trim().replace(/\.cy\.ts$/, "");
|
|
5789
6208
|
if (!name) return;
|
|
5790
6209
|
const fileName = `${name}.cy.ts`;
|
|
5791
|
-
const
|
|
6210
|
+
const cfg = this.loginSetupConfig;
|
|
6211
|
+
if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {
|
|
6212
|
+
const e2eName = this._e2eHandle.name ?? "e2e";
|
|
6213
|
+
const fromPath = `cypress/${e2eName}/${fileName}`;
|
|
6214
|
+
const importPath = buildLoginImportPath(fromPath, cfg.filePath);
|
|
6215
|
+
const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(
|
|
6216
|
+
importPath,
|
|
6217
|
+
cfg.beforeFn,
|
|
6218
|
+
cfg.beforeEachFn
|
|
6219
|
+
);
|
|
6220
|
+
const header = importLine ? `${importLine}
|
|
5792
6221
|
|
|
6222
|
+
` : "";
|
|
6223
|
+
const inner = [beforeBlock, beforeEachBlock].filter(Boolean).join("");
|
|
6224
|
+
const template = `${header}describe('${escapeSingleQuotes(name)}', () => {
|
|
6225
|
+
${inner}
|
|
5793
6226
|
it('should ', () => {
|
|
5794
6227
|
|
|
5795
6228
|
});
|
|
5796
6229
|
|
|
5797
6230
|
});
|
|
5798
6231
|
`;
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
6232
|
+
try {
|
|
6233
|
+
const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });
|
|
6234
|
+
const writable = await fileHandle.createWritable();
|
|
6235
|
+
await writable.write(template);
|
|
6236
|
+
await writable.close();
|
|
6237
|
+
} catch {
|
|
6238
|
+
}
|
|
6239
|
+
} else {
|
|
6240
|
+
const template = `describe('${escapeSingleQuotes(name)}', () => {
|
|
6241
|
+
|
|
6242
|
+
it('should ', () => {
|
|
6243
|
+
|
|
6244
|
+
});
|
|
6245
|
+
|
|
6246
|
+
});
|
|
6247
|
+
`;
|
|
6248
|
+
try {
|
|
6249
|
+
const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });
|
|
6250
|
+
const writable = await fileHandle.createWritable();
|
|
6251
|
+
await writable.write(template);
|
|
6252
|
+
await writable.close();
|
|
6253
|
+
} catch {
|
|
6254
|
+
}
|
|
5805
6255
|
}
|
|
5806
6256
|
this.isCreatingFile = false;
|
|
5807
6257
|
await this.getFoldersData();
|
|
@@ -5829,6 +6279,30 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
5829
6279
|
const comment = this.testNotes ? this.transformationService.buildBlockComment(this.testNotes) + "\n" : "";
|
|
5830
6280
|
content = this.transformationService.insertItBlock(content, comment + this.testItBlock);
|
|
5831
6281
|
if (!content) return;
|
|
6282
|
+
const cfg = this.loginSetupConfig;
|
|
6283
|
+
if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {
|
|
6284
|
+
const fns = [cfg.beforeFn, cfg.beforeEachFn].filter(Boolean);
|
|
6285
|
+
if (!hasLoginBlocks(content, fns)) {
|
|
6286
|
+
const e2eName = this._e2eHandle?.name ?? "e2e";
|
|
6287
|
+
const fileName = this.selectedFile?.name ?? "";
|
|
6288
|
+
const fromPath = `cypress/${e2eName}/${fileName}`;
|
|
6289
|
+
const importPath = buildLoginImportPath(fromPath, cfg.filePath);
|
|
6290
|
+
const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(importPath, cfg.beforeFn, cfg.beforeEachFn);
|
|
6291
|
+
const result = await import_sweetalert2.default.fire({
|
|
6292
|
+
title: this.t("CONFIG.LOGIN_SETUP_INJECT_TITLE"),
|
|
6293
|
+
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>`,
|
|
6294
|
+
icon: "question",
|
|
6295
|
+
showCancelButton: true,
|
|
6296
|
+
confirmButtonText: this.t("CONFIG.LOGIN_SETUP_INJECT_CONFIRM"),
|
|
6297
|
+
cancelButtonText: this.t("CONFIG.LOGIN_SETUP_CANCEL_BTN"),
|
|
6298
|
+
confirmButtonColor: "#1f6feb",
|
|
6299
|
+
width: 460
|
|
6300
|
+
});
|
|
6301
|
+
if (result.isConfirmed) {
|
|
6302
|
+
content = injectLoginBlocksIntoExisting(content, importLine, beforeBlock, beforeEachBlock);
|
|
6303
|
+
}
|
|
6304
|
+
}
|
|
6305
|
+
}
|
|
5832
6306
|
const writable = await this.selectedFileHandle.createWritable();
|
|
5833
6307
|
await writable.write(content);
|
|
5834
6308
|
await writable.close();
|
|
@@ -6023,8 +6497,8 @@ var AdvancedTestEditorElement = class extends HTMLElement {
|
|
|
6023
6497
|
});
|
|
6024
6498
|
}
|
|
6025
6499
|
};
|
|
6026
|
-
if (!customElements.get("advanced-test-editor")) {
|
|
6027
|
-
customElements.define("advanced-test-editor", AdvancedTestEditorElement);
|
|
6500
|
+
if (!customElements.get("lib-e2e-advanced-test-editor")) {
|
|
6501
|
+
customElements.define("lib-e2e-advanced-test-editor", AdvancedTestEditorElement);
|
|
6028
6502
|
}
|
|
6029
6503
|
|
|
6030
6504
|
// src/components/file-preview/file-preview.styles.ts
|
|
@@ -6040,9 +6514,6 @@ var FILE_PREVIEW_STYLES = `
|
|
|
6040
6514
|
.file-name { flex: 1; font-size: 12px; color: #8b949e;
|
|
6041
6515
|
font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; }
|
|
6042
6516
|
.body { display: flex; flex: 1; overflow: hidden; min-height: 0; }
|
|
6043
|
-
/* Host for the CodeMirror editor (or the textarea fallback). */
|
|
6044
|
-
.editor-host { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }
|
|
6045
|
-
.editor-host .cm-editor { flex: 1; min-height: 0; }
|
|
6046
6517
|
.editor {
|
|
6047
6518
|
flex: 1; min-width: 0; padding: 14px;
|
|
6048
6519
|
background: #0d1117; color: #c9d1d9; border: none; outline: none;
|
|
@@ -6232,7 +6703,7 @@ function renderFilePreview(state, t) {
|
|
|
6232
6703
|
<button id="btn-copy" title="${t("FILE_PREVIEW.COPY_TITLE")}">\u{1F4CB}</button>
|
|
6233
6704
|
</div>
|
|
6234
6705
|
<div class="body">
|
|
6235
|
-
${showDiff ? `<div class="diff-panel" id="diff-panel">${buildDiffHtml(originalContent ?? "", currentContent, t)}</div>` : `<
|
|
6706
|
+
${showDiff ? `<div class="diff-panel" id="diff-panel">${buildDiffHtml(originalContent ?? "", currentContent, t)}</div>` : `<textarea class="editor" id="editor" spellcheck="false">${escHtml(fileContent ?? "")}</textarea>`}
|
|
6236
6707
|
${blocksPanelHtml}
|
|
6237
6708
|
</div>
|
|
6238
6709
|
${runResultHtml}
|
|
@@ -6250,7 +6721,6 @@ function renderFilePreview(state, t) {
|
|
|
6250
6721
|
var FilePreviewElement = class extends HTMLElement {
|
|
6251
6722
|
shadow;
|
|
6252
6723
|
textarea = null;
|
|
6253
|
-
editor = null;
|
|
6254
6724
|
fileName = null;
|
|
6255
6725
|
closeLabel = "";
|
|
6256
6726
|
translation = translationService;
|
|
@@ -6276,29 +6746,20 @@ var FilePreviewElement = class extends HTMLElement {
|
|
|
6276
6746
|
if (!this.closeLabel) this.closeLabel = this.translation.translate("FILE_PREVIEW.CLOSE_BTN");
|
|
6277
6747
|
this.render();
|
|
6278
6748
|
}
|
|
6279
|
-
disconnectedCallback() {
|
|
6280
|
-
this.editor?.destroy();
|
|
6281
|
-
this.editor = null;
|
|
6282
|
-
}
|
|
6283
6749
|
t(key) {
|
|
6284
6750
|
return this.translation.translate(key);
|
|
6285
6751
|
}
|
|
6286
|
-
/** Current editor content (CodeMirror if upgraded, else the textarea/fallback). */
|
|
6287
|
-
currentValue() {
|
|
6288
|
-
return this.editor?.getValue() ?? this.textarea?.value ?? this._fileContent ?? "";
|
|
6289
|
-
}
|
|
6290
6752
|
get fileContent() {
|
|
6291
6753
|
return this._fileContent;
|
|
6292
6754
|
}
|
|
6293
6755
|
set fileContent(v) {
|
|
6294
6756
|
if (this._originalContent === null) this._originalContent = v;
|
|
6295
6757
|
this._fileContent = v;
|
|
6296
|
-
if (this.
|
|
6297
|
-
else if (this.textarea) this.textarea.value = v ?? "";
|
|
6758
|
+
if (this.textarea) this.textarea.value = v ?? "";
|
|
6298
6759
|
else this.render();
|
|
6299
6760
|
}
|
|
6300
6761
|
saveFile() {
|
|
6301
|
-
const content = this.
|
|
6762
|
+
const content = this.textarea?.value ?? this._fileContent ?? "";
|
|
6302
6763
|
this.dispatchEvent(new CustomEvent("save", { detail: content, bubbles: true, composed: true }));
|
|
6303
6764
|
}
|
|
6304
6765
|
onClose() {
|
|
@@ -6347,7 +6808,7 @@ var FilePreviewElement = class extends HTMLElement {
|
|
|
6347
6808
|
* (and warns) when the file has no valid describe() block to insert into.
|
|
6348
6809
|
*/
|
|
6349
6810
|
insertBlocks() {
|
|
6350
|
-
const base = this.
|
|
6811
|
+
const base = this.textarea?.value ?? this._fileContent ?? "";
|
|
6351
6812
|
let content = base;
|
|
6352
6813
|
if (this.interceptorsBlock) {
|
|
6353
6814
|
const merged = advancedTestTransformationService.insertBeforeEach(content, this.interceptorsBlock);
|
|
@@ -6367,14 +6828,12 @@ var FilePreviewElement = class extends HTMLElement {
|
|
|
6367
6828
|
showToast(this.t("FILE_PREVIEW.INSERT_DONE"));
|
|
6368
6829
|
}
|
|
6369
6830
|
render() {
|
|
6370
|
-
this.editor?.destroy();
|
|
6371
|
-
this.editor = null;
|
|
6372
6831
|
this.shadow.innerHTML = `<style>${FILE_PREVIEW_STYLES}</style>${renderFilePreview({
|
|
6373
6832
|
fileName: this.fileName,
|
|
6374
6833
|
showDiff: this._showDiff,
|
|
6375
6834
|
fileContent: this._fileContent,
|
|
6376
6835
|
originalContent: this._originalContent,
|
|
6377
|
-
currentContent: this._fileContent ?? "",
|
|
6836
|
+
currentContent: this.textarea?.value ?? this._fileContent ?? "",
|
|
6378
6837
|
itBlock: this.itBlock,
|
|
6379
6838
|
interceptorsBlock: this.interceptorsBlock,
|
|
6380
6839
|
closeLabel: this.closeLabel,
|
|
@@ -6388,13 +6847,12 @@ var FilePreviewElement = class extends HTMLElement {
|
|
|
6388
6847
|
this.textarea.addEventListener("input", () => {
|
|
6389
6848
|
this._fileContent = ta.value;
|
|
6390
6849
|
});
|
|
6391
|
-
void this.upgradeEditor();
|
|
6392
6850
|
}
|
|
6393
6851
|
this.shadow.getElementById("btn-save")?.addEventListener("click", () => this.saveFile());
|
|
6394
6852
|
this.shadow.getElementById("btn-close")?.addEventListener("click", () => this.onClose());
|
|
6395
6853
|
this.shadow.getElementById("btn-launch")?.addEventListener("click", () => this.launchTest());
|
|
6396
6854
|
this.shadow.getElementById("btn-copy")?.addEventListener("click", () => {
|
|
6397
|
-
this.copyToClipboard(this.
|
|
6855
|
+
this.copyToClipboard(this.textarea?.value ?? this._fileContent ?? "");
|
|
6398
6856
|
});
|
|
6399
6857
|
this.shadow.getElementById("btn-diff")?.addEventListener("click", () => this.toggleDiff());
|
|
6400
6858
|
this.shadow.getElementById("btn-insert")?.addEventListener("click", () => this.insertBlocks());
|
|
@@ -6405,37 +6863,9 @@ var FilePreviewElement = class extends HTMLElement {
|
|
|
6405
6863
|
this.copyToClipboard(this.interceptorsBlock);
|
|
6406
6864
|
});
|
|
6407
6865
|
}
|
|
6408
|
-
/**
|
|
6409
|
-
* Lazily upgrades the textarea to a CodeMirror editor (syntax highlight +
|
|
6410
|
-
* Cypress autocomplete). On any failure the textarea is left in place, so the
|
|
6411
|
-
* editor degrades gracefully when CodeMirror can't load.
|
|
6412
|
-
*/
|
|
6413
|
-
async upgradeEditor() {
|
|
6414
|
-
const host = this.shadow.getElementById("editor-host");
|
|
6415
|
-
const ta = this.textarea;
|
|
6416
|
-
if (!host || !ta) return;
|
|
6417
|
-
try {
|
|
6418
|
-
const handle = await createCodeEditor({
|
|
6419
|
-
parent: host,
|
|
6420
|
-
root: this.shadow,
|
|
6421
|
-
doc: this._fileContent ?? "",
|
|
6422
|
-
onChange: (value) => {
|
|
6423
|
-
this._fileContent = value;
|
|
6424
|
-
}
|
|
6425
|
-
});
|
|
6426
|
-
if (!host.isConnected) {
|
|
6427
|
-
handle.destroy();
|
|
6428
|
-
return;
|
|
6429
|
-
}
|
|
6430
|
-
ta.remove();
|
|
6431
|
-
this.textarea = null;
|
|
6432
|
-
this.editor = handle;
|
|
6433
|
-
} catch {
|
|
6434
|
-
}
|
|
6435
|
-
}
|
|
6436
6866
|
};
|
|
6437
|
-
if (!customElements.get("file-preview")) {
|
|
6438
|
-
customElements.define("file-preview", FilePreviewElement);
|
|
6867
|
+
if (!customElements.get("lib-e2e-file-preview")) {
|
|
6868
|
+
customElements.define("lib-e2e-file-preview", FilePreviewElement);
|
|
6439
6869
|
}
|
|
6440
6870
|
|
|
6441
6871
|
// src/components/help-panel/help-panel.styles.ts
|
|
@@ -6531,12 +6961,12 @@ var REFERENCE_SECTIONS = [
|
|
|
6531
6961
|
{ title: "HELP.SEC_PANELS", items: ["HELP.PANEL_TESTS", "HELP.PANEL_COMMANDS", "HELP.PANEL_CONFIG", "HELP.PANEL_FILES"] },
|
|
6532
6962
|
{ title: "HELP.SEC_SELECTOR", items: ["HELP.SELECTOR_1", "HELP.SELECTOR_2"] },
|
|
6533
6963
|
{ title: "HELP.SEC_DATA", items: ["HELP.DATA_1", "HELP.DATA_2"] },
|
|
6534
|
-
{ title: "HELP.SEC_ADVANCED", items: ["HELP.ADV_INVISIBLE", "HELP.ADV_RUNNER", "HELP.ADV_CROSSAPP", "HELP.ADV_DRAG"] }
|
|
6964
|
+
{ title: "HELP.SEC_ADVANCED", items: ["HELP.ADV_INVISIBLE", "HELP.ADV_RUNNER", "HELP.ADV_CROSSAPP", "HELP.ADV_DRAG", "HELP.ADV_LOGIN"] }
|
|
6535
6965
|
];
|
|
6536
6966
|
var GUIDE_SECTIONS = [
|
|
6537
6967
|
{ 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"] },
|
|
6538
|
-
{ 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"] },
|
|
6539
|
-
{ 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"
|
|
6968
|
+
{ 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"] },
|
|
6969
|
+
{ 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"] }
|
|
6540
6970
|
];
|
|
6541
6971
|
function sectionsHtml(sections, t) {
|
|
6542
6972
|
return sections.map(
|
|
@@ -6583,12 +7013,12 @@ var HelpPanelElement = class extends HTMLElement {
|
|
|
6583
7013
|
});
|
|
6584
7014
|
}
|
|
6585
7015
|
};
|
|
6586
|
-
if (!customElements.get("help-panel")) {
|
|
6587
|
-
customElements.define("help-panel", HelpPanelElement);
|
|
7016
|
+
if (!customElements.get("lib-e2e-help-panel")) {
|
|
7017
|
+
customElements.define("lib-e2e-help-panel", HelpPanelElement);
|
|
6588
7018
|
}
|
|
6589
7019
|
|
|
6590
7020
|
// src/components/lib-e2e-recorder/lib-e2e-recorder.ts
|
|
6591
|
-
var
|
|
7021
|
+
var import_sweetalert22 = __toESM(require("sweetalert2"), 1);
|
|
6592
7022
|
|
|
6593
7023
|
// src/components/lib-e2e-recorder/lib-e2e-recorder.styles.ts
|
|
6594
7024
|
var DIRECTIONS = ["up-left", "up-right", "down-left", "down-right"];
|
|
@@ -6789,6 +7219,129 @@ function renderRecorderWidget(rec, paused, t) {
|
|
|
6789
7219
|
<div class="rec-badge">${paused ? t("RECORDER.BADGE_PAUSED") : t("RECORDER.BADGE_REC")}</div>`;
|
|
6790
7220
|
}
|
|
6791
7221
|
|
|
7222
|
+
// src/components/lib-e2e-recorder/assertion-builder.ts
|
|
7223
|
+
init_code_format_utils();
|
|
7224
|
+
var NO_VALUE_ASSERTIONS = /* @__PURE__ */ new Set(["be.visible", "not.exist", "be.disabled", "be.checked"]);
|
|
7225
|
+
function injectAssertionBuilder(container, t, onAddCommand) {
|
|
7226
|
+
container.insertAdjacentHTML("beforeend", `
|
|
7227
|
+
<div id="assertion-builder"
|
|
7228
|
+
style="padding:10px 12px;border-top:1px solid #21262d;background:#0d1117">
|
|
7229
|
+
<div style="font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px">
|
|
7230
|
+
${t("RECORDER.ASSERTION_SECTION")}
|
|
7231
|
+
</div>
|
|
7232
|
+
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end">
|
|
7233
|
+
<input id="assert-selector" type="text"
|
|
7234
|
+
placeholder="${t("RECORDER.ASSERT_SELECTOR_PH").replace(/"/g, """)}"
|
|
7235
|
+
style="flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
7236
|
+
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;
|
|
7237
|
+
font-family:'Cascadia Code','Fira Code',monospace"/>
|
|
7238
|
+
<select id="assert-type"
|
|
7239
|
+
style="padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;
|
|
7240
|
+
color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0">
|
|
7241
|
+
<option value="be.visible">be.visible</option>
|
|
7242
|
+
<option value="not.exist">not.exist</option>
|
|
7243
|
+
<option value="be.disabled">be.disabled</option>
|
|
7244
|
+
<option value="be.checked">be.checked</option>
|
|
7245
|
+
<option value="contain.text">contain.text</option>
|
|
7246
|
+
<option value="have.value">have.value</option>
|
|
7247
|
+
<option value="have.length">have.length</option>
|
|
7248
|
+
<option value="have.class">have.class</option>
|
|
7249
|
+
<option value="have.attr">have.attr</option>
|
|
7250
|
+
</select>
|
|
7251
|
+
<input id="assert-value" type="text" placeholder="${t("RECORDER.ASSERT_VALUE_PH")}"
|
|
7252
|
+
style="flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
7253
|
+
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none"/>
|
|
7254
|
+
<button id="btn-add-assertion"
|
|
7255
|
+
style="padding:5px 12px;border:none;border-radius:5px;cursor:pointer;
|
|
7256
|
+
font-size:11px;font-weight:500;background:#2f81f7;color:#fff;
|
|
7257
|
+
white-space:nowrap;flex-shrink:0">
|
|
7258
|
+
${t("RECORDER.ASSERT_ADD_BTN")}
|
|
7259
|
+
</button>
|
|
7260
|
+
</div>
|
|
7261
|
+
</div>`);
|
|
7262
|
+
document.getElementById("btn-add-assertion")?.addEventListener("click", () => {
|
|
7263
|
+
const sel = document.getElementById("assert-selector").value.trim();
|
|
7264
|
+
const type = document.getElementById("assert-type").value;
|
|
7265
|
+
const val = document.getElementById("assert-value").value.trim();
|
|
7266
|
+
if (!sel) return;
|
|
7267
|
+
const s = escapeSingleQuotes(sel);
|
|
7268
|
+
const v = escapeSingleQuotes(val);
|
|
7269
|
+
const cmd = NO_VALUE_ASSERTIONS.has(type) || !val ? `cy.get('${s}').should('${type}')` : `cy.get('${s}').should('${type}', '${v}')`;
|
|
7270
|
+
onAddCommand(cmd);
|
|
7271
|
+
document.getElementById("assert-selector").value = "";
|
|
7272
|
+
document.getElementById("assert-value").value = "";
|
|
7273
|
+
});
|
|
7274
|
+
}
|
|
7275
|
+
|
|
7276
|
+
// src/components/lib-e2e-recorder/filesystem-setup.ts
|
|
7277
|
+
function mountFilesystemSetupContent(container, t, onSkip, onSelect) {
|
|
7278
|
+
container.innerHTML = `
|
|
7279
|
+
<div style="padding:16px 20px 20px;color:#8b949e;font-size:13px;line-height:1.7">
|
|
7280
|
+
<p>${t("RECORDER.FS_INTRO_HTML")}</p>
|
|
7281
|
+
<p style="margin-top:10px;margin-bottom:6px;font-size:11px;color:#8b949e">
|
|
7282
|
+
${t("RECORDER.FS_STRUCTURE_HINT_HTML")}
|
|
7283
|
+
</p>
|
|
7284
|
+
<pre style="margin:0;padding:10px 14px;background:#0d1117;border:1px solid #21262d;
|
|
7285
|
+
border-radius:8px;font-size:11px;color:#c9d1d9;line-height:1.8;
|
|
7286
|
+
font-family:'Cascadia Code','Fira Code','Consolas',monospace">
|
|
7287
|
+
cypress/ <span style="color:#484f58">${t("RECORDER.FS_TREE_PICK_HINT")}</span>
|
|
7288
|
+
\u2514\u2500\u2500 e2e/ <span style="color:#484f58">${t("RECORDER.FS_TREE_READ_HINT")}</span>
|
|
7289
|
+
\u2514\u2500\u2500 *.cy.ts</pre>
|
|
7290
|
+
<p style="margin-top:8px;font-size:11px;color:#484f58">
|
|
7291
|
+
${t("RECORDER.FS_PERMISSION_NOTE")}
|
|
7292
|
+
</p>
|
|
7293
|
+
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:20px">
|
|
7294
|
+
<button id="fs-skip"
|
|
7295
|
+
style="padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;
|
|
7296
|
+
font-size:12px;font-weight:500;background:transparent;color:#8b949e">
|
|
7297
|
+
${t("RECORDER.FS_LATER_BTN")}
|
|
7298
|
+
</button>
|
|
7299
|
+
<button id="fs-select"
|
|
7300
|
+
style="padding:7px 16px;border:none;border-radius:6px;cursor:pointer;
|
|
7301
|
+
font-size:12px;font-weight:500;background:#2f81f7;color:#fff">
|
|
7302
|
+
${t("RECORDER.FS_SELECT_BTN")}
|
|
7303
|
+
</button>
|
|
7304
|
+
</div>
|
|
7305
|
+
</div>`;
|
|
7306
|
+
document.getElementById("fs-skip")?.addEventListener("click", () => {
|
|
7307
|
+
void onSkip();
|
|
7308
|
+
});
|
|
7309
|
+
document.getElementById("fs-select")?.addEventListener("click", () => {
|
|
7310
|
+
void onSelect();
|
|
7311
|
+
});
|
|
7312
|
+
}
|
|
7313
|
+
|
|
7314
|
+
// src/utils/swal-mount.utils.ts
|
|
7315
|
+
function mountComponentInSwal(tagName, container, props, events) {
|
|
7316
|
+
const el = document.createElement(tagName);
|
|
7317
|
+
Object.assign(el, props);
|
|
7318
|
+
container.appendChild(el);
|
|
7319
|
+
for (const { name, handler } of events ?? []) {
|
|
7320
|
+
el.addEventListener(name, handler);
|
|
7321
|
+
}
|
|
7322
|
+
return el;
|
|
7323
|
+
}
|
|
7324
|
+
|
|
7325
|
+
// src/utils/fixture-convert.utils.ts
|
|
7326
|
+
function toFixtureInterceptors(interceptors, fixtures) {
|
|
7327
|
+
const fixtureNames = new Set(fixtures.map((f) => f.name));
|
|
7328
|
+
return interceptors.map((icp) => {
|
|
7329
|
+
const match = icp.match(/\.as\('([^']+)'\)$/);
|
|
7330
|
+
if (!match) return icp;
|
|
7331
|
+
const fixtureFile = `${match[1]}.json`;
|
|
7332
|
+
if (!fixtureNames.has(fixtureFile)) return icp;
|
|
7333
|
+
return icp.replace(/\)\.as\(/, `, { fixture: '${fixtureFile}' }).as(`);
|
|
7334
|
+
});
|
|
7335
|
+
}
|
|
7336
|
+
function simplifyFixtureWaits(commands, fixtures) {
|
|
7337
|
+
const fixtureAliases = new Set(fixtures.map((f) => f.name.replace(/\.json$/, "")));
|
|
7338
|
+
return commands.map((cmd) => {
|
|
7339
|
+
const match = cmd.match(/^cy\.wait\('@([^']+)'\)/);
|
|
7340
|
+
if (!match || !fixtureAliases.has(match[1])) return cmd;
|
|
7341
|
+
return `cy.wait('@${match[1]}').then((interception) => { })`;
|
|
7342
|
+
});
|
|
7343
|
+
}
|
|
7344
|
+
|
|
6792
7345
|
// src/components/lib-e2e-recorder/lib-e2e-recorder.ts
|
|
6793
7346
|
var LibE2eRecorderElement = class extends HTMLElement {
|
|
6794
7347
|
shadow;
|
|
@@ -6815,6 +7368,7 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6815
7368
|
httpMonitor;
|
|
6816
7369
|
smartSelectorEnabled = true;
|
|
6817
7370
|
_needsRecordingRebuild = false;
|
|
7371
|
+
issueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };
|
|
6818
7372
|
recording;
|
|
6819
7373
|
persistence;
|
|
6820
7374
|
translation;
|
|
@@ -6887,6 +7441,10 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6887
7441
|
this.recording.destroy();
|
|
6888
7442
|
this._needsRecordingRebuild = true;
|
|
6889
7443
|
}
|
|
7444
|
+
// HttpMonitor reads extendedHttpCommands and fixtureMode synchronously inside
|
|
7445
|
+
// fetch/XHR interception handlers, so they must live in localStorage (sync).
|
|
7446
|
+
// IndexedDB is the persistent source of truth; this method mirrors it into
|
|
7447
|
+
// localStorage on every mount so the sync cache is always fresh.
|
|
6890
7448
|
async initHttpConfig() {
|
|
6891
7449
|
const config = await this.persistence.getConfig("extendedHttpCommands");
|
|
6892
7450
|
if (config === null) {
|
|
@@ -6934,9 +7492,9 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6934
7492
|
}
|
|
6935
7493
|
showSelectorPicker(target) {
|
|
6936
7494
|
Promise.resolve().then(() => (init_selector_picker(), selector_picker_exports)).then(() => {
|
|
6937
|
-
const existing = document.querySelector("selector-picker");
|
|
7495
|
+
const existing = document.querySelector("lib-e2e-selector-picker");
|
|
6938
7496
|
if (existing) existing.remove();
|
|
6939
|
-
const picker = document.createElement("selector-picker");
|
|
7497
|
+
const picker = document.createElement("lib-e2e-selector-picker");
|
|
6940
7498
|
picker.targetElement = target;
|
|
6941
7499
|
picker.recording = this.recording;
|
|
6942
7500
|
picker.translation = this.translation;
|
|
@@ -6958,6 +7516,11 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6958
7516
|
const strategy = config?.["selectorStrategy"];
|
|
6959
7517
|
if (strategy) this.recording.selectorStrategy = strategy;
|
|
6960
7518
|
this.smartSelectorEnabled = config?.["smartSelectorEnabled"] !== "false";
|
|
7519
|
+
this.issueTrackerConfig = {
|
|
7520
|
+
enabled: config?.["issueTrackerEnabled"] === "true",
|
|
7521
|
+
provider: config?.["issueTrackerProvider"] ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,
|
|
7522
|
+
baseUrl: config?.["issueTrackerBaseUrl"] ?? ""
|
|
7523
|
+
};
|
|
6961
7524
|
}
|
|
6962
7525
|
// ── cross-app session continuity (spec 006) ───────────────────────────────
|
|
6963
7526
|
/**
|
|
@@ -6993,7 +7556,7 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
6993
7556
|
}
|
|
6994
7557
|
async promptResumeOrDiscard(session) {
|
|
6995
7558
|
const t = this.translation.translate.bind(this.translation);
|
|
6996
|
-
const result = await
|
|
7559
|
+
const result = await import_sweetalert22.default.fire({
|
|
6997
7560
|
title: t("RECORDER.SESSION_RESUME_TITLE"),
|
|
6998
7561
|
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>`,
|
|
6999
7562
|
showCancelButton: true,
|
|
@@ -7212,8 +7775,9 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
7212
7775
|
this.showFilesystemSetupDialog();
|
|
7213
7776
|
}
|
|
7214
7777
|
showFilesystemSetupDialog() {
|
|
7215
|
-
|
|
7216
|
-
|
|
7778
|
+
const t = this.translation.translate.bind(this.translation);
|
|
7779
|
+
import_sweetalert22.default.fire({
|
|
7780
|
+
title: t("RECORDER.FS_TITLE"),
|
|
7217
7781
|
html: '<div id="fs-setup-content"></div>',
|
|
7218
7782
|
showCloseButton: true,
|
|
7219
7783
|
showConfirmButton: false,
|
|
@@ -7222,276 +7786,171 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
7222
7786
|
setSwal2DataCyAttribute();
|
|
7223
7787
|
const container = document.getElementById("fs-setup-content");
|
|
7224
7788
|
if (!container) return;
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7231
|
-
|
|
7232
|
-
|
|
7233
|
-
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
|
|
7240
|
-
|
|
7241
|
-
<button id="fs-skip"
|
|
7242
|
-
style="padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;
|
|
7243
|
-
font-size:12px;font-weight:500;background:transparent;color:#8b949e">
|
|
7244
|
-
${this.translation.translate("RECORDER.FS_LATER_BTN")}
|
|
7245
|
-
</button>
|
|
7246
|
-
<button id="fs-select"
|
|
7247
|
-
style="padding:7px 16px;border:none;border-radius:6px;cursor:pointer;
|
|
7248
|
-
font-size:12px;font-weight:500;background:#2f81f7;color:#fff">
|
|
7249
|
-
${this.translation.translate("RECORDER.FS_SELECT_BTN")}
|
|
7250
|
-
</button>
|
|
7251
|
-
</div>
|
|
7252
|
-
</div>`;
|
|
7253
|
-
document.getElementById("fs-skip")?.addEventListener("click", async () => {
|
|
7254
|
-
await this.persistence.setConfigKey("allowReadWriteFiles", "false");
|
|
7255
|
-
import_sweetalert2.default.close();
|
|
7256
|
-
});
|
|
7257
|
-
document.getElementById("fs-select")?.addEventListener("click", async () => {
|
|
7258
|
-
try {
|
|
7259
|
-
await this.persistence.requestDirectoryPermissions();
|
|
7260
|
-
import_sweetalert2.default.close();
|
|
7261
|
-
showToast(this.translation.translate("RECORDER.FS_SUCCESS_TOAST"));
|
|
7262
|
-
} catch (e) {
|
|
7263
|
-
if (e?.name !== "AbortError") {
|
|
7264
|
-
showToast(this.translation.translate("RECORDER.FS_ERROR_TOAST"), false);
|
|
7789
|
+
mountFilesystemSetupContent(
|
|
7790
|
+
container,
|
|
7791
|
+
t,
|
|
7792
|
+
async () => {
|
|
7793
|
+
await this.persistence.setConfigKey("allowReadWriteFiles", "false");
|
|
7794
|
+
import_sweetalert22.default.close();
|
|
7795
|
+
},
|
|
7796
|
+
async () => {
|
|
7797
|
+
try {
|
|
7798
|
+
await this.persistence.requestDirectoryPermissions();
|
|
7799
|
+
import_sweetalert22.default.close();
|
|
7800
|
+
showToast(t("RECORDER.FS_SUCCESS_TOAST"));
|
|
7801
|
+
} catch (e) {
|
|
7802
|
+
if (e?.name !== "AbortError") {
|
|
7803
|
+
showToast(t("RECORDER.FS_ERROR_TOAST"), false);
|
|
7804
|
+
}
|
|
7265
7805
|
}
|
|
7266
7806
|
}
|
|
7267
|
-
|
|
7807
|
+
);
|
|
7268
7808
|
}
|
|
7269
7809
|
});
|
|
7270
7810
|
}
|
|
7271
7811
|
// ── dialogs ──────────────────────────────────────────────────────────────
|
|
7272
7812
|
showCommandsDialog() {
|
|
7273
|
-
this.
|
|
7274
|
-
|
|
7813
|
+
this.openSwalDialog(
|
|
7814
|
+
"isCommandsDialogOpen",
|
|
7815
|
+
"commands-modal-content",
|
|
7816
|
+
{
|
|
7275
7817
|
title: this.translation.translate("MAIN_FRAME.DIALOG_COMMANDS"),
|
|
7276
7818
|
html: '<div id="commands-modal-content" style="min-height:250px;padding:0"></div>',
|
|
7277
7819
|
showCloseButton: true,
|
|
7278
|
-
showConfirmButton: false,
|
|
7279
7820
|
allowOutsideClick: false,
|
|
7280
7821
|
backdrop: false,
|
|
7281
|
-
width: 640
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7822
|
+
width: 640
|
|
7823
|
+
},
|
|
7824
|
+
(container) => {
|
|
7825
|
+
const child = mountComponentInSwal("lib-e2e-test-previsualizer", container, {
|
|
7826
|
+
translation: this.translation,
|
|
7827
|
+
commands: this.cypressCommands,
|
|
7828
|
+
interceptors: this.interceptors,
|
|
7829
|
+
editable: true
|
|
7830
|
+
}, [
|
|
7831
|
+
{ name: "deletecommand", handler: (e) => this.recording.removeCommand(e.detail) },
|
|
7832
|
+
{ name: "movecommand", handler: (e) => this.recording.moveCommand(e.detail.from, e.detail.to) },
|
|
7833
|
+
{ name: "deleteinterceptor", handler: (e) => this.recording.removeInterceptor(e.detail) }
|
|
7834
|
+
]);
|
|
7835
|
+
this._previsualizerRef = child;
|
|
7836
|
+
injectAssertionBuilder(container, this.translation.translate.bind(this.translation), (cmd) => this.recording.appendCommand(cmd));
|
|
7837
|
+
},
|
|
7838
|
+
{
|
|
7839
|
+
// Make the container click-through so the page underneath remains interactive
|
|
7840
|
+
onDidOpenPreamble: () => {
|
|
7286
7841
|
const swalContainer = document.querySelector(".swal2-container");
|
|
7287
7842
|
if (swalContainer) {
|
|
7288
7843
|
swalContainer.style.pointerEvents = "none";
|
|
7289
7844
|
const popup = swalContainer.querySelector(".swal2-popup");
|
|
7290
7845
|
if (popup) popup.style.pointerEvents = "all";
|
|
7291
7846
|
}
|
|
7292
|
-
const container = document.getElementById("commands-modal-content");
|
|
7293
|
-
if (!container) return;
|
|
7294
|
-
const child = document.createElement("test-previsualizer");
|
|
7295
|
-
child.translation = this.translation;
|
|
7296
|
-
child.commands = this.cypressCommands;
|
|
7297
|
-
child.interceptors = this.interceptors;
|
|
7298
|
-
child.editable = true;
|
|
7299
|
-
container.appendChild(child);
|
|
7300
|
-
this._previsualizerRef = child;
|
|
7301
|
-
child.addEventListener("deletecommand", (e) => {
|
|
7302
|
-
this.recording.removeCommand(e.detail);
|
|
7303
|
-
});
|
|
7304
|
-
child.addEventListener("movecommand", (e) => {
|
|
7305
|
-
this.recording.moveCommand(e.detail.from, e.detail.to);
|
|
7306
|
-
});
|
|
7307
|
-
child.addEventListener("deleteinterceptor", (e) => {
|
|
7308
|
-
this.recording.removeInterceptor(e.detail);
|
|
7309
|
-
});
|
|
7310
|
-
const assertionHtml = `
|
|
7311
|
-
<div id="assertion-builder"
|
|
7312
|
-
style="padding:10px 12px;border-top:1px solid #21262d;background:#0d1117">
|
|
7313
|
-
<div style="font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px">
|
|
7314
|
-
${this.translation.translate("RECORDER.ASSERTION_SECTION")}
|
|
7315
|
-
</div>
|
|
7316
|
-
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end">
|
|
7317
|
-
<input id="assert-selector" type="text"
|
|
7318
|
-
placeholder="${this.translation.translate("RECORDER.ASSERT_SELECTOR_PH").replace(/"/g, """)}"
|
|
7319
|
-
style="flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
7320
|
-
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;
|
|
7321
|
-
font-family:'Cascadia Code','Fira Code',monospace"/>
|
|
7322
|
-
<select id="assert-type"
|
|
7323
|
-
style="padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;
|
|
7324
|
-
color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0">
|
|
7325
|
-
<option value="be.visible">be.visible</option>
|
|
7326
|
-
<option value="not.exist">not.exist</option>
|
|
7327
|
-
<option value="be.disabled">be.disabled</option>
|
|
7328
|
-
<option value="be.checked">be.checked</option>
|
|
7329
|
-
<option value="contain.text">contain.text</option>
|
|
7330
|
-
<option value="have.value">have.value</option>
|
|
7331
|
-
<option value="have.length">have.length</option>
|
|
7332
|
-
<option value="have.class">have.class</option>
|
|
7333
|
-
<option value="have.attr">have.attr</option>
|
|
7334
|
-
</select>
|
|
7335
|
-
<input id="assert-value" type="text" placeholder="${this.translation.translate("RECORDER.ASSERT_VALUE_PH")}"
|
|
7336
|
-
style="flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;
|
|
7337
|
-
border-radius:5px;color:#c9d1d9;font-size:11px;outline:none"/>
|
|
7338
|
-
<button id="btn-add-assertion"
|
|
7339
|
-
style="padding:5px 12px;border:none;border-radius:5px;cursor:pointer;
|
|
7340
|
-
font-size:11px;font-weight:500;background:#2f81f7;color:#fff;
|
|
7341
|
-
white-space:nowrap;flex-shrink:0">
|
|
7342
|
-
${this.translation.translate("RECORDER.ASSERT_ADD_BTN")}
|
|
7343
|
-
</button>
|
|
7344
|
-
</div>
|
|
7345
|
-
</div>`;
|
|
7346
|
-
container.insertAdjacentHTML("beforeend", assertionHtml);
|
|
7347
|
-
const NO_VALUE_ASSERTIONS = /* @__PURE__ */ new Set(["be.visible", "not.exist", "be.disabled", "be.checked"]);
|
|
7348
|
-
document.getElementById("btn-add-assertion")?.addEventListener("click", () => {
|
|
7349
|
-
const sel = document.getElementById("assert-selector").value.trim();
|
|
7350
|
-
const type = document.getElementById("assert-type").value;
|
|
7351
|
-
const val = document.getElementById("assert-value").value.trim();
|
|
7352
|
-
if (!sel) return;
|
|
7353
|
-
const s = escapeSingleQuotes(sel);
|
|
7354
|
-
const v = escapeSingleQuotes(val);
|
|
7355
|
-
const cmd = NO_VALUE_ASSERTIONS.has(type) || !val ? `cy.get('${s}').should('${type}')` : `cy.get('${s}').should('${type}', '${v}')`;
|
|
7356
|
-
this.recording.appendCommand(cmd);
|
|
7357
|
-
document.getElementById("assert-selector").value = "";
|
|
7358
|
-
document.getElementById("assert-value").value = "";
|
|
7359
|
-
});
|
|
7360
7847
|
},
|
|
7361
|
-
|
|
7362
|
-
this.isCommandsDialogOpen = false;
|
|
7848
|
+
onWillClose: () => {
|
|
7363
7849
|
this._previsualizerRef = null;
|
|
7364
7850
|
}
|
|
7365
|
-
}
|
|
7366
|
-
|
|
7367
|
-
});
|
|
7851
|
+
}
|
|
7852
|
+
);
|
|
7368
7853
|
}
|
|
7369
7854
|
showSavedTestsDialog() {
|
|
7370
|
-
this.
|
|
7371
|
-
|
|
7855
|
+
this.openSwalDialog(
|
|
7856
|
+
"isSavedTestsDialogOpen",
|
|
7857
|
+
"saved-tests-modal-content",
|
|
7858
|
+
{
|
|
7372
7859
|
title: this.translation.translate("MAIN_FRAME.DIALOG_SAVED_TESTS"),
|
|
7373
7860
|
html: '<div id="saved-tests-modal-content" style="min-height:250px;padding:0"></div>',
|
|
7374
7861
|
showCloseButton: true,
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7385
|
-
child.translation = this.translation;
|
|
7386
|
-
container.appendChild(child);
|
|
7387
|
-
},
|
|
7388
|
-
willClose: () => {
|
|
7389
|
-
this.isSavedTestsDialogOpen = false;
|
|
7390
|
-
}
|
|
7391
|
-
});
|
|
7392
|
-
this.resizePopup();
|
|
7393
|
-
});
|
|
7862
|
+
width: 680
|
|
7863
|
+
},
|
|
7864
|
+
(container) => {
|
|
7865
|
+
mountComponentInSwal("lib-e2e-test-editor", container, {
|
|
7866
|
+
persistence: this.persistence,
|
|
7867
|
+
translation: this.translation,
|
|
7868
|
+
issueTrackerConfig: this.issueTrackerConfig
|
|
7869
|
+
});
|
|
7870
|
+
}
|
|
7871
|
+
);
|
|
7394
7872
|
}
|
|
7395
7873
|
showSaveTestDialog() {
|
|
7396
|
-
this.
|
|
7397
|
-
|
|
7874
|
+
this.openSwalDialog(
|
|
7875
|
+
"isSaveTestDialogOpen",
|
|
7876
|
+
"save-test-modal-content",
|
|
7877
|
+
{
|
|
7398
7878
|
title: this.translation.translate("MAIN_FRAME.DIALOG_SAVE"),
|
|
7399
7879
|
html: '<div id="save-test-modal-content" style="padding:0"></div>',
|
|
7400
|
-
showCloseButton:
|
|
7401
|
-
showConfirmButton: false,
|
|
7880
|
+
showCloseButton: false,
|
|
7402
7881
|
allowOutsideClick: false,
|
|
7403
|
-
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
this.persistence.getGeneralConfig().then((config) => {
|
|
7412
|
-
const providerId = config?.["issueTrackerProviderId"];
|
|
7413
|
-
if (providerId) child.issueTrackerProviderId = providerId;
|
|
7414
|
-
});
|
|
7415
|
-
container.appendChild(child);
|
|
7416
|
-
child.addEventListener("savetest", (e) => {
|
|
7882
|
+
allowEscapeKey: false
|
|
7883
|
+
},
|
|
7884
|
+
(container) => {
|
|
7885
|
+
mountComponentInSwal("lib-e2e-save-test", container, {
|
|
7886
|
+
translation: this.translation,
|
|
7887
|
+
issueTrackerConfig: this.issueTrackerConfig
|
|
7888
|
+
}, [
|
|
7889
|
+
{ name: "savetest", handler: (e) => {
|
|
7417
7890
|
const { description, notes, tags, ticketId } = e.detail ?? {};
|
|
7418
|
-
this.onSaveTest(description ?? null, tags ?? [], notes ?? "", ticketId ??
|
|
7419
|
-
|
|
7420
|
-
}
|
|
7421
|
-
|
|
7891
|
+
this.onSaveTest(description ?? null, tags ?? [], notes ?? "", ticketId ?? "");
|
|
7892
|
+
import_sweetalert22.default.close();
|
|
7893
|
+
} },
|
|
7894
|
+
{ name: "saveandexport", handler: (e) => {
|
|
7422
7895
|
const { description, notes, tags, ticketId } = e.detail ?? {};
|
|
7423
|
-
this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? "", ticketId ??
|
|
7424
|
-
|
|
7425
|
-
}
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
});
|
|
7431
|
-
});
|
|
7896
|
+
this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? "", ticketId ?? "");
|
|
7897
|
+
import_sweetalert22.default.close();
|
|
7898
|
+
} }
|
|
7899
|
+
]);
|
|
7900
|
+
},
|
|
7901
|
+
{ skipResize: true }
|
|
7902
|
+
);
|
|
7432
7903
|
}
|
|
7433
7904
|
showSettingsDialog() {
|
|
7434
|
-
this.
|
|
7435
|
-
|
|
7905
|
+
this.openSwalDialog(
|
|
7906
|
+
"isSettingsDialogOpen",
|
|
7907
|
+
"settings-modal-content",
|
|
7908
|
+
{
|
|
7436
7909
|
title: this.translation.translate("MAIN_FRAME.SETTINGS"),
|
|
7437
7910
|
html: '<div id="settings-modal-content" style="padding:0"></div>',
|
|
7438
7911
|
showCloseButton: true,
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
const child = document.createElement("e2e-configuration");
|
|
7448
|
-
child.persistence = this.persistence;
|
|
7449
|
-
child.translation = this.translation;
|
|
7450
|
-
container.appendChild(child);
|
|
7451
|
-
child.addEventListener("smartselectorchange", (e) => {
|
|
7912
|
+
width: 520
|
|
7913
|
+
},
|
|
7914
|
+
(container) => {
|
|
7915
|
+
mountComponentInSwal("lib-e2e-configuration", container, {
|
|
7916
|
+
persistence: this.persistence,
|
|
7917
|
+
translation: this.translation
|
|
7918
|
+
}, [
|
|
7919
|
+
{ name: "smartselectorchange", handler: (e) => {
|
|
7452
7920
|
this.smartSelectorEnabled = e.detail;
|
|
7453
|
-
}
|
|
7454
|
-
|
|
7921
|
+
} },
|
|
7922
|
+
{ name: "starthiddenchange", handler: (e) => {
|
|
7455
7923
|
this.isVisible = !e.detail;
|
|
7456
7924
|
this.style.display = this.isVisible ? "" : "none";
|
|
7457
|
-
}
|
|
7458
|
-
|
|
7459
|
-
|
|
7460
|
-
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
}
|
|
7464
|
-
|
|
7465
|
-
});
|
|
7925
|
+
} },
|
|
7926
|
+
{ name: "resetwidgetposition", handler: () => this.resetWidgetPosition() },
|
|
7927
|
+
{ name: "issuetrackerchange", handler: (e) => {
|
|
7928
|
+
this.issueTrackerConfig = e.detail;
|
|
7929
|
+
} }
|
|
7930
|
+
]);
|
|
7931
|
+
}
|
|
7932
|
+
);
|
|
7466
7933
|
}
|
|
7467
7934
|
showHelpDialog() {
|
|
7468
|
-
this.
|
|
7469
|
-
|
|
7935
|
+
this.openSwalDialog(
|
|
7936
|
+
"isHelpDialogOpen",
|
|
7937
|
+
"help-modal-content",
|
|
7938
|
+
{
|
|
7470
7939
|
title: this.translation.translate("HELP.TITLE"),
|
|
7471
7940
|
html: '<div id="help-modal-content" style="padding:0"></div>',
|
|
7472
7941
|
showCloseButton: true,
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
const child = document.createElement("help-panel");
|
|
7482
|
-
child.translation = this.translation;
|
|
7483
|
-
container.appendChild(child);
|
|
7484
|
-
},
|
|
7485
|
-
willClose: () => {
|
|
7486
|
-
this.isHelpDialogOpen = false;
|
|
7487
|
-
}
|
|
7488
|
-
});
|
|
7489
|
-
this.resizePopup();
|
|
7490
|
-
});
|
|
7942
|
+
width: 560
|
|
7943
|
+
},
|
|
7944
|
+
(container) => {
|
|
7945
|
+
mountComponentInSwal("lib-e2e-help-panel", container, {
|
|
7946
|
+
translation: this.translation
|
|
7947
|
+
});
|
|
7948
|
+
}
|
|
7949
|
+
);
|
|
7491
7950
|
}
|
|
7492
7951
|
showAdvancedEditorDialog(testId) {
|
|
7493
7952
|
this.toggleModal("isAdvancedEditorDialogOpen", () => {
|
|
7494
|
-
|
|
7953
|
+
import_sweetalert22.default.fire({
|
|
7495
7954
|
title: this.translation.translate("MAIN_FRAME.SHOW_ADVANCED_EDITOR"),
|
|
7496
7955
|
html: '<div id="advanced-editor-modal-content" style="flex:1;min-height:0;display:flex;flex-direction:column;padding:0"></div>',
|
|
7497
7956
|
showCloseButton: true,
|
|
@@ -7502,42 +7961,33 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7502
7961
|
didOpen: () => {
|
|
7503
7962
|
makeSwalDraggable();
|
|
7504
7963
|
setSwal2DataCyAttribute();
|
|
7505
|
-
|
|
7506
|
-
if (popup) {
|
|
7507
|
-
popup.style.height = "600px";
|
|
7508
|
-
const htmlContainer = popup.querySelector(".swal2-html-container");
|
|
7509
|
-
if (htmlContainer) {
|
|
7510
|
-
htmlContainer.style.flex = "1";
|
|
7511
|
-
htmlContainer.style.minHeight = "0";
|
|
7512
|
-
htmlContainer.style.overflow = "hidden";
|
|
7513
|
-
htmlContainer.style.padding = "0";
|
|
7514
|
-
htmlContainer.style.margin = "0";
|
|
7515
|
-
htmlContainer.style.display = "flex";
|
|
7516
|
-
htmlContainer.style.flexDirection = "column";
|
|
7517
|
-
}
|
|
7518
|
-
}
|
|
7964
|
+
ensurePopupDimensions(import_sweetalert22.default.getPopup(), 600);
|
|
7519
7965
|
const container = document.getElementById("advanced-editor-modal-content");
|
|
7520
7966
|
if (!container) return;
|
|
7521
|
-
const child =
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7967
|
+
const child = mountComponentInSwal("lib-e2e-advanced-test-editor", container, {
|
|
7968
|
+
persistence: this.persistence,
|
|
7969
|
+
translation: this.translation,
|
|
7970
|
+
...testId !== void 0 ? { testId } : {}
|
|
7971
|
+
}, [
|
|
7972
|
+
{ name: "selectorstrategychange", handler: (e) => {
|
|
7973
|
+
this.recording.selectorStrategy = e.detail;
|
|
7974
|
+
} },
|
|
7975
|
+
{ name: "closemodal", handler: () => import_sweetalert22.default.close() },
|
|
7976
|
+
{ name: "openfileeditor", handler: (e) => {
|
|
7977
|
+
import_sweetalert22.default.close();
|
|
7978
|
+
setTimeout(() => this.showFileEditorDialog(
|
|
7979
|
+
e.detail.handle,
|
|
7980
|
+
e.detail.content,
|
|
7981
|
+
e.detail.fileName,
|
|
7982
|
+
e.detail.testId,
|
|
7983
|
+
e.detail.itBlock,
|
|
7984
|
+
e.detail.interceptorsBlock,
|
|
7985
|
+
e.detail.notes
|
|
7986
|
+
), 150);
|
|
7987
|
+
} }
|
|
7988
|
+
]);
|
|
7989
|
+
void this.persistence.getLoginSetup().then((cfg) => {
|
|
7990
|
+
child.loginSetupConfig = cfg;
|
|
7541
7991
|
});
|
|
7542
7992
|
},
|
|
7543
7993
|
willClose: () => {
|
|
@@ -7545,13 +7995,13 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7545
7995
|
}
|
|
7546
7996
|
});
|
|
7547
7997
|
setTimeout(() => {
|
|
7548
|
-
const popup =
|
|
7998
|
+
const popup = import_sweetalert22.default.getPopup();
|
|
7549
7999
|
if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 0 });
|
|
7550
8000
|
}, 0);
|
|
7551
8001
|
});
|
|
7552
8002
|
}
|
|
7553
8003
|
showFileEditorDialog(handle, content, fileName, testId, itBlock = "", interceptorsBlock = "", notes = "") {
|
|
7554
|
-
|
|
8004
|
+
import_sweetalert22.default.fire({
|
|
7555
8005
|
title: this.translation.translate("RECORDER.FILE_EDITOR_TITLE"),
|
|
7556
8006
|
html: '<div id="file-editor-modal-content" style="flex:1;min-height:0;display:flex;flex-direction:column;padding:0"></div>',
|
|
7557
8007
|
showCloseButton: false,
|
|
@@ -7562,89 +8012,106 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7562
8012
|
didOpen: () => {
|
|
7563
8013
|
makeSwalDraggable();
|
|
7564
8014
|
setSwal2DataCyAttribute();
|
|
7565
|
-
|
|
7566
|
-
if (popup) {
|
|
7567
|
-
popup.style.height = "640px";
|
|
7568
|
-
const htmlContainer = popup.querySelector(".swal2-html-container");
|
|
7569
|
-
if (htmlContainer) {
|
|
7570
|
-
htmlContainer.style.flex = "1";
|
|
7571
|
-
htmlContainer.style.minHeight = "0";
|
|
7572
|
-
htmlContainer.style.overflow = "hidden";
|
|
7573
|
-
htmlContainer.style.padding = "0";
|
|
7574
|
-
htmlContainer.style.margin = "0";
|
|
7575
|
-
htmlContainer.style.display = "flex";
|
|
7576
|
-
htmlContainer.style.flexDirection = "column";
|
|
7577
|
-
}
|
|
7578
|
-
}
|
|
8015
|
+
ensurePopupDimensions(import_sweetalert22.default.getPopup(), 640);
|
|
7579
8016
|
const container = document.getElementById("file-editor-modal-content");
|
|
7580
8017
|
if (!container) return;
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
8018
|
+
mountComponentInSwal("lib-e2e-file-preview", container, {
|
|
8019
|
+
translation: this.translation,
|
|
8020
|
+
fileContent: content,
|
|
8021
|
+
fileName,
|
|
8022
|
+
closeLabel: this.translation.translate("FILE_PREVIEW.BACK_TO_EDITOR"),
|
|
8023
|
+
itBlock,
|
|
8024
|
+
interceptorsBlock,
|
|
8025
|
+
notes
|
|
8026
|
+
}, [
|
|
8027
|
+
{ name: "close", handler: () => {
|
|
8028
|
+
import_sweetalert22.default.close();
|
|
8029
|
+
setTimeout(() => this.showAdvancedEditorDialog(testId), 150);
|
|
8030
|
+
} },
|
|
8031
|
+
{ name: "save", handler: async (e) => {
|
|
8032
|
+
try {
|
|
8033
|
+
const writable = await handle.createWritable();
|
|
8034
|
+
await writable.write(e.detail);
|
|
8035
|
+
await writable.close();
|
|
8036
|
+
showToast(this.translation.translate("RECORDER.FILE_SAVED_TOAST"));
|
|
8037
|
+
} catch {
|
|
8038
|
+
showToast(this.translation.translate("RECORDER.FILE_SAVE_ERROR_TOAST"), false);
|
|
8039
|
+
}
|
|
8040
|
+
import_sweetalert22.default.close();
|
|
8041
|
+
setTimeout(() => this.showAdvancedEditorDialog(testId), 150);
|
|
8042
|
+
} }
|
|
8043
|
+
]);
|
|
7606
8044
|
}
|
|
7607
8045
|
});
|
|
7608
8046
|
this.resizePopup();
|
|
7609
8047
|
}
|
|
7610
8048
|
// ── save handlers ─────────────────────────────────────────────────────────
|
|
7611
|
-
async onSaveTest(description, tags = [], notes = "", ticketId =
|
|
7612
|
-
if (description)
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
8049
|
+
async onSaveTest(description, tags = [], notes = "", ticketId = "") {
|
|
8050
|
+
if (!description) return;
|
|
8051
|
+
await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes, ticketId || void 0);
|
|
8052
|
+
const uploadedFiles = this.recording.getUploadedFilesSnapshot();
|
|
8053
|
+
if (uploadedFiles.length > 0) {
|
|
8054
|
+
const filenames = uploadedFiles.map((f) => f.filename).join(", ");
|
|
8055
|
+
showToast(
|
|
8056
|
+
this.translation.translate("RECORDER.FILE_UPLOAD_MANUAL_TOAST").replace("{files}", filenames),
|
|
8057
|
+
false
|
|
8058
|
+
);
|
|
7620
8059
|
}
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
8060
|
+
this.recording.clearCommands();
|
|
8061
|
+
this.clearRecordingHistory();
|
|
8062
|
+
this.cypressCommands = [];
|
|
8063
|
+
this.interceptors = [];
|
|
8064
|
+
}
|
|
8065
|
+
async onSaveAndExportTest(description, tags = [], notes = "", ticketId = "") {
|
|
8066
|
+
if (!description) return;
|
|
8067
|
+
const fixtures = this.recording.getFixturesSnapshot();
|
|
8068
|
+
const isFixtureMode = this.httpMonitor?.isFixtureModeEnabled() ?? false;
|
|
8069
|
+
let finalInterceptors = this.interceptors;
|
|
8070
|
+
let finalCommands = this.cypressCommands;
|
|
8071
|
+
if (isFixtureMode && fixtures.length > 0) {
|
|
8072
|
+
try {
|
|
8073
|
+
const n = await this.persistence.writeFixtures(fixtures);
|
|
8074
|
+
finalInterceptors = toFixtureInterceptors(this.interceptors, fixtures);
|
|
8075
|
+
finalCommands = simplifyFixtureWaits(this.cypressCommands, fixtures);
|
|
8076
|
+
showToast(`${this.translation.translate("RECORDER.FIXTURES_WRITTEN_TOAST")} (${n})`);
|
|
8077
|
+
} catch {
|
|
8078
|
+
showToast(this.translation.translate("RECORDER.FIXTURES_NO_FOLDER_TOAST"), false);
|
|
8079
|
+
}
|
|
7632
8080
|
}
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
8081
|
+
const uploadedFiles = this.recording.getUploadedFilesSnapshot();
|
|
8082
|
+
if (uploadedFiles.length > 0) {
|
|
8083
|
+
const filenames = uploadedFiles.map((f) => f.filename).join(", ");
|
|
8084
|
+
const hasAccess = await this.persistence.hasDirectoryAccess();
|
|
8085
|
+
if (hasAccess) {
|
|
8086
|
+
try {
|
|
8087
|
+
for (const uf of uploadedFiles) {
|
|
8088
|
+
await this.persistence.writeUploadedFile(uf.filename, uf.bytes);
|
|
8089
|
+
}
|
|
8090
|
+
showToast(this.translation.translate("RECORDER.FILE_UPLOAD_COPIED_TOAST").replace("{files}", filenames));
|
|
8091
|
+
} catch {
|
|
8092
|
+
showToast(
|
|
8093
|
+
this.translation.translate("RECORDER.FILE_UPLOAD_COPY_ERROR_TOAST").replace("{files}", filenames),
|
|
8094
|
+
false
|
|
8095
|
+
);
|
|
8096
|
+
}
|
|
8097
|
+
} else {
|
|
8098
|
+
showToast(
|
|
8099
|
+
this.translation.translate("RECORDER.FILE_UPLOAD_MANUAL_TOAST").replace("{files}", filenames),
|
|
8100
|
+
false
|
|
8101
|
+
);
|
|
8102
|
+
}
|
|
7642
8103
|
}
|
|
8104
|
+
const id = await this.persistence.insertTest(description, finalCommands, finalInterceptors, tags, notes, ticketId || void 0);
|
|
8105
|
+
this.recording.clearCommands();
|
|
8106
|
+
this.clearRecordingHistory();
|
|
8107
|
+
this.cypressCommands = [];
|
|
8108
|
+
this.interceptors = [];
|
|
8109
|
+
setTimeout(() => this.showAdvancedEditorDialog(id), 300);
|
|
7643
8110
|
}
|
|
7644
8111
|
// ── helpers ───────────────────────────────────────────────────────────────
|
|
7645
8112
|
toggleModal(flag, openFn) {
|
|
7646
8113
|
if (this[flag]) {
|
|
7647
|
-
|
|
8114
|
+
import_sweetalert22.default.close();
|
|
7648
8115
|
this[flag] = false;
|
|
7649
8116
|
return;
|
|
7650
8117
|
}
|
|
@@ -7653,10 +8120,32 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
7653
8120
|
}
|
|
7654
8121
|
resizePopup() {
|
|
7655
8122
|
setTimeout(() => {
|
|
7656
|
-
const popup =
|
|
8123
|
+
const popup = import_sweetalert22.default.getPopup();
|
|
7657
8124
|
if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 200 });
|
|
7658
8125
|
}, 0);
|
|
7659
8126
|
}
|
|
8127
|
+
openSwalDialog(flag, contentId, swalOptions, onMount, extra) {
|
|
8128
|
+
this.toggleModal(flag, () => {
|
|
8129
|
+
import_sweetalert22.default.fire({
|
|
8130
|
+
showConfirmButton: false,
|
|
8131
|
+
color: "#e6edf3",
|
|
8132
|
+
...swalOptions,
|
|
8133
|
+
didOpen: () => {
|
|
8134
|
+
makeSwalDraggable();
|
|
8135
|
+
setSwal2DataCyAttribute();
|
|
8136
|
+
extra?.onDidOpenPreamble?.();
|
|
8137
|
+
const container = document.getElementById(contentId);
|
|
8138
|
+
if (!container) return;
|
|
8139
|
+
onMount(container);
|
|
8140
|
+
},
|
|
8141
|
+
willClose: () => {
|
|
8142
|
+
this[flag] = false;
|
|
8143
|
+
extra?.onWillClose?.();
|
|
8144
|
+
}
|
|
8145
|
+
});
|
|
8146
|
+
if (!extra?.skipResize) this.resizePopup();
|
|
8147
|
+
});
|
|
8148
|
+
}
|
|
7660
8149
|
render() {
|
|
7661
8150
|
const rec = this.isRecording;
|
|
7662
8151
|
const paused = this.isPaused;
|
|
@@ -7685,26 +8174,21 @@ if (!customElements.get("lib-e2e-recorder")) {
|
|
|
7685
8174
|
}
|
|
7686
8175
|
|
|
7687
8176
|
// src/index.ts
|
|
7688
|
-
var VERSION = "0.
|
|
8177
|
+
var VERSION = "0.10.0";
|
|
7689
8178
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7690
8179
|
0 && (module.exports = {
|
|
7691
8180
|
ACTIVE_SESSION_BREADCRUMB_KEY,
|
|
7692
8181
|
AdvancedTestEditorElement,
|
|
7693
8182
|
AdvancedTestTransformationService,
|
|
7694
|
-
CHAIN_METHODS,
|
|
7695
|
-
CYPRESS_COMPLETIONS,
|
|
7696
|
-
CY_METHODS,
|
|
7697
8183
|
ConfigurationElement,
|
|
7698
8184
|
DB_SCHEMA,
|
|
7699
8185
|
DB_STORE_NAMES,
|
|
7700
|
-
DEFAULT_ISSUE_TRACKER_PROVIDER_ID,
|
|
7701
8186
|
DEFAULT_RESUME_TTL_MINUTES,
|
|
7702
8187
|
DRAG_THRESHOLD,
|
|
7703
8188
|
FilePreviewElement,
|
|
7704
8189
|
HelpPanelElement,
|
|
7705
8190
|
HttpMonitor,
|
|
7706
8191
|
INPUT_TYPES,
|
|
7707
|
-
ISSUE_TRACKER_PROVIDERS,
|
|
7708
8192
|
LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,
|
|
7709
8193
|
LOCALE_BY_LANG,
|
|
7710
8194
|
LibE2eRecorderElement,
|
|
@@ -7715,25 +8199,19 @@ var VERSION = "0.8.0";
|
|
|
7715
8199
|
SUPPORTED_LANGS,
|
|
7716
8200
|
SaveTestElement,
|
|
7717
8201
|
SelectorPickerElement,
|
|
7718
|
-
Subject,
|
|
7719
8202
|
TOGGLE_MARGIN,
|
|
7720
|
-
TOP_LEVEL,
|
|
7721
8203
|
TestEditorElement,
|
|
7722
8204
|
TestPrevisualizerElement,
|
|
7723
8205
|
TransformationService,
|
|
7724
8206
|
TranslationService,
|
|
7725
8207
|
VERSION,
|
|
8208
|
+
_resetHttpMonitorState,
|
|
7726
8209
|
advancedTestTransformationService,
|
|
7727
8210
|
boxOffsetForDirection,
|
|
7728
8211
|
boxTopLeftFor,
|
|
7729
|
-
buildTicketComment,
|
|
7730
|
-
buildTicketUrl,
|
|
7731
8212
|
clampTogglePosition,
|
|
7732
|
-
createCodeEditor,
|
|
7733
8213
|
defaultTogglePosition,
|
|
7734
|
-
|
|
7735
|
-
filterCypressCompletions,
|
|
7736
|
-
findIssueTrackerProvider,
|
|
8214
|
+
ensurePopupDimensions,
|
|
7737
8215
|
generateAlias,
|
|
7738
8216
|
inferAssertionCommand,
|
|
7739
8217
|
injectStyles,
|
|
@@ -7743,9 +8221,7 @@ var VERSION = "0.8.0";
|
|
|
7743
8221
|
makeModalResizable,
|
|
7744
8222
|
makeSwalDraggable,
|
|
7745
8223
|
makeSwalDraggableByContentId,
|
|
7746
|
-
persistenceService,
|
|
7747
8224
|
resolveExpandDirection,
|
|
7748
|
-
resolveTicketUrl,
|
|
7749
8225
|
selectTestsForExport,
|
|
7750
8226
|
setSwal2DataCyAttribute,
|
|
7751
8227
|
showToast,
|