@testsmith/testblocks 0.9.1 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/executor.js +5 -1
- package/dist/cli/index.js +9 -2
- package/dist/cli/reporters/HTMLReporter.js +21 -8
- package/dist/cli/reporters/JUnitReporter.js +16 -8
- package/dist/cli/reporters/types.d.ts +1 -0
- package/dist/client/assets/{index-BCKY2YTp.js → index-BB7IxLgr.js} +71 -71
- package/dist/client/assets/{index-BCKY2YTp.js.map → index-BB7IxLgr.js.map} +1 -1
- package/dist/client/assets/index-DTBSYs3n.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/core/blocks/playwright/assertions.js +10 -20
- package/dist/core/blocks/playwright/interactions.js +7 -14
- package/dist/core/blocks/playwright/navigation.js +2 -4
- package/dist/core/blocks/playwright/retrieval.js +3 -6
- package/dist/core/blocks/playwright/utils.d.ts +4 -0
- package/dist/core/blocks/playwright/utils.js +8 -0
- package/dist/core/types.d.ts +1 -0
- package/dist/server/executor.js +7 -1
- package/dist/server/globals.d.ts +4 -0
- package/dist/server/globals.js +7 -0
- package/dist/server/index.js +4 -2
- package/dist/server/startServer.js +6 -4
- package/package.json +1 -1
- package/dist/client/assets/index-C5yUtTzz.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--ts-blue: #205d96;--ts-blue-light: #e0f2fe;--ts-blue-dark: #1a4a78;--ts-green: #9fc93c;--ts-green-light: #ecfccb;--ts-green-dark: #5c7a1f;--ts-gray: #59575d;--ts-gray-light: #6b7280;--ts-gray-bg: #f8fafc;--primary-color: var(--ts-blue);--primary-dark: var(--ts-blue-dark);--primary-light: var(--ts-blue-light);--secondary-color: var(--ts-gray);--background: var(--ts-gray-bg);--surface: #ffffff;--error: #d32f2f;--success: var(--ts-green-dark);--success-light: var(--ts-green-light);--warning: #e67e00;--text-primary: var(--ts-gray);--text-secondary: var(--ts-gray-light);--border-color: #e0e0e0}*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,sans-serif;background-color:var(--background);color:var(--text-primary)}.app{display:flex;flex-direction:column;height:100vh;overflow:hidden}.header{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:56px;background:var(--primary-color);color:#fff;box-shadow:0 2px 4px #0000001a;z-index:100}.header h1{font-size:20px;font-weight:500;display:flex;align-items:center;gap:8px}.header-actions{display:flex;gap:8px}.btn{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;border:none;border-radius:4px;font-size:14px;font-weight:500;cursor:pointer;transition:background-color .2s,opacity .2s}.btn:disabled{opacity:.6;cursor:not-allowed}.btn-primary{background:#fff;color:var(--primary-color)}.btn-primary:hover:not(:disabled){background:#ffffffe6}.btn-secondary{background:#ffffff26;color:#fff}.btn-secondary:hover:not(:disabled){background:#ffffff40}.btn-success{background:var(--ts-green);color:#fff}.btn-success:hover:not(:disabled){background:var(--ts-green-dark)}.btn-danger{background:var(--error);color:#fff}.btn-danger:hover:not(:disabled){background:#c62828}.main-content{display:flex;flex:1;overflow:hidden}.sidebar{width:280px;background:var(--surface);border-right:1px solid var(--border-color);display:flex;flex-direction:column;overflow:hidden;transition:width .2s ease}.sidebar.collapsed{width:40px}.sidebar-toggle-header{display:flex;align-items:center;justify-content:flex-end;padding:8px;border-bottom:1px solid var(--border-color)}.sidebar.collapsed .sidebar-toggle-header{justify-content:center}.sidebar-header{padding:16px;border-bottom:1px solid var(--border-color)}.sidebar-header h2{font-size:14px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px}.test-list{flex:1;overflow-y:auto;padding:8px}.test-item{padding:12px;border-radius:4px;cursor:pointer;border:1px solid transparent;margin-bottom:4px;transition:background-color .2s}.test-item:hover{background:var(--background)}.test-item.active{background:#1976d214;border-color:var(--primary-color)}.test-item-name{font-weight:500;font-size:14px;margin-bottom:4px}.test-item-steps{font-size:12px;color:var(--text-secondary)}.add-test-btn{margin:8px;padding:12px;border:2px dashed var(--border-color);border-radius:4px;background:transparent;color:var(--text-secondary);cursor:pointer;font-size:14px;transition:border-color .2s,color .2s}.add-test-btn:hover{border-color:var(--primary-color);color:var(--primary-color)}.editor-area{flex:1;display:flex;flex-direction:column;overflow:hidden}.editor-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 16px;background:var(--surface);border-bottom:1px solid var(--border-color)}.test-name-input{font-size:16px;font-weight:500;padding:8px 12px;border:1px solid var(--border-color);border-radius:4px;width:300px}.test-name-input:focus{outline:none;border-color:var(--primary-color)}.blockly-container{flex:1;position:relative}#blockly-div{position:absolute;top:0;left:0;right:0;bottom:0}.blocklyTreeSeparator{height:1px!important;margin:12px 8px!important;background-color:#0006!important;border:none!important}.blocklyWidgetDiv .blocklyHtmlInput{max-width:350px;font-family:monospace;font-size:12px;line-height:1.4}.results-panel{width:350px;background:var(--surface);border-left:1px solid var(--border-color);display:flex;flex-direction:column;overflow:hidden;transition:width .2s ease}.results-panel.collapsed{width:40px}.results-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--border-color);gap:12px}.results-panel.collapsed .results-header{justify-content:center;padding:12px 8px}.panel-toggle-btn{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;padding:4px 8px;border-radius:4px;flex-shrink:0}.panel-toggle-btn:hover{background:var(--hover-bg);color:var(--text-primary)}.results-header h2{font-size:14px;font-weight:600;color:var(--text-secondary);text-transform:uppercase;letter-spacing:.5px;flex:1;display:flex;align-items:center;gap:8px}.results-summary{display:flex;gap:8px;font-size:12px;font-weight:500;text-transform:none}.results-summary .passed-count{color:var(--success)}.results-summary .failed-count{color:var(--danger)}.results-summary .skipped-count{color:#f59e0b}.results-actions{display:flex;gap:8px}.btn-report{padding:4px 8px;font-size:11px;font-weight:500;border:1px solid var(--border-color);border-radius:4px;background:var(--surface);color:var(--text-secondary);cursor:pointer;transition:all .2s}.btn-report:hover{background:var(--primary-light);border-color:var(--primary-color);color:var(--primary-color)}.results-content{flex:1;overflow-y:auto;padding:16px}.result-item{padding:12px;border-radius:4px;margin-bottom:8px;border-left:4px solid}.result-item.passed{background:#388e3c14;border-left-color:var(--success)}.result-item.failed{background:#d32f2f14;border-left-color:var(--error)}.result-item.running{background:#1976d214;border-left-color:var(--primary-color)}.result-step{font-size:13px;margin-bottom:4px}.result-error{font-size:12px;color:var(--error);font-family:monospace;white-space:pre-wrap;margin-top:8px}.result-duration{font-size:11px;color:var(--text-secondary)}.modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1000}.modal{background:var(--surface);border-radius:8px;padding:24px;min-width:400px;max-width:600px;max-height:80vh;overflow-y:auto;box-shadow:0 4px 20px #00000026}.modal h2{margin-bottom:16px}.modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:24px}.folder-hooks-modal{background:var(--surface);border-radius:8px;width:90vw;max-width:1200px;height:80vh;display:flex;flex-direction:column;box-shadow:0 4px 20px #00000026}.folder-hooks-header{padding:16px 24px;border-bottom:1px solid var(--border-color);position:relative}.folder-hooks-header h2{margin:0 0 4px;font-size:18px}.folder-hooks-description{font-size:13px;color:var(--text-secondary);margin:0}.folder-hooks-tabs{display:flex;border-bottom:1px solid var(--border-color);padding:0 16px;background:var(--background)}.folder-hooks-tab{padding:12px 16px;border:none;background:transparent;color:var(--text-secondary);font-size:13px;font-weight:500;cursor:pointer;border-bottom:2px solid transparent;display:flex;align-items:center;gap:8px}.folder-hooks-tab:hover{color:var(--text-primary)}.folder-hooks-tab.active{color:var(--primary-color);border-bottom-color:var(--primary-color)}.folder-hooks-tab .tab-badge{font-size:10px;padding:2px 6px;border-radius:10px;background:var(--primary-color);color:#fff}.folder-hooks-workspace{flex:1;min-height:0}.folder-hooks-footer{padding:16px 24px;border-top:1px solid var(--border-color);display:flex;justify-content:flex-end;gap:8px}.form-group{margin-bottom:16px}.form-group label{display:block;font-size:14px;font-weight:500;margin-bottom:6px}.form-group input,.form-group textarea{width:100%;padding:10px 12px;border:1px solid var(--border-color);border-radius:4px;font-size:14px}.form-group input:focus,.form-group textarea:focus{outline:none;border-color:var(--primary-color)}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:var(--text-secondary);text-align:center;padding:40px}.empty-state h3{margin-bottom:8px;color:var(--text-primary)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--background)}::-webkit-scrollbar-thumb{background:#bdbdbd;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#9e9e9e}.status-indicator{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:6px}.status-indicator.running{background:var(--primary-color);animation:pulse 1s infinite}.status-indicator.passed{background:var(--success)}.status-indicator.failed{background:var(--error)}.sidebar-section{border-bottom:1px solid var(--border-color)}.sidebar-section:last-child{border-bottom:none;flex:1;display:flex;flex-direction:column;overflow:hidden}.sidebar-header.clickable{cursor:pointer;-webkit-user-select:none;user-select:none}.sidebar-header.clickable:hover{background:var(--background)}.variables-list{padding:8px}.variable-item{display:flex;align-items:center;gap:8px;padding:6px 0}.variable-name{font-family:monospace;font-size:12px;color:var(--primary-color);min-width:80px;flex-shrink:0}.variable-value{flex:1;padding:4px 8px;border:1px solid var(--border-color);border-radius:4px;font-size:12px}.variable-value:focus{outline:none;border-color:var(--primary-color)}.global-variables{background:linear-gradient(to right,rgba(32,93,150,.05),transparent)}.variable-item.global{padding:4px 0}.variable-item.global .variable-name{color:var(--ts-blue);font-size:11px;word-break:break-all}.variable-value.readonly{background:var(--background);color:var(--text-secondary);font-family:monospace;font-size:11px;padding:2px 6px;border:none;border-radius:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.variable-value.global-input{flex:1;padding:4px 6px;border:1px solid rgba(32,93,150,.3);border-radius:4px;font-size:11px;font-family:monospace;background:#205d960d;color:var(--text-primary)}.variable-value.global-input:focus{outline:none;border-color:var(--ts-blue);background:#205d961a}.variable-group{margin-bottom:8px}.variable-group-header{font-weight:600;font-size:11px;color:var(--text-secondary);text-transform:uppercase;padding:4px 0;border-bottom:1px solid var(--border-color);margin-bottom:4px}.variable-group-content{padding-left:12px;border-left:2px solid rgba(32,93,150,.3)}.global-badge{font-size:12px;margin-left:8px;opacity:.7}.btn-icon{background:none;border:none;color:var(--text-secondary);cursor:pointer;padding:4px 8px;font-size:16px;line-height:1;border-radius:4px}.btn-icon:hover{background:var(--background);color:var(--error)}.add-variable-btn{width:100%;margin-top:8px;padding:8px;border:1px dashed var(--border-color);border-radius:4px;background:transparent;color:var(--text-secondary);cursor:pointer;font-size:12px}.add-variable-btn:hover{border-color:var(--primary-color);color:var(--primary-color)}.test-item{display:flex;align-items:center;justify-content:space-between}.test-item-content{flex:1;min-width:0}.test-item-name{display:flex;align-items:center;gap:6px}.data-driven-badge{font-size:10px;font-weight:600;background:#1565c0;color:#fff;padding:1px 5px;border-radius:8px;margin-left:4px}.btn-run-test{background:none;border:1px solid var(--border-color);border-radius:4px;padding:4px 8px;cursor:pointer;font-size:10px;color:var(--text-secondary);flex-shrink:0;margin-left:8px}.btn-run-test:hover:not(:disabled){background:var(--primary-color);border-color:var(--primary-color);color:#fff}.btn-run-test:disabled{opacity:.5;cursor:not-allowed}.status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0}.status-dot.passed{background:var(--success)}.status-dot.failed{background:var(--error)}.test-item.passed{background:#388e3c0d}.test-item.failed{background:#d32f2f0d}.test-item.passed.active{background:#388e3c1f}.test-item.failed.active{background:#d32f2f1f}.test-item.disabled{opacity:.6;background:#9e9e9e0d}.test-item.disabled.active{background:#9e9e9e1f}.test-item.disabled .btn-run-test{opacity:.4;cursor:not-allowed}.test-name-disabled{text-decoration:line-through;color:var(--text-secondary)}.status-dot.skipped{background:#f59e0b}.test-item.skipped{background:#f59e0b0d}.test-item.skipped.active{background:#f59e0b1f}.test-id-indicator{display:flex;align-items:center;gap:6px;color:#ffffffe6;font-size:13px;padding:6px 12px;border-radius:4px;background:#ffffff1a}.test-id-indicator code{font-family:Monaco,Menlo,monospace;background:#fff3;padding:2px 6px;border-radius:3px;font-size:12px}.headless-toggle{display:flex;align-items:center;gap:6px;color:#fff;font-size:14px;cursor:pointer;padding:8px 12px;border-radius:4px;background:#ffffff1a}.headless-toggle:hover{background:#fff3}.headless-toggle input[type=checkbox]{width:16px;height:16px;cursor:pointer}.create-block-modal{min-width:500px;max-width:600px}.create-block-modal h2{color:var(--text-primary);margin-bottom:20px}.helper-text{font-size:12px;color:var(--text-secondary);margin-bottom:8px}.color-picker{display:flex;gap:8px}.color-option{width:32px;height:32px;border-radius:4px;border:2px solid transparent;cursor:pointer;transition:transform .1s,border-color .1s}.color-option:hover{transform:scale(1.1)}.color-option.selected{border-color:var(--text-primary)}.param-list{max-height:200px;overflow-y:auto;border:1px solid var(--border-color);border-radius:4px;padding:8px}.empty-params{color:var(--text-secondary);font-size:13px;padding:12px;text-align:center}.param-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:4px;cursor:pointer;font-size:13px}.param-item:hover{background:var(--background)}.param-item input[type=checkbox]{flex-shrink:0}.param-name{font-weight:500;color:var(--primary-color)}.param-source{color:var(--text-secondary);font-size:11px}.param-default{color:var(--text-secondary);font-size:11px;margin-left:auto;font-family:monospace}.steps-preview{max-height:150px;overflow-y:auto;border:1px solid var(--border-color);border-radius:4px;padding:8px}.step-preview-item{display:flex;align-items:center;gap:8px;padding:4px 8px;font-size:13px}.step-number{color:var(--text-secondary);font-size:11px;width:20px}.step-type{color:var(--text-primary)}.create-block-modal .btn-primary{background:var(--primary-color);color:#fff}.create-block-modal .btn-primary:hover{background:var(--primary-dark)}.create-block-modal .btn-secondary{background:var(--background);color:var(--text-primary)}.result-test-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.result-file-name{color:var(--text-secondary);font-size:12px;margin-right:4px}.result-test-name{font-weight:500;flex:1}.result-steps{margin-top:8px;border-top:1px solid var(--border-color);padding-top:8px}.step-result-item{margin-bottom:6px;border-radius:4px;background:#00000005}.step-result-item.passed{border-left:3px solid var(--success)}.step-result-item.failed{border-left:3px solid var(--error)}.step-result-header{display:flex;align-items:center;gap:8px;padding:6px 8px;cursor:pointer;-webkit-user-select:none;user-select:none}.step-result-header:hover{background:#0000000a}.step-result-type{font-size:12px;color:var(--text-primary);white-space:nowrap}.step-result-summary{flex:1;font-size:11px;color:var(--text-secondary);font-family:monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:300px}.step-result-duration{font-size:11px;color:var(--text-secondary);white-space:nowrap}.step-result-expand{font-size:10px;color:var(--text-secondary);width:16px;text-align:center}.step-result-header.expandable{cursor:pointer}.step-result-header.expandable:hover{background:#0000000a}.step-result-details{padding:8px;background:var(--background);border-radius:0 0 4px 4px}.step-output{background:var(--surface);border-radius:4px;padding:8px}.step-result-error{padding:6px 8px;font-size:11px;color:var(--error);background:#d32f2f0d;font-family:monospace}.step-screenshot{margin-bottom:12px}.screenshot-label{font-size:11px;font-weight:600;color:var(--text-secondary);margin-bottom:6px;text-transform:uppercase;letter-spacing:.5px}.failure-screenshot{max-width:100%;max-height:300px;border:2px solid var(--error);border-radius:6px;cursor:pointer;transition:transform .2s,box-shadow .2s;display:block}.failure-screenshot:hover{transform:scale(1.02);box-shadow:0 4px 12px #d32f2f4d}.stack-trace{font-size:10px;line-height:1.4;color:var(--error);max-height:200px;overflow-y:auto}.step-result-response{padding:8px;background:var(--background);border-radius:0 0 4px 4px}.response-status{display:flex;align-items:center;gap:8px;margin-bottom:8px}.response-label{font-size:11px;color:var(--text-secondary)}.response-status-code{font-family:monospace;font-size:12px;font-weight:600;padding:2px 6px;border-radius:3px;background:var(--surface)}.response-status-code.status-success{color:var(--success);background:#388e3c1a}.response-status-code.status-client-error{color:var(--warning);background:#f57c001a}.response-status-code.status-server-error{color:var(--error);background:#d32f2f1a}.response-section{margin-top:8px}.response-section summary{font-size:11px;color:var(--text-secondary);cursor:pointer;padding:4px 0;-webkit-user-select:none;user-select:none}.response-section summary:hover{color:var(--primary-color)}.response-pre{margin:4px 0 0;padding:8px;background:var(--surface);border:1px solid var(--border-color);border-radius:4px;font-size:11px;font-family:monospace;overflow-x:auto;max-height:200px;overflow-y:auto;white-space:pre-wrap;word-break:break-all}.lifecycle-badge{display:inline-block;font-size:10px;font-weight:600;text-transform:uppercase;padding:2px 6px;border-radius:3px;background:var(--ts-gray);color:#fff;letter-spacing:.5px}.result-item.lifecycle,.result-item.lifecycle.passed{border-left-color:var(--ts-gray);background:#59575d14}.result-item.lifecycle.failed{border-left-color:#d32f2f;background:#d32f2f14}.editor-tabs{display:flex;background:var(--surface);border-bottom:1px solid var(--border-color);padding:0 8px}.editor-tab{padding:10px 16px;border:none;background:transparent;color:var(--text-secondary);font-size:13px;font-weight:500;cursor:pointer;border-bottom:2px solid transparent;transition:all .2s;display:flex;align-items:center;gap:6px}.editor-tab:hover{color:var(--text-primary);background:var(--background)}.editor-tab.active{color:var(--primary-color);border-bottom-color:var(--primary-color)}.editor-tab.test-tab{margin:0 auto 0 0;font-weight:600}.editor-tab.test-tab.active{color:var(--primary-color)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;font-size:11px;font-weight:600;background:var(--ts-gray);color:#fff;border-radius:9px}.editor-tab.active .tab-badge{background:var(--primary-color)}.lifecycle-toolbar-info{display:flex;align-items:center;gap:8px;color:var(--text-primary);font-size:14px;font-weight:500}.lifecycle-icon{font-size:16px}.lifecycle-hint{color:var(--text-secondary);font-weight:400;font-size:13px}.sidebar-tabs{display:flex;border-bottom:1px solid var(--border-color)}.sidebar-tab{flex:1;padding:10px;border:none;background:transparent;color:var(--text-secondary);font-size:13px;font-weight:500;cursor:pointer;border-bottom:2px solid transparent;transition:all .2s}.sidebar-tab:hover{color:var(--text-primary);background:var(--background)}.sidebar-tab.active{color:var(--primary-color);border-bottom-color:var(--primary-color)}.file-tree-section,.file-tree{flex:1;overflow:hidden;display:flex;flex-direction:column}.file-tree-header{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-bottom:1px solid var(--border-color);background:var(--background)}.file-tree-root-name{font-weight:600;font-size:13px;color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.file-tree-refresh{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:16px;padding:4px;border-radius:4px}.file-tree-refresh:hover{background:var(--surface);color:var(--primary-color)}.file-tree-header-actions{display:flex;align-items:center;gap:4px}.file-tree-action-btn{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;padding:4px 6px;border-radius:4px}.file-tree-action-btn:hover{background:var(--surface);color:var(--primary-color)}.folder-actions{position:relative;margin-left:auto}.folder-action-btn{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:14px;font-weight:700;width:20px;height:20px;border-radius:4px;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .15s}.file-tree-item:hover .folder-action-btn{opacity:1}.folder-action-btn:hover{background:var(--primary-light);color:var(--primary-color)}.folder-actions-menu{position:absolute;top:100%;right:0;background:#fff;border:1px solid var(--border-color);border-radius:6px;box-shadow:0 4px 12px #00000026;z-index:100;min-width:140px;padding:4px 0}.folder-actions-menu button{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;border:none;background:none;text-align:left;font-size:13px;color:var(--text-primary);cursor:pointer}.folder-actions-menu button:hover{background:var(--primary-light);color:var(--primary-color)}.folder-actions-menu button.delete-action:hover{background:#fee2e2;color:#dc2626}.folder-actions-menu button.run-action{color:#16a34a;font-weight:500}.folder-actions-menu button.run-action:hover{background:#dcfce7;color:#15803d}.folder-actions-menu button:disabled{opacity:.5;cursor:not-allowed}.file-tree-run-btn{color:#16a34a!important}.file-tree-run-btn:hover:not(:disabled){background:#dcfce7!important}.file-tree-run-btn:disabled{opacity:.5;cursor:not-allowed}.file-tree-content{flex:1;overflow-y:auto;padding:4px 0}.file-tree-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px 16px;color:var(--text-secondary);text-align:center}.file-tree-empty p{margin:4px 0;font-size:13px}.file-tree-hint{font-size:12px;opacity:.7}.file-tree-item{display:flex;align-items:center;gap:6px;padding:6px 8px;cursor:pointer;font-size:13px;color:var(--text-primary);border-left:2px solid transparent;transition:all .15s;position:relative}.file-tree-item:hover{background:var(--background)}.file-tree-item.selected{background:#1976d214;border-left-color:var(--primary-color)}.file-tree-item.folder{color:var(--text-secondary)}.file-tree-item[draggable=true]{cursor:grab}.file-tree-item[draggable=true]:active{cursor:grabbing}.file-tree-item.dragging{opacity:.5;background:var(--background)}.file-tree-item.drag-over{background:#1976d226;border-left-color:var(--primary-color);border-left-width:3px}.file-tree-item.drag-over:after{content:"";position:absolute;left:0;right:0;top:0;bottom:0;border:2px dashed var(--primary-color);border-radius:4px;pointer-events:none}.file-tree-icon{font-size:14px;flex-shrink:0}.file-tree-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.file-tree-badge{font-size:10px;font-weight:600;padding:2px 6px;border-radius:10px;background:var(--primary-color);color:#fff;flex-shrink:0}.file-tree-failed-indicator{color:#ef4444;font-size:10px;margin-left:4px;flex-shrink:0}.folder-hooks-btn{background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:12px;padding:2px 4px;opacity:0;transition:opacity .2s;flex-shrink:0}.file-tree-item.folder:hover .folder-hooks-btn{opacity:1}.folder-hooks-btn:hover{color:var(--primary-color)}.folder-hooks-indicator{font-size:10px;color:var(--primary-color);margin-left:4px;flex-shrink:0}.header-version{margin-left:8px;font-size:11px;font-weight:400;color:#ffffff80;background:#ffffff1a;padding:2px 6px;border-radius:4px}.header-file-path{margin-left:12px;font-size:12px;font-weight:400;color:#ffffffb3;max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-flex;align-items:center;gap:8px}.auto-save-indicator{font-size:11px;padding:2px 8px;border-radius:4px;flex-shrink:0}.auto-save-indicator.saving{background:#ffc10733;color:#ffc107;animation:pulse 1s ease-in-out infinite}.auto-save-indicator.saved{background:#4caf5033;color:#4caf50}@keyframes pulse{0%,to{opacity:1}50%{opacity:.5}}.folder-hooks-label{background:rgba(var(--ts-blue),.1);background:#e0f2fe;color:var(--ts-blue);padding:2px 8px;border-radius:4px;font-size:11px;font-weight:500;margin-right:6px}.help-modal{width:950px;max-width:95vw;height:85vh;max-height:85vh;display:flex;flex-direction:column;padding:0;overflow:hidden}.help-header{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;border-bottom:1px solid var(--border-color);flex-shrink:0}.help-header h2{margin:0;font-size:20px;font-weight:500}.btn-close{background:none;border:none;font-size:24px;cursor:pointer;color:var(--text-secondary);padding:4px 8px;border-radius:4px;line-height:1}.btn-close:hover{background:var(--background);color:var(--text-primary)}.help-layout{display:flex;flex:1;overflow:hidden}.help-nav{width:200px;flex-shrink:0;background:var(--background);border-right:1px solid var(--border-color);padding:12px 0;overflow-y:auto}.help-nav-item{display:block;width:100%;padding:10px 20px;border:none;background:none;text-align:left;cursor:pointer;font-size:14px;color:var(--text-secondary);transition:background .2s,color .2s}.help-nav-item:hover{background:#0000000a;color:var(--text-primary)}.help-nav-item.active{background:#1976d21a;color:var(--primary-color);font-weight:500;border-left:3px solid var(--primary-color);padding-left:17px}.help-content{flex:1;overflow-y:auto;padding:24px 32px}.help-content h3{margin:0 0 8px;font-size:22px;font-weight:600;color:var(--text-primary)}.help-content>p{margin:0 0 24px;color:var(--text-secondary);font-size:15px;line-height:1.5}.help-feature{margin-bottom:24px;padding:16px 20px;background:var(--background);border-radius:8px}.help-feature h4{margin:0 0 12px;font-size:15px;font-weight:600;color:var(--text-primary)}.help-feature ol,.help-feature ul{margin:0;padding-left:20px}.help-feature li{margin-bottom:8px;line-height:1.5;color:var(--text-primary)}.help-feature li:last-child{margin-bottom:0}.help-feature p{margin:0 0 12px;line-height:1.5}.help-feature code{background:#0000000f;padding:2px 6px;border-radius:4px;font-family:SF Mono,Monaco,Courier New,monospace;font-size:13px;color:var(--primary-dark)}.help-tip{margin-bottom:24px;padding:14px 18px;background:#1976d214;border-left:3px solid var(--primary-color);border-radius:0 8px 8px 0;font-size:14px;line-height:1.5}.help-tip code{background:#0000000f;padding:2px 6px;border-radius:4px;font-family:SF Mono,Monaco,Courier New,monospace;font-size:13px}.help-code{margin:12px 0 0;padding:12px 16px;background:#1e1e1e;color:#d4d4d4;border-radius:6px;font-family:SF Mono,Monaco,Courier New,monospace;font-size:13px;line-height:1.5;overflow-x:auto;white-space:pre}.scan-project-btn{margin-top:8px}.scan-project-btn:disabled{opacity:.6;cursor:not-allowed}.matches-section{margin-top:12px}.matches-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;font-size:13px;color:var(--text-secondary)}.matches-actions{display:flex;gap:12px}.btn-link{background:none;border:none;color:var(--primary-color);cursor:pointer;font-size:12px;padding:0}.btn-link:hover{text-decoration:underline}.matches-list{max-height:200px;overflow-y:auto;border:1px solid var(--border-color);border-radius:6px;background:var(--surface)}.match-file-group{border-bottom:1px solid var(--border-color)}.match-file-group:last-child{border-bottom:none}.match-file-name{font-size:12px;font-weight:600;color:var(--text-primary);padding:8px 12px 4px;background:var(--background)}.match-item{display:flex;align-items:center;gap:8px;padding:6px 12px;cursor:pointer;transition:background .15s}.match-item:hover{background:#00000008}.match-item input[type=checkbox]{flex-shrink:0}.match-location{font-size:13px;color:var(--text-primary);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.match-detail{font-size:12px;color:var(--text-secondary);margin-left:4px}.record-dialog{min-width:500px;max-width:600px}.record-dialog .modal-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding-bottom:12px;border-bottom:1px solid var(--border-color)}.record-dialog .modal-header h2{margin:0;font-size:18px}.record-dialog .modal-body{min-height:150px}.record-url-input{display:flex;flex-direction:column;gap:12px}.record-url-input p{margin:0;color:var(--text-primary)}.url-input{width:100%;padding:10px 12px;border:1px solid var(--border-color);border-radius:4px;font-size:14px}.url-input:focus{outline:none;border-color:var(--primary-color)}.record-hint{font-size:13px;color:var(--text-secondary);margin-top:4px}.record-status{display:flex;align-items:center;gap:16px;padding:20px;background:var(--background);border-radius:8px;margin:16px 0}.record-status.recording{border-left:4px solid var(--error);background:#d32f2f0d}.record-status.processing{border-left:4px solid var(--warning);background:#f57c000d;justify-content:center}.recording-indicator{width:16px;height:16px;background:var(--error);border-radius:50%;animation:pulse 1.5s ease-in-out infinite;flex-shrink:0}@keyframes pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.6;transform:scale(.9)}}.recording-info h3{margin:0 0 8px;font-size:16px;color:var(--text-primary)}.recording-info p{margin:0;font-size:13px;color:var(--text-secondary)}.processing-spinner{width:24px;height:24px;border:3px solid var(--border-color);border-top-color:var(--primary-color);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.record-preview h3{margin:0 0 12px;font-size:15px}.steps-preview{max-height:300px;overflow-y:auto;border:1px solid var(--border-color);border-radius:6px;background:var(--surface)}.step-preview-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-bottom:1px solid var(--border-color);font-size:13px}.step-preview-item:last-child{border-bottom:none}.step-number{font-weight:600;color:var(--text-secondary);min-width:24px}.step-description{color:var(--text-primary);font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.record-empty{text-align:center;padding:24px;color:var(--text-secondary)}.record-empty p{margin:0 0 8px}.record-error{color:var(--error);font-size:13px;padding:8px 12px;background:#d32f2f1a;border-radius:4px}.record-error-state{text-align:center;padding:20px}.record-error-state h3{margin:0 0 12px;color:var(--error)}.record-error-state .record-error{margin-bottom:16px}.btn-warning{background:var(--warning);color:#fff}.btn-warning:hover:not(:disabled){background:#e65100}.advanced-options{margin-top:16px;border-top:1px solid var(--border-color);padding-top:12px}.advanced-toggle{display:flex;align-items:center;gap:8px;background:none;border:none;padding:8px 0;font-size:13px;color:var(--text-secondary);cursor:pointer;width:100%;text-align:left}.advanced-toggle:hover{color:var(--text-primary)}.advanced-toggle .toggle-icon{font-size:10px;width:12px}.advanced-content{padding:12px 0 4px 20px}.option-row{display:flex;align-items:center;gap:12px;margin-bottom:8px}.option-row label{font-size:13px;color:var(--text-primary);white-space:nowrap;min-width:120px}.option-input{flex:1;padding:6px 10px;border:1px solid var(--border-color);border-radius:4px;font-size:13px;font-family:Monaco,Menlo,Ubuntu Mono,monospace}.option-input:focus{outline:none;border-color:var(--primary-color)}.option-hint{font-size:12px;color:var(--text-secondary);margin:4px 0 0}.json-editor-modal{width:600px;max-width:90vw;min-height:400px;max-height:80vh;display:flex;flex-direction:column;padding:0}.json-editor-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border-color)}.json-editor-header h3{margin:0;font-size:16px;font-weight:600}.json-editor-toolbar{display:flex;align-items:center;gap:8px;padding:12px 20px;background:var(--background);border-bottom:1px solid var(--border-color)}.json-editor-toolbar .btn-small{padding:4px 12px;font-size:12px}.json-status{margin-left:auto;font-size:12px;font-weight:500;padding:4px 8px;border-radius:4px}.json-status.valid{color:var(--success);background:var(--success-light)}.json-status.invalid{color:var(--error);background:#fef2f2}.json-editor-content{flex:1;display:flex;flex-direction:column;padding:16px 20px;min-height:200px}.json-textarea{flex:1;width:100%;min-height:250px;padding:12px;border:1px solid var(--border-color);border-radius:4px;font-family:Monaco,Menlo,Ubuntu Mono,Consolas,monospace;font-size:13px;line-height:1.5;resize:vertical;background:#fafafa}.json-textarea:focus{outline:none;border-color:var(--primary-color);background:#fff}.json-textarea.has-error{border-color:var(--error);background:#fef8f8}.json-error{margin-top:8px;padding:8px 12px;background:#fef2f2;border:1px solid #fecaca;border-radius:4px;color:var(--error);font-size:12px;font-family:monospace}.json-editor-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 20px;border-top:1px solid var(--border-color);background:var(--background)}.json-edit-button{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;margin-left:4px;background:var(--primary-light);border:1px solid var(--primary-color);border-radius:3px;color:var(--primary-color);font-size:11px;cursor:pointer;transition:background .2s}.json-edit-button:hover{background:var(--primary-color);color:#fff}.reopen-folder-prompt{display:flex;flex-direction:column;gap:8px;padding:12px;margin:8px;background:var(--primary-light);border:1px solid var(--primary-color);border-radius:6px;font-size:13px}.reopen-folder-prompt span{color:var(--text-secondary)}.reopen-folder-prompt strong{color:var(--text-primary);word-break:break-all}.reopen-folder-prompt .btn{align-self:flex-start}.toast-container{position:fixed;top:16px;right:16px;z-index:10000;display:flex;flex-direction:column;gap:8px;max-width:400px}.toast{display:flex;align-items:center;gap:10px;padding:12px 16px;border-radius:6px;background:#fff;box-shadow:0 4px 12px #00000026;animation:toast-slide-in .3s ease}@keyframes toast-slide-in{0%{transform:translate(100%);opacity:0}to{transform:translate(0);opacity:1}}.toast-icon{flex-shrink:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:50%;font-size:12px;font-weight:700}.toast-success .toast-icon{background:var(--success-light);color:var(--success)}.toast-error .toast-icon{background:#ffebee;color:var(--error)}.toast-warning .toast-icon{background:#fff3e0;color:var(--warning)}.toast-info .toast-icon{background:var(--primary-light);color:var(--primary-color)}.toast-message{flex:1;font-size:13px;color:var(--text-primary)}.toast-dismiss{flex-shrink:0;background:none;border:none;font-size:18px;color:var(--text-secondary);cursor:pointer;padding:0;line-height:1}.toast-dismiss:hover{color:var(--text-primary)}.variables-editor{display:flex;flex-direction:column;gap:8px}.variable-editor-item{display:flex;align-items:flex-start;gap:8px;padding:8px;background:var(--background);border-radius:4px}.variable-editor-item .var-name{flex:0 0 120px;position:relative}.variable-editor-item .var-value{flex:1;min-width:0}.variable-editor-item input,.variable-editor-item textarea{width:100%;padding:6px 8px;border:1px solid var(--border-color);border-radius:4px;font-size:13px;font-family:monospace}.variable-editor-item input:focus,.variable-editor-item textarea:focus{outline:none;border-color:var(--primary-color)}.variable-editor-item .var-actions{display:flex;gap:4px}.variable-editor-item .btn-icon{padding:4px 8px;background:none;border:1px solid var(--border-color);border-radius:4px;cursor:pointer;font-size:12px}.variable-editor-item .btn-icon:hover{background:var(--border-color)}.variable-editor-item .btn-icon.delete:hover{background:#ffebee;border-color:var(--error);color:var(--error)}.variable-editor-item.duplicate{background:#fff3e0}.variable-editor-item .duplicate-warning{position:absolute;right:6px;top:50%;transform:translateY(-50%);color:#f57c00;font-size:14px;cursor:help}.add-variable-btn{align-self:flex-start;padding:6px 12px;background:var(--primary-light);border:1px dashed var(--primary-color);border-radius:4px;color:var(--primary-color);font-size:13px;cursor:pointer}.add-variable-btn:hover{background:var(--primary-color);color:#fff;border-style:solid}.variables-section-header{display:flex;align-items:center;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--border-color);margin-bottom:8px}.variables-section-header h4{margin:0;font-size:13px;font-weight:600;color:var(--text-primary)}.variables-empty{padding:16px;text-align:center;color:var(--text-secondary);font-size:13px;background:var(--background);border-radius:4px}.context-menu{position:fixed;background:#fff;border:1px solid var(--border-color);border-radius:6px;box-shadow:0 4px 12px #00000026;min-width:180px;z-index:10000;padding:4px 0}.context-menu-item{display:block;width:100%;padding:8px 12px;border:none;background:none;text-align:left;font-size:13px;color:var(--text-primary);cursor:pointer}.context-menu-item:hover:not(.disabled){background:var(--primary-light);color:var(--primary-color)}.context-menu-item.disabled{color:var(--text-secondary);cursor:not-allowed}.create-variable-dialog{background:var(--surface);border-radius:8px;min-width:400px;max-width:500px;box-shadow:0 4px 20px #00000026}.create-variable-dialog .modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border-color)}.create-variable-dialog .modal-header h2{margin:0;font-size:16px;font-weight:600}.create-variable-dialog .modal-close{background:none;border:none;font-size:24px;color:var(--text-secondary);cursor:pointer;padding:0;line-height:1}.create-variable-dialog .modal-close:hover{color:var(--text-primary)}.create-variable-dialog .modal-body{padding:16px 20px}.create-variable-dialog .form-group{margin-bottom:16px}.create-variable-dialog .form-group:last-child{margin-bottom:0}.create-variable-dialog .form-group label{display:block;font-size:13px;font-weight:500;margin-bottom:6px;color:var(--text-primary)}.create-variable-dialog .form-group code{background:var(--background);padding:2px 6px;border-radius:3px;font-size:12px}.create-variable-dialog .field-values-list{display:flex;flex-direction:column;gap:6px}.create-variable-dialog .field-value-option{display:flex;align-items:center;gap:8px;padding:8px 10px;border:1px solid var(--border-color);border-radius:4px;cursor:pointer;font-size:13px}.create-variable-dialog .field-value-option:hover{background:var(--background)}.create-variable-dialog .field-value-option input[type=radio]{margin:0}.create-variable-dialog .field-label{font-weight:500;color:var(--text-secondary);flex-shrink:0}.create-variable-dialog .field-value{color:var(--primary-color);font-family:monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.create-variable-dialog .single-field-value{display:flex;gap:8px;padding:8px 10px;background:var(--background);border-radius:4px;font-size:13px}.create-variable-dialog .variable-type-options{display:flex;flex-direction:column;gap:8px}.create-variable-dialog .type-option{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--border-color);border-radius:4px;cursor:pointer}.create-variable-dialog .type-option:hover{background:var(--background)}.create-variable-dialog .type-option input[type=radio]{margin:0}.create-variable-dialog .type-option span:nth-child(2){font-weight:500}.create-variable-dialog .type-hint{width:100%;margin-left:22px;font-size:12px;color:var(--text-secondary)}.create-variable-dialog .form-group input[type=text]{width:100%;padding:8px 10px;border:1px solid var(--border-color);border-radius:4px;font-size:14px}.create-variable-dialog .form-group input[type=text]:focus{outline:none;border-color:var(--primary-color);box-shadow:0 0 0 2px var(--primary-light)}.create-variable-dialog .variable-preview{margin-top:6px;font-size:12px;color:var(--text-secondary)}.create-variable-dialog .variable-preview code{background:var(--success-light);color:var(--success)}.create-variable-dialog .modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:16px 20px;border-top:1px solid var(--border-color)}.prompt-dialog{min-width:400px;max-width:450px}.prompt-dialog .modal-header{display:flex;align-items:center;justify-content:space-between;padding-bottom:16px;margin-bottom:16px;border-bottom:1px solid var(--border-color)}.prompt-dialog .modal-header h2{margin:0;font-size:18px}.prompt-dialog .modal-body{padding:0}.prompt-field{margin-bottom:16px}.prompt-field:last-child{margin-bottom:0}.prompt-field label{display:block;margin-bottom:6px;font-weight:500;color:var(--text-primary)}.prompt-field input[type=text]{width:100%;padding:10px 12px;border:1px solid var(--border-color);border-radius:4px;font-size:14px;background:var(--bg-primary);color:var(--text-primary);box-sizing:border-box}.prompt-field input[type=text]:focus{outline:none;border-color:var(--primary-color);box-shadow:0 0 0 2px var(--primary-light)}
|
package/dist/client/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
overflow: hidden;
|
|
17
17
|
}
|
|
18
18
|
</style>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-BB7IxLgr.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DTBSYs3n.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
|
@@ -14,7 +14,6 @@ exports.assertionBlocks = [
|
|
|
14
14
|
tooltip: 'Assert that an element is visible (auto-waits)',
|
|
15
15
|
inputs: [
|
|
16
16
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
17
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
18
17
|
],
|
|
19
18
|
previousStatement: true,
|
|
20
19
|
nextStatement: true,
|
|
@@ -22,7 +21,7 @@ exports.assertionBlocks = [
|
|
|
22
21
|
const page = context.page;
|
|
23
22
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
24
23
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
25
|
-
const timeout =
|
|
24
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
26
25
|
const expect = await (0, utils_1.getExpect)();
|
|
27
26
|
const locator = page.locator(selector);
|
|
28
27
|
context.logger.info(`Asserting ${displaySelector} is visible`);
|
|
@@ -43,7 +42,6 @@ exports.assertionBlocks = [
|
|
|
43
42
|
tooltip: 'Assert that an element is not visible (auto-waits)',
|
|
44
43
|
inputs: [
|
|
45
44
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
46
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
47
45
|
],
|
|
48
46
|
previousStatement: true,
|
|
49
47
|
nextStatement: true,
|
|
@@ -51,7 +49,7 @@ exports.assertionBlocks = [
|
|
|
51
49
|
const page = context.page;
|
|
52
50
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
53
51
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
54
|
-
const timeout =
|
|
52
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
55
53
|
const expect = await (0, utils_1.getExpect)();
|
|
56
54
|
const locator = page.locator(selector);
|
|
57
55
|
context.logger.info(`Asserting ${displaySelector} is not visible`);
|
|
@@ -73,7 +71,6 @@ exports.assertionBlocks = [
|
|
|
73
71
|
inputs: [
|
|
74
72
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
75
73
|
{ name: 'TEXT', type: 'field', fieldType: 'text', required: true },
|
|
76
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
77
74
|
],
|
|
78
75
|
previousStatement: true,
|
|
79
76
|
nextStatement: true,
|
|
@@ -82,7 +79,7 @@ exports.assertionBlocks = [
|
|
|
82
79
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
83
80
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
84
81
|
const expectedText = (0, utils_1.resolveVariables)(params.TEXT, context);
|
|
85
|
-
const timeout =
|
|
82
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
86
83
|
const expect = await (0, utils_1.getExpect)();
|
|
87
84
|
const locator = page.locator(selector);
|
|
88
85
|
context.logger.info(`Asserting ${displaySelector} contains "${expectedText}"`);
|
|
@@ -104,7 +101,6 @@ exports.assertionBlocks = [
|
|
|
104
101
|
inputs: [
|
|
105
102
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
106
103
|
{ name: 'TEXT', type: 'field', fieldType: 'text', required: true },
|
|
107
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
108
104
|
],
|
|
109
105
|
previousStatement: true,
|
|
110
106
|
nextStatement: true,
|
|
@@ -113,7 +109,7 @@ exports.assertionBlocks = [
|
|
|
113
109
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
114
110
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
115
111
|
const expectedText = (0, utils_1.resolveVariables)(params.TEXT, context);
|
|
116
|
-
const timeout =
|
|
112
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
117
113
|
const expect = await (0, utils_1.getExpect)();
|
|
118
114
|
const locator = page.locator(selector);
|
|
119
115
|
context.logger.info(`Asserting ${displaySelector} text equals "${expectedText}"`);
|
|
@@ -134,14 +130,13 @@ exports.assertionBlocks = [
|
|
|
134
130
|
tooltip: 'Assert that current URL contains expected value (auto-waits)',
|
|
135
131
|
inputs: [
|
|
136
132
|
{ name: 'TEXT', type: 'field', fieldType: 'text', required: true },
|
|
137
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
138
133
|
],
|
|
139
134
|
previousStatement: true,
|
|
140
135
|
nextStatement: true,
|
|
141
136
|
execute: async (params, context) => {
|
|
142
137
|
const page = context.page;
|
|
143
138
|
const expectedText = (0, utils_1.resolveVariables)(params.TEXT, context);
|
|
144
|
-
const timeout =
|
|
139
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
145
140
|
const expect = await (0, utils_1.getExpect)();
|
|
146
141
|
// Escape special regex characters and create a regex pattern
|
|
147
142
|
const escapedText = expectedText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -164,14 +159,13 @@ exports.assertionBlocks = [
|
|
|
164
159
|
tooltip: 'Assert that page title contains expected value (auto-waits)',
|
|
165
160
|
inputs: [
|
|
166
161
|
{ name: 'TEXT', type: 'field', fieldType: 'text', required: true },
|
|
167
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
168
162
|
],
|
|
169
163
|
previousStatement: true,
|
|
170
164
|
nextStatement: true,
|
|
171
165
|
execute: async (params, context) => {
|
|
172
166
|
const page = context.page;
|
|
173
167
|
const expectedText = (0, utils_1.resolveVariables)(params.TEXT, context);
|
|
174
|
-
const timeout =
|
|
168
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
175
169
|
const expect = await (0, utils_1.getExpect)();
|
|
176
170
|
// Escape special regex characters and create a regex pattern
|
|
177
171
|
const escapedText = expectedText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -193,7 +187,6 @@ exports.assertionBlocks = [
|
|
|
193
187
|
tooltip: 'Assert that an element is enabled (auto-waits)',
|
|
194
188
|
inputs: [
|
|
195
189
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
196
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
197
190
|
],
|
|
198
191
|
previousStatement: true,
|
|
199
192
|
nextStatement: true,
|
|
@@ -201,7 +194,7 @@ exports.assertionBlocks = [
|
|
|
201
194
|
const page = context.page;
|
|
202
195
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
203
196
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
204
|
-
const timeout =
|
|
197
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
205
198
|
const expect = await (0, utils_1.getExpect)();
|
|
206
199
|
const locator = page.locator(selector);
|
|
207
200
|
context.logger.info(`Asserting ${displaySelector} is enabled`);
|
|
@@ -223,7 +216,6 @@ exports.assertionBlocks = [
|
|
|
223
216
|
inputs: [
|
|
224
217
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
225
218
|
{ name: 'EXPECTED', type: 'field', fieldType: 'checkbox', default: true },
|
|
226
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
227
219
|
],
|
|
228
220
|
previousStatement: true,
|
|
229
221
|
nextStatement: true,
|
|
@@ -232,7 +224,7 @@ exports.assertionBlocks = [
|
|
|
232
224
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
233
225
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
234
226
|
const expected = params.EXPECTED;
|
|
235
|
-
const timeout =
|
|
227
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
236
228
|
const expect = await (0, utils_1.getExpect)();
|
|
237
229
|
const locator = page.locator(selector);
|
|
238
230
|
context.logger.info(`Asserting ${displaySelector} is ${expected ? 'checked' : 'unchecked'}`);
|
|
@@ -261,7 +253,6 @@ exports.assertionBlocks = [
|
|
|
261
253
|
inputs: [
|
|
262
254
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
263
255
|
{ name: 'VALUE', type: 'field', fieldType: 'text', required: true },
|
|
264
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
265
256
|
],
|
|
266
257
|
previousStatement: true,
|
|
267
258
|
nextStatement: true,
|
|
@@ -270,7 +261,7 @@ exports.assertionBlocks = [
|
|
|
270
261
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
271
262
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
272
263
|
const expectedValue = (0, utils_1.resolveVariables)(params.VALUE, context);
|
|
273
|
-
const timeout =
|
|
264
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
274
265
|
const expect = await (0, utils_1.getExpect)();
|
|
275
266
|
const locator = page.locator(selector);
|
|
276
267
|
context.logger.info(`Asserting ${displaySelector} has value "${expectedValue}"`);
|
|
@@ -294,7 +285,6 @@ exports.assertionBlocks = [
|
|
|
294
285
|
inputs: [
|
|
295
286
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
296
287
|
{ name: 'VALUE', type: 'field', fieldType: 'text', required: true },
|
|
297
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
298
288
|
],
|
|
299
289
|
previousStatement: true,
|
|
300
290
|
nextStatement: true,
|
|
@@ -303,7 +293,7 @@ exports.assertionBlocks = [
|
|
|
303
293
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
304
294
|
const displaySelector = (0, utils_1.getDisplaySelector)(params, context);
|
|
305
295
|
const expectedValue = (0, utils_1.resolveVariables)(params.VALUE, context);
|
|
306
|
-
const timeout =
|
|
296
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
307
297
|
const expect = await (0, utils_1.getExpect)();
|
|
308
298
|
const locator = page.locator(selector);
|
|
309
299
|
context.logger.info(`Asserting ${displaySelector} value contains "${expectedValue}"`);
|
|
@@ -14,14 +14,13 @@ exports.interactionBlocks = [
|
|
|
14
14
|
tooltip: 'Click on an element (auto-waits for element to be visible and stable)',
|
|
15
15
|
inputs: [
|
|
16
16
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
17
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
18
17
|
],
|
|
19
18
|
previousStatement: true,
|
|
20
19
|
nextStatement: true,
|
|
21
20
|
execute: async (params, context) => {
|
|
22
21
|
const page = context.page;
|
|
23
22
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
24
|
-
const timeout =
|
|
23
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
25
24
|
context.logger.info(`Clicking: ${selector}`);
|
|
26
25
|
const locator = page.locator(selector);
|
|
27
26
|
// Wait for element to be visible and stable before clicking
|
|
@@ -45,7 +44,6 @@ exports.interactionBlocks = [
|
|
|
45
44
|
inputs: [
|
|
46
45
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
47
46
|
{ name: 'VALUE', type: 'field', fieldType: 'text', required: true },
|
|
48
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
49
47
|
],
|
|
50
48
|
previousStatement: true,
|
|
51
49
|
nextStatement: true,
|
|
@@ -54,7 +52,7 @@ exports.interactionBlocks = [
|
|
|
54
52
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
55
53
|
const rawValue = params.VALUE;
|
|
56
54
|
const value = (0, utils_1.resolveVariables)(rawValue, context);
|
|
57
|
-
const timeout =
|
|
55
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
58
56
|
context.logger.info(`Filling ${selector} with "${value}"`);
|
|
59
57
|
const locator = page.locator(selector);
|
|
60
58
|
await locator.fill(value, { timeout });
|
|
@@ -76,7 +74,6 @@ exports.interactionBlocks = [
|
|
|
76
74
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
77
75
|
{ name: 'TEXT', type: 'field', fieldType: 'text', required: true },
|
|
78
76
|
{ name: 'DELAY', type: 'field', fieldType: 'number', default: 50 },
|
|
79
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
80
77
|
],
|
|
81
78
|
previousStatement: true,
|
|
82
79
|
nextStatement: true,
|
|
@@ -85,7 +82,7 @@ exports.interactionBlocks = [
|
|
|
85
82
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
86
83
|
const text = (0, utils_1.resolveVariables)(params.TEXT, context);
|
|
87
84
|
const delay = params.DELAY;
|
|
88
|
-
const timeout =
|
|
85
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
89
86
|
context.logger.info(`Typing "${text}" into ${selector}`);
|
|
90
87
|
const locator = page.locator(selector);
|
|
91
88
|
await locator.pressSequentially(text, { delay, timeout });
|
|
@@ -107,7 +104,6 @@ exports.interactionBlocks = [
|
|
|
107
104
|
inputs: [
|
|
108
105
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
109
106
|
{ name: 'KEY', type: 'field', fieldType: 'dropdown', options: [['Enter', 'Enter'], ['Tab', 'Tab'], ['Escape', 'Escape'], ['Backspace', 'Backspace'], ['ArrowUp', 'ArrowUp'], ['ArrowDown', 'ArrowDown'], ['ArrowLeft', 'ArrowLeft'], ['ArrowRight', 'ArrowRight']] },
|
|
110
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
111
107
|
],
|
|
112
108
|
previousStatement: true,
|
|
113
109
|
nextStatement: true,
|
|
@@ -115,7 +111,7 @@ exports.interactionBlocks = [
|
|
|
115
111
|
const page = context.page;
|
|
116
112
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
117
113
|
const key = params.KEY;
|
|
118
|
-
const timeout =
|
|
114
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
119
115
|
context.logger.info(`Pressing ${key} on ${selector}`);
|
|
120
116
|
const locator = page.locator(selector);
|
|
121
117
|
await locator.press(key, { timeout });
|
|
@@ -135,7 +131,6 @@ exports.interactionBlocks = [
|
|
|
135
131
|
inputs: [
|
|
136
132
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
137
133
|
{ name: 'VALUE', type: 'field', fieldType: 'text', required: true },
|
|
138
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
139
134
|
],
|
|
140
135
|
previousStatement: true,
|
|
141
136
|
nextStatement: true,
|
|
@@ -143,7 +138,7 @@ exports.interactionBlocks = [
|
|
|
143
138
|
const page = context.page;
|
|
144
139
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
145
140
|
const value = (0, utils_1.resolveVariables)(params.VALUE, context);
|
|
146
|
-
const timeout =
|
|
141
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
147
142
|
context.logger.info(`Selecting "${value}" in ${selector}`);
|
|
148
143
|
const locator = page.locator(selector);
|
|
149
144
|
await locator.selectOption(value, { timeout });
|
|
@@ -163,7 +158,6 @@ exports.interactionBlocks = [
|
|
|
163
158
|
inputs: [
|
|
164
159
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
165
160
|
{ name: 'ACTION', type: 'field', fieldType: 'dropdown', options: [['Check', 'check'], ['Uncheck', 'uncheck']] },
|
|
166
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
167
161
|
],
|
|
168
162
|
previousStatement: true,
|
|
169
163
|
nextStatement: true,
|
|
@@ -171,7 +165,7 @@ exports.interactionBlocks = [
|
|
|
171
165
|
const page = context.page;
|
|
172
166
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
173
167
|
const action = params.ACTION;
|
|
174
|
-
const timeout =
|
|
168
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
175
169
|
context.logger.info(`${action === 'check' ? 'Checking' : 'Unchecking'} ${selector}`);
|
|
176
170
|
const locator = page.locator(selector);
|
|
177
171
|
if (action === 'check') {
|
|
@@ -195,14 +189,13 @@ exports.interactionBlocks = [
|
|
|
195
189
|
tooltip: 'Hover over an element (auto-waits)',
|
|
196
190
|
inputs: [
|
|
197
191
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
198
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
199
192
|
],
|
|
200
193
|
previousStatement: true,
|
|
201
194
|
nextStatement: true,
|
|
202
195
|
execute: async (params, context) => {
|
|
203
196
|
const page = context.page;
|
|
204
197
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
205
|
-
const timeout =
|
|
198
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
206
199
|
context.logger.info(`Hovering over ${selector}`);
|
|
207
200
|
const locator = page.locator(selector);
|
|
208
201
|
await locator.hover({ timeout });
|
|
@@ -40,7 +40,6 @@ exports.navigationBlocks = [
|
|
|
40
40
|
inputs: [
|
|
41
41
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
42
42
|
{ name: 'STATE', type: 'field', fieldType: 'dropdown', options: [['Visible', 'visible'], ['Hidden', 'hidden'], ['Attached', 'attached'], ['Detached', 'detached']] },
|
|
43
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
44
43
|
],
|
|
45
44
|
previousStatement: true,
|
|
46
45
|
nextStatement: true,
|
|
@@ -48,7 +47,7 @@ exports.navigationBlocks = [
|
|
|
48
47
|
const page = context.page;
|
|
49
48
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
50
49
|
const state = params.STATE;
|
|
51
|
-
const timeout =
|
|
50
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
52
51
|
context.logger.info(`Waiting for ${selector} to be ${state}`);
|
|
53
52
|
await page.waitForSelector(selector, { state, timeout });
|
|
54
53
|
return {
|
|
@@ -66,14 +65,13 @@ exports.navigationBlocks = [
|
|
|
66
65
|
tooltip: 'Wait for URL to match',
|
|
67
66
|
inputs: [
|
|
68
67
|
{ name: 'URL', type: 'field', fieldType: 'text', required: true },
|
|
69
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
70
68
|
],
|
|
71
69
|
previousStatement: true,
|
|
72
70
|
nextStatement: true,
|
|
73
71
|
execute: async (params, context) => {
|
|
74
72
|
const page = context.page;
|
|
75
73
|
const url = (0, utils_1.resolveVariables)(params.URL, context);
|
|
76
|
-
const timeout =
|
|
74
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
77
75
|
context.logger.info(`Waiting for URL to match: ${url}`);
|
|
78
76
|
await page.waitForURL(url, { timeout });
|
|
79
77
|
return {
|
|
@@ -14,13 +14,12 @@ exports.retrievalBlocks = [
|
|
|
14
14
|
tooltip: 'Get text content of an element (auto-waits)',
|
|
15
15
|
inputs: [
|
|
16
16
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
17
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
18
17
|
],
|
|
19
18
|
output: { type: 'String' },
|
|
20
19
|
execute: async (params, context) => {
|
|
21
20
|
const page = context.page;
|
|
22
21
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
23
|
-
const timeout =
|
|
22
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
24
23
|
const locator = page.locator(selector);
|
|
25
24
|
await locator.waitFor({ state: 'visible', timeout });
|
|
26
25
|
const text = await locator.textContent({ timeout });
|
|
@@ -43,14 +42,13 @@ exports.retrievalBlocks = [
|
|
|
43
42
|
inputs: [
|
|
44
43
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
45
44
|
{ name: 'ATTRIBUTE', type: 'field', fieldType: 'text', required: true },
|
|
46
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
47
45
|
],
|
|
48
46
|
output: { type: 'String' },
|
|
49
47
|
execute: async (params, context) => {
|
|
50
48
|
const page = context.page;
|
|
51
49
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
52
50
|
const attribute = params.ATTRIBUTE;
|
|
53
|
-
const timeout =
|
|
51
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
54
52
|
const locator = page.locator(selector);
|
|
55
53
|
await locator.waitFor({ state: 'attached', timeout });
|
|
56
54
|
const value = await locator.getAttribute(attribute, { timeout });
|
|
@@ -72,13 +70,12 @@ exports.retrievalBlocks = [
|
|
|
72
70
|
tooltip: 'Get current value of an input field (auto-waits)',
|
|
73
71
|
inputs: [
|
|
74
72
|
{ name: 'SELECTOR', type: 'field', fieldType: 'text', required: true },
|
|
75
|
-
{ name: 'TIMEOUT', type: 'field', fieldType: 'number', default: 30000 },
|
|
76
73
|
],
|
|
77
74
|
output: { type: 'String' },
|
|
78
75
|
execute: async (params, context) => {
|
|
79
76
|
const page = context.page;
|
|
80
77
|
const selector = (0, utils_1.resolveSelector)(params, context);
|
|
81
|
-
const timeout =
|
|
78
|
+
const timeout = (0, utils_1.getTimeout)(context);
|
|
82
79
|
const locator = page.locator(selector);
|
|
83
80
|
await locator.waitFor({ state: 'visible', timeout });
|
|
84
81
|
const value = await locator.inputValue({ timeout });
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { ExecutionContext } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Get the global web timeout from context
|
|
4
|
+
*/
|
|
5
|
+
export declare function getTimeout(context: ExecutionContext): number;
|
|
2
6
|
export declare function getExpect(): Promise<any>;
|
|
3
7
|
/**
|
|
4
8
|
* Execute a web assertion with soft assertion support
|
|
@@ -33,11 +33,19 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getTimeout = getTimeout;
|
|
36
37
|
exports.getExpect = getExpect;
|
|
37
38
|
exports.executeWebAssertion = executeWebAssertion;
|
|
38
39
|
exports.resolveVariables = resolveVariables;
|
|
39
40
|
exports.resolveSelector = resolveSelector;
|
|
40
41
|
exports.getDisplaySelector = getDisplaySelector;
|
|
42
|
+
const DEFAULT_WEB_TIMEOUT = 30000;
|
|
43
|
+
/**
|
|
44
|
+
* Get the global web timeout from context
|
|
45
|
+
*/
|
|
46
|
+
function getTimeout(context) {
|
|
47
|
+
return context.webTimeout ?? DEFAULT_WEB_TIMEOUT;
|
|
48
|
+
}
|
|
41
49
|
// Import Playwright's expect for assertions with auto-waiting
|
|
42
50
|
// We use dynamic import with string concatenation to prevent Vite from
|
|
43
51
|
// trying to bundle the playwright package (which is Node.js-only)
|
package/dist/core/types.d.ts
CHANGED
package/dist/server/executor.js
CHANGED
|
@@ -121,7 +121,10 @@ class TestExecutor {
|
|
|
121
121
|
this.browser = await playwright_1.chromium.launch({
|
|
122
122
|
headless: this.options.headless,
|
|
123
123
|
});
|
|
124
|
-
|
|
124
|
+
// Use consistent viewport size for headless and headed modes
|
|
125
|
+
this.context = await this.browser.newContext({
|
|
126
|
+
viewport: { width: 1920, height: 1080 },
|
|
127
|
+
});
|
|
125
128
|
this.page = await this.context.newPage();
|
|
126
129
|
if (this.options.timeout) {
|
|
127
130
|
this.page.setDefaultTimeout(this.options.timeout);
|
|
@@ -196,6 +199,7 @@ class TestExecutor {
|
|
|
196
199
|
plugins: this.plugins,
|
|
197
200
|
testIdAttribute: this.options.testIdAttribute,
|
|
198
201
|
procedures: mergedProcedures,
|
|
202
|
+
webTimeout: this.options.timeout,
|
|
199
203
|
};
|
|
200
204
|
// Check if there are any enabled tests
|
|
201
205
|
const enabledTests = testFile.tests.filter(t => !t.disabled);
|
|
@@ -426,6 +430,7 @@ class TestExecutor {
|
|
|
426
430
|
// Enable soft assertions if configured on the test
|
|
427
431
|
softAssertions: test.softAssertions || false,
|
|
428
432
|
softAssertionErrors: [],
|
|
433
|
+
webTimeout: this.options.timeout,
|
|
429
434
|
};
|
|
430
435
|
// Run beforeTest hooks
|
|
431
436
|
for (const plugin of this.plugins.values()) {
|
|
@@ -517,6 +522,7 @@ class TestExecutor {
|
|
|
517
522
|
// Enable soft assertions if configured on the test
|
|
518
523
|
softAssertions: test.softAssertions || false,
|
|
519
524
|
softAssertionErrors: [],
|
|
525
|
+
webTimeout: this.options.timeout,
|
|
520
526
|
};
|
|
521
527
|
// Inject data values into variables
|
|
522
528
|
for (const [key, value] of Object.entries(dataSet.values)) {
|
package/dist/server/globals.d.ts
CHANGED
|
@@ -56,6 +56,10 @@ export declare function getGlobalProcedures(): Record<string, ProcedureDefinitio
|
|
|
56
56
|
* Get the configured test ID attribute (defaults to 'data-testid')
|
|
57
57
|
*/
|
|
58
58
|
export declare function getTestIdAttribute(): string;
|
|
59
|
+
/**
|
|
60
|
+
* Get the configured global timeout in milliseconds (defaults to 30000)
|
|
61
|
+
*/
|
|
62
|
+
export declare function getGlobalTimeout(): number;
|
|
59
63
|
/**
|
|
60
64
|
* Set the test ID attribute and persist to globals.json
|
|
61
65
|
*/
|
package/dist/server/globals.js
CHANGED
|
@@ -47,6 +47,7 @@ exports.getGlobals = getGlobals;
|
|
|
47
47
|
exports.getGlobalVariables = getGlobalVariables;
|
|
48
48
|
exports.getGlobalProcedures = getGlobalProcedures;
|
|
49
49
|
exports.getTestIdAttribute = getTestIdAttribute;
|
|
50
|
+
exports.getGlobalTimeout = getGlobalTimeout;
|
|
50
51
|
exports.setTestIdAttribute = setTestIdAttribute;
|
|
51
52
|
exports.discoverSnippets = discoverSnippets;
|
|
52
53
|
exports.loadSnippet = loadSnippet;
|
|
@@ -118,6 +119,12 @@ function getGlobalProcedures() {
|
|
|
118
119
|
function getTestIdAttribute() {
|
|
119
120
|
return loadedGlobals.testIdAttribute || 'data-testid';
|
|
120
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Get the configured global timeout in milliseconds (defaults to 30000)
|
|
124
|
+
*/
|
|
125
|
+
function getGlobalTimeout() {
|
|
126
|
+
return loadedGlobals.timeout || 30000;
|
|
127
|
+
}
|
|
121
128
|
/**
|
|
122
129
|
* Set the test ID attribute and persist to globals.json
|
|
123
130
|
*/
|
package/dist/server/index.js
CHANGED
|
@@ -384,7 +384,8 @@ app.post('/api/reports/html', (req, res) => {
|
|
|
384
384
|
summary: {
|
|
385
385
|
totalTests: results.length,
|
|
386
386
|
passed: results.filter(r => r.status === 'passed').length,
|
|
387
|
-
failed: results.filter(r => r.status !== 'passed').length,
|
|
387
|
+
failed: results.filter(r => r.status !== 'passed' && r.status !== 'skipped').length,
|
|
388
|
+
skipped: results.filter(r => r.status === 'skipped').length,
|
|
388
389
|
duration: results.reduce((sum, r) => sum + r.duration, 0),
|
|
389
390
|
},
|
|
390
391
|
testFiles: [{
|
|
@@ -420,7 +421,8 @@ app.post('/api/reports/junit', (req, res) => {
|
|
|
420
421
|
summary: {
|
|
421
422
|
totalTests: results.length,
|
|
422
423
|
passed: results.filter(r => r.status === 'passed').length,
|
|
423
|
-
failed: results.filter(r => r.status !== 'passed').length,
|
|
424
|
+
failed: results.filter(r => r.status !== 'passed' && r.status !== 'skipped').length,
|
|
425
|
+
skipped: results.filter(r => r.status === 'skipped').length,
|
|
424
426
|
duration: results.reduce((sum, r) => sum + r.duration, 0),
|
|
425
427
|
},
|
|
426
428
|
testFiles: [{
|
|
@@ -244,7 +244,7 @@ async function startServer(options = {}) {
|
|
|
244
244
|
const testIdAttr = (0, globals_1.getTestIdAttribute)();
|
|
245
245
|
const executor = new executor_1.TestExecutor({
|
|
246
246
|
headless: req.query.headless !== 'false',
|
|
247
|
-
timeout: Number(req.query.timeout) ||
|
|
247
|
+
timeout: Number(req.query.timeout) || (0, globals_1.getGlobalTimeout)(),
|
|
248
248
|
variables: globalVars,
|
|
249
249
|
procedures: globalProcs,
|
|
250
250
|
testIdAttribute: testIdAttr,
|
|
@@ -294,7 +294,7 @@ async function startServer(options = {}) {
|
|
|
294
294
|
const testIdAttr = (0, globals_1.getTestIdAttribute)();
|
|
295
295
|
const executor = new executor_1.TestExecutor({
|
|
296
296
|
headless: req.query.headless !== 'false',
|
|
297
|
-
timeout: Number(req.query.timeout) ||
|
|
297
|
+
timeout: Number(req.query.timeout) || (0, globals_1.getGlobalTimeout)(),
|
|
298
298
|
variables: globalVars,
|
|
299
299
|
procedures: globalProcs,
|
|
300
300
|
testIdAttribute: testIdAttr,
|
|
@@ -429,7 +429,8 @@ async function startServer(options = {}) {
|
|
|
429
429
|
summary: {
|
|
430
430
|
totalTests: results.length,
|
|
431
431
|
passed: results.filter(r => r.status === 'passed').length,
|
|
432
|
-
failed: results.filter(r => r.status !== 'passed').length,
|
|
432
|
+
failed: results.filter(r => r.status !== 'passed' && r.status !== 'skipped').length,
|
|
433
|
+
skipped: results.filter(r => r.status === 'skipped').length,
|
|
433
434
|
duration: results.reduce((sum, r) => sum + r.duration, 0),
|
|
434
435
|
},
|
|
435
436
|
testFiles: [{
|
|
@@ -464,7 +465,8 @@ async function startServer(options = {}) {
|
|
|
464
465
|
summary: {
|
|
465
466
|
totalTests: results.length,
|
|
466
467
|
passed: results.filter(r => r.status === 'passed').length,
|
|
467
|
-
failed: results.filter(r => r.status !== 'passed').length,
|
|
468
|
+
failed: results.filter(r => r.status !== 'passed' && r.status !== 'skipped').length,
|
|
469
|
+
skipped: results.filter(r => r.status === 'skipped').length,
|
|
468
470
|
duration: results.reduce((sum, r) => sum + r.duration, 0),
|
|
469
471
|
},
|
|
470
472
|
testFiles: [{
|