lib-e2e-cypress-for-dummys-ts 0.6.1 → 0.9.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 +53 -0
- package/dist/{chunk-FDMUIHDZ.js → chunk-CQEDHL7A.js} +1 -1
- package/dist/chunk-CQEDHL7A.js.map +1 -0
- package/dist/index.cjs +1269 -190
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -5
- package/dist/index.d.ts +90 -5
- package/dist/index.js +1266 -192
- package/dist/index.js.map +1 -1
- package/dist/selector-picker-JM5HID3Z.js +7 -0
- package/package.json +74 -74
- 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-JM5HID3Z.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -469,6 +469,7 @@ __export(index_exports, {
|
|
|
469
469
|
DEFAULT_RESUME_TTL_MINUTES: () => DEFAULT_RESUME_TTL_MINUTES,
|
|
470
470
|
DRAG_THRESHOLD: () => DRAG_THRESHOLD,
|
|
471
471
|
FilePreviewElement: () => FilePreviewElement,
|
|
472
|
+
HelpPanelElement: () => HelpPanelElement,
|
|
472
473
|
HttpMonitor: () => HttpMonitor,
|
|
473
474
|
INPUT_TYPES: () => INPUT_TYPES,
|
|
474
475
|
LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES: () => LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,
|
|
@@ -494,6 +495,7 @@ __export(index_exports, {
|
|
|
494
495
|
clampTogglePosition: () => clampTogglePosition,
|
|
495
496
|
defaultTogglePosition: () => defaultTogglePosition,
|
|
496
497
|
generateAlias: () => generateAlias,
|
|
498
|
+
inferAssertionCommand: () => inferAssertionCommand,
|
|
497
499
|
injectStyles: () => injectStyles,
|
|
498
500
|
isLang: () => isLang,
|
|
499
501
|
isLocalHost: () => isLocalHost,
|
|
@@ -645,7 +647,10 @@ var I18N_ES = {
|
|
|
645
647
|
SAVE_AND_EDIT: "\u{1F4DD} Guardar y editar",
|
|
646
648
|
REMOVE_TAG_TITLE: "Quitar",
|
|
647
649
|
NOTES_LABEL: "Descripci\xF3n / Notas (opcional):",
|
|
648
|
-
NOTES_PLACEHOLDER: "Qu\xE9 valida este test, condiciones previas, etc."
|
|
650
|
+
NOTES_PLACEHOLDER: "Qu\xE9 valida este test, condiciones previas, etc.",
|
|
651
|
+
TICKET_LABEL: "Ticket / Issue (opcional):",
|
|
652
|
+
TICKET_PLACEHOLDER: "Ej: PROJ-123, #42",
|
|
653
|
+
TICKET_WARN: "ID no v\xE1lido para el proveedor configurado (se guardar\xE1 igualmente)"
|
|
649
654
|
},
|
|
650
655
|
TEST_EDITOR: {
|
|
651
656
|
NO_TAGS: "Sin etiquetas",
|
|
@@ -659,7 +664,11 @@ var I18N_ES = {
|
|
|
659
664
|
COPY_ICPS_BTN: "\u{1F4CB} Copiar interceptores",
|
|
660
665
|
DEFAULT_DESCRIBE: "Suite de tests",
|
|
661
666
|
NO_TESTS: "No hay tests guardados",
|
|
662
|
-
DELETE_TITLE: "Eliminar"
|
|
667
|
+
DELETE_TITLE: "Eliminar",
|
|
668
|
+
GROUP_BY_TICKET: "\u{1F3AB} Agrupar por ticket",
|
|
669
|
+
UNGROUP_TICKET: "\u{1F3AB} Desagrupar",
|
|
670
|
+
NO_TICKET: "Sin ticket",
|
|
671
|
+
TICKET_LINK_TITLE: "Abrir ticket"
|
|
663
672
|
},
|
|
664
673
|
CONFIG: {
|
|
665
674
|
LANG_SECTION: "\u{1F310} Idioma",
|
|
@@ -667,6 +676,9 @@ var I18N_ES = {
|
|
|
667
676
|
HTTP_SECTION: "\u26A1 HTTP Avanzado",
|
|
668
677
|
HTTP_TITLE: "Validaciones de body",
|
|
669
678
|
HTTP_SUB: "GET \u2192 response \xB7 POST/PUT \u2192 request",
|
|
679
|
+
FIXTURE_SECTION: "\u{1F9EA} Fixtures HTTP",
|
|
680
|
+
FIXTURE_TITLE: "Grabar respuestas como fixtures",
|
|
681
|
+
FIXTURE_SUB: "Las GET se guardan en cypress/fixtures y se stubean con cy.intercept({ fixture }).",
|
|
670
682
|
SELECTOR_SECTION: "\u{1F3AF} Estrategia de selector",
|
|
671
683
|
SELECTOR_LABEL: "Atributo preferido para cy.get()",
|
|
672
684
|
SELECTOR_OPT_DATACY: "data-cy (por defecto)",
|
|
@@ -714,7 +726,13 @@ var I18N_ES = {
|
|
|
714
726
|
WIDGET_POSITION_SECTION: "\u{1F9F2} Posici\xF3n del widget",
|
|
715
727
|
WIDGET_POSITION_HINT: "Arrastra el bot\xF3n de grabar para moverlo donde no estorbe. Se recuerda su posici\xF3n.",
|
|
716
728
|
WIDGET_POSITION_RESET_BTN: "\u21BA Restablecer posici\xF3n",
|
|
717
|
-
WIDGET_POSITION_RESET_DONE: "\u2713 Posici\xF3n restablecida"
|
|
729
|
+
WIDGET_POSITION_RESET_DONE: "\u2713 Posici\xF3n restablecida",
|
|
730
|
+
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue tracker",
|
|
731
|
+
ISSUE_TRACKER_TITLE: "Vincular tests a tickets",
|
|
732
|
+
ISSUE_TRACKER_SUB: "A\xF1ade un ID de ticket al guardar y genera un enlace clickable en el listado.",
|
|
733
|
+
ISSUE_TRACKER_PROVIDER: "Proveedor",
|
|
734
|
+
ISSUE_TRACKER_BASE_URL: "URL base",
|
|
735
|
+
ISSUE_TRACKER_BASE_URL_PH: "Ej: https://miproyecto.atlassian.net"
|
|
718
736
|
},
|
|
719
737
|
SELECTOR_PICKER: {
|
|
720
738
|
TITLE: "Selecciona un elemento del DOM",
|
|
@@ -803,6 +821,8 @@ var I18N_ES = {
|
|
|
803
821
|
FILE_EDITOR_TITLE: "\u270F\uFE0F Editor de archivo",
|
|
804
822
|
FILE_SAVED_TOAST: "\u2713 Archivo guardado",
|
|
805
823
|
FILE_SAVE_ERROR_TOAST: "Error al guardar el archivo",
|
|
824
|
+
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures escritos en cypress/fixtures",
|
|
825
|
+
FIXTURES_NO_FOLDER_TOAST: "No se pudieron escribir los fixtures (configura la carpeta Cypress)",
|
|
806
826
|
BTN_CONFIG: "Config",
|
|
807
827
|
BTN_FILES: "Ficheros",
|
|
808
828
|
BTN_COMMANDS: "Comandos",
|
|
@@ -817,7 +837,76 @@ var I18N_ES = {
|
|
|
817
837
|
SESSION_RESUME_TEXT: "Hay una grabaci\xF3n activa sin terminar.",
|
|
818
838
|
SESSION_RESUME_COUNT: "comandos capturados",
|
|
819
839
|
SESSION_CONTINUE_BTN: "Continuar grabando",
|
|
820
|
-
SESSION_DISCARD_BTN: "Descartar"
|
|
840
|
+
SESSION_DISCARD_BTN: "Descartar",
|
|
841
|
+
BTN_HELP: "Ayuda"
|
|
842
|
+
},
|
|
843
|
+
HELP: {
|
|
844
|
+
TITLE: "\u2753 Ayuda \u2014 Gu\xEDa r\xE1pida",
|
|
845
|
+
INTRO: "Todo lo que puede hacer el grabador.",
|
|
846
|
+
SEC_RECORDING: "\u23FA Grabar",
|
|
847
|
+
RECORDING_1: "Pulsa \u23FA (o Ctrl+R) para empezar; \u23F9 para parar y guardar.",
|
|
848
|
+
RECORDING_2: "Pausa / reanuda con \u23F8 (o Ctrl+P).",
|
|
849
|
+
SEC_SHORTCUTS: "\u2328\uFE0F Atajos de teclado",
|
|
850
|
+
SC_RECORD: "Ctrl+R \u2014 Grabar / detener",
|
|
851
|
+
SC_PAUSE: "Ctrl+P \u2014 Pausar / reanudar",
|
|
852
|
+
SC_TESTS: "Ctrl+1 \u2014 Panel de tests guardados",
|
|
853
|
+
SC_COMMANDS: "Ctrl+2 \u2014 Panel de comandos",
|
|
854
|
+
SC_CONFIG: "Ctrl+3 \u2014 Configuraci\xF3n",
|
|
855
|
+
SC_VISIBILITY: "Ctrl+Shift+E \u2014 Mostrar / ocultar el widget",
|
|
856
|
+
SC_HELP: "Ctrl+Shift+H \u2014 Esta ayuda",
|
|
857
|
+
SEC_CAPTURED: "\u{1F3AF} Qu\xE9 se graba",
|
|
858
|
+
CAP_CLICK: "Click \u2192 .click()",
|
|
859
|
+
CAP_DBLCLICK: "Doble-click \u2192 .dblclick()",
|
|
860
|
+
CAP_RIGHTCLICK: "Click derecho \u2192 .rightclick()",
|
|
861
|
+
CAP_TYPE: "Escribir en un campo \u2192 .clear().type(...)",
|
|
862
|
+
CAP_CHECK: "Checkbox / radio \u2192 .check() / .uncheck()",
|
|
863
|
+
CAP_SELECT: "<select> \u2192 .select(...)",
|
|
864
|
+
CAP_KEYS: 'Enter / Escape \u2192 .type("{enter}") / ("{esc}")',
|
|
865
|
+
CAP_ROUTE: "Cambio de ruta (SPA) \u2192 cy.url().should(...)",
|
|
866
|
+
CAP_HTTP: "fetch / XHR \u2192 cy.intercept + cy.wait",
|
|
867
|
+
SEC_ASSERT: "\u2705 Aserciones",
|
|
868
|
+
ASSERT_1: "Alt+click sobre un elemento para verificarlo sin ejecutar su acci\xF3n (texto, valor, checked o visible).",
|
|
869
|
+
ASSERT_2: "O usa el constructor de aserciones en el panel de Comandos.",
|
|
870
|
+
SEC_PANELS: "\u{1F5C2} Paneles",
|
|
871
|
+
PANEL_TESTS: "\u{1F4CB} Tests \u2014 guardados: filtrar por tag, copiar, combinar, exportar.",
|
|
872
|
+
PANEL_COMMANDS: "\u2328\uFE0F Comandos \u2014 de la grabaci\xF3n actual: reordenar, borrar, a\xF1adir aserciones.",
|
|
873
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 idioma, selector, HTTP, carpeta Cypress, datos, visibilidad, posici\xF3n.",
|
|
874
|
+
PANEL_FILES: "\u{1F4C1} Ficheros \u2014 inserta tests en tus .cy.ts y lanza el runner.",
|
|
875
|
+
SEC_SELECTOR: "\u{1F50E} Selectores",
|
|
876
|
+
SELECTOR_1: "Elige el atributo preferido (data-cy, data-testid, aria-label, id) en Config.",
|
|
877
|
+
SELECTOR_2: "Si un click no tiene selector fiable, aparece un picker para elegir el mejor ancestro.",
|
|
878
|
+
SEC_DATA: "\u{1F4BE} Datos",
|
|
879
|
+
DATA_1: "Exporta tests a JSON (todo / selecci\xF3n / por tags).",
|
|
880
|
+
DATA_2: "Importa un JSON: se fusiona con lo existente (no se borra nada).",
|
|
881
|
+
SEC_ADVANCED: "\u{1F680} Avanzado",
|
|
882
|
+
ADV_INVISIBLE: "Modo invisible: start-hidden + Ctrl+Shift+E para grabar en producci\xF3n sin molestar.",
|
|
883
|
+
ADV_RUNNER: "Runner local: npx lib-e2e-cypress-runner para lanzar un spec headless desde el editor.",
|
|
884
|
+
ADV_CROSSAPP: "Cross-app: la grabaci\xF3n sobrevive al cambiar de micro-frontend (mismo origen).",
|
|
885
|
+
ADV_DRAG: "Arrastra el bot\xF3n \u23FA para mover el widget; recuerda su posici\xF3n.",
|
|
886
|
+
CLOSE: "Cerrar",
|
|
887
|
+
TAB_REFERENCE: "Referencia r\xE1pida",
|
|
888
|
+
TAB_GUIDE: "Gu\xEDa de uso",
|
|
889
|
+
GUIDE_INTRO: "C\xF3mo sacarle partido al grabador, qu\xE9 cubre y qu\xE9 no.",
|
|
890
|
+
G_SEC_WORKFLOW: "\u{1F9ED} Flujo de trabajo",
|
|
891
|
+
G_WF_1: "1. Pulsa \u23FA (o Ctrl+R) para empezar a grabar.",
|
|
892
|
+
G_WF_2: "2. Usa tu app como un usuario: clicks, formularios, navegaci\xF3n. Cada acci\xF3n se convierte en un comando Cypress.",
|
|
893
|
+
G_WF_3: "3. A\xF1ade verificaciones con Alt+click sobre lo que quieras comprobar.",
|
|
894
|
+
G_WF_4: "4. Pulsa \u23F9 para parar; ponle nombre y tags, y gu\xE1rdalo.",
|
|
895
|
+
G_WF_5: "5. En \u{1F4C1} Ficheros, inserta el test en un .cy.ts o l\xE1nzalo con el runner local.",
|
|
896
|
+
G_SEC_COVERED: "\u2705 Qu\xE9 cubre",
|
|
897
|
+
G_COV_1: "Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.",
|
|
898
|
+
G_COV_2: "Navegaci\xF3n SPA (pushState/replaceState/popstate) \u2192 cy.url().should(...).",
|
|
899
|
+
G_COV_3: "Llamadas fetch/XHR (GET/POST/PUT) \u2192 cy.intercept + cy.wait, con validaci\xF3n de body opcional.",
|
|
900
|
+
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
901
|
+
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
902
|
+
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
903
|
+
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
904
|
+
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
905
|
+
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
906
|
+
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
907
|
+
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
908
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse.",
|
|
909
|
+
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
821
910
|
}
|
|
822
911
|
};
|
|
823
912
|
|
|
@@ -845,7 +934,10 @@ var I18N_EN = {
|
|
|
845
934
|
SAVE_AND_EDIT: "\u{1F4DD} Save and edit",
|
|
846
935
|
REMOVE_TAG_TITLE: "Remove",
|
|
847
936
|
NOTES_LABEL: "Description / Notes (optional):",
|
|
848
|
-
NOTES_PLACEHOLDER: "What this test validates, preconditions, etc."
|
|
937
|
+
NOTES_PLACEHOLDER: "What this test validates, preconditions, etc.",
|
|
938
|
+
TICKET_LABEL: "Ticket / Issue (optional):",
|
|
939
|
+
TICKET_PLACEHOLDER: "E.g.: PROJ-123, #42",
|
|
940
|
+
TICKET_WARN: "Invalid ID for the configured provider (will be saved anyway)"
|
|
849
941
|
},
|
|
850
942
|
TEST_EDITOR: {
|
|
851
943
|
NO_TAGS: "No tags",
|
|
@@ -859,7 +951,11 @@ var I18N_EN = {
|
|
|
859
951
|
COPY_ICPS_BTN: "\u{1F4CB} Copy interceptors",
|
|
860
952
|
DEFAULT_DESCRIBE: "Test suite",
|
|
861
953
|
NO_TESTS: "No saved tests",
|
|
862
|
-
DELETE_TITLE: "Delete"
|
|
954
|
+
DELETE_TITLE: "Delete",
|
|
955
|
+
GROUP_BY_TICKET: "\u{1F3AB} Group by ticket",
|
|
956
|
+
UNGROUP_TICKET: "\u{1F3AB} Ungroup",
|
|
957
|
+
NO_TICKET: "No ticket",
|
|
958
|
+
TICKET_LINK_TITLE: "Open ticket"
|
|
863
959
|
},
|
|
864
960
|
CONFIG: {
|
|
865
961
|
LANG_SECTION: "\u{1F310} Language",
|
|
@@ -867,6 +963,9 @@ var I18N_EN = {
|
|
|
867
963
|
HTTP_SECTION: "\u26A1 Advanced HTTP",
|
|
868
964
|
HTTP_TITLE: "Body validations",
|
|
869
965
|
HTTP_SUB: "GET \u2192 response \xB7 POST/PUT \u2192 request",
|
|
966
|
+
FIXTURE_SECTION: "\u{1F9EA} HTTP Fixtures",
|
|
967
|
+
FIXTURE_TITLE: "Record responses as fixtures",
|
|
968
|
+
FIXTURE_SUB: "GET responses are saved to cypress/fixtures and stubbed via cy.intercept({ fixture }).",
|
|
870
969
|
SELECTOR_SECTION: "\u{1F3AF} Selector strategy",
|
|
871
970
|
SELECTOR_LABEL: "Preferred attribute for cy.get()",
|
|
872
971
|
SELECTOR_OPT_DATACY: "data-cy (default)",
|
|
@@ -914,7 +1013,13 @@ var I18N_EN = {
|
|
|
914
1013
|
WIDGET_POSITION_SECTION: "\u{1F9F2} Widget position",
|
|
915
1014
|
WIDGET_POSITION_HINT: "Drag the record button to move it out of the way. Its position is remembered.",
|
|
916
1015
|
WIDGET_POSITION_RESET_BTN: "\u21BA Reset position",
|
|
917
|
-
WIDGET_POSITION_RESET_DONE: "\u2713 Position reset"
|
|
1016
|
+
WIDGET_POSITION_RESET_DONE: "\u2713 Position reset",
|
|
1017
|
+
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue tracker",
|
|
1018
|
+
ISSUE_TRACKER_TITLE: "Link tests to tickets",
|
|
1019
|
+
ISSUE_TRACKER_SUB: "Add a ticket ID when saving and generate a clickable link in the test list.",
|
|
1020
|
+
ISSUE_TRACKER_PROVIDER: "Provider",
|
|
1021
|
+
ISSUE_TRACKER_BASE_URL: "Base URL",
|
|
1022
|
+
ISSUE_TRACKER_BASE_URL_PH: "E.g.: https://myproject.atlassian.net"
|
|
918
1023
|
},
|
|
919
1024
|
SELECTOR_PICKER: {
|
|
920
1025
|
TITLE: "Select a DOM element",
|
|
@@ -1003,6 +1108,8 @@ var I18N_EN = {
|
|
|
1003
1108
|
FILE_EDITOR_TITLE: "\u270F\uFE0F File editor",
|
|
1004
1109
|
FILE_SAVED_TOAST: "\u2713 File saved",
|
|
1005
1110
|
FILE_SAVE_ERROR_TOAST: "Error saving the file",
|
|
1111
|
+
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures written to cypress/fixtures",
|
|
1112
|
+
FIXTURES_NO_FOLDER_TOAST: "Could not write fixtures (configure the Cypress folder)",
|
|
1006
1113
|
BTN_CONFIG: "Config",
|
|
1007
1114
|
BTN_FILES: "Files",
|
|
1008
1115
|
BTN_COMMANDS: "Commands",
|
|
@@ -1017,7 +1124,76 @@ var I18N_EN = {
|
|
|
1017
1124
|
SESSION_RESUME_TEXT: "There is an unfinished active recording.",
|
|
1018
1125
|
SESSION_RESUME_COUNT: "commands captured",
|
|
1019
1126
|
SESSION_CONTINUE_BTN: "Keep recording",
|
|
1020
|
-
SESSION_DISCARD_BTN: "Discard"
|
|
1127
|
+
SESSION_DISCARD_BTN: "Discard",
|
|
1128
|
+
BTN_HELP: "Help"
|
|
1129
|
+
},
|
|
1130
|
+
HELP: {
|
|
1131
|
+
TITLE: "\u2753 Help \u2014 Quick guide",
|
|
1132
|
+
INTRO: "Everything the recorder can do.",
|
|
1133
|
+
SEC_RECORDING: "\u23FA Recording",
|
|
1134
|
+
RECORDING_1: "Press \u23FA (or Ctrl+R) to start; \u23F9 to stop and save.",
|
|
1135
|
+
RECORDING_2: "Pause / resume with \u23F8 (or Ctrl+P).",
|
|
1136
|
+
SEC_SHORTCUTS: "\u2328\uFE0F Keyboard shortcuts",
|
|
1137
|
+
SC_RECORD: "Ctrl+R \u2014 Record / stop",
|
|
1138
|
+
SC_PAUSE: "Ctrl+P \u2014 Pause / resume",
|
|
1139
|
+
SC_TESTS: "Ctrl+1 \u2014 Saved tests panel",
|
|
1140
|
+
SC_COMMANDS: "Ctrl+2 \u2014 Commands panel",
|
|
1141
|
+
SC_CONFIG: "Ctrl+3 \u2014 Settings",
|
|
1142
|
+
SC_VISIBILITY: "Ctrl+Shift+E \u2014 Show / hide the widget",
|
|
1143
|
+
SC_HELP: "Ctrl+Shift+H \u2014 This help",
|
|
1144
|
+
SEC_CAPTURED: "\u{1F3AF} What gets recorded",
|
|
1145
|
+
CAP_CLICK: "Click \u2192 .click()",
|
|
1146
|
+
CAP_DBLCLICK: "Double-click \u2192 .dblclick()",
|
|
1147
|
+
CAP_RIGHTCLICK: "Right-click \u2192 .rightclick()",
|
|
1148
|
+
CAP_TYPE: "Type into a field \u2192 .clear().type(...)",
|
|
1149
|
+
CAP_CHECK: "Checkbox / radio \u2192 .check() / .uncheck()",
|
|
1150
|
+
CAP_SELECT: "<select> \u2192 .select(...)",
|
|
1151
|
+
CAP_KEYS: 'Enter / Escape \u2192 .type("{enter}") / ("{esc}")',
|
|
1152
|
+
CAP_ROUTE: "Route change (SPA) \u2192 cy.url().should(...)",
|
|
1153
|
+
CAP_HTTP: "fetch / XHR \u2192 cy.intercept + cy.wait",
|
|
1154
|
+
SEC_ASSERT: "\u2705 Assertions",
|
|
1155
|
+
ASSERT_1: "Alt+click an element to verify it without running its action (text, value, checked or visible).",
|
|
1156
|
+
ASSERT_2: "Or use the assertion builder in the Commands panel.",
|
|
1157
|
+
SEC_PANELS: "\u{1F5C2} Panels",
|
|
1158
|
+
PANEL_TESTS: "\u{1F4CB} Tests \u2014 saved tests: filter by tag, copy, combine, export.",
|
|
1159
|
+
PANEL_COMMANDS: "\u2328\uFE0F Commands \u2014 current recording: reorder, delete, add assertions.",
|
|
1160
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 language, selector, HTTP, Cypress folder, data, visibility, position.",
|
|
1161
|
+
PANEL_FILES: "\u{1F4C1} Files \u2014 insert tests into your .cy.ts and launch the runner.",
|
|
1162
|
+
SEC_SELECTOR: "\u{1F50E} Selectors",
|
|
1163
|
+
SELECTOR_1: "Choose the preferred attribute (data-cy, data-testid, aria-label, id) in Config.",
|
|
1164
|
+
SELECTOR_2: "If a click has no reliable selector, a picker appears to choose the best ancestor.",
|
|
1165
|
+
SEC_DATA: "\u{1F4BE} Data",
|
|
1166
|
+
DATA_1: "Export tests to JSON (all / selection / by tags).",
|
|
1167
|
+
DATA_2: "Import a JSON: it merges into your data (nothing is wiped).",
|
|
1168
|
+
SEC_ADVANCED: "\u{1F680} Advanced",
|
|
1169
|
+
ADV_INVISIBLE: "Invisible mode: start-hidden + Ctrl+Shift+E to record in production unobtrusively.",
|
|
1170
|
+
ADV_RUNNER: "Local runner: npx lib-e2e-cypress-runner to run a spec headless from the editor.",
|
|
1171
|
+
ADV_CROSSAPP: "Cross-app: the recording survives switching micro-frontend (same origin).",
|
|
1172
|
+
ADV_DRAG: "Drag the \u23FA button to move the widget; its position is remembered.",
|
|
1173
|
+
CLOSE: "Close",
|
|
1174
|
+
TAB_REFERENCE: "Quick reference",
|
|
1175
|
+
TAB_GUIDE: "Usage guide",
|
|
1176
|
+
GUIDE_INTRO: "How to get the most out of the recorder, and what it does / doesn't cover.",
|
|
1177
|
+
G_SEC_WORKFLOW: "\u{1F9ED} Workflow",
|
|
1178
|
+
G_WF_1: "1. Press \u23FA (or Ctrl+R) to start recording.",
|
|
1179
|
+
G_WF_2: "2. Use your app like a user: clicks, forms, navigation. Each action becomes a Cypress command.",
|
|
1180
|
+
G_WF_3: "3. Add checks with Alt+click on whatever you want to verify.",
|
|
1181
|
+
G_WF_4: "4. Press \u23F9 to stop; give it a name and tags, and save it.",
|
|
1182
|
+
G_WF_5: "5. In \u{1F4C1} Files, insert the test into a .cy.ts or run it with the local runner.",
|
|
1183
|
+
G_SEC_COVERED: "\u2705 What it covers",
|
|
1184
|
+
G_COV_1: "Clicks, double-click, right-click, text inputs, checkbox/radio, select and Enter/Escape keys.",
|
|
1185
|
+
G_COV_2: "SPA navigation (pushState/replaceState/popstate) \u2192 cy.url().should(...).",
|
|
1186
|
+
G_COV_3: "fetch/XHR calls (GET/POST/PUT) \u2192 cy.intercept + cy.wait, with optional body validation.",
|
|
1187
|
+
G_COV_4: "Reliable selector (data-cy/testid/aria/id) and a picker when none is obvious.",
|
|
1188
|
+
G_COV_5: "Automatic assertions (Alt+click) and the manual builder.",
|
|
1189
|
+
G_COV_6: "Continuity when switching micro-frontend (same origin), invisible mode and i18n.",
|
|
1190
|
+
G_SEC_NOTCOVERED: "\u{1F6AB} What it does NOT cover (yet)",
|
|
1191
|
+
G_NC_1: "Different origins / subdomains (same origin only).",
|
|
1192
|
+
G_NC_2: "File upload (selectFile), drag & drop, and hover.",
|
|
1193
|
+
G_NC_3: "The Tab key (Cypress can't .type() it).",
|
|
1194
|
+
G_NC_4: "DELETE requests (intentionally ignored).",
|
|
1195
|
+
G_NC_5: "Third-party iframes and Shadow DOM may not be captured.",
|
|
1196
|
+
G_NC_6: "Programmatic login generation (on the roadmap)."
|
|
1021
1197
|
}
|
|
1022
1198
|
};
|
|
1023
1199
|
|
|
@@ -1045,7 +1221,11 @@ var I18N_FR = {
|
|
|
1045
1221
|
SAVE_AND_EDIT: "\u{1F4DD} Enregistrer et \xE9diter",
|
|
1046
1222
|
REMOVE_TAG_TITLE: "Retirer",
|
|
1047
1223
|
NOTES_LABEL: "Description / Notes (optionnel) :",
|
|
1048
|
-
NOTES_PLACEHOLDER: "Ce que ce test valide, conditions pr\xE9alables, etc."
|
|
1224
|
+
NOTES_PLACEHOLDER: "Ce que ce test valide, conditions pr\xE9alables, etc.",
|
|
1225
|
+
TICKET_LABEL: "Ticket / Issue (optionnel) :",
|
|
1226
|
+
TICKET_PLACEHOLDER: "Ex : PROJ-123, #42",
|
|
1227
|
+
TICKET_WARN: "ID non valide pour le fournisseur configur\xE9 (sera enregistr\xE9 quand m\xEAme)"
|
|
1228
|
+
// TODO: translate
|
|
1049
1229
|
},
|
|
1050
1230
|
TEST_EDITOR: {
|
|
1051
1231
|
NO_TAGS: "Sans \xE9tiquettes",
|
|
@@ -1059,7 +1239,11 @@ var I18N_FR = {
|
|
|
1059
1239
|
COPY_ICPS_BTN: "\u{1F4CB} Copier les intercepteurs",
|
|
1060
1240
|
DEFAULT_DESCRIBE: "Suite de tests",
|
|
1061
1241
|
NO_TESTS: "Aucun test enregistr\xE9",
|
|
1062
|
-
DELETE_TITLE: "Supprimer"
|
|
1242
|
+
DELETE_TITLE: "Supprimer",
|
|
1243
|
+
GROUP_BY_TICKET: "\u{1F3AB} Grouper par ticket",
|
|
1244
|
+
UNGROUP_TICKET: "\u{1F3AB} D\xE9grouper",
|
|
1245
|
+
NO_TICKET: "Sans ticket",
|
|
1246
|
+
TICKET_LINK_TITLE: "Ouvrir le ticket"
|
|
1063
1247
|
},
|
|
1064
1248
|
CONFIG: {
|
|
1065
1249
|
LANG_SECTION: "\u{1F310} Langue",
|
|
@@ -1067,6 +1251,9 @@ var I18N_FR = {
|
|
|
1067
1251
|
HTTP_SECTION: "\u26A1 HTTP Avanc\xE9",
|
|
1068
1252
|
HTTP_TITLE: "Validations du corps",
|
|
1069
1253
|
HTTP_SUB: "GET \u2192 r\xE9ponse \xB7 POST/PUT \u2192 requ\xEAte",
|
|
1254
|
+
FIXTURE_SECTION: "\u{1F9EA} Fixtures HTTP",
|
|
1255
|
+
FIXTURE_TITLE: "Enregistrer les r\xE9ponses comme fixtures",
|
|
1256
|
+
FIXTURE_SUB: "Les GET sont enregistr\xE9es dans cypress/fixtures et stub\xE9es via cy.intercept({ fixture }).",
|
|
1070
1257
|
SELECTOR_SECTION: "\u{1F3AF} Strat\xE9gie de s\xE9lecteur",
|
|
1071
1258
|
SELECTOR_LABEL: "Attribut pr\xE9f\xE9r\xE9 pour cy.get()",
|
|
1072
1259
|
SELECTOR_OPT_DATACY: "data-cy (par d\xE9faut)",
|
|
@@ -1114,7 +1301,13 @@ var I18N_FR = {
|
|
|
1114
1301
|
WIDGET_POSITION_SECTION: "\u{1F9F2} Position du widget",
|
|
1115
1302
|
WIDGET_POSITION_HINT: "Fais glisser le bouton d'enregistrement pour le d\xE9placer. Sa position est m\xE9moris\xE9e.",
|
|
1116
1303
|
WIDGET_POSITION_RESET_BTN: "\u21BA R\xE9initialiser la position",
|
|
1117
|
-
WIDGET_POSITION_RESET_DONE: "\u2713 Position r\xE9initialis\xE9e"
|
|
1304
|
+
WIDGET_POSITION_RESET_DONE: "\u2713 Position r\xE9initialis\xE9e",
|
|
1305
|
+
ISSUE_TRACKER_SECTION: "\u{1F3AB} Gestionnaire de tickets",
|
|
1306
|
+
ISSUE_TRACKER_TITLE: "Lier les tests aux tickets",
|
|
1307
|
+
ISSUE_TRACKER_SUB: "Ajoutez un ID de ticket lors de l'enregistrement et g\xE9n\xE9rez un lien cliquable.",
|
|
1308
|
+
ISSUE_TRACKER_PROVIDER: "Fournisseur",
|
|
1309
|
+
ISSUE_TRACKER_BASE_URL: "URL de base",
|
|
1310
|
+
ISSUE_TRACKER_BASE_URL_PH: "Ex : https://monprojet.atlassian.net"
|
|
1118
1311
|
},
|
|
1119
1312
|
SELECTOR_PICKER: {
|
|
1120
1313
|
TITLE: "S\xE9lectionnez un \xE9l\xE9ment du DOM",
|
|
@@ -1203,6 +1396,8 @@ var I18N_FR = {
|
|
|
1203
1396
|
FILE_EDITOR_TITLE: "\u270F\uFE0F \xC9diteur de fichier",
|
|
1204
1397
|
FILE_SAVED_TOAST: "\u2713 Fichier enregistr\xE9",
|
|
1205
1398
|
FILE_SAVE_ERROR_TOAST: "Erreur lors de l'enregistrement",
|
|
1399
|
+
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures \xE9crites dans cypress/fixtures",
|
|
1400
|
+
FIXTURES_NO_FOLDER_TOAST: "Impossible d'\xE9crire les fixtures (configure le dossier Cypress)",
|
|
1206
1401
|
BTN_CONFIG: "Config",
|
|
1207
1402
|
BTN_FILES: "Fichiers",
|
|
1208
1403
|
BTN_COMMANDS: "Commandes",
|
|
@@ -1217,7 +1412,77 @@ var I18N_FR = {
|
|
|
1217
1412
|
SESSION_RESUME_TEXT: "Un enregistrement actif est inachev\xE9.",
|
|
1218
1413
|
SESSION_RESUME_COUNT: "commandes captur\xE9es",
|
|
1219
1414
|
SESSION_CONTINUE_BTN: "Continuer l'enregistrement",
|
|
1220
|
-
SESSION_DISCARD_BTN: "Ignorer"
|
|
1415
|
+
SESSION_DISCARD_BTN: "Ignorer",
|
|
1416
|
+
BTN_HELP: "Aide"
|
|
1417
|
+
},
|
|
1418
|
+
HELP: {
|
|
1419
|
+
TITLE: "\u2753 Aide \u2014 Guide rapide",
|
|
1420
|
+
INTRO: "Tout ce que l'enregistreur sait faire.",
|
|
1421
|
+
SEC_RECORDING: "\u23FA Enregistrer",
|
|
1422
|
+
RECORDING_1: "Appuie sur \u23FA (ou Ctrl+R) pour commencer ; \u23F9 pour arr\xEAter et enregistrer.",
|
|
1423
|
+
RECORDING_2: "Pause / reprise avec \u23F8 (ou Ctrl+P).",
|
|
1424
|
+
SEC_SHORTCUTS: "\u2328\uFE0F Raccourcis clavier",
|
|
1425
|
+
SC_RECORD: "Ctrl+R \u2014 Enregistrer / arr\xEAter",
|
|
1426
|
+
SC_PAUSE: "Ctrl+P \u2014 Pause / reprise",
|
|
1427
|
+
SC_TESTS: "Ctrl+1 \u2014 Panneau des tests enregistr\xE9s",
|
|
1428
|
+
SC_COMMANDS: "Ctrl+2 \u2014 Panneau des commandes",
|
|
1429
|
+
SC_CONFIG: "Ctrl+3 \u2014 Param\xE8tres",
|
|
1430
|
+
SC_VISIBILITY: "Ctrl+Shift+E \u2014 Afficher / masquer le widget",
|
|
1431
|
+
SC_HELP: "Ctrl+Shift+H \u2014 Cette aide",
|
|
1432
|
+
SEC_CAPTURED: "\u{1F3AF} Ce qui est enregistr\xE9",
|
|
1433
|
+
CAP_CLICK: "Clic \u2192 .click()",
|
|
1434
|
+
CAP_DBLCLICK: "Double-clic \u2192 .dblclick()",
|
|
1435
|
+
CAP_RIGHTCLICK: "Clic droit \u2192 .rightclick()",
|
|
1436
|
+
CAP_TYPE: "Saisie dans un champ \u2192 .clear().type(...)",
|
|
1437
|
+
CAP_CHECK: "Case \xE0 cocher / radio \u2192 .check() / .uncheck()",
|
|
1438
|
+
CAP_SELECT: "<select> \u2192 .select(...)",
|
|
1439
|
+
CAP_KEYS: 'Entr\xE9e / \xC9chap \u2192 .type("{enter}") / ("{esc}")',
|
|
1440
|
+
CAP_ROUTE: "Changement de route (SPA) \u2192 cy.url().should(...)",
|
|
1441
|
+
CAP_HTTP: "fetch / XHR \u2192 cy.intercept + cy.wait",
|
|
1442
|
+
SEC_ASSERT: "\u2705 Assertions",
|
|
1443
|
+
ASSERT_1: "Alt+clic sur un \xE9l\xE9ment pour le v\xE9rifier sans ex\xE9cuter son action (texte, valeur, coch\xE9 ou visible).",
|
|
1444
|
+
ASSERT_2: "Ou utilise le constructeur d'assertions dans le panneau Commandes.",
|
|
1445
|
+
SEC_PANELS: "\u{1F5C2} Panneaux",
|
|
1446
|
+
PANEL_TESTS: "\u{1F4CB} Tests \u2014 enregistr\xE9s : filtrer par tag, copier, combiner, exporter.",
|
|
1447
|
+
PANEL_COMMANDS: "\u2328\uFE0F Commandes \u2014 enregistrement en cours : r\xE9ordonner, supprimer, ajouter des assertions.",
|
|
1448
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 langue, s\xE9lecteur, HTTP, dossier Cypress, donn\xE9es, visibilit\xE9, position.",
|
|
1449
|
+
PANEL_FILES: "\u{1F4C1} Fichiers \u2014 ins\xE8re des tests dans tes .cy.ts et lance le runner.",
|
|
1450
|
+
SEC_SELECTOR: "\u{1F50E} S\xE9lecteurs",
|
|
1451
|
+
SELECTOR_1: "Choisis l'attribut pr\xE9f\xE9r\xE9 (data-cy, data-testid, aria-label, id) dans Config.",
|
|
1452
|
+
SELECTOR_2: "Si un clic n'a pas de s\xE9lecteur fiable, un s\xE9lecteur appara\xEEt pour choisir le meilleur anc\xEAtre.",
|
|
1453
|
+
SEC_DATA: "\u{1F4BE} Donn\xE9es",
|
|
1454
|
+
DATA_1: "Exporte les tests en JSON (tout / s\xE9lection / par tags).",
|
|
1455
|
+
DATA_2: "Importe un JSON : il fusionne avec tes donn\xE9es (rien n'est effac\xE9).",
|
|
1456
|
+
SEC_ADVANCED: "\u{1F680} Avanc\xE9",
|
|
1457
|
+
ADV_INVISIBLE: "Mode invisible : start-hidden + Ctrl+Shift+E pour enregistrer en production discr\xE8tement.",
|
|
1458
|
+
ADV_RUNNER: "Runner local : npx lib-e2e-cypress-runner pour lancer un spec headless depuis l'\xE9diteur.",
|
|
1459
|
+
ADV_CROSSAPP: "Cross-app : l'enregistrement survit au changement de micro-frontend (m\xEAme origine).",
|
|
1460
|
+
ADV_DRAG: "Fais glisser le bouton \u23FA pour d\xE9placer le widget ; sa position est m\xE9moris\xE9e.",
|
|
1461
|
+
CLOSE: "Fermer",
|
|
1462
|
+
TAB_REFERENCE: "R\xE9f\xE9rence rapide",
|
|
1463
|
+
TAB_GUIDE: "Guide d'utilisation",
|
|
1464
|
+
// TODO: translate (fr) — usage guide body kept in Spanish for now.
|
|
1465
|
+
GUIDE_INTRO: "C\xF3mo sacarle partido al grabador, qu\xE9 cubre y qu\xE9 no.",
|
|
1466
|
+
G_SEC_WORKFLOW: "\u{1F9ED} Flujo de trabajo",
|
|
1467
|
+
G_WF_1: "1. Pulsa \u23FA (o Ctrl+R) para empezar a grabar.",
|
|
1468
|
+
G_WF_2: "2. Usa tu app como un usuario: clicks, formularios, navegaci\xF3n. Cada acci\xF3n se convierte en un comando Cypress.",
|
|
1469
|
+
G_WF_3: "3. A\xF1ade verificaciones con Alt+click sobre lo que quieras comprobar.",
|
|
1470
|
+
G_WF_4: "4. Pulsa \u23F9 para parar; ponle nombre y tags, y gu\xE1rdalo.",
|
|
1471
|
+
G_WF_5: "5. En \u{1F4C1} Ficheros, inserta el test en un .cy.ts o l\xE1nzalo con el runner local.",
|
|
1472
|
+
G_SEC_COVERED: "\u2705 Qu\xE9 cubre",
|
|
1473
|
+
G_COV_1: "Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.",
|
|
1474
|
+
G_COV_2: "Navegaci\xF3n SPA (pushState/replaceState/popstate) \u2192 cy.url().should(...).",
|
|
1475
|
+
G_COV_3: "Llamadas fetch/XHR (GET/POST/PUT) \u2192 cy.intercept + cy.wait, con validaci\xF3n de body opcional.",
|
|
1476
|
+
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
1477
|
+
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
1478
|
+
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
1479
|
+
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
1480
|
+
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
1481
|
+
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
1482
|
+
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
1483
|
+
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
1484
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse.",
|
|
1485
|
+
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
1221
1486
|
}
|
|
1222
1487
|
};
|
|
1223
1488
|
|
|
@@ -1245,7 +1510,11 @@ var I18N_IT = {
|
|
|
1245
1510
|
SAVE_AND_EDIT: "\u{1F4DD} Salva e modifica",
|
|
1246
1511
|
REMOVE_TAG_TITLE: "Rimuovi",
|
|
1247
1512
|
NOTES_LABEL: "Descrizione / Note (opzionale):",
|
|
1248
|
-
NOTES_PLACEHOLDER: "Cosa valida questo test, condizioni preliminari, ecc."
|
|
1513
|
+
NOTES_PLACEHOLDER: "Cosa valida questo test, condizioni preliminari, ecc.",
|
|
1514
|
+
TICKET_LABEL: "Ticket / Issue (opzionale):",
|
|
1515
|
+
TICKET_PLACEHOLDER: "Es: PROJ-123, #42",
|
|
1516
|
+
TICKET_WARN: "ID non valido per il provider configurato (verr\xE0 salvato comunque)"
|
|
1517
|
+
// TODO: translate
|
|
1249
1518
|
},
|
|
1250
1519
|
TEST_EDITOR: {
|
|
1251
1520
|
NO_TAGS: "Nessuna etichetta",
|
|
@@ -1259,7 +1528,11 @@ var I18N_IT = {
|
|
|
1259
1528
|
COPY_ICPS_BTN: "\u{1F4CB} Copia interceptor",
|
|
1260
1529
|
DEFAULT_DESCRIBE: "Suite di test",
|
|
1261
1530
|
NO_TESTS: "Nessun test salvato",
|
|
1262
|
-
DELETE_TITLE: "Elimina"
|
|
1531
|
+
DELETE_TITLE: "Elimina",
|
|
1532
|
+
GROUP_BY_TICKET: "\u{1F3AB} Raggruppa per ticket",
|
|
1533
|
+
UNGROUP_TICKET: "\u{1F3AB} Separa",
|
|
1534
|
+
NO_TICKET: "Senza ticket",
|
|
1535
|
+
TICKET_LINK_TITLE: "Apri ticket"
|
|
1263
1536
|
},
|
|
1264
1537
|
CONFIG: {
|
|
1265
1538
|
LANG_SECTION: "\u{1F310} Lingua",
|
|
@@ -1267,6 +1540,9 @@ var I18N_IT = {
|
|
|
1267
1540
|
HTTP_SECTION: "\u26A1 HTTP Avanzato",
|
|
1268
1541
|
HTTP_TITLE: "Validazioni del body",
|
|
1269
1542
|
HTTP_SUB: "GET \u2192 risposta \xB7 POST/PUT \u2192 richiesta",
|
|
1543
|
+
FIXTURE_SECTION: "\u{1F9EA} Fixture HTTP",
|
|
1544
|
+
FIXTURE_TITLE: "Registra le risposte come fixture",
|
|
1545
|
+
FIXTURE_SUB: "Le GET vengono salvate in cypress/fixtures e stubbate con cy.intercept({ fixture }).",
|
|
1270
1546
|
SELECTOR_SECTION: "\u{1F3AF} Strategia selettore",
|
|
1271
1547
|
SELECTOR_LABEL: "Attributo preferito per cy.get()",
|
|
1272
1548
|
SELECTOR_OPT_DATACY: "data-cy (predefinito)",
|
|
@@ -1314,7 +1590,13 @@ var I18N_IT = {
|
|
|
1314
1590
|
WIDGET_POSITION_SECTION: "\u{1F9F2} Posizione del widget",
|
|
1315
1591
|
WIDGET_POSITION_HINT: "Trascina il pulsante di registrazione per spostarlo. La posizione viene ricordata.",
|
|
1316
1592
|
WIDGET_POSITION_RESET_BTN: "\u21BA Reimposta posizione",
|
|
1317
|
-
WIDGET_POSITION_RESET_DONE: "\u2713 Posizione reimpostata"
|
|
1593
|
+
WIDGET_POSITION_RESET_DONE: "\u2713 Posizione reimpostata",
|
|
1594
|
+
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue tracker",
|
|
1595
|
+
ISSUE_TRACKER_TITLE: "Collega i test ai ticket",
|
|
1596
|
+
ISSUE_TRACKER_SUB: "Aggiungi un ID ticket al salvataggio e genera un link cliccabile nell'elenco.",
|
|
1597
|
+
ISSUE_TRACKER_PROVIDER: "Provider",
|
|
1598
|
+
ISSUE_TRACKER_BASE_URL: "URL base",
|
|
1599
|
+
ISSUE_TRACKER_BASE_URL_PH: "Es: https://mioprogetto.atlassian.net"
|
|
1318
1600
|
},
|
|
1319
1601
|
SELECTOR_PICKER: {
|
|
1320
1602
|
TITLE: "Seleziona un elemento DOM",
|
|
@@ -1403,6 +1685,8 @@ var I18N_IT = {
|
|
|
1403
1685
|
FILE_EDITOR_TITLE: "\u270F\uFE0F Editor di file",
|
|
1404
1686
|
FILE_SAVED_TOAST: "\u2713 File salvato",
|
|
1405
1687
|
FILE_SAVE_ERROR_TOAST: "Errore durante il salvataggio",
|
|
1688
|
+
FIXTURES_WRITTEN_TOAST: "\u2713 Fixture scritte in cypress/fixtures",
|
|
1689
|
+
FIXTURES_NO_FOLDER_TOAST: "Impossibile scrivere le fixture (configura la cartella Cypress)",
|
|
1406
1690
|
BTN_CONFIG: "Config",
|
|
1407
1691
|
BTN_FILES: "File",
|
|
1408
1692
|
BTN_COMMANDS: "Comandi",
|
|
@@ -1417,7 +1701,77 @@ var I18N_IT = {
|
|
|
1417
1701
|
SESSION_RESUME_TEXT: "C'\xE8 una registrazione attiva non terminata.",
|
|
1418
1702
|
SESSION_RESUME_COUNT: "comandi catturati",
|
|
1419
1703
|
SESSION_CONTINUE_BTN: "Continua a registrare",
|
|
1420
|
-
SESSION_DISCARD_BTN: "Annulla"
|
|
1704
|
+
SESSION_DISCARD_BTN: "Annulla",
|
|
1705
|
+
BTN_HELP: "Aiuto"
|
|
1706
|
+
},
|
|
1707
|
+
HELP: {
|
|
1708
|
+
TITLE: "\u2753 Aiuto \u2014 Guida rapida",
|
|
1709
|
+
INTRO: "Tutto ci\xF2 che il registratore sa fare.",
|
|
1710
|
+
SEC_RECORDING: "\u23FA Registrare",
|
|
1711
|
+
RECORDING_1: "Premi \u23FA (o Ctrl+R) per iniziare; \u23F9 per fermare e salvare.",
|
|
1712
|
+
RECORDING_2: "Pausa / ripresa con \u23F8 (o Ctrl+P).",
|
|
1713
|
+
SEC_SHORTCUTS: "\u2328\uFE0F Scorciatoie da tastiera",
|
|
1714
|
+
SC_RECORD: "Ctrl+R \u2014 Registra / ferma",
|
|
1715
|
+
SC_PAUSE: "Ctrl+P \u2014 Pausa / ripresa",
|
|
1716
|
+
SC_TESTS: "Ctrl+1 \u2014 Pannello test salvati",
|
|
1717
|
+
SC_COMMANDS: "Ctrl+2 \u2014 Pannello comandi",
|
|
1718
|
+
SC_CONFIG: "Ctrl+3 \u2014 Impostazioni",
|
|
1719
|
+
SC_VISIBILITY: "Ctrl+Shift+E \u2014 Mostra / nascondi il widget",
|
|
1720
|
+
SC_HELP: "Ctrl+Shift+H \u2014 Questo aiuto",
|
|
1721
|
+
SEC_CAPTURED: "\u{1F3AF} Cosa viene registrato",
|
|
1722
|
+
CAP_CLICK: "Click \u2192 .click()",
|
|
1723
|
+
CAP_DBLCLICK: "Doppio click \u2192 .dblclick()",
|
|
1724
|
+
CAP_RIGHTCLICK: "Click destro \u2192 .rightclick()",
|
|
1725
|
+
CAP_TYPE: "Digitare in un campo \u2192 .clear().type(...)",
|
|
1726
|
+
CAP_CHECK: "Checkbox / radio \u2192 .check() / .uncheck()",
|
|
1727
|
+
CAP_SELECT: "<select> \u2192 .select(...)",
|
|
1728
|
+
CAP_KEYS: 'Invio / Esc \u2192 .type("{enter}") / ("{esc}")',
|
|
1729
|
+
CAP_ROUTE: "Cambio di rotta (SPA) \u2192 cy.url().should(...)",
|
|
1730
|
+
CAP_HTTP: "fetch / XHR \u2192 cy.intercept + cy.wait",
|
|
1731
|
+
SEC_ASSERT: "\u2705 Asserzioni",
|
|
1732
|
+
ASSERT_1: "Alt+click su un elemento per verificarlo senza eseguire la sua azione (testo, valore, checked o visibile).",
|
|
1733
|
+
ASSERT_2: "Oppure usa il costruttore di asserzioni nel pannello Comandi.",
|
|
1734
|
+
SEC_PANELS: "\u{1F5C2} Pannelli",
|
|
1735
|
+
PANEL_TESTS: "\u{1F4CB} Test \u2014 salvati: filtra per tag, copia, combina, esporta.",
|
|
1736
|
+
PANEL_COMMANDS: "\u2328\uFE0F Comandi \u2014 registrazione corrente: riordina, elimina, aggiungi asserzioni.",
|
|
1737
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 lingua, selettore, HTTP, cartella Cypress, dati, visibilit\xE0, posizione.",
|
|
1738
|
+
PANEL_FILES: "\u{1F4C1} File \u2014 inserisci test nei tuoi .cy.ts e avvia il runner.",
|
|
1739
|
+
SEC_SELECTOR: "\u{1F50E} Selettori",
|
|
1740
|
+
SELECTOR_1: "Scegli l'attributo preferito (data-cy, data-testid, aria-label, id) in Config.",
|
|
1741
|
+
SELECTOR_2: "Se un click non ha un selettore affidabile, appare un picker per scegliere l'antenato migliore.",
|
|
1742
|
+
SEC_DATA: "\u{1F4BE} Dati",
|
|
1743
|
+
DATA_1: "Esporta i test in JSON (tutto / selezione / per tag).",
|
|
1744
|
+
DATA_2: "Importa un JSON: si fonde con i tuoi dati (non si cancella nulla).",
|
|
1745
|
+
SEC_ADVANCED: "\u{1F680} Avanzato",
|
|
1746
|
+
ADV_INVISIBLE: "Modalit\xE0 invisibile: start-hidden + Ctrl+Shift+E per registrare in produzione senza disturbare.",
|
|
1747
|
+
ADV_RUNNER: "Runner locale: npx lib-e2e-cypress-runner per eseguire uno spec headless dall'editor.",
|
|
1748
|
+
ADV_CROSSAPP: "Cross-app: la registrazione sopravvive al cambio di micro-frontend (stessa origine).",
|
|
1749
|
+
ADV_DRAG: "Trascina il pulsante \u23FA per spostare il widget; la posizione viene ricordata.",
|
|
1750
|
+
CLOSE: "Chiudi",
|
|
1751
|
+
TAB_REFERENCE: "Riferimento rapido",
|
|
1752
|
+
TAB_GUIDE: "Guida all'uso",
|
|
1753
|
+
// TODO: translate (it) — usage guide body kept in Spanish for now.
|
|
1754
|
+
GUIDE_INTRO: "C\xF3mo sacarle partido al grabador, qu\xE9 cubre y qu\xE9 no.",
|
|
1755
|
+
G_SEC_WORKFLOW: "\u{1F9ED} Flujo de trabajo",
|
|
1756
|
+
G_WF_1: "1. Pulsa \u23FA (o Ctrl+R) para empezar a grabar.",
|
|
1757
|
+
G_WF_2: "2. Usa tu app como un usuario: clicks, formularios, navegaci\xF3n. Cada acci\xF3n se convierte en un comando Cypress.",
|
|
1758
|
+
G_WF_3: "3. A\xF1ade verificaciones con Alt+click sobre lo que quieras comprobar.",
|
|
1759
|
+
G_WF_4: "4. Pulsa \u23F9 para parar; ponle nombre y tags, y gu\xE1rdalo.",
|
|
1760
|
+
G_WF_5: "5. En \u{1F4C1} Ficheros, inserta el test en un .cy.ts o l\xE1nzalo con el runner local.",
|
|
1761
|
+
G_SEC_COVERED: "\u2705 Qu\xE9 cubre",
|
|
1762
|
+
G_COV_1: "Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.",
|
|
1763
|
+
G_COV_2: "Navegaci\xF3n SPA (pushState/replaceState/popstate) \u2192 cy.url().should(...).",
|
|
1764
|
+
G_COV_3: "Llamadas fetch/XHR (GET/POST/PUT) \u2192 cy.intercept + cy.wait, con validaci\xF3n de body opcional.",
|
|
1765
|
+
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
1766
|
+
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
1767
|
+
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
1768
|
+
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
1769
|
+
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
1770
|
+
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
1771
|
+
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
1772
|
+
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
1773
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse.",
|
|
1774
|
+
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
1421
1775
|
}
|
|
1422
1776
|
};
|
|
1423
1777
|
|
|
@@ -1445,7 +1799,11 @@ var I18N_DE = {
|
|
|
1445
1799
|
SAVE_AND_EDIT: "\u{1F4DD} Speichern und bearbeiten",
|
|
1446
1800
|
REMOVE_TAG_TITLE: "Entfernen",
|
|
1447
1801
|
NOTES_LABEL: "Beschreibung / Notizen (optional):",
|
|
1448
|
-
NOTES_PLACEHOLDER: "Was dieser Test validiert, Voraussetzungen usw."
|
|
1802
|
+
NOTES_PLACEHOLDER: "Was dieser Test validiert, Voraussetzungen usw.",
|
|
1803
|
+
TICKET_LABEL: "Ticket / Issue (optional):",
|
|
1804
|
+
TICKET_PLACEHOLDER: "Z. B.: PROJ-123, #42",
|
|
1805
|
+
TICKET_WARN: "Ung\xFCltige ID f\xFCr den konfigurierten Anbieter (wird trotzdem gespeichert)"
|
|
1806
|
+
// TODO: translate
|
|
1449
1807
|
},
|
|
1450
1808
|
TEST_EDITOR: {
|
|
1451
1809
|
NO_TAGS: "Keine Tags",
|
|
@@ -1459,7 +1817,11 @@ var I18N_DE = {
|
|
|
1459
1817
|
COPY_ICPS_BTN: "\u{1F4CB} Interceptors kopieren",
|
|
1460
1818
|
DEFAULT_DESCRIBE: "Test-Suite",
|
|
1461
1819
|
NO_TESTS: "Keine gespeicherten Tests",
|
|
1462
|
-
DELETE_TITLE: "L\xF6schen"
|
|
1820
|
+
DELETE_TITLE: "L\xF6schen",
|
|
1821
|
+
GROUP_BY_TICKET: "\u{1F3AB} Nach Ticket gruppieren",
|
|
1822
|
+
UNGROUP_TICKET: "\u{1F3AB} Gruppierung aufheben",
|
|
1823
|
+
NO_TICKET: "Kein Ticket",
|
|
1824
|
+
TICKET_LINK_TITLE: "Ticket \xF6ffnen"
|
|
1463
1825
|
},
|
|
1464
1826
|
CONFIG: {
|
|
1465
1827
|
LANG_SECTION: "\u{1F310} Sprache",
|
|
@@ -1467,6 +1829,9 @@ var I18N_DE = {
|
|
|
1467
1829
|
HTTP_SECTION: "\u26A1 Erweitertes HTTP",
|
|
1468
1830
|
HTTP_TITLE: "Body-Validierungen",
|
|
1469
1831
|
HTTP_SUB: "GET \u2192 Antwort \xB7 POST/PUT \u2192 Anfrage",
|
|
1832
|
+
FIXTURE_SECTION: "\u{1F9EA} HTTP-Fixtures",
|
|
1833
|
+
FIXTURE_TITLE: "Antworten als Fixtures aufzeichnen",
|
|
1834
|
+
FIXTURE_SUB: "GET-Antworten werden in cypress/fixtures gespeichert und mit cy.intercept({ fixture }) gestubbt.",
|
|
1470
1835
|
SELECTOR_SECTION: "\u{1F3AF} Selector-Strategie",
|
|
1471
1836
|
SELECTOR_LABEL: "Bevorzugtes Attribut f\xFCr cy.get()",
|
|
1472
1837
|
SELECTOR_OPT_DATACY: "data-cy (Standard)",
|
|
@@ -1514,7 +1879,13 @@ var I18N_DE = {
|
|
|
1514
1879
|
WIDGET_POSITION_SECTION: "\u{1F9F2} Widget-Position",
|
|
1515
1880
|
WIDGET_POSITION_HINT: "Ziehe den Aufnahme-Button, um ihn aus dem Weg zu schieben. Die Position wird gespeichert.",
|
|
1516
1881
|
WIDGET_POSITION_RESET_BTN: "\u21BA Position zur\xFCcksetzen",
|
|
1517
|
-
WIDGET_POSITION_RESET_DONE: "\u2713 Position zur\xFCckgesetzt"
|
|
1882
|
+
WIDGET_POSITION_RESET_DONE: "\u2713 Position zur\xFCckgesetzt",
|
|
1883
|
+
ISSUE_TRACKER_SECTION: "\u{1F3AB} Issue-Tracker",
|
|
1884
|
+
ISSUE_TRACKER_TITLE: "Tests mit Tickets verkn\xFCpfen",
|
|
1885
|
+
ISSUE_TRACKER_SUB: "F\xFCge beim Speichern eine Ticket-ID hinzu und erstelle einen klickbaren Link.",
|
|
1886
|
+
ISSUE_TRACKER_PROVIDER: "Anbieter",
|
|
1887
|
+
ISSUE_TRACKER_BASE_URL: "Basis-URL",
|
|
1888
|
+
ISSUE_TRACKER_BASE_URL_PH: "Z. B.: https://meinprojekt.atlassian.net"
|
|
1518
1889
|
},
|
|
1519
1890
|
SELECTOR_PICKER: {
|
|
1520
1891
|
TITLE: "DOM-Element ausw\xE4hlen",
|
|
@@ -1603,6 +1974,8 @@ var I18N_DE = {
|
|
|
1603
1974
|
FILE_EDITOR_TITLE: "\u270F\uFE0F Datei-Editor",
|
|
1604
1975
|
FILE_SAVED_TOAST: "\u2713 Datei gespeichert",
|
|
1605
1976
|
FILE_SAVE_ERROR_TOAST: "Fehler beim Speichern",
|
|
1977
|
+
FIXTURES_WRITTEN_TOAST: "\u2713 Fixtures in cypress/fixtures geschrieben",
|
|
1978
|
+
FIXTURES_NO_FOLDER_TOAST: "Fixtures konnten nicht geschrieben werden (Cypress-Ordner konfigurieren)",
|
|
1606
1979
|
BTN_CONFIG: "Config",
|
|
1607
1980
|
BTN_FILES: "Dateien",
|
|
1608
1981
|
BTN_COMMANDS: "Befehle",
|
|
@@ -1617,7 +1990,77 @@ var I18N_DE = {
|
|
|
1617
1990
|
SESSION_RESUME_TEXT: "Es gibt eine nicht abgeschlossene aktive Aufzeichnung.",
|
|
1618
1991
|
SESSION_RESUME_COUNT: "erfasste Befehle",
|
|
1619
1992
|
SESSION_CONTINUE_BTN: "Weiter aufzeichnen",
|
|
1620
|
-
SESSION_DISCARD_BTN: "Verwerfen"
|
|
1993
|
+
SESSION_DISCARD_BTN: "Verwerfen",
|
|
1994
|
+
BTN_HELP: "Hilfe"
|
|
1995
|
+
},
|
|
1996
|
+
HELP: {
|
|
1997
|
+
TITLE: "\u2753 Hilfe \u2014 Kurzanleitung",
|
|
1998
|
+
INTRO: "Alles, was der Recorder kann.",
|
|
1999
|
+
SEC_RECORDING: "\u23FA Aufzeichnen",
|
|
2000
|
+
RECORDING_1: "Dr\xFCcke \u23FA (oder Ctrl+R) zum Starten; \u23F9 zum Stoppen und Speichern.",
|
|
2001
|
+
RECORDING_2: "Pause / Fortsetzen mit \u23F8 (oder Ctrl+P).",
|
|
2002
|
+
SEC_SHORTCUTS: "\u2328\uFE0F Tastenk\xFCrzel",
|
|
2003
|
+
SC_RECORD: "Ctrl+R \u2014 Aufzeichnen / stoppen",
|
|
2004
|
+
SC_PAUSE: "Ctrl+P \u2014 Pausieren / fortsetzen",
|
|
2005
|
+
SC_TESTS: "Ctrl+1 \u2014 Panel gespeicherte Tests",
|
|
2006
|
+
SC_COMMANDS: "Ctrl+2 \u2014 Befehle-Panel",
|
|
2007
|
+
SC_CONFIG: "Ctrl+3 \u2014 Einstellungen",
|
|
2008
|
+
SC_VISIBILITY: "Ctrl+Shift+E \u2014 Widget ein-/ausblenden",
|
|
2009
|
+
SC_HELP: "Ctrl+Shift+H \u2014 Diese Hilfe",
|
|
2010
|
+
SEC_CAPTURED: "\u{1F3AF} Was aufgezeichnet wird",
|
|
2011
|
+
CAP_CLICK: "Klick \u2192 .click()",
|
|
2012
|
+
CAP_DBLCLICK: "Doppelklick \u2192 .dblclick()",
|
|
2013
|
+
CAP_RIGHTCLICK: "Rechtsklick \u2192 .rightclick()",
|
|
2014
|
+
CAP_TYPE: "In ein Feld tippen \u2192 .clear().type(...)",
|
|
2015
|
+
CAP_CHECK: "Checkbox / Radio \u2192 .check() / .uncheck()",
|
|
2016
|
+
CAP_SELECT: "<select> \u2192 .select(...)",
|
|
2017
|
+
CAP_KEYS: 'Enter / Escape \u2192 .type("{enter}") / ("{esc}")',
|
|
2018
|
+
CAP_ROUTE: "Routenwechsel (SPA) \u2192 cy.url().should(...)",
|
|
2019
|
+
CAP_HTTP: "fetch / XHR \u2192 cy.intercept + cy.wait",
|
|
2020
|
+
SEC_ASSERT: "\u2705 Assertions",
|
|
2021
|
+
ASSERT_1: "Alt+Klick auf ein Element, um es zu pr\xFCfen, ohne seine Aktion auszul\xF6sen (Text, Wert, checked oder sichtbar).",
|
|
2022
|
+
ASSERT_2: "Oder nutze den Assertion-Builder im Befehle-Panel.",
|
|
2023
|
+
SEC_PANELS: "\u{1F5C2} Panels",
|
|
2024
|
+
PANEL_TESTS: "\u{1F4CB} Tests \u2014 gespeichert: nach Tag filtern, kopieren, kombinieren, exportieren.",
|
|
2025
|
+
PANEL_COMMANDS: "\u2328\uFE0F Befehle \u2014 aktuelle Aufzeichnung: umsortieren, l\xF6schen, Assertions hinzuf\xFCgen.",
|
|
2026
|
+
PANEL_CONFIG: "\u2699\uFE0F Config \u2014 Sprache, Selektor, HTTP, Cypress-Ordner, Daten, Sichtbarkeit, Position.",
|
|
2027
|
+
PANEL_FILES: "\u{1F4C1} Dateien \u2014 Tests in deine .cy.ts einf\xFCgen und den Runner starten.",
|
|
2028
|
+
SEC_SELECTOR: "\u{1F50E} Selektoren",
|
|
2029
|
+
SELECTOR_1: "W\xE4hle das bevorzugte Attribut (data-cy, data-testid, aria-label, id) unter Config.",
|
|
2030
|
+
SELECTOR_2: "Hat ein Klick keinen zuverl\xE4ssigen Selektor, erscheint ein Picker zur Wahl des besten Vorfahren.",
|
|
2031
|
+
SEC_DATA: "\u{1F4BE} Daten",
|
|
2032
|
+
DATA_1: "Tests als JSON exportieren (alle / Auswahl / nach Tags).",
|
|
2033
|
+
DATA_2: "JSON importieren: wird zu deinen Daten hinzugef\xFCgt (nichts wird gel\xF6scht).",
|
|
2034
|
+
SEC_ADVANCED: "\u{1F680} Erweitert",
|
|
2035
|
+
ADV_INVISIBLE: "Unsichtbarer Modus: start-hidden + Ctrl+Shift+E, um in Produktion unauff\xE4llig aufzuzeichnen.",
|
|
2036
|
+
ADV_RUNNER: "Lokaler Runner: npx lib-e2e-cypress-runner, um einen Spec headless aus dem Editor zu starten.",
|
|
2037
|
+
ADV_CROSSAPP: "Cross-App: die Aufzeichnung \xFCbersteht den Wechsel des Micro-Frontends (gleicher Origin).",
|
|
2038
|
+
ADV_DRAG: "Ziehe den \u23FA-Button, um das Widget zu verschieben; die Position wird gemerkt.",
|
|
2039
|
+
CLOSE: "Schlie\xDFen",
|
|
2040
|
+
TAB_REFERENCE: "Kurzreferenz",
|
|
2041
|
+
TAB_GUIDE: "Nutzungsleitfaden",
|
|
2042
|
+
// TODO: translate (de) — usage guide body kept in Spanish for now.
|
|
2043
|
+
GUIDE_INTRO: "C\xF3mo sacarle partido al grabador, qu\xE9 cubre y qu\xE9 no.",
|
|
2044
|
+
G_SEC_WORKFLOW: "\u{1F9ED} Flujo de trabajo",
|
|
2045
|
+
G_WF_1: "1. Pulsa \u23FA (o Ctrl+R) para empezar a grabar.",
|
|
2046
|
+
G_WF_2: "2. Usa tu app como un usuario: clicks, formularios, navegaci\xF3n. Cada acci\xF3n se convierte en un comando Cypress.",
|
|
2047
|
+
G_WF_3: "3. A\xF1ade verificaciones con Alt+click sobre lo que quieras comprobar.",
|
|
2048
|
+
G_WF_4: "4. Pulsa \u23F9 para parar; ponle nombre y tags, y gu\xE1rdalo.",
|
|
2049
|
+
G_WF_5: "5. En \u{1F4C1} Ficheros, inserta el test en un .cy.ts o l\xE1nzalo con el runner local.",
|
|
2050
|
+
G_SEC_COVERED: "\u2705 Qu\xE9 cubre",
|
|
2051
|
+
G_COV_1: "Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.",
|
|
2052
|
+
G_COV_2: "Navegaci\xF3n SPA (pushState/replaceState/popstate) \u2192 cy.url().should(...).",
|
|
2053
|
+
G_COV_3: "Llamadas fetch/XHR (GET/POST/PUT) \u2192 cy.intercept + cy.wait, con validaci\xF3n de body opcional.",
|
|
2054
|
+
G_COV_4: "Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.",
|
|
2055
|
+
G_COV_5: "Aserciones autom\xE1ticas (Alt+click) y constructor manual.",
|
|
2056
|
+
G_COV_6: "Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.",
|
|
2057
|
+
G_SEC_NOTCOVERED: "\u{1F6AB} Qu\xE9 NO cubre (por ahora)",
|
|
2058
|
+
G_NC_1: "Or\xEDgenes distintos / subdominios (solo mismo origen).",
|
|
2059
|
+
G_NC_2: "Subida de ficheros (selectFile), arrastrar y soltar, y hover.",
|
|
2060
|
+
G_NC_3: "La tecla Tab (Cypress no la soporta en .type()).",
|
|
2061
|
+
G_NC_4: "Peticiones DELETE (se ignoran a prop\xF3sito).",
|
|
2062
|
+
G_NC_5: "iframes y Shadow DOM de terceros pueden no capturarse.",
|
|
2063
|
+
G_NC_6: "Generaci\xF3n de login program\xE1tico (en el roadmap)."
|
|
1621
2064
|
}
|
|
1622
2065
|
};
|
|
1623
2066
|
|
|
@@ -1750,6 +2193,32 @@ var advancedTestTransformationService = new AdvancedTestTransformationService();
|
|
|
1750
2193
|
|
|
1751
2194
|
// src/services/recording.service.ts
|
|
1752
2195
|
init_selector_quality_utils();
|
|
2196
|
+
|
|
2197
|
+
// src/utils/assertion.utils.ts
|
|
2198
|
+
var MAX_TEXT_LENGTH = 60;
|
|
2199
|
+
function inferAssertionCommand(el, selector) {
|
|
2200
|
+
const should = (body) => `cy.get('${selector}').should(${body})`;
|
|
2201
|
+
const tag = el.tagName.toLowerCase();
|
|
2202
|
+
if (tag === "input") {
|
|
2203
|
+
const input = el;
|
|
2204
|
+
const type = (input.getAttribute("type") ?? "text").toLowerCase();
|
|
2205
|
+
if (type === "checkbox" || type === "radio") {
|
|
2206
|
+
return should(`'${input.checked ? "be.checked" : "not.be.checked"}'`);
|
|
2207
|
+
}
|
|
2208
|
+
return input.value ? should(`'have.value', '${escapeSingleQuotes(input.value)}'`) : should(`'be.visible'`);
|
|
2209
|
+
}
|
|
2210
|
+
if (tag === "textarea" || tag === "select") {
|
|
2211
|
+
const value = el.value;
|
|
2212
|
+
return value ? should(`'have.value', '${escapeSingleQuotes(value)}'`) : should(`'be.visible'`);
|
|
2213
|
+
}
|
|
2214
|
+
const text = (el.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
2215
|
+
if (text && text.length <= MAX_TEXT_LENGTH) {
|
|
2216
|
+
return should(`'contain.text', '${escapeSingleQuotes(text)}'`);
|
|
2217
|
+
}
|
|
2218
|
+
return should(`'be.visible'`);
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
// src/services/recording.service.ts
|
|
1753
2222
|
var OWN_SELECTOR = '[data-cy="lib-e2e-cypress-for-dummys"]';
|
|
1754
2223
|
function createSessionId() {
|
|
1755
2224
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
@@ -1764,6 +2233,7 @@ var RecordingService = class {
|
|
|
1764
2233
|
isPaused$ = new Subject(false);
|
|
1765
2234
|
selectorNotFound$ = new Subject(null);
|
|
1766
2235
|
inputDebounceTimers = /* @__PURE__ */ new Map();
|
|
2236
|
+
fixtures = /* @__PURE__ */ new Map();
|
|
1767
2237
|
abort = new AbortController();
|
|
1768
2238
|
selectorStrategy = "data-cy";
|
|
1769
2239
|
/** Stable id of the current live session (null when none has started). */
|
|
@@ -1773,13 +2243,18 @@ var RecordingService = class {
|
|
|
1773
2243
|
origPushState = history.pushState.bind(history);
|
|
1774
2244
|
origReplaceState = history.replaceState.bind(history);
|
|
1775
2245
|
constructor() {
|
|
2246
|
+
this.listenToAssertClicks();
|
|
1776
2247
|
this.listenToClicks();
|
|
2248
|
+
this.listenToDoubleClicks();
|
|
2249
|
+
this.listenToContextMenu();
|
|
1777
2250
|
this.listenToInput();
|
|
1778
2251
|
this.listenToSelect();
|
|
2252
|
+
this.listenToKeys();
|
|
1779
2253
|
this.listenToRouteChanges();
|
|
1780
2254
|
}
|
|
1781
2255
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
1782
2256
|
startRecording() {
|
|
2257
|
+
this.clearCommands();
|
|
1783
2258
|
this.sessionId = createSessionId();
|
|
1784
2259
|
this.startedAt = Date.now();
|
|
1785
2260
|
this.isPaused$.next(false);
|
|
@@ -1866,17 +2341,27 @@ var RecordingService = class {
|
|
|
1866
2341
|
if (index < 0 || index >= ints.length) return;
|
|
1867
2342
|
this.interceptors$.next([...ints.slice(0, index), ...ints.slice(index + 1)]);
|
|
1868
2343
|
}
|
|
1869
|
-
registerInterceptor(method, url, alias) {
|
|
2344
|
+
registerInterceptor(method, url, alias, fixtureFile) {
|
|
1870
2345
|
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
1871
|
-
const
|
|
2346
|
+
const wildcard = this.urlToWildcard(url, method);
|
|
2347
|
+
const command = fixtureFile ? `cy.intercept('${method}', '${wildcard}', { fixture: '${fixtureFile}' }).as('${alias}')` : `cy.intercept('${method}', '${wildcard}').as('${alias}')`;
|
|
1872
2348
|
const current = this.interceptors$.getValue();
|
|
1873
2349
|
if (!current.includes(command)) {
|
|
1874
2350
|
this.interceptors$.next([...current, command]);
|
|
1875
2351
|
}
|
|
1876
2352
|
}
|
|
2353
|
+
/** Registers a captured response as a Cypress fixture (name → JSON content). */
|
|
2354
|
+
registerFixture(name, content) {
|
|
2355
|
+
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2356
|
+
this.fixtures.set(name, content);
|
|
2357
|
+
}
|
|
2358
|
+
getFixturesSnapshot() {
|
|
2359
|
+
return [...this.fixtures.entries()].map(([name, content]) => ({ name, content }));
|
|
2360
|
+
}
|
|
1877
2361
|
clearCommands() {
|
|
1878
2362
|
this.commands$.next([]);
|
|
1879
2363
|
this.interceptors$.next([]);
|
|
2364
|
+
this.fixtures.clear();
|
|
1880
2365
|
}
|
|
1881
2366
|
clearInterceptors() {
|
|
1882
2367
|
this.interceptors$.next([]);
|
|
@@ -1930,6 +2415,39 @@ var RecordingService = class {
|
|
|
1930
2415
|
this.inputDebounceTimers.clear();
|
|
1931
2416
|
}
|
|
1932
2417
|
// ── DOM listeners ─────────────────────────────────────────────────────────
|
|
2418
|
+
/**
|
|
2419
|
+
* Alt+click captures an ASSERTION for the element instead of a click, and
|
|
2420
|
+
* suppresses the element's real action. Runs in the capture phase so it fires
|
|
2421
|
+
* before the app's handlers and before the bubble-phase click listener below
|
|
2422
|
+
* (stopImmediatePropagation prevents a duplicate `.click()`). See spec 009.
|
|
2423
|
+
*/
|
|
2424
|
+
listenToAssertClicks() {
|
|
2425
|
+
document.addEventListener(
|
|
2426
|
+
"click",
|
|
2427
|
+
(e) => {
|
|
2428
|
+
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2429
|
+
if (!e.altKey) return;
|
|
2430
|
+
const target = e.target;
|
|
2431
|
+
if (!target || this.isOwnElement(target)) return;
|
|
2432
|
+
const tag = target.tagName?.toLowerCase();
|
|
2433
|
+
if (tag === "body" || tag === "html") return;
|
|
2434
|
+
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2435
|
+
if (!container) return;
|
|
2436
|
+
const selector = this.getReliableSelector(container);
|
|
2437
|
+
if (!selector || this.isOwnSelector(selector)) return;
|
|
2438
|
+
e.preventDefault();
|
|
2439
|
+
e.stopImmediatePropagation();
|
|
2440
|
+
const emit = () => this.addCommand(inferAssertionCommand(container, selector));
|
|
2441
|
+
const type = (container.getAttribute("type") ?? "").toLowerCase();
|
|
2442
|
+
if (container.tagName.toLowerCase() === "input" && (type === "checkbox" || type === "radio")) {
|
|
2443
|
+
queueMicrotask(emit);
|
|
2444
|
+
} else {
|
|
2445
|
+
emit();
|
|
2446
|
+
}
|
|
2447
|
+
},
|
|
2448
|
+
{ capture: true, signal: this.abort.signal }
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
1933
2451
|
listenToClicks() {
|
|
1934
2452
|
document.addEventListener(
|
|
1935
2453
|
"click",
|
|
@@ -1944,6 +2462,70 @@ var RecordingService = class {
|
|
|
1944
2462
|
{ signal: this.abort.signal }
|
|
1945
2463
|
);
|
|
1946
2464
|
}
|
|
2465
|
+
/** Centralised selector resolution for the pointer/key listeners (spec 010). */
|
|
2466
|
+
resolveSelectorFor(target) {
|
|
2467
|
+
if (!target || this.isOwnElement(target)) return null;
|
|
2468
|
+
const tag = target.tagName?.toLowerCase();
|
|
2469
|
+
if (tag === "body" || tag === "html") return null;
|
|
2470
|
+
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2471
|
+
if (!container) return null;
|
|
2472
|
+
const selector = this.getReliableSelector(container);
|
|
2473
|
+
if (!selector || this.isOwnSelector(selector)) return null;
|
|
2474
|
+
return selector;
|
|
2475
|
+
}
|
|
2476
|
+
listenToDoubleClicks() {
|
|
2477
|
+
document.addEventListener(
|
|
2478
|
+
"dblclick",
|
|
2479
|
+
(e) => {
|
|
2480
|
+
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2481
|
+
if (e.altKey) return;
|
|
2482
|
+
const selector = this.resolveSelectorFor(e.target);
|
|
2483
|
+
if (!selector) return;
|
|
2484
|
+
const clickCmd = `cy.get('${selector}').click()`;
|
|
2485
|
+
let cmds = this.commands$.getValue();
|
|
2486
|
+
let removed = 0;
|
|
2487
|
+
while (removed < 2 && cmds.length > 0 && cmds[cmds.length - 1] === clickCmd) {
|
|
2488
|
+
cmds = cmds.slice(0, -1);
|
|
2489
|
+
removed++;
|
|
2490
|
+
}
|
|
2491
|
+
if (removed > 0) this.commands$.next(cmds);
|
|
2492
|
+
this.addCommand(`cy.get('${selector}').dblclick()`);
|
|
2493
|
+
},
|
|
2494
|
+
{ signal: this.abort.signal }
|
|
2495
|
+
);
|
|
2496
|
+
}
|
|
2497
|
+
listenToContextMenu() {
|
|
2498
|
+
document.addEventListener(
|
|
2499
|
+
"contextmenu",
|
|
2500
|
+
(e) => {
|
|
2501
|
+
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2502
|
+
const selector = this.resolveSelectorFor(e.target);
|
|
2503
|
+
if (!selector) return;
|
|
2504
|
+
this.addCommand(`cy.get('${selector}').rightclick()`);
|
|
2505
|
+
},
|
|
2506
|
+
{ signal: this.abort.signal }
|
|
2507
|
+
);
|
|
2508
|
+
}
|
|
2509
|
+
/** Enter → type('{enter}'), Escape → type('{esc}'), only inside a field. */
|
|
2510
|
+
listenToKeys() {
|
|
2511
|
+
document.addEventListener(
|
|
2512
|
+
"keydown",
|
|
2513
|
+
(e) => {
|
|
2514
|
+
if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;
|
|
2515
|
+
const key = e.key;
|
|
2516
|
+
if (key !== "Enter" && key !== "Escape") return;
|
|
2517
|
+
const target = e.target;
|
|
2518
|
+
const tag = target?.tagName?.toLowerCase();
|
|
2519
|
+
if (tag !== "input" && tag !== "textarea" && tag !== "select") return;
|
|
2520
|
+
const selector = this.resolveSelectorFor(target);
|
|
2521
|
+
if (!selector) return;
|
|
2522
|
+
this.flushInputDebounce(target);
|
|
2523
|
+
const token = key === "Enter" ? "{enter}" : "{esc}";
|
|
2524
|
+
this.addCommand(`cy.get('${selector}').type('${token}')`);
|
|
2525
|
+
},
|
|
2526
|
+
{ signal: this.abort.signal }
|
|
2527
|
+
);
|
|
2528
|
+
}
|
|
1947
2529
|
listenToInput() {
|
|
1948
2530
|
document.addEventListener(
|
|
1949
2531
|
"input",
|
|
@@ -2022,11 +2604,32 @@ var RecordingService = class {
|
|
|
2022
2604
|
}
|
|
2023
2605
|
return;
|
|
2024
2606
|
}
|
|
2607
|
+
if (!this.isInteractiveElement(target)) {
|
|
2608
|
+
const interactive = target.closest(
|
|
2609
|
+
'button,a,input,select,textarea,label,summary,mat-option,[role="button"],[role="link"],[role="menuitem"],[role="option"],[role="tab"]'
|
|
2610
|
+
);
|
|
2611
|
+
if (!interactive) return;
|
|
2612
|
+
target = interactive;
|
|
2613
|
+
}
|
|
2025
2614
|
}
|
|
2026
2615
|
const tag = target.tagName.toLowerCase();
|
|
2027
2616
|
if (tag === "input" || tag === "textarea" || tag === "select") {
|
|
2028
2617
|
const container2 = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2029
|
-
if (!container2)
|
|
2618
|
+
if (!container2) {
|
|
2619
|
+
this.selectorNotFound$.next({ target, action: "click" });
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
if (tag === "input") {
|
|
2623
|
+
const input = target;
|
|
2624
|
+
const type = (input.getAttribute("type") ?? "").toLowerCase();
|
|
2625
|
+
if (type === "checkbox" || type === "radio") {
|
|
2626
|
+
const selector2 = this.getReliableSelector(container2);
|
|
2627
|
+
if (selector2 && !this.isOwnSelector(selector2)) {
|
|
2628
|
+
const action = type === "radio" || input.checked ? "check" : "uncheck";
|
|
2629
|
+
this.addCommand(`cy.get('${selector2}').${action}()`);
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2030
2633
|
return;
|
|
2031
2634
|
}
|
|
2032
2635
|
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
@@ -2040,6 +2643,10 @@ var RecordingService = class {
|
|
|
2040
2643
|
this.handleMatOptionClick(target, selector);
|
|
2041
2644
|
return;
|
|
2042
2645
|
}
|
|
2646
|
+
if (!selector) {
|
|
2647
|
+
this.selectorNotFound$.next({ target, action: "click" });
|
|
2648
|
+
return;
|
|
2649
|
+
}
|
|
2043
2650
|
this.addGenericCommand({
|
|
2044
2651
|
selector,
|
|
2045
2652
|
action: (s) => `cy.get('${s}').click()`
|
|
@@ -2073,16 +2680,30 @@ var RecordingService = class {
|
|
|
2073
2680
|
this.inputDebounceTimers.set(
|
|
2074
2681
|
target,
|
|
2075
2682
|
setTimeout(() => {
|
|
2076
|
-
const selector = this.getReliableSelector(container);
|
|
2077
|
-
const value = target.value.replace(/'/g, "\\'");
|
|
2078
|
-
this.addGenericCommand({
|
|
2079
|
-
selector,
|
|
2080
|
-
action: (s) => `cy.get('${s}').clear().type('${value}')`
|
|
2081
|
-
});
|
|
2082
2683
|
this.inputDebounceTimers.delete(target);
|
|
2684
|
+
this.recordInputValue(target);
|
|
2083
2685
|
}, 1e3)
|
|
2084
2686
|
);
|
|
2085
2687
|
}
|
|
2688
|
+
/** Records a text field's current value as a `clear().type()` command. */
|
|
2689
|
+
recordInputValue(target) {
|
|
2690
|
+
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
2691
|
+
if (!container) return;
|
|
2692
|
+
const selector = this.getReliableSelector(container);
|
|
2693
|
+
const value = target.value.replace(/'/g, "\\'");
|
|
2694
|
+
this.addGenericCommand({
|
|
2695
|
+
selector,
|
|
2696
|
+
action: (s) => `cy.get('${s}').clear().type('${value}')`
|
|
2697
|
+
});
|
|
2698
|
+
}
|
|
2699
|
+
/** Flushes any pending debounced value for an element, recording it now. */
|
|
2700
|
+
flushInputDebounce(target) {
|
|
2701
|
+
const timer = this.inputDebounceTimers.get(target);
|
|
2702
|
+
if (timer === void 0) return;
|
|
2703
|
+
clearTimeout(timer);
|
|
2704
|
+
this.inputDebounceTimers.delete(target);
|
|
2705
|
+
this.recordInputValue(target);
|
|
2706
|
+
}
|
|
2086
2707
|
// ── Select helpers ────────────────────────────────────────────────────────
|
|
2087
2708
|
handleSelectEvent(target) {
|
|
2088
2709
|
const container = target.closest("[data-cy], [data-testid], [aria-label], [id]");
|
|
@@ -2177,9 +2798,9 @@ var PersistenceService = class {
|
|
|
2177
2798
|
return this._db;
|
|
2178
2799
|
}
|
|
2179
2800
|
// ── Tests ─────────────────────────────────────────────────────────────────
|
|
2180
|
-
async insertTest(name, commands = [], interceptors = [], tags = [], notes) {
|
|
2801
|
+
async insertTest(name, commands = [], interceptors = [], tags = [], notes, ticketId) {
|
|
2181
2802
|
const db = await this.getDB();
|
|
2182
|
-
const record = { name, createdAt: Date.now(), ...tags.length ? { tags } : {}, ...notes ? { notes } : {} };
|
|
2803
|
+
const record = { name, createdAt: Date.now(), ...tags.length ? { tags } : {}, ...notes ? { notes } : {}, ...ticketId ? { ticketId } : {} };
|
|
2183
2804
|
const id = await db.add("tests", record);
|
|
2184
2805
|
if (commands.length) await this.insertCommands(commands, id);
|
|
2185
2806
|
if (interceptors.length) await this.insertInterceptors(interceptors, id);
|
|
@@ -2333,6 +2954,31 @@ ${commands.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
|
2333
2954
|
await this.setConfigKey("cypressDirectoryHandle", dirHandle);
|
|
2334
2955
|
await this.setConfigKey("allowReadWriteFiles", "true");
|
|
2335
2956
|
}
|
|
2957
|
+
/**
|
|
2958
|
+
* Writes captured fixtures into `cypress/fixtures/` using the configured Cypress
|
|
2959
|
+
* folder handle (spec 012). Returns the number written. Throws if no folder is
|
|
2960
|
+
* configured or write permission is denied.
|
|
2961
|
+
*/
|
|
2962
|
+
async writeFixtures(fixtures) {
|
|
2963
|
+
if (!fixtures.length) return 0;
|
|
2964
|
+
const config = await this.getGeneralConfig();
|
|
2965
|
+
const dirHandle = config?.["cypressDirectoryHandle"];
|
|
2966
|
+
if (!dirHandle) throw new Error("No Cypress folder configured");
|
|
2967
|
+
const perm = dirHandle;
|
|
2968
|
+
let state = await perm.queryPermission({ mode: "readwrite" });
|
|
2969
|
+
if (state !== "granted") state = await perm.requestPermission({ mode: "readwrite" });
|
|
2970
|
+
if (state !== "granted") throw new Error("Write permission denied");
|
|
2971
|
+
const fixturesDir = await dirHandle.getDirectoryHandle("fixtures", { create: true });
|
|
2972
|
+
let written = 0;
|
|
2973
|
+
for (const fx of fixtures) {
|
|
2974
|
+
const fileHandle = await fixturesDir.getFileHandle(fx.name, { create: true });
|
|
2975
|
+
const writable = await fileHandle.createWritable();
|
|
2976
|
+
await writable.write(fx.content);
|
|
2977
|
+
await writable.close();
|
|
2978
|
+
written++;
|
|
2979
|
+
}
|
|
2980
|
+
return written;
|
|
2981
|
+
}
|
|
2336
2982
|
async bulkInsertWithoutId(store, items) {
|
|
2337
2983
|
if (!Array.isArray(items)) return;
|
|
2338
2984
|
const db = await this.getDB();
|
|
@@ -2385,6 +3031,14 @@ function parseJsonObject(text) {
|
|
|
2385
3031
|
}
|
|
2386
3032
|
return null;
|
|
2387
3033
|
}
|
|
3034
|
+
function prettyJsonOrNull(text) {
|
|
3035
|
+
try {
|
|
3036
|
+
const parsed = JSON.parse(text);
|
|
3037
|
+
if (parsed && typeof parsed === "object") return JSON.stringify(parsed, null, 2);
|
|
3038
|
+
} catch {
|
|
3039
|
+
}
|
|
3040
|
+
return null;
|
|
3041
|
+
}
|
|
2388
3042
|
function parseRequestBody(init) {
|
|
2389
3043
|
const body = init?.body;
|
|
2390
3044
|
if (typeof body === "string") return parseJsonObject(body);
|
|
@@ -2418,6 +3072,9 @@ var HttpMonitor = class {
|
|
|
2418
3072
|
isExtendedHttpEnabled() {
|
|
2419
3073
|
return localStorage.getItem("extendedHttpCommands") === "true";
|
|
2420
3074
|
}
|
|
3075
|
+
isFixtureModeEnabled() {
|
|
3076
|
+
return localStorage.getItem("fixtureMode") === "true";
|
|
3077
|
+
}
|
|
2421
3078
|
installFetch() {
|
|
2422
3079
|
if (this.originalFetch) return;
|
|
2423
3080
|
const originalFetch = window.fetch;
|
|
@@ -2481,14 +3138,21 @@ var HttpMonitor = class {
|
|
|
2481
3138
|
const alias = generateAlias(method, url);
|
|
2482
3139
|
this.recording.registerInterceptor(method, url, alias);
|
|
2483
3140
|
const extendedHttp = this.isExtendedHttpEnabled();
|
|
3141
|
+
const fixtureMode = this.isFixtureModeEnabled();
|
|
2484
3142
|
const requestBody = extendedHttp ? parseRequestBody(init) : null;
|
|
3143
|
+
let responseText = null;
|
|
2485
3144
|
let responseBody = null;
|
|
2486
|
-
if (extendedHttp) {
|
|
3145
|
+
if (extendedHttp || fixtureMode && method === "GET") {
|
|
2487
3146
|
try {
|
|
2488
|
-
|
|
3147
|
+
responseText = await responseClone.text();
|
|
3148
|
+
if (extendedHttp) responseBody = parseJsonObject(responseText);
|
|
2489
3149
|
} catch {
|
|
2490
3150
|
}
|
|
2491
3151
|
}
|
|
3152
|
+
if (fixtureMode && method === "GET" && responseText !== null) {
|
|
3153
|
+
const pretty = prettyJsonOrNull(responseText);
|
|
3154
|
+
if (pretty !== null) this.recording.registerFixture(`${alias}.json`, pretty);
|
|
3155
|
+
}
|
|
2492
3156
|
const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);
|
|
2493
3157
|
this.recording.addCommand(cmd);
|
|
2494
3158
|
}
|
|
@@ -2496,6 +3160,10 @@ var HttpMonitor = class {
|
|
|
2496
3160
|
if (!INTERCEPTED_METHODS.includes(method)) return;
|
|
2497
3161
|
const alias = generateAlias(method, url);
|
|
2498
3162
|
this.recording.registerInterceptor(method, url, alias);
|
|
3163
|
+
if (this.isFixtureModeEnabled() && method === "GET") {
|
|
3164
|
+
const pretty = prettyJsonOrNull(responseText);
|
|
3165
|
+
if (pretty !== null) this.recording.registerFixture(`${alias}.json`, pretty);
|
|
3166
|
+
}
|
|
2499
3167
|
const extendedHttp = this.isExtendedHttpEnabled();
|
|
2500
3168
|
const responseBody = extendedHttp ? parseJsonObject(responseText) : null;
|
|
2501
3169
|
const cmd = buildCyWaitCommand(method, alias, extendedHttp, requestBody, responseBody);
|
|
@@ -2613,6 +3281,10 @@ var LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES = `
|
|
|
2613
3281
|
align-items: stretch;
|
|
2614
3282
|
box-sizing: border-box;
|
|
2615
3283
|
overflow: hidden !important;
|
|
3284
|
+
/* Left-align modal body text/code (SweetAlert defaults it to centre, which
|
|
3285
|
+
inherits into the panels \u2014 including their shadow DOM). Titles/buttons keep
|
|
3286
|
+
their own alignment. */
|
|
3287
|
+
text-align: left !important;
|
|
2616
3288
|
}
|
|
2617
3289
|
/* The single wrapper div we inject inside each modal fills the container */
|
|
2618
3290
|
.swal2-html-container > div {
|
|
@@ -3021,12 +3693,39 @@ if (!customElements.get("test-previsualizer")) {
|
|
|
3021
3693
|
customElements.define("test-previsualizer", TestPrevisualizerElement);
|
|
3022
3694
|
}
|
|
3023
3695
|
|
|
3696
|
+
// src/models/issue-tracker.model.ts
|
|
3697
|
+
var ISSUE_TRACKER_PRESETS = {
|
|
3698
|
+
jira: { id: "jira", label: "Jira", urlPattern: "{baseUrl}/browse/{id}", idPattern: /^[A-Z][A-Z0-9]+-\d+$/ },
|
|
3699
|
+
github: { id: "github", label: "GitHub Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
3700
|
+
gitlab: { id: "gitlab", label: "GitLab Issues", urlPattern: "{baseUrl}/-/issues/{id}", idPattern: /^\d+$/ },
|
|
3701
|
+
azure: { id: "azure", label: "Azure DevOps", urlPattern: "{baseUrl}/_workitems/edit/{id}", idPattern: /^\d+$/ },
|
|
3702
|
+
bitbucket: { id: "bitbucket", label: "Bitbucket Issues", urlPattern: "{baseUrl}/issues/{id}", idPattern: /^\d+$/ },
|
|
3703
|
+
custom: { id: "custom", label: "Custom", urlPattern: "{baseUrl}/{id}", idPattern: /.+/ }
|
|
3704
|
+
};
|
|
3705
|
+
var DEFAULT_ISSUE_TRACKER_CONFIG = {
|
|
3706
|
+
enabled: false,
|
|
3707
|
+
provider: "jira",
|
|
3708
|
+
baseUrl: ""
|
|
3709
|
+
};
|
|
3710
|
+
|
|
3711
|
+
// src/utils/ticket.utils.ts
|
|
3712
|
+
function buildTicketUrl(ticketId, config) {
|
|
3713
|
+
if (!config.enabled || !ticketId.trim() || !config.baseUrl.trim()) return null;
|
|
3714
|
+
const preset = ISSUE_TRACKER_PRESETS[config.provider];
|
|
3715
|
+
const base = config.baseUrl.replace(/\/+$/, "");
|
|
3716
|
+
return preset.urlPattern.replace("{baseUrl}", base).replace("{id}", encodeURIComponent(ticketId.trim()));
|
|
3717
|
+
}
|
|
3718
|
+
function isValidTicketId(ticketId, provider) {
|
|
3719
|
+
if (!ticketId.trim()) return false;
|
|
3720
|
+
return ISSUE_TRACKER_PRESETS[provider].idPattern.test(ticketId.trim());
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3024
3723
|
// src/components/save-test/save-test.styles.ts
|
|
3025
3724
|
var SAVE_TEST_STYLES = `
|
|
3026
3725
|
:host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }
|
|
3027
3726
|
* { box-sizing: border-box; }
|
|
3028
3727
|
.container { padding: 24px 28px; text-align: left; }
|
|
3029
|
-
.btn-row
|
|
3728
|
+
.btn-row { text-align: center; }
|
|
3030
3729
|
p { margin: 0 0 20px; font-size: 14px; color: #8b949e; line-height: 1.5; }
|
|
3031
3730
|
.btn-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }
|
|
3032
3731
|
button {
|
|
@@ -3096,10 +3795,15 @@ function renderSaveTestAsk(t) {
|
|
|
3096
3795
|
</div>
|
|
3097
3796
|
</div>`;
|
|
3098
3797
|
}
|
|
3099
|
-
function renderSaveTestDesc(description, notes, tags, t) {
|
|
3798
|
+
function renderSaveTestDesc(description, notes, tags, ticketId, issueTrackerEnabled, ticketWarn, t) {
|
|
3100
3799
|
const chipsHtml = tags.map(
|
|
3101
3800
|
(tag) => `<span class="chip">${escHtml(tag)}<button class="chip-del" data-tag="${escAttr(tag)}" title="${t("SAVE_TEST.REMOVE_TAG_TITLE")}">\u2715</button></span>`
|
|
3102
3801
|
).join("");
|
|
3802
|
+
const ticketHtml = issueTrackerEnabled ? `
|
|
3803
|
+
<span class="tag-label">${t("SAVE_TEST.TICKET_LABEL")}</span>
|
|
3804
|
+
<input id="ticket-input" type="text" placeholder="${escAttr(t("SAVE_TEST.TICKET_PLACEHOLDER"))}"
|
|
3805
|
+
value="${escAttr(ticketId)}" autocomplete="off" />
|
|
3806
|
+
${ticketWarn ? `<span class="ticket-warn">\u26A0 ${t("SAVE_TEST.TICKET_WARN")}</span>` : ""}` : "";
|
|
3103
3807
|
return `
|
|
3104
3808
|
<div class="container">
|
|
3105
3809
|
<p>${t("SAVE_TEST.DESC_LABEL")} (<code>it()</code>):</p>
|
|
@@ -3113,6 +3817,7 @@ function renderSaveTestDesc(description, notes, tags, t) {
|
|
|
3113
3817
|
<button class="btn-tag-add" id="btn-add-tag">${t("SAVE_TEST.ADD_TAG")}</button>
|
|
3114
3818
|
</div>
|
|
3115
3819
|
<div class="chips" id="chips-container">${chipsHtml || `<span style="color:#484f58;font-size:11px">${t("SAVE_TEST.NO_TAGS")}</span>`}</div>
|
|
3820
|
+
${ticketHtml}
|
|
3116
3821
|
<div class="btn-row">
|
|
3117
3822
|
<button class="btn-primary" id="btn-confirm">${t("SAVE_TEST.SAVE_BTN")}</button>
|
|
3118
3823
|
<button class="btn-success" id="btn-export">${t("SAVE_TEST.SAVE_AND_EDIT")}</button>
|
|
@@ -3128,6 +3833,8 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
3128
3833
|
description = "";
|
|
3129
3834
|
notes = "";
|
|
3130
3835
|
tags = [];
|
|
3836
|
+
ticketId = "";
|
|
3837
|
+
issueTrackerConfig = DEFAULT_ISSUE_TRACKER_CONFIG;
|
|
3131
3838
|
translation = translationService;
|
|
3132
3839
|
constructor() {
|
|
3133
3840
|
super();
|
|
@@ -3144,19 +3851,20 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
3144
3851
|
this.render();
|
|
3145
3852
|
}
|
|
3146
3853
|
confirmSave() {
|
|
3147
|
-
this.dispatch("savetest", { description: this.description.trim(), notes: this.notes, tags: [...this.tags] });
|
|
3854
|
+
this.dispatch("savetest", { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() });
|
|
3148
3855
|
}
|
|
3149
3856
|
confirmSaveAndExport() {
|
|
3150
|
-
this.dispatch("saveandexport", { description: this.description.trim(), notes: this.notes, tags: [...this.tags] });
|
|
3857
|
+
this.dispatch("saveandexport", { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() });
|
|
3151
3858
|
}
|
|
3152
3859
|
cancel() {
|
|
3153
|
-
this.dispatch("savetest", { description: null, notes: "", tags: [] });
|
|
3860
|
+
this.dispatch("savetest", { description: null, notes: "", tags: [], ticketId: "" });
|
|
3154
3861
|
}
|
|
3155
3862
|
restartComponent() {
|
|
3156
3863
|
this._step = "ask";
|
|
3157
3864
|
this.description = "";
|
|
3158
3865
|
this.notes = "";
|
|
3159
3866
|
this.tags = [];
|
|
3867
|
+
this.ticketId = "";
|
|
3160
3868
|
this.render();
|
|
3161
3869
|
}
|
|
3162
3870
|
addTag(tag) {
|
|
@@ -3173,6 +3881,10 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
3173
3881
|
t(key) {
|
|
3174
3882
|
return this.translation.translate(key);
|
|
3175
3883
|
}
|
|
3884
|
+
get ticketIdWarning() {
|
|
3885
|
+
if (!this.ticketId.trim() || !this.issueTrackerConfig.enabled) return false;
|
|
3886
|
+
return !isValidTicketId(this.ticketId, this.issueTrackerConfig.provider);
|
|
3887
|
+
}
|
|
3176
3888
|
dispatch(type, detail) {
|
|
3177
3889
|
this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));
|
|
3178
3890
|
}
|
|
@@ -3182,16 +3894,21 @@ var SaveTestElement = class extends HTMLElement {
|
|
|
3182
3894
|
this.shadow.getElementById("btn-yes")?.addEventListener("click", () => this.askSave());
|
|
3183
3895
|
this.shadow.getElementById("btn-no")?.addEventListener("click", () => this.cancel());
|
|
3184
3896
|
} else {
|
|
3185
|
-
this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.t.bind(this))}`;
|
|
3897
|
+
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))}`;
|
|
3186
3898
|
const descInput = this.shadow.getElementById("desc-input");
|
|
3187
3899
|
const notesInput = this.shadow.getElementById("notes-input");
|
|
3188
3900
|
const tagInput = this.shadow.getElementById("tag-input");
|
|
3901
|
+
const ticketInput = this.shadow.getElementById("ticket-input");
|
|
3189
3902
|
descInput.addEventListener("input", () => {
|
|
3190
3903
|
this.description = descInput.value;
|
|
3191
3904
|
});
|
|
3192
3905
|
notesInput.addEventListener("input", () => {
|
|
3193
3906
|
this.notes = notesInput.value;
|
|
3194
3907
|
});
|
|
3908
|
+
ticketInput?.addEventListener("input", () => {
|
|
3909
|
+
this.ticketId = ticketInput.value;
|
|
3910
|
+
this.render();
|
|
3911
|
+
});
|
|
3195
3912
|
const tryAddTag = () => {
|
|
3196
3913
|
this.addTag(tagInput.value);
|
|
3197
3914
|
tagInput.value = "";
|
|
@@ -3283,6 +4000,18 @@ var TEST_EDITOR_STYLES = `
|
|
|
3283
4000
|
padding: 1px 7px; border-radius: 20px; font-size: 10px;
|
|
3284
4001
|
background: rgba(47,129,247,0.1); color: #8b949e; border: 1px solid rgba(47,129,247,0.2);
|
|
3285
4002
|
}
|
|
4003
|
+
.ticket-badge, .ticket-link {
|
|
4004
|
+
padding: 1px 7px; border-radius: 20px; font-size: 10px; font-weight: 500;
|
|
4005
|
+
background: rgba(210,153,34,0.12); color: #d29922; border: 1px solid rgba(210,153,34,0.3);
|
|
4006
|
+
white-space: nowrap; flex-shrink: 0;
|
|
4007
|
+
}
|
|
4008
|
+
.ticket-link {
|
|
4009
|
+
text-decoration: none; cursor: pointer;
|
|
4010
|
+
transition: background 0.12s, border-color 0.12s;
|
|
4011
|
+
}
|
|
4012
|
+
.ticket-link::before { content: '\u{1F3AB} '; font-size: 9px; }
|
|
4013
|
+
.ticket-link:hover { background: rgba(210,153,34,0.22); border-color: rgba(210,153,34,0.55); color: #e3b341; }
|
|
4014
|
+
.ticket-badge::before { content: '\u{1F3AB} '; font-size: 9px; }
|
|
3286
4015
|
.btn-icon {
|
|
3287
4016
|
padding: 3px 8px; border: none; border-radius: 6px; cursor: pointer;
|
|
3288
4017
|
font-size: 11px; background: #21262d; color: #8b949e;
|
|
@@ -3314,6 +4043,13 @@ var TEST_EDITOR_STYLES = `
|
|
|
3314
4043
|
.code-preview::-webkit-scrollbar { height: 4px; }
|
|
3315
4044
|
.code-preview::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }
|
|
3316
4045
|
.code-preview-icp { margin-top: 8px; }
|
|
4046
|
+
.ticket-group { margin-bottom: 8px; }
|
|
4047
|
+
.ticket-group-header {
|
|
4048
|
+
padding: 4px 10px; margin-bottom: 4px;
|
|
4049
|
+
font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.7px;
|
|
4050
|
+
color: #d29922; border-left: 3px solid rgba(210,153,34,0.5);
|
|
4051
|
+
background: rgba(210,153,34,0.06); border-radius: 0 4px 4px 0;
|
|
4052
|
+
}
|
|
3317
4053
|
.sh-kw { color: #ff7b72; }
|
|
3318
4054
|
.sh-bi { color: #d2a8ff; }
|
|
3319
4055
|
.sh-str { color: #a5d6ff; }
|
|
@@ -3420,8 +4156,48 @@ function highlightLine(line) {
|
|
|
3420
4156
|
}
|
|
3421
4157
|
|
|
3422
4158
|
// src/components/test-editor/test-editor.template.ts
|
|
4159
|
+
function renderTestRow(test, i, state, t) {
|
|
4160
|
+
const { selectMode, selectedIds, expandedIndex, interceptorsByTest, locale, issueTrackerConfig } = state;
|
|
4161
|
+
const expanded = expandedIndex === i;
|
|
4162
|
+
const date = new Date(test.createdAt).toLocaleString(locale, { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
4163
|
+
const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];
|
|
4164
|
+
const tagsHtml = (test.tags ?? []).length ? `<span class="test-tags">${(test.tags ?? []).map((tag) => `<span class="test-tag">${escHtml(tag)}</span>`).join("")}</span>` : "";
|
|
4165
|
+
const checkbox = selectMode ? `<input type="checkbox" ${selectedIds.has(test.id) ? "checked" : ""} data-select="${test.id}" />` : "";
|
|
4166
|
+
const hasIcps = (test.interceptors ?? []).length > 0;
|
|
4167
|
+
const itBlockCode = `it('${escapeSingleQuotes(test.name)}', () => {
|
|
4168
|
+
${(test.commands ?? []).map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4169
|
+
});`;
|
|
4170
|
+
const icpBlockCode = icps.length ? `beforeEach(() => {
|
|
4171
|
+
// Auto-generated Cypress interceptors
|
|
4172
|
+
${icps.map((c) => normalizeBlock(c, " ")).join("\n")}
|
|
4173
|
+
});` : "";
|
|
4174
|
+
const notesHtml = expanded && test.notes ? `<p class="test-notes">${escHtml(test.notes)}</p>` : "";
|
|
4175
|
+
const ticketId = test.ticketId;
|
|
4176
|
+
const ticketUrl = ticketId ? buildTicketUrl(ticketId, issueTrackerConfig) : null;
|
|
4177
|
+
const ticketHtml = ticketId ? ticketUrl ? `<a class="ticket-link" href="${escAttr(ticketUrl)}" target="_blank" rel="noopener noreferrer" title="${t("TEST_EDITOR.TICKET_LINK_TITLE")}">${escHtml(ticketId)}</a>` : `<span class="ticket-badge">${escHtml(ticketId)}</span>` : "";
|
|
4178
|
+
const body = expanded ? `
|
|
4179
|
+
<div class="row-body">
|
|
4180
|
+
${notesHtml}
|
|
4181
|
+
<pre class="code-preview">${syntaxHighlight(itBlockCode)}</pre>
|
|
4182
|
+
${icpBlockCode ? `<pre class="code-preview code-preview-icp">${syntaxHighlight(icpBlockCode)}</pre>` : ""}
|
|
4183
|
+
</div>` : "";
|
|
4184
|
+
return `
|
|
4185
|
+
<div class="row${selectedIds.has(test.id) ? " selected-row" : ""}">
|
|
4186
|
+
<div class="row-header" data-action="expand" data-idx="${i}">
|
|
4187
|
+
${checkbox}
|
|
4188
|
+
<span class="test-name">${escHtml(test.name)}</span>
|
|
4189
|
+
${tagsHtml}
|
|
4190
|
+
${ticketHtml}
|
|
4191
|
+
<span class="test-date">${date}</span>
|
|
4192
|
+
<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>
|
|
4193
|
+
${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>` : ""}
|
|
4194
|
+
<button class="btn-icon btn-del" data-action="delete" data-id="${test.id}" title="${t("TEST_EDITOR.DELETE_TITLE")}">\u{1F5D1}</button>
|
|
4195
|
+
</div>
|
|
4196
|
+
${body}
|
|
4197
|
+
</div>`;
|
|
4198
|
+
}
|
|
3423
4199
|
function renderTestEditor(state, t) {
|
|
3424
|
-
const { tags, visible, selectedVisible, activeTag, selectMode,
|
|
4200
|
+
const { tags, visible, selectedVisible, activeTag, selectMode, describeName, groupByTicket } = state;
|
|
3425
4201
|
const tagFilterHtml = tags.length ? `<div class="tag-filter">
|
|
3426
4202
|
${tags.map((tag) => `<button class="tag-chip${activeTag === tag ? " active" : ""}" data-filter-tag="${escAttr(tag)}">${escHtml(tag)}</button>`).join("")}
|
|
3427
4203
|
</div>` : `<div class="tag-filter" style="color:#484f58;font-size:11px">${t("TEST_EDITOR.NO_TAGS")}</div>`;
|
|
@@ -3430,44 +4206,36 @@ function renderTestEditor(state, t) {
|
|
|
3430
4206
|
<input id="describe-name" type="text" placeholder="${t("TEST_EDITOR.DESCRIBE_PLACEHOLDER")}" value="${escAttr(describeName)}" />
|
|
3431
4207
|
<button class="btn-gen-describe" id="btn-gen-describe">${t("TEST_EDITOR.COPY_DESCRIBE")}</button>
|
|
3432
4208
|
</div>` : "";
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
const
|
|
3436
|
-
const
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
${checkbox}
|
|
3458
|
-
<span class="test-name">${escHtml(test.name)}</span>
|
|
3459
|
-
${tagsHtml}
|
|
3460
|
-
<span class="test-date">${date}</span>
|
|
3461
|
-
<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>
|
|
3462
|
-
${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>` : ""}
|
|
3463
|
-
<button class="btn-icon btn-del" data-action="delete" data-id="${test.id}" title="${t("TEST_EDITOR.DELETE_TITLE")}">\u{1F5D1}</button>
|
|
3464
|
-
</div>
|
|
3465
|
-
${body}
|
|
3466
|
-
</div>`;
|
|
3467
|
-
}).join("");
|
|
4209
|
+
let rows;
|
|
4210
|
+
if (groupByTicket) {
|
|
4211
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4212
|
+
for (const test of visible) {
|
|
4213
|
+
const key = test.ticketId?.trim() || "";
|
|
4214
|
+
const group = groups.get(key) ?? [];
|
|
4215
|
+
group.push(test);
|
|
4216
|
+
groups.set(key, group);
|
|
4217
|
+
}
|
|
4218
|
+
const sortedKeys = [...groups.keys()].sort(
|
|
4219
|
+
(a, b) => a === "" ? 1 : b === "" ? -1 : a.localeCompare(b)
|
|
4220
|
+
);
|
|
4221
|
+
rows = sortedKeys.map((key) => {
|
|
4222
|
+
const group = groups.get(key);
|
|
4223
|
+
const header = `<div class="ticket-group-header">${key ? escHtml(key) : t("TEST_EDITOR.NO_TICKET")}</div>`;
|
|
4224
|
+
const groupRows = group.map((test) => {
|
|
4225
|
+
const i = visible.indexOf(test);
|
|
4226
|
+
return renderTestRow(test, i, state, t);
|
|
4227
|
+
}).join("");
|
|
4228
|
+
return `<div class="ticket-group">${header}${groupRows}</div>`;
|
|
4229
|
+
}).join("");
|
|
4230
|
+
} else {
|
|
4231
|
+
rows = visible.map((test, i) => renderTestRow(test, i, state, t)).join("");
|
|
4232
|
+
}
|
|
3468
4233
|
return `
|
|
3469
4234
|
<div class="toolbar">
|
|
3470
4235
|
${tagFilterHtml}
|
|
4236
|
+
<button class="btn-select${groupByTicket ? " active" : ""}" id="btn-group-ticket">
|
|
4237
|
+
${groupByTicket ? t("TEST_EDITOR.UNGROUP_TICKET") : t("TEST_EDITOR.GROUP_BY_TICKET")}
|
|
4238
|
+
</button>
|
|
3471
4239
|
<button class="btn-select${selectMode ? " active" : ""}" id="btn-select-mode">
|
|
3472
4240
|
${selectMode ? t("TEST_EDITOR.CANCEL_SELECT") : t("TEST_EDITOR.MULTI_SELECT")}
|
|
3473
4241
|
</button>
|
|
@@ -3490,6 +4258,8 @@ var TestEditorElement = class extends HTMLElement {
|
|
|
3490
4258
|
selectMode = false;
|
|
3491
4259
|
selectedIds = /* @__PURE__ */ new Set();
|
|
3492
4260
|
describeName = "";
|
|
4261
|
+
groupByTicket = false;
|
|
4262
|
+
issueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };
|
|
3493
4263
|
constructor() {
|
|
3494
4264
|
super();
|
|
3495
4265
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
@@ -3520,6 +4290,10 @@ var TestEditorElement = class extends HTMLElement {
|
|
|
3520
4290
|
hasInterceptors(testId) {
|
|
3521
4291
|
return Array.isArray(this.interceptorsByTest[testId]) && this.interceptorsByTest[testId].length > 0;
|
|
3522
4292
|
}
|
|
4293
|
+
toggleGroupByTicket() {
|
|
4294
|
+
this.groupByTicket = !this.groupByTicket;
|
|
4295
|
+
this.render();
|
|
4296
|
+
}
|
|
3523
4297
|
toggleSelectMode() {
|
|
3524
4298
|
this.selectMode = !this.selectMode;
|
|
3525
4299
|
if (!this.selectMode) this.selectedIds.clear();
|
|
@@ -3584,8 +4358,11 @@ ${beforeEach}${itBlocks}
|
|
|
3584
4358
|
describeName: this.describeName,
|
|
3585
4359
|
expandedIndex: this.expandedIndex,
|
|
3586
4360
|
interceptorsByTest: this.interceptorsByTest,
|
|
3587
|
-
locale: localeForLang(this.translation.getLang())
|
|
4361
|
+
locale: localeForLang(this.translation.getLang()),
|
|
4362
|
+
groupByTicket: this.groupByTicket,
|
|
4363
|
+
issueTrackerConfig: this.issueTrackerConfig
|
|
3588
4364
|
}, this.t.bind(this))}`;
|
|
4365
|
+
this.shadow.getElementById("btn-group-ticket")?.addEventListener("click", () => this.toggleGroupByTicket());
|
|
3589
4366
|
this.shadow.getElementById("btn-select-mode")?.addEventListener("click", () => this.toggleSelectMode());
|
|
3590
4367
|
this.shadow.querySelectorAll("[data-filter-tag]").forEach((el) => {
|
|
3591
4368
|
el.addEventListener("click", () => {
|
|
@@ -3650,7 +4427,7 @@ if (!customElements.get("test-editor")) {
|
|
|
3650
4427
|
|
|
3651
4428
|
// src/components/configuration/configuration.styles.ts
|
|
3652
4429
|
var CONFIGURATION_STYLES = `
|
|
3653
|
-
:host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }
|
|
4430
|
+
: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; }
|
|
3654
4431
|
* { box-sizing: border-box; }
|
|
3655
4432
|
|
|
3656
4433
|
/* \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 */
|
|
@@ -3874,7 +4651,7 @@ function renderExportOverlay(state, t) {
|
|
|
3874
4651
|
</div>`;
|
|
3875
4652
|
}
|
|
3876
4653
|
function renderConfiguration(state, t) {
|
|
3877
|
-
const { selectedLanguage, advancedHttpConfig, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes } = state;
|
|
4654
|
+
const { selectedLanguage, advancedHttpConfig, fixtureMode, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes, issueTrackerConfig } = state;
|
|
3878
4655
|
const langOptions = LANGS.map(
|
|
3879
4656
|
(l) => `<option value="${l.value}" ${selectedLanguage === l.value ? "selected" : ""}>${l.label}</option>`
|
|
3880
4657
|
).join("");
|
|
@@ -3902,6 +4679,18 @@ function renderConfiguration(state, t) {
|
|
|
3902
4679
|
</label>
|
|
3903
4680
|
</div>
|
|
3904
4681
|
|
|
4682
|
+
<!-- HTTP Fixtures -->
|
|
4683
|
+
<div class="card">
|
|
4684
|
+
<div class="card-hd">${t("CONFIG.FIXTURE_SECTION")}</div>
|
|
4685
|
+
<label class="check-row">
|
|
4686
|
+
<input type="checkbox" id="fixture-toggle" ${fixtureMode ? "checked" : ""} />
|
|
4687
|
+
<div>
|
|
4688
|
+
<div class="check-title">${t("CONFIG.FIXTURE_TITLE")}</div>
|
|
4689
|
+
<div class="check-sub">${t("CONFIG.FIXTURE_SUB")}</div>
|
|
4690
|
+
</div>
|
|
4691
|
+
</label>
|
|
4692
|
+
</div>
|
|
4693
|
+
|
|
3905
4694
|
<!-- Smart Selector -->
|
|
3906
4695
|
<div class="card">
|
|
3907
4696
|
<div class="card-hd">${t("CONFIG.SMART_SELECTOR_SECTION")}</div>
|
|
@@ -3983,6 +4772,34 @@ function renderConfiguration(state, t) {
|
|
|
3983
4772
|
</div>
|
|
3984
4773
|
</div>
|
|
3985
4774
|
|
|
4775
|
+
<!-- Issue Tracker -->
|
|
4776
|
+
<div class="card card-wide">
|
|
4777
|
+
<div class="card-hd">${t("CONFIG.ISSUE_TRACKER_SECTION")}</div>
|
|
4778
|
+
<label class="check-row">
|
|
4779
|
+
<input type="checkbox" id="issue-tracker-toggle" ${issueTrackerConfig.enabled ? "checked" : ""} />
|
|
4780
|
+
<div>
|
|
4781
|
+
<div class="check-title">${t("CONFIG.ISSUE_TRACKER_TITLE")}</div>
|
|
4782
|
+
<div class="check-sub">${t("CONFIG.ISSUE_TRACKER_SUB")}</div>
|
|
4783
|
+
</div>
|
|
4784
|
+
</label>
|
|
4785
|
+
${issueTrackerConfig.enabled ? `
|
|
4786
|
+
<div class="field-row" style="margin-top:10px">
|
|
4787
|
+
<span class="field-label">${t("CONFIG.ISSUE_TRACKER_PROVIDER")}</span>
|
|
4788
|
+
<select id="issue-tracker-provider">
|
|
4789
|
+
${Object.values(ISSUE_TRACKER_PRESETS).map(
|
|
4790
|
+
(p) => `<option value="${p.id}" ${issueTrackerConfig.provider === p.id ? "selected" : ""}>${escHtml(p.label)}</option>`
|
|
4791
|
+
).join("")}
|
|
4792
|
+
</select>
|
|
4793
|
+
</div>
|
|
4794
|
+
<div class="field-row" style="margin-top:8px">
|
|
4795
|
+
<span class="field-label">${t("CONFIG.ISSUE_TRACKER_BASE_URL")}</span>
|
|
4796
|
+
<input id="issue-tracker-base-url" type="text"
|
|
4797
|
+
placeholder="${escAttr(t("CONFIG.ISSUE_TRACKER_BASE_URL_PH"))}"
|
|
4798
|
+
value="${escAttr(issueTrackerConfig.baseUrl)}"
|
|
4799
|
+
style="flex:1;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none" />
|
|
4800
|
+
</div>` : ""}
|
|
4801
|
+
</div>
|
|
4802
|
+
|
|
3986
4803
|
<!-- Data -->
|
|
3987
4804
|
<div class="card card-wide">
|
|
3988
4805
|
<div class="card-hd">${t("CONFIG.DATA_SECTION")}</div>
|
|
@@ -4006,6 +4823,7 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4006
4823
|
translation;
|
|
4007
4824
|
selectedLanguage = "es";
|
|
4008
4825
|
advancedHttpConfig = false;
|
|
4826
|
+
fixtureMode = false;
|
|
4009
4827
|
selectorStrategy = "data-cy";
|
|
4010
4828
|
smartSelectorEnabled = true;
|
|
4011
4829
|
startHidden = false;
|
|
@@ -4015,12 +4833,14 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4015
4833
|
exportTests = [];
|
|
4016
4834
|
exportSelectedIds = /* @__PURE__ */ new Set();
|
|
4017
4835
|
exportSelectedTags = /* @__PURE__ */ new Set();
|
|
4836
|
+
issueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };
|
|
4018
4837
|
filesystemGranted = false;
|
|
4019
4838
|
cypressFolderName = null;
|
|
4020
4839
|
constructor() {
|
|
4021
4840
|
super();
|
|
4022
4841
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
4023
4842
|
this.advancedHttpConfig = localStorage.getItem("extendedHttpCommands") === "true";
|
|
4843
|
+
this.fixtureMode = localStorage.getItem("fixtureMode") === "true";
|
|
4024
4844
|
}
|
|
4025
4845
|
connectedCallback() {
|
|
4026
4846
|
if (!this.persistence) this.persistence = new PersistenceService();
|
|
@@ -4038,6 +4858,7 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4038
4858
|
this.translation.setLang(this.selectedLanguage);
|
|
4039
4859
|
}
|
|
4040
4860
|
this.advancedHttpConfig = localStorage.getItem("extendedHttpCommands") === "true";
|
|
4861
|
+
this.fixtureMode = localStorage.getItem("fixtureMode") === "true";
|
|
4041
4862
|
this.selectorStrategy = config?.["selectorStrategy"] ?? "data-cy";
|
|
4042
4863
|
this.smartSelectorEnabled = config?.["smartSelectorEnabled"] !== "false";
|
|
4043
4864
|
this.startHidden = config?.["startHidden"] === "true";
|
|
@@ -4049,6 +4870,11 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4049
4870
|
this.filesystemGranted = config?.["allowReadWriteFiles"] === "true";
|
|
4050
4871
|
const handle = config?.["cypressDirectoryHandle"];
|
|
4051
4872
|
this.cypressFolderName = handle?.name ?? null;
|
|
4873
|
+
this.issueTrackerConfig = {
|
|
4874
|
+
enabled: config?.["issueTrackerEnabled"] === "true",
|
|
4875
|
+
provider: config?.["issueTrackerProvider"] ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,
|
|
4876
|
+
baseUrl: config?.["issueTrackerBaseUrl"] ?? ""
|
|
4877
|
+
};
|
|
4052
4878
|
this.render();
|
|
4053
4879
|
}
|
|
4054
4880
|
async onLanguageChange(lang) {
|
|
@@ -4063,6 +4889,12 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4063
4889
|
this.persistence.setConfig({ extendedHttpCommands: checked ? "true" : "false" });
|
|
4064
4890
|
this.render();
|
|
4065
4891
|
}
|
|
4892
|
+
onFixtureModeChange(checked) {
|
|
4893
|
+
this.fixtureMode = checked;
|
|
4894
|
+
localStorage.setItem("fixtureMode", checked ? "true" : "false");
|
|
4895
|
+
this.persistence.setConfig({ fixtureMode: checked ? "true" : "false" });
|
|
4896
|
+
this.render();
|
|
4897
|
+
}
|
|
4066
4898
|
async onStartHiddenChange(checked) {
|
|
4067
4899
|
this.startHidden = checked;
|
|
4068
4900
|
await this.persistence.setConfig({ startHidden: checked ? "true" : "false" });
|
|
@@ -4091,6 +4923,23 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4091
4923
|
this.dispatchEvent(new CustomEvent("selectorstrategychange", { detail: strategy, bubbles: true, composed: true }));
|
|
4092
4924
|
this.render();
|
|
4093
4925
|
}
|
|
4926
|
+
async onIssueTrackerEnabledChange(enabled) {
|
|
4927
|
+
this.issueTrackerConfig = { ...this.issueTrackerConfig, enabled };
|
|
4928
|
+
await this.persistence.setConfig({ issueTrackerEnabled: enabled ? "true" : "false" });
|
|
4929
|
+
this.dispatchEvent(new CustomEvent("issuetrackerchange", { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));
|
|
4930
|
+
this.render();
|
|
4931
|
+
}
|
|
4932
|
+
async onIssueTrackerProviderChange(provider) {
|
|
4933
|
+
this.issueTrackerConfig = { ...this.issueTrackerConfig, provider };
|
|
4934
|
+
await this.persistence.setConfig({ issueTrackerProvider: provider });
|
|
4935
|
+
this.dispatchEvent(new CustomEvent("issuetrackerchange", { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));
|
|
4936
|
+
this.render();
|
|
4937
|
+
}
|
|
4938
|
+
async onIssueTrackerBaseUrlChange(baseUrl) {
|
|
4939
|
+
this.issueTrackerConfig = { ...this.issueTrackerConfig, baseUrl };
|
|
4940
|
+
await this.persistence.setConfig({ issueTrackerBaseUrl: baseUrl });
|
|
4941
|
+
this.dispatchEvent(new CustomEvent("issuetrackerchange", { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));
|
|
4942
|
+
}
|
|
4094
4943
|
async changeFolder() {
|
|
4095
4944
|
try {
|
|
4096
4945
|
await this.persistence.requestDirectoryPermissions();
|
|
@@ -4181,6 +5030,7 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4181
5030
|
this.shadow.innerHTML = `<style>${CONFIGURATION_STYLES}</style>${renderConfiguration({
|
|
4182
5031
|
selectedLanguage: this.selectedLanguage,
|
|
4183
5032
|
advancedHttpConfig: this.advancedHttpConfig,
|
|
5033
|
+
fixtureMode: this.fixtureMode,
|
|
4184
5034
|
selectorStrategy: this.selectorStrategy,
|
|
4185
5035
|
filesystemGranted: this.filesystemGranted,
|
|
4186
5036
|
cypressFolderName: this.cypressFolderName,
|
|
@@ -4191,7 +5041,8 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4191
5041
|
exportMode: this.exportMode,
|
|
4192
5042
|
exportTests: this.exportTests,
|
|
4193
5043
|
exportSelectedIds: this.exportSelectedIds,
|
|
4194
|
-
exportSelectedTags: this.exportSelectedTags
|
|
5044
|
+
exportSelectedTags: this.exportSelectedTags,
|
|
5045
|
+
issueTrackerConfig: this.issueTrackerConfig
|
|
4195
5046
|
}, this.t.bind(this))}`;
|
|
4196
5047
|
;
|
|
4197
5048
|
this.shadow.getElementById("lang-select").addEventListener(
|
|
@@ -4202,6 +5053,10 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4202
5053
|
"change",
|
|
4203
5054
|
(e) => this.onAdvancedHttpConfigChange(e.target.checked)
|
|
4204
5055
|
);
|
|
5056
|
+
this.shadow.getElementById("fixture-toggle").addEventListener(
|
|
5057
|
+
"change",
|
|
5058
|
+
(e) => this.onFixtureModeChange(e.target.checked)
|
|
5059
|
+
);
|
|
4205
5060
|
this.shadow.getElementById("smart-selector-toggle").addEventListener(
|
|
4206
5061
|
"change",
|
|
4207
5062
|
(e) => this.onSmartSelectorChange(e.target.checked)
|
|
@@ -4219,6 +5074,19 @@ var ConfigurationElement = class extends HTMLElement {
|
|
|
4219
5074
|
"change",
|
|
4220
5075
|
(e) => this.onSelectorStrategyChange(e.target.value)
|
|
4221
5076
|
);
|
|
5077
|
+
;
|
|
5078
|
+
this.shadow.getElementById("issue-tracker-toggle")?.addEventListener(
|
|
5079
|
+
"change",
|
|
5080
|
+
(e) => this.onIssueTrackerEnabledChange(e.target.checked)
|
|
5081
|
+
);
|
|
5082
|
+
this.shadow.getElementById("issue-tracker-provider")?.addEventListener(
|
|
5083
|
+
"change",
|
|
5084
|
+
(e) => this.onIssueTrackerProviderChange(e.target.value)
|
|
5085
|
+
);
|
|
5086
|
+
this.shadow.getElementById("issue-tracker-base-url")?.addEventListener(
|
|
5087
|
+
"change",
|
|
5088
|
+
(e) => this.onIssueTrackerBaseUrlChange(e.target.value)
|
|
5089
|
+
);
|
|
4222
5090
|
this.shadow.getElementById("btn-change-folder")?.addEventListener("click", () => this.changeFolder());
|
|
4223
5091
|
this.shadow.getElementById("btn-revoke")?.addEventListener("click", () => this.revokeAccess());
|
|
4224
5092
|
this.shadow.getElementById("btn-export")?.addEventListener("click", () => this.openExportDialog());
|
|
@@ -5175,6 +6043,155 @@ if (!customElements.get("file-preview")) {
|
|
|
5175
6043
|
customElements.define("file-preview", FilePreviewElement);
|
|
5176
6044
|
}
|
|
5177
6045
|
|
|
6046
|
+
// src/components/help-panel/help-panel.styles.ts
|
|
6047
|
+
var HELP_PANEL_STYLES = `
|
|
6048
|
+
:host { display: block; }
|
|
6049
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
6050
|
+
|
|
6051
|
+
.help-tabs {
|
|
6052
|
+
display: flex;
|
|
6053
|
+
gap: 4px;
|
|
6054
|
+
border-bottom: 1px solid #21262d;
|
|
6055
|
+
margin-bottom: 8px;
|
|
6056
|
+
}
|
|
6057
|
+
.help-tab {
|
|
6058
|
+
appearance: none;
|
|
6059
|
+
border: none;
|
|
6060
|
+
background: transparent;
|
|
6061
|
+
color: #8b949e;
|
|
6062
|
+
font-size: 12px;
|
|
6063
|
+
font-weight: 600;
|
|
6064
|
+
padding: 8px 12px;
|
|
6065
|
+
cursor: pointer;
|
|
6066
|
+
border-bottom: 2px solid transparent;
|
|
6067
|
+
margin-bottom: -1px;
|
|
6068
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
6069
|
+
transition: color .12s, border-color .12s;
|
|
6070
|
+
}
|
|
6071
|
+
.help-tab:hover { color: #c9d1d9; }
|
|
6072
|
+
.help-tab.active { color: #e6edf3; border-bottom-color: #2f81f7; }
|
|
6073
|
+
|
|
6074
|
+
.help-panel {
|
|
6075
|
+
max-height: 60vh;
|
|
6076
|
+
overflow-y: auto;
|
|
6077
|
+
padding: 4px 6px 8px;
|
|
6078
|
+
color: #c9d1d9;
|
|
6079
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
6080
|
+
font-size: 13px;
|
|
6081
|
+
line-height: 1.55;
|
|
6082
|
+
}
|
|
6083
|
+
|
|
6084
|
+
.help-intro {
|
|
6085
|
+
margin: 0 0 12px;
|
|
6086
|
+
color: #8b949e;
|
|
6087
|
+
font-size: 12px;
|
|
6088
|
+
}
|
|
6089
|
+
|
|
6090
|
+
.help-sec { margin: 0 0 14px; }
|
|
6091
|
+
|
|
6092
|
+
.help-sec-hd {
|
|
6093
|
+
margin: 0 0 6px;
|
|
6094
|
+
font-size: 12px;
|
|
6095
|
+
font-weight: 700;
|
|
6096
|
+
color: #e6edf3;
|
|
6097
|
+
letter-spacing: .3px;
|
|
6098
|
+
border-bottom: 1px solid #21262d;
|
|
6099
|
+
padding-bottom: 4px;
|
|
6100
|
+
}
|
|
6101
|
+
|
|
6102
|
+
.help-list {
|
|
6103
|
+
margin: 0;
|
|
6104
|
+
padding: 0;
|
|
6105
|
+
list-style: none;
|
|
6106
|
+
}
|
|
6107
|
+
|
|
6108
|
+
.help-list li {
|
|
6109
|
+
padding: 3px 0 3px 14px;
|
|
6110
|
+
position: relative;
|
|
6111
|
+
color: #c9d1d9;
|
|
6112
|
+
}
|
|
6113
|
+
|
|
6114
|
+
.help-list li::before {
|
|
6115
|
+
content: '\xB7';
|
|
6116
|
+
position: absolute;
|
|
6117
|
+
left: 3px;
|
|
6118
|
+
color: #2f81f7;
|
|
6119
|
+
font-weight: 700;
|
|
6120
|
+
}
|
|
6121
|
+
`;
|
|
6122
|
+
|
|
6123
|
+
// src/components/help-panel/help-panel.template.ts
|
|
6124
|
+
init_html_utils();
|
|
6125
|
+
var REFERENCE_SECTIONS = [
|
|
6126
|
+
{ title: "HELP.SEC_RECORDING", items: ["HELP.RECORDING_1", "HELP.RECORDING_2"] },
|
|
6127
|
+
{
|
|
6128
|
+
title: "HELP.SEC_SHORTCUTS",
|
|
6129
|
+
items: ["HELP.SC_RECORD", "HELP.SC_PAUSE", "HELP.SC_TESTS", "HELP.SC_COMMANDS", "HELP.SC_CONFIG", "HELP.SC_VISIBILITY", "HELP.SC_HELP"]
|
|
6130
|
+
},
|
|
6131
|
+
{
|
|
6132
|
+
title: "HELP.SEC_CAPTURED",
|
|
6133
|
+
items: ["HELP.CAP_CLICK", "HELP.CAP_DBLCLICK", "HELP.CAP_RIGHTCLICK", "HELP.CAP_TYPE", "HELP.CAP_CHECK", "HELP.CAP_SELECT", "HELP.CAP_KEYS", "HELP.CAP_ROUTE", "HELP.CAP_HTTP"]
|
|
6134
|
+
},
|
|
6135
|
+
{ title: "HELP.SEC_ASSERT", items: ["HELP.ASSERT_1", "HELP.ASSERT_2"] },
|
|
6136
|
+
{ title: "HELP.SEC_PANELS", items: ["HELP.PANEL_TESTS", "HELP.PANEL_COMMANDS", "HELP.PANEL_CONFIG", "HELP.PANEL_FILES"] },
|
|
6137
|
+
{ title: "HELP.SEC_SELECTOR", items: ["HELP.SELECTOR_1", "HELP.SELECTOR_2"] },
|
|
6138
|
+
{ title: "HELP.SEC_DATA", items: ["HELP.DATA_1", "HELP.DATA_2"] },
|
|
6139
|
+
{ title: "HELP.SEC_ADVANCED", items: ["HELP.ADV_INVISIBLE", "HELP.ADV_RUNNER", "HELP.ADV_CROSSAPP", "HELP.ADV_DRAG"] }
|
|
6140
|
+
];
|
|
6141
|
+
var GUIDE_SECTIONS = [
|
|
6142
|
+
{ title: "HELP.G_SEC_WORKFLOW", items: ["HELP.G_WF_1", "HELP.G_WF_2", "HELP.G_WF_3", "HELP.G_WF_4", "HELP.G_WF_5"] },
|
|
6143
|
+
{ title: "HELP.G_SEC_COVERED", items: ["HELP.G_COV_1", "HELP.G_COV_2", "HELP.G_COV_3", "HELP.G_COV_4", "HELP.G_COV_5", "HELP.G_COV_6"] },
|
|
6144
|
+
{ title: "HELP.G_SEC_NOTCOVERED", items: ["HELP.G_NC_1", "HELP.G_NC_2", "HELP.G_NC_3", "HELP.G_NC_4", "HELP.G_NC_5", "HELP.G_NC_6"] }
|
|
6145
|
+
];
|
|
6146
|
+
function sectionsHtml(sections, t) {
|
|
6147
|
+
return sections.map(
|
|
6148
|
+
(s) => `
|
|
6149
|
+
<section class="help-sec">
|
|
6150
|
+
<h3 class="help-sec-hd">${escHtml(t(s.title))}</h3>
|
|
6151
|
+
<ul class="help-list">${s.items.map((k) => `<li>${escHtml(t(k))}</li>`).join("")}</ul>
|
|
6152
|
+
</section>`
|
|
6153
|
+
).join("");
|
|
6154
|
+
}
|
|
6155
|
+
function renderHelpPanel(t, activeTab = "reference") {
|
|
6156
|
+
const tab = (id, key) => `<button class="help-tab ${activeTab === id ? "active" : ""}" data-tab="${id}">${escHtml(t(key))}</button>`;
|
|
6157
|
+
const body = activeTab === "guide" ? `<p class="help-intro">${escHtml(t("HELP.GUIDE_INTRO"))}</p>${sectionsHtml(GUIDE_SECTIONS, t)}` : `<p class="help-intro">${escHtml(t("HELP.INTRO"))}</p>${sectionsHtml(REFERENCE_SECTIONS, t)}`;
|
|
6158
|
+
return `
|
|
6159
|
+
<div class="help-root">
|
|
6160
|
+
<div class="help-tabs" role="tablist">
|
|
6161
|
+
${tab("reference", "HELP.TAB_REFERENCE")}
|
|
6162
|
+
${tab("guide", "HELP.TAB_GUIDE")}
|
|
6163
|
+
</div>
|
|
6164
|
+
<div class="help-panel" data-tab-panel="${activeTab}">${body}</div>
|
|
6165
|
+
</div>`;
|
|
6166
|
+
}
|
|
6167
|
+
|
|
6168
|
+
// src/components/help-panel/help-panel.ts
|
|
6169
|
+
var HelpPanelElement = class extends HTMLElement {
|
|
6170
|
+
shadow;
|
|
6171
|
+
activeTab = "reference";
|
|
6172
|
+
translation;
|
|
6173
|
+
constructor() {
|
|
6174
|
+
super();
|
|
6175
|
+
this.shadow = this.attachShadow({ mode: "open" });
|
|
6176
|
+
}
|
|
6177
|
+
connectedCallback() {
|
|
6178
|
+
if (!this.translation) this.translation = new TranslationService();
|
|
6179
|
+
this.render();
|
|
6180
|
+
}
|
|
6181
|
+
render() {
|
|
6182
|
+
this.shadow.innerHTML = `<style>${HELP_PANEL_STYLES}</style>${renderHelpPanel(this.translation.translate.bind(this.translation), this.activeTab)}`;
|
|
6183
|
+
this.shadow.querySelectorAll("[data-tab]").forEach((btn) => {
|
|
6184
|
+
btn.addEventListener("click", () => {
|
|
6185
|
+
this.activeTab = btn.dataset["tab"] ?? "reference";
|
|
6186
|
+
this.render();
|
|
6187
|
+
});
|
|
6188
|
+
});
|
|
6189
|
+
}
|
|
6190
|
+
};
|
|
6191
|
+
if (!customElements.get("help-panel")) {
|
|
6192
|
+
customElements.define("help-panel", HelpPanelElement);
|
|
6193
|
+
}
|
|
6194
|
+
|
|
5178
6195
|
// src/components/lib-e2e-recorder/lib-e2e-recorder.ts
|
|
5179
6196
|
var import_sweetalert2 = __toESM(require("sweetalert2"), 1);
|
|
5180
6197
|
|
|
@@ -5182,22 +6199,15 @@ var import_sweetalert2 = __toESM(require("sweetalert2"), 1);
|
|
|
5182
6199
|
var DIRECTIONS = ["up-left", "up-right", "down-left", "down-right"];
|
|
5183
6200
|
function directionBlocks() {
|
|
5184
6201
|
return DIRECTIONS.map((dir) => {
|
|
5185
|
-
const sx = dir.endsWith("left") ? -1 : 1;
|
|
5186
|
-
const sy = dir.startsWith("up") ? -1 : 1;
|
|
5187
6202
|
const tv = dir.startsWith("up") ? "bottom" : "top";
|
|
5188
6203
|
const th = dir.endsWith("left") ? "right" : "left";
|
|
5189
6204
|
const ov = tv === "bottom" ? "top" : "bottom";
|
|
5190
6205
|
const oh = th === "right" ? "left" : "right";
|
|
5191
6206
|
const sel = `.widget[data-expand="${dir}"]`;
|
|
5192
|
-
const labelGeneral = `${sel} .btn-action::after { ${oh}: calc(100% + 9px); ${th}: auto; top: 50%; bottom: auto; transform: translateY(-50%); }`;
|
|
5193
|
-
const labelEnds = `${sel} .btn-action[data-n="1"]::after, ${sel} .btn-action[data-n="4"]::after { ${ov}: calc(100% + 9px); ${tv}: auto; left: 50%; right: auto; transform: translateX(-50%); }`;
|
|
5194
6207
|
return `
|
|
5195
|
-
${sel} {
|
|
5196
|
-
${sel} .btn-
|
|
5197
|
-
${sel} .
|
|
5198
|
-
${sel} .btn-action { ${tv}: 28px; ${th}: 28px; ${ov}: auto; ${oh}: auto; }
|
|
5199
|
-
${labelGeneral}
|
|
5200
|
-
${labelEnds}
|
|
6208
|
+
${sel} .btn-toggle { ${tv}: 24px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }
|
|
6209
|
+
${sel} .btn-pause { ${tv}: 78px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }
|
|
6210
|
+
${sel} .action-menu { ${tv}: 118px; ${th}: 8px; ${ov}: auto; ${oh}: auto; transform-origin: ${tv} ${th}; }
|
|
5201
6211
|
`;
|
|
5202
6212
|
}).join("\n");
|
|
5203
6213
|
}
|
|
@@ -5207,9 +6217,10 @@ function getRecorderStyles(rec, paused) {
|
|
|
5207
6217
|
*, *::before, *::after { box-sizing: border-box; }
|
|
5208
6218
|
|
|
5209
6219
|
/*
|
|
5210
|
-
*
|
|
5211
|
-
*
|
|
5212
|
-
*
|
|
6220
|
+
* Hit area. Position (left/top) is set from JS so the widget can be dragged;
|
|
6221
|
+
* data-expand orients the action-menu popover toward the viewport interior.
|
|
6222
|
+
* The menu is a DOM child, so hovering it keeps :host(.widget):hover alive even
|
|
6223
|
+
* though it visually overflows this box. Defaults to bottom-right.
|
|
5213
6224
|
*/
|
|
5214
6225
|
.widget {
|
|
5215
6226
|
position: fixed;
|
|
@@ -5218,12 +6229,10 @@ function getRecorderStyles(rec, paused) {
|
|
|
5218
6229
|
width: 190px;
|
|
5219
6230
|
height: 190px;
|
|
5220
6231
|
z-index: 2147483647;
|
|
5221
|
-
--sx: -1;
|
|
5222
|
-
--sy: -1;
|
|
5223
6232
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
5224
6233
|
}
|
|
5225
6234
|
|
|
5226
|
-
/* \u2500\u2500 Toggle \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
|
|
6235
|
+
/* \u2500\u2500 Toggle (FAB) \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 */
|
|
5227
6236
|
.btn-toggle {
|
|
5228
6237
|
position: absolute;
|
|
5229
6238
|
bottom: 24px;
|
|
@@ -5276,83 +6285,58 @@ function getRecorderStyles(rec, paused) {
|
|
|
5276
6285
|
.btn-pause:hover { transform: scale(1.12); }
|
|
5277
6286
|
.btn-pause:active { transform: scale(0.93); }
|
|
5278
6287
|
|
|
5279
|
-
/* \u2500\u2500 Action
|
|
5280
|
-
.
|
|
6288
|
+
/* \u2500\u2500 Action menu (labelled grid popover) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
6289
|
+
.action-menu {
|
|
5281
6290
|
position: absolute;
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
align-items: center;
|
|
5292
|
-
justify-content: center;
|
|
5293
|
-
background: rgba(13,17,23,.92);
|
|
6291
|
+
display: grid;
|
|
6292
|
+
grid-template-columns: repeat(3, 1fr);
|
|
6293
|
+
gap: 4px;
|
|
6294
|
+
padding: 8px;
|
|
6295
|
+
width: 174px;
|
|
6296
|
+
background: rgba(13,17,23,.97);
|
|
6297
|
+
border: 1px solid rgba(48,54,61,.9);
|
|
6298
|
+
border-radius: 12px;
|
|
6299
|
+
box-shadow: 0 8px 28px rgba(0,0,0,.5);
|
|
5294
6300
|
backdrop-filter: blur(14px);
|
|
5295
6301
|
-webkit-backdrop-filter: blur(14px);
|
|
5296
|
-
color: #8b949e;
|
|
5297
|
-
box-shadow: 0 4px 18px rgba(0,0,0,.45), 0 0 0 1px rgba(48,54,61,.75);
|
|
5298
6302
|
opacity: 0;
|
|
5299
|
-
transform: scale(0.
|
|
6303
|
+
transform: scale(0.9);
|
|
5300
6304
|
pointer-events: none;
|
|
5301
|
-
transition: opacity .
|
|
5302
|
-
|
|
5303
|
-
}
|
|
5304
|
-
|
|
5305
|
-
/* Label chip */
|
|
5306
|
-
.btn-action::after {
|
|
5307
|
-
content: attr(data-label);
|
|
5308
|
-
position: absolute;
|
|
5309
|
-
right: calc(100% + 9px);
|
|
5310
|
-
top: 50%;
|
|
5311
|
-
transform: translateY(-50%);
|
|
5312
|
-
background: rgba(13,17,23,.95);
|
|
5313
|
-
color: #e6edf3;
|
|
5314
|
-
font-size: 11px;
|
|
5315
|
-
font-weight: 500;
|
|
5316
|
-
padding: 3px 9px;
|
|
5317
|
-
border-radius: 6px;
|
|
5318
|
-
white-space: nowrap;
|
|
5319
|
-
pointer-events: none;
|
|
5320
|
-
opacity: 0;
|
|
5321
|
-
transition: opacity .15s .05s;
|
|
5322
|
-
border: 1px solid rgba(48,54,61,.8);
|
|
5323
|
-
box-shadow: 0 2px 8px rgba(0,0,0,.35);
|
|
6305
|
+
transition: opacity .16s, transform .2s cubic-bezier(.34,1.56,.64,1);
|
|
6306
|
+
z-index: 3;
|
|
5324
6307
|
}
|
|
5325
|
-
.
|
|
5326
|
-
.btn-action:hover { background: #21262d; color: #e6edf3; }
|
|
5327
|
-
.btn-action:active { background: #30363d !important; }
|
|
5328
|
-
|
|
5329
|
-
/* Expand: spring + stagger */
|
|
5330
|
-
.widget:hover .btn-action {
|
|
6308
|
+
.widget:hover .action-menu {
|
|
5331
6309
|
opacity: 1;
|
|
6310
|
+
transform: scale(1);
|
|
5332
6311
|
pointer-events: all;
|
|
5333
|
-
transition: opacity .2s, transform .32s cubic-bezier(.34,1.56,.64,1),
|
|
5334
|
-
background .15s, color .12s, box-shadow .15s;
|
|
5335
6312
|
}
|
|
5336
6313
|
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
6314
|
+
.action-item {
|
|
6315
|
+
display: flex;
|
|
6316
|
+
flex-direction: column;
|
|
6317
|
+
align-items: center;
|
|
6318
|
+
justify-content: flex-start;
|
|
6319
|
+
gap: 3px;
|
|
6320
|
+
padding: 8px 4px;
|
|
6321
|
+
border: none;
|
|
6322
|
+
border-radius: 8px;
|
|
6323
|
+
cursor: pointer;
|
|
6324
|
+
background: transparent;
|
|
6325
|
+
color: #c9d1d9;
|
|
6326
|
+
font-size: 18px;
|
|
6327
|
+
line-height: 1;
|
|
6328
|
+
transition: background .12s;
|
|
5349
6329
|
}
|
|
5350
|
-
.
|
|
5351
|
-
|
|
5352
|
-
|
|
6330
|
+
.action-item:hover { background: #21262d; }
|
|
6331
|
+
.action-item .label {
|
|
6332
|
+
font-size: 9px;
|
|
6333
|
+
font-weight: 500;
|
|
6334
|
+
color: #8b949e;
|
|
6335
|
+
white-space: nowrap;
|
|
5353
6336
|
}
|
|
6337
|
+
.action-item:hover .label { color: #e6edf3; }
|
|
5354
6338
|
|
|
5355
|
-
/* Per-direction anchors
|
|
6339
|
+
/* Per-direction anchors */
|
|
5356
6340
|
${directionBlocks()}
|
|
5357
6341
|
|
|
5358
6342
|
/* \u2500\u2500 REC / PAUSED badge \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 */
|
|
@@ -5386,14 +6370,18 @@ function getRecorderStyles(rec, paused) {
|
|
|
5386
6370
|
function renderRecorderWidget(rec, paused, t) {
|
|
5387
6371
|
return `
|
|
5388
6372
|
<div class="widget">
|
|
5389
|
-
<
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
6373
|
+
<div class="action-menu">
|
|
6374
|
+
<button class="action-item" data-action="config">
|
|
6375
|
+
<span class="ico">\u2699\uFE0F</span><span class="label">${t("RECORDER.BTN_CONFIG")}</span></button>
|
|
6376
|
+
<button class="action-item" data-action="browse">
|
|
6377
|
+
<span class="ico">\u{1F4C1}</span><span class="label">${t("RECORDER.BTN_FILES")}</span></button>
|
|
6378
|
+
<button class="action-item" data-action="commands">
|
|
6379
|
+
<span class="ico">\u2328\uFE0F</span><span class="label">${t("RECORDER.BTN_COMMANDS")}</span></button>
|
|
6380
|
+
<button class="action-item" data-action="tests">
|
|
6381
|
+
<span class="ico">\u{1F4CB}</span><span class="label">${t("RECORDER.BTN_TESTS")}</span></button>
|
|
6382
|
+
<button class="action-item" data-action="help">
|
|
6383
|
+
<span class="ico">\u2753</span><span class="label">${t("RECORDER.BTN_HELP")}</span></button>
|
|
6384
|
+
</div>
|
|
5397
6385
|
<button class="btn-pause" data-action="pause"
|
|
5398
6386
|
title="${paused ? t("RECORDER.RESUME_TITLE") : t("RECORDER.PAUSE_TITLE")}">
|
|
5399
6387
|
${paused ? "\u25B6" : "\u23F8"}
|
|
@@ -5406,6 +6394,26 @@ function renderRecorderWidget(rec, paused, t) {
|
|
|
5406
6394
|
<div class="rec-badge">${paused ? t("RECORDER.BADGE_PAUSED") : t("RECORDER.BADGE_REC")}</div>`;
|
|
5407
6395
|
}
|
|
5408
6396
|
|
|
6397
|
+
// src/utils/fixture-convert.utils.ts
|
|
6398
|
+
function toFixtureInterceptors(interceptors, fixtures) {
|
|
6399
|
+
const fixtureNames = new Set(fixtures.map((f) => f.name));
|
|
6400
|
+
return interceptors.map((icp) => {
|
|
6401
|
+
const match = icp.match(/\.as\('([^']+)'\)$/);
|
|
6402
|
+
if (!match) return icp;
|
|
6403
|
+
const fixtureFile = `${match[1]}.json`;
|
|
6404
|
+
if (!fixtureNames.has(fixtureFile)) return icp;
|
|
6405
|
+
return icp.replace(/\)\.as\(/, `, { fixture: '${fixtureFile}' }).as(`);
|
|
6406
|
+
});
|
|
6407
|
+
}
|
|
6408
|
+
function simplifyFixtureWaits(commands, fixtures) {
|
|
6409
|
+
const fixtureAliases = new Set(fixtures.map((f) => f.name.replace(/\.json$/, "")));
|
|
6410
|
+
return commands.map((cmd) => {
|
|
6411
|
+
const match = cmd.match(/^cy\.wait\('@([^']+)'\)/);
|
|
6412
|
+
if (!match || !fixtureAliases.has(match[1])) return cmd;
|
|
6413
|
+
return `cy.wait('@${match[1]}').then((interception) => { })`;
|
|
6414
|
+
});
|
|
6415
|
+
}
|
|
6416
|
+
|
|
5409
6417
|
// src/components/lib-e2e-recorder/lib-e2e-recorder.ts
|
|
5410
6418
|
var LibE2eRecorderElement = class extends HTMLElement {
|
|
5411
6419
|
shadow;
|
|
@@ -5432,6 +6440,7 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
5432
6440
|
httpMonitor;
|
|
5433
6441
|
smartSelectorEnabled = true;
|
|
5434
6442
|
_needsRecordingRebuild = false;
|
|
6443
|
+
issueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };
|
|
5435
6444
|
recording;
|
|
5436
6445
|
persistence;
|
|
5437
6446
|
translation;
|
|
@@ -5445,6 +6454,7 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
5445
6454
|
isSaveTestDialogOpen = false;
|
|
5446
6455
|
isSettingsDialogOpen = false;
|
|
5447
6456
|
isAdvancedEditorDialogOpen = false;
|
|
6457
|
+
isHelpDialogOpen = false;
|
|
5448
6458
|
constructor() {
|
|
5449
6459
|
super();
|
|
5450
6460
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
@@ -5511,6 +6521,8 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
5511
6521
|
} else {
|
|
5512
6522
|
localStorage.setItem("extendedHttpCommands", config["extendedHttpCommands"] ?? "true");
|
|
5513
6523
|
}
|
|
6524
|
+
const fx = await this.persistence.getConfig("fixtureMode");
|
|
6525
|
+
localStorage.setItem("fixtureMode", fx?.["fixtureMode"] ?? "false");
|
|
5514
6526
|
}
|
|
5515
6527
|
async initLanguage() {
|
|
5516
6528
|
const config = await this.persistence.getConfig("language");
|
|
@@ -5572,6 +6584,11 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
5572
6584
|
const strategy = config?.["selectorStrategy"];
|
|
5573
6585
|
if (strategy) this.recording.selectorStrategy = strategy;
|
|
5574
6586
|
this.smartSelectorEnabled = config?.["smartSelectorEnabled"] !== "false";
|
|
6587
|
+
this.issueTrackerConfig = {
|
|
6588
|
+
enabled: config?.["issueTrackerEnabled"] === "true",
|
|
6589
|
+
provider: config?.["issueTrackerProvider"] ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,
|
|
6590
|
+
baseUrl: config?.["issueTrackerBaseUrl"] ?? ""
|
|
6591
|
+
};
|
|
5575
6592
|
}
|
|
5576
6593
|
// ── cross-app session continuity (spec 006) ───────────────────────────────
|
|
5577
6594
|
/**
|
|
@@ -5778,6 +6795,9 @@ var LibE2eRecorderElement = class extends HTMLElement {
|
|
|
5778
6795
|
} else if (key === "3") {
|
|
5779
6796
|
event.preventDefault();
|
|
5780
6797
|
this.showSettingsDialog();
|
|
6798
|
+
} else if (key === "h" && event.shiftKey) {
|
|
6799
|
+
event.preventDefault();
|
|
6800
|
+
this.showHelpDialog();
|
|
5781
6801
|
}
|
|
5782
6802
|
}
|
|
5783
6803
|
toggleVisibility() {
|
|
@@ -5994,6 +7014,7 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
5994
7014
|
const child = document.createElement("test-editor");
|
|
5995
7015
|
child.persistence = this.persistence;
|
|
5996
7016
|
child.translation = this.translation;
|
|
7017
|
+
child.issueTrackerConfig = this.issueTrackerConfig;
|
|
5997
7018
|
container.appendChild(child);
|
|
5998
7019
|
},
|
|
5999
7020
|
willClose: () => {
|
|
@@ -6019,15 +7040,16 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
6019
7040
|
if (!container) return;
|
|
6020
7041
|
const child = document.createElement("save-test");
|
|
6021
7042
|
child.translation = this.translation;
|
|
7043
|
+
child.issueTrackerConfig = this.issueTrackerConfig;
|
|
6022
7044
|
container.appendChild(child);
|
|
6023
7045
|
child.addEventListener("savetest", (e) => {
|
|
6024
|
-
const { description, notes, tags } = e.detail ?? {};
|
|
6025
|
-
this.onSaveTest(description ?? null, tags ?? [], notes ?? "");
|
|
7046
|
+
const { description, notes, tags, ticketId } = e.detail ?? {};
|
|
7047
|
+
this.onSaveTest(description ?? null, tags ?? [], notes ?? "", ticketId ?? "");
|
|
6026
7048
|
import_sweetalert2.default.close();
|
|
6027
7049
|
});
|
|
6028
7050
|
child.addEventListener("saveandexport", (e) => {
|
|
6029
|
-
const { description, notes, tags } = e.detail ?? {};
|
|
6030
|
-
this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? "");
|
|
7051
|
+
const { description, notes, tags, ticketId } = e.detail ?? {};
|
|
7052
|
+
this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? "", ticketId ?? "");
|
|
6031
7053
|
import_sweetalert2.default.close();
|
|
6032
7054
|
});
|
|
6033
7055
|
},
|
|
@@ -6063,6 +7085,9 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
6063
7085
|
this.style.display = this.isVisible ? "" : "none";
|
|
6064
7086
|
});
|
|
6065
7087
|
child.addEventListener("resetwidgetposition", () => this.resetWidgetPosition());
|
|
7088
|
+
child.addEventListener("issuetrackerchange", (e) => {
|
|
7089
|
+
this.issueTrackerConfig = e.detail;
|
|
7090
|
+
});
|
|
6066
7091
|
},
|
|
6067
7092
|
willClose: () => {
|
|
6068
7093
|
this.isSettingsDialogOpen = false;
|
|
@@ -6071,6 +7096,31 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
6071
7096
|
this.resizePopup();
|
|
6072
7097
|
});
|
|
6073
7098
|
}
|
|
7099
|
+
showHelpDialog() {
|
|
7100
|
+
this.toggleModal("isHelpDialogOpen", () => {
|
|
7101
|
+
import_sweetalert2.default.fire({
|
|
7102
|
+
title: this.translation.translate("HELP.TITLE"),
|
|
7103
|
+
html: '<div id="help-modal-content" style="padding:0"></div>',
|
|
7104
|
+
showCloseButton: true,
|
|
7105
|
+
showConfirmButton: false,
|
|
7106
|
+
width: 560,
|
|
7107
|
+
color: "#e6edf3",
|
|
7108
|
+
didOpen: () => {
|
|
7109
|
+
makeSwalDraggable();
|
|
7110
|
+
setSwal2DataCyAttribute();
|
|
7111
|
+
const container = document.getElementById("help-modal-content");
|
|
7112
|
+
if (!container) return;
|
|
7113
|
+
const child = document.createElement("help-panel");
|
|
7114
|
+
child.translation = this.translation;
|
|
7115
|
+
container.appendChild(child);
|
|
7116
|
+
},
|
|
7117
|
+
willClose: () => {
|
|
7118
|
+
this.isHelpDialogOpen = false;
|
|
7119
|
+
}
|
|
7120
|
+
});
|
|
7121
|
+
this.resizePopup();
|
|
7122
|
+
});
|
|
7123
|
+
}
|
|
6074
7124
|
showAdvancedEditorDialog(testId) {
|
|
6075
7125
|
this.toggleModal("isAdvancedEditorDialogOpen", () => {
|
|
6076
7126
|
import_sweetalert2.default.fire({
|
|
@@ -6135,7 +7185,7 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
6135
7185
|
showFileEditorDialog(handle, content, fileName, testId, itBlock = "", interceptorsBlock = "", notes = "") {
|
|
6136
7186
|
import_sweetalert2.default.fire({
|
|
6137
7187
|
title: this.translation.translate("RECORDER.FILE_EDITOR_TITLE"),
|
|
6138
|
-
html: '<div id="file-editor-modal-content" style="
|
|
7188
|
+
html: '<div id="file-editor-modal-content" style="flex:1;min-height:0;display:flex;flex-direction:column;padding:0"></div>',
|
|
6139
7189
|
showCloseButton: false,
|
|
6140
7190
|
showConfirmButton: false,
|
|
6141
7191
|
allowOutsideClick: false,
|
|
@@ -6144,6 +7194,20 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
6144
7194
|
didOpen: () => {
|
|
6145
7195
|
makeSwalDraggable();
|
|
6146
7196
|
setSwal2DataCyAttribute();
|
|
7197
|
+
const popup = import_sweetalert2.default.getPopup();
|
|
7198
|
+
if (popup) {
|
|
7199
|
+
popup.style.height = "640px";
|
|
7200
|
+
const htmlContainer = popup.querySelector(".swal2-html-container");
|
|
7201
|
+
if (htmlContainer) {
|
|
7202
|
+
htmlContainer.style.flex = "1";
|
|
7203
|
+
htmlContainer.style.minHeight = "0";
|
|
7204
|
+
htmlContainer.style.overflow = "hidden";
|
|
7205
|
+
htmlContainer.style.padding = "0";
|
|
7206
|
+
htmlContainer.style.margin = "0";
|
|
7207
|
+
htmlContainer.style.display = "flex";
|
|
7208
|
+
htmlContainer.style.flexDirection = "column";
|
|
7209
|
+
}
|
|
7210
|
+
}
|
|
6147
7211
|
const container = document.getElementById("file-editor-modal-content");
|
|
6148
7212
|
if (!container) return;
|
|
6149
7213
|
const child = document.createElement("file-preview");
|
|
@@ -6176,24 +7240,36 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
6176
7240
|
this.resizePopup();
|
|
6177
7241
|
}
|
|
6178
7242
|
// ── save handlers ─────────────────────────────────────────────────────────
|
|
6179
|
-
async onSaveTest(description, tags = [], notes = "") {
|
|
6180
|
-
if (description)
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
7243
|
+
async onSaveTest(description, tags = [], notes = "", ticketId = "") {
|
|
7244
|
+
if (!description) return;
|
|
7245
|
+
await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes, ticketId || void 0);
|
|
7246
|
+
this.recording.clearCommands();
|
|
7247
|
+
this.clearRecordingHistory();
|
|
7248
|
+
this.cypressCommands = [];
|
|
7249
|
+
this.interceptors = [];
|
|
7250
|
+
}
|
|
7251
|
+
async onSaveAndExportTest(description, tags = [], notes = "", ticketId = "") {
|
|
7252
|
+
if (!description) return;
|
|
7253
|
+
const fixtures = this.recording.getFixturesSnapshot();
|
|
7254
|
+
const isFixtureMode = this.httpMonitor?.isFixtureModeEnabled() ?? false;
|
|
7255
|
+
let finalInterceptors = this.interceptors;
|
|
7256
|
+
let finalCommands = this.cypressCommands;
|
|
7257
|
+
if (isFixtureMode && fixtures.length > 0) {
|
|
7258
|
+
try {
|
|
7259
|
+
const n = await this.persistence.writeFixtures(fixtures);
|
|
7260
|
+
finalInterceptors = toFixtureInterceptors(this.interceptors, fixtures);
|
|
7261
|
+
finalCommands = simplifyFixtureWaits(this.cypressCommands, fixtures);
|
|
7262
|
+
showToast(`${this.translation.translate("RECORDER.FIXTURES_WRITTEN_TOAST")} (${n})`);
|
|
7263
|
+
} catch {
|
|
7264
|
+
showToast(this.translation.translate("RECORDER.FIXTURES_NO_FOLDER_TOAST"), false);
|
|
7265
|
+
}
|
|
6196
7266
|
}
|
|
7267
|
+
const id = await this.persistence.insertTest(description, finalCommands, finalInterceptors, tags, notes, ticketId || void 0);
|
|
7268
|
+
this.recording.clearCommands();
|
|
7269
|
+
this.clearRecordingHistory();
|
|
7270
|
+
this.cypressCommands = [];
|
|
7271
|
+
this.interceptors = [];
|
|
7272
|
+
setTimeout(() => this.showAdvancedEditorDialog(id), 300);
|
|
6197
7273
|
}
|
|
6198
7274
|
// ── helpers ───────────────────────────────────────────────────────────────
|
|
6199
7275
|
toggleModal(flag, openFn) {
|
|
@@ -6230,6 +7306,7 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
|
|
|
6230
7306
|
this.shadow.querySelector('[data-action="commands"]')?.addEventListener("click", () => this.showCommandsDialog());
|
|
6231
7307
|
this.shadow.querySelector('[data-action="config"]')?.addEventListener("click", () => this.showSettingsDialog());
|
|
6232
7308
|
this.shadow.querySelector('[data-action="browse"]')?.addEventListener("click", () => this.showAdvancedEditorDialog());
|
|
7309
|
+
this.shadow.querySelector('[data-action="help"]')?.addEventListener("click", () => this.showHelpDialog());
|
|
6233
7310
|
this.applyWidgetPosition();
|
|
6234
7311
|
}
|
|
6235
7312
|
};
|
|
@@ -6238,7 +7315,7 @@ if (!customElements.get("lib-e2e-recorder")) {
|
|
|
6238
7315
|
}
|
|
6239
7316
|
|
|
6240
7317
|
// src/index.ts
|
|
6241
|
-
var VERSION = "0.
|
|
7318
|
+
var VERSION = "0.9.0";
|
|
6242
7319
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6243
7320
|
0 && (module.exports = {
|
|
6244
7321
|
ACTIVE_SESSION_BREADCRUMB_KEY,
|
|
@@ -6250,6 +7327,7 @@ var VERSION = "0.6.1";
|
|
|
6250
7327
|
DEFAULT_RESUME_TTL_MINUTES,
|
|
6251
7328
|
DRAG_THRESHOLD,
|
|
6252
7329
|
FilePreviewElement,
|
|
7330
|
+
HelpPanelElement,
|
|
6253
7331
|
HttpMonitor,
|
|
6254
7332
|
INPUT_TYPES,
|
|
6255
7333
|
LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,
|
|
@@ -6275,6 +7353,7 @@ var VERSION = "0.6.1";
|
|
|
6275
7353
|
clampTogglePosition,
|
|
6276
7354
|
defaultTogglePosition,
|
|
6277
7355
|
generateAlias,
|
|
7356
|
+
inferAssertionCommand,
|
|
6278
7357
|
injectStyles,
|
|
6279
7358
|
isLang,
|
|
6280
7359
|
isLocalHost,
|