ui5-test-runner 5.13.1 → 6.0.0-beta.2

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.
Files changed (186) hide show
  1. package/README.md +3 -2
  2. package/dist/Npm.js +80 -0
  3. package/dist/browsers/IBrowser.js +1 -0
  4. package/dist/browsers/factory.js +9 -0
  5. package/dist/browsers/puppeteer.js +158 -0
  6. package/dist/cli.js +20 -0
  7. package/dist/configuration/CommandLine.js +112 -0
  8. package/dist/configuration/Configuration.js +1 -0
  9. package/dist/configuration/ConfigurationValidator.js +79 -0
  10. package/dist/configuration/Option.js +1 -0
  11. package/dist/configuration/OptionValidationError.js +15 -0
  12. package/dist/configuration/indexedOptions.js +13 -0
  13. package/dist/configuration/options.js +191 -0
  14. package/dist/configuration/validators/OptionValidator.js +1 -0
  15. package/dist/configuration/validators/boolean.js +15 -0
  16. package/dist/configuration/validators/browser.js +11 -0
  17. package/dist/configuration/validators/fsEntry.js +70 -0
  18. package/dist/configuration/validators/index.js +20 -0
  19. package/dist/configuration/validators/integer.js +10 -0
  20. package/dist/configuration/validators/percent.js +17 -0
  21. package/dist/configuration/validators/regexp.js +20 -0
  22. package/dist/configuration/validators/string.js +7 -0
  23. package/dist/configuration/validators/timeout.js +24 -0
  24. package/dist/configuration/validators/url.js +8 -0
  25. package/dist/modes/ModeFunction.js +1 -0
  26. package/dist/modes/Modes.js +9 -0
  27. package/dist/modes/execute.js +27 -0
  28. package/dist/modes/help.js +3 -0
  29. package/dist/modes/log/ILogStorage.js +1 -0
  30. package/dist/modes/log/LogMetrics.js +9 -0
  31. package/dist/modes/log/LogReader.js +37 -0
  32. package/dist/modes/log/LogStorage.js +68 -0
  33. package/dist/modes/log/REserve.js +101 -0
  34. package/dist/modes/log/index.js +58 -0
  35. package/dist/modes/test/REserve.js +31 -0
  36. package/dist/modes/test/agent.js +8 -0
  37. package/dist/modes/test/browser.js +37 -0
  38. package/dist/modes/test/index.js +66 -0
  39. package/dist/modes/test/pageTask.js +145 -0
  40. package/dist/modes/test/report.js +3 -0
  41. package/dist/modes/test/server.js +109 -0
  42. package/dist/modes/version.js +11 -0
  43. package/dist/platform/Exit.js +139 -0
  44. package/dist/platform/FileSystem.js +13 -0
  45. package/dist/platform/Host.js +10 -0
  46. package/dist/platform/Http.js +38 -0
  47. package/dist/platform/Path.js +5 -0
  48. package/dist/platform/Process.js +133 -0
  49. package/dist/platform/Terminal.js +47 -0
  50. package/dist/platform/Thread.js +43 -0
  51. package/dist/platform/ZLib.js +7 -0
  52. package/dist/platform/assert.js +17 -0
  53. package/dist/platform/constants.js +5 -0
  54. package/dist/platform/environment.js +28 -0
  55. package/dist/platform/index.js +13 -0
  56. package/dist/platform/logger/ILogger.js +1 -0
  57. package/dist/platform/logger/allCompressed.js +54 -0
  58. package/dist/platform/logger/compress.js +277 -0
  59. package/dist/platform/logger/output/BaseLoggerOutput.js +158 -0
  60. package/dist/platform/logger/output/InteractiveLoggerOutput.js +102 -0
  61. package/dist/platform/logger/output/StaticLoggerOutput.js +32 -0
  62. package/dist/platform/logger/output/factory.js +10 -0
  63. package/dist/platform/logger/output.js +58 -0
  64. package/dist/platform/logger/proxy.js +6 -0
  65. package/dist/platform/logger/toInternalLogAttributes.js +22 -0
  66. package/dist/platform/logger/types.js +7 -0
  67. package/dist/platform/logger.js +138 -0
  68. package/dist/platform/mock.js +104 -0
  69. package/dist/platform/version.js +8 -0
  70. package/dist/platform/workerBootstrap.js +21 -0
  71. package/dist/reports/html.js +46 -0
  72. package/dist/types/AgentState.js +1 -0
  73. package/dist/types/CommonTestReportFormat.js +50 -0
  74. package/dist/types/IError.js +1 -0
  75. package/dist/types/IUserInterfaceController.js +1 -0
  76. package/dist/types/typeUtilities.js +1 -0
  77. package/dist/ui/agent.js +3 -0
  78. package/dist/ui/html-report.js +2 -0
  79. package/dist/ui/lib.js +1 -0
  80. package/dist/ui/log-viewer.js +2 -0
  81. package/dist/utils/node/Folder.js +28 -0
  82. package/dist/utils/node/FramedStreamReader.js +86 -0
  83. package/dist/utils/node/FramedStreamWriter.js +27 -0
  84. package/dist/utils/shared/ProgressBar.js +43 -0
  85. package/dist/utils/shared/TestReportBuilder.js +48 -0
  86. package/dist/utils/shared/memoize.js +19 -0
  87. package/dist/utils/shared/object.js +8 -0
  88. package/dist/utils/shared/parallelize.js +59 -0
  89. package/dist/utils/shared/string.js +23 -0
  90. package/dist/utils/shared/toIError.js +17 -0
  91. package/package.json +73 -50
  92. package/.releaserc +0 -5
  93. package/index.js +0 -175
  94. package/jest.config.json +0 -31
  95. package/src/add-test-pages.js +0 -67
  96. package/src/batch.js +0 -214
  97. package/src/browsers.js +0 -319
  98. package/src/capabilities/index.js +0 -204
  99. package/src/capabilities/tests/basic/iframe.html +0 -8
  100. package/src/capabilities/tests/basic/index.html +0 -12
  101. package/src/capabilities/tests/basic/index.js +0 -20
  102. package/src/capabilities/tests/basic/ui5.html +0 -24
  103. package/src/capabilities/tests/dynamic-include/index.js +0 -21
  104. package/src/capabilities/tests/dynamic-include/mix.html +0 -11
  105. package/src/capabilities/tests/dynamic-include/one.html +0 -11
  106. package/src/capabilities/tests/dynamic-include/post.js +0 -3
  107. package/src/capabilities/tests/dynamic-include/test.js +0 -1
  108. package/src/capabilities/tests/dynamic-include/two.html +0 -11
  109. package/src/capabilities/tests/index.js +0 -16
  110. package/src/capabilities/tests/local-storage/index.html +0 -16
  111. package/src/capabilities/tests/local-storage/index.js +0 -21
  112. package/src/capabilities/tests/screenshot/index.html +0 -23
  113. package/src/capabilities/tests/screenshot/index.js +0 -24
  114. package/src/capabilities/tests/scripts/coverage.html +0 -32
  115. package/src/capabilities/tests/scripts/iframe.html +0 -18
  116. package/src/capabilities/tests/scripts/index.js +0 -59
  117. package/src/capabilities/tests/scripts/qunit.html +0 -22
  118. package/src/capabilities/tests/scripts/testsuite.html +0 -10
  119. package/src/capabilities/tests/scripts/testsuite.js +0 -8
  120. package/src/capabilities/tests/timeout/index.html +0 -21
  121. package/src/capabilities/tests/timeout/index.js +0 -19
  122. package/src/capabilities/tests/traces/index.html +0 -18
  123. package/src/capabilities/tests/traces/index.js +0 -81
  124. package/src/capabilities/tests/ui5/focus.html +0 -89
  125. package/src/capabilities/tests/ui5/index.js +0 -39
  126. package/src/capabilities/tests/ui5/language.html +0 -50
  127. package/src/capabilities/tests/ui5/timezone.html +0 -27
  128. package/src/clean.js +0 -22
  129. package/src/cors.js +0 -21
  130. package/src/coverage.js +0 -384
  131. package/src/csv-reader.js +0 -36
  132. package/src/csv-writer.js +0 -55
  133. package/src/defaults/.nycrc.json +0 -4
  134. package/src/defaults/browser.js +0 -217
  135. package/src/defaults/happy-dom.js +0 -123
  136. package/src/defaults/jsdom/compatibility.js +0 -163
  137. package/src/defaults/jsdom/debug.js +0 -23
  138. package/src/defaults/jsdom/resource-loader.js +0 -44
  139. package/src/defaults/jsdom/sap.ui.test.matchers.visible.js +0 -39
  140. package/src/defaults/jsdom.js +0 -95
  141. package/src/defaults/json-report.js +0 -36
  142. package/src/defaults/junit-xml-report.js +0 -90
  143. package/src/defaults/playwright.js +0 -142
  144. package/src/defaults/puppeteer.js +0 -124
  145. package/src/defaults/report/common.js +0 -38
  146. package/src/defaults/report/decompress.js +0 -19
  147. package/src/defaults/report/default.html +0 -99
  148. package/src/defaults/report/main.js +0 -69
  149. package/src/defaults/report/progress.js +0 -60
  150. package/src/defaults/report/styles.css +0 -66
  151. package/src/defaults/report.js +0 -91
  152. package/src/defaults/scan-ui5.js +0 -26
  153. package/src/defaults/selenium-webdriver/chrome.js +0 -39
  154. package/src/defaults/selenium-webdriver/edge.js +0 -24
  155. package/src/defaults/selenium-webdriver/firefox.js +0 -30
  156. package/src/defaults/selenium-webdriver.js +0 -129
  157. package/src/defaults/text-report.js +0 -108
  158. package/src/defaults/webdriverio.js +0 -80
  159. package/src/end.js +0 -62
  160. package/src/endpoints.js +0 -219
  161. package/src/error.js +0 -54
  162. package/src/get-job-progress.js +0 -78
  163. package/src/handle.js +0 -43
  164. package/src/if.js +0 -10
  165. package/src/inject/jest2qunit.js +0 -289
  166. package/src/inject/opa-iframe-coverage.js +0 -22
  167. package/src/inject/post.js +0 -141
  168. package/src/inject/qunit-hooks.js +0 -107
  169. package/src/inject/qunit-redirect.js +0 -65
  170. package/src/inject/ui5-coverage.js +0 -33
  171. package/src/job-mode.js +0 -65
  172. package/src/job.js +0 -493
  173. package/src/npm.js +0 -136
  174. package/src/options.js +0 -95
  175. package/src/output.js +0 -739
  176. package/src/parallelize.js +0 -63
  177. package/src/qunit-hooks.js +0 -219
  178. package/src/report.js +0 -89
  179. package/src/reserve.js +0 -25
  180. package/src/start.js +0 -133
  181. package/src/symbols.js +0 -8
  182. package/src/tests.js +0 -183
  183. package/src/timeout.js +0 -53
  184. package/src/tools.js +0 -179
  185. package/src/ui5.js +0 -199
  186. package/src/unhandled.js +0 -32
@@ -0,0 +1,2 @@
1
+ !function(){try{if("undefined"!=typeof document){var e=document.createElement("style");e.appendChild(document.createTextNode('body,#app{height:100vh;font-family:var(--sapFontFamily,"72", Arial, sans-serif);background:var(--sapBackgroundColor,#f7f7f7);flex-direction:column;margin:0;display:flex;overflow:hidden}#header{background:var(--sapShellBar_Background,#354a5e);color:var(--sapShellBar_TextColor,#fff);flex:none;align-items:center;gap:1rem;padding:.5rem 1rem;display:flex}#header h1{color:inherit;flex:1;margin:0;font-size:1rem;font-weight:700}#toolbar{background:var(--sapGroup_ContentBackground,#fff);border-bottom:1px solid var(--sapGroup_TitleBorderColor,#d9d9d9);flex-wrap:wrap;flex:none;align-items:center;gap:.75rem;padding:.5rem 1rem;display:flex}#toolbar ui5-message-strip{flex:0 0 100%;margin-top:.25rem}#logTableWrapper{flex:1;overflow-y:auto}#logTable{border-collapse:collapse;width:100%;font-size:.875rem}#logTable thead th{background:var(--sapList_HeaderBackground,#f7f7f7);text-align:left;border-bottom:1px solid var(--sapList_BorderColor,#d9d9d9);white-space:nowrap;padding:.4rem .5rem;font-weight:700;position:sticky;top:0}#logTable thead th.col-clickable{cursor:pointer;-webkit-user-select:none;user-select:none}#logTable thead th.col-clickable:hover{background:var(--sapList_Hover_Background,#f1f1f1);text-decoration:underline}#logTable tbody tr{cursor:pointer;border-bottom:1px solid var(--sapList_BorderColor,#d9d9d9)}#logTable tbody tr:hover{background:var(--sapList_Hover_Background,#f1f1f1)}#logTable tbody td{vertical-align:top;text-overflow:ellipsis;white-space:nowrap;max-width:400px;padding:.25rem .5rem;overflow:hidden}#logTable tbody td.col-message{max-width:600px}.log-details-row{align-items:baseline;gap:.5rem;min-width:400px;padding:.2rem 0;display:flex}.log-details-label{color:var(--sapContent_LabelColor,#6a6d70);flex-shrink:0;min-width:6rem;font-size:.8rem}.log-details-value{word-break:break-all;flex:1}.log-details-actions{flex-shrink:0;gap:.25rem;display:flex}.log-details-error{white-space:pre-wrap;background:var(--sapField_ReadOnly_Background,#f2f2f2);border-radius:.25rem;flex:1;max-height:200px;padding:.5rem;font-family:monospace;font-size:.75rem;overflow-y:auto}.log-details-section-label{color:var(--sapContent_LabelColor,#6a6d70);margin-top:.5rem;margin-bottom:.25rem;font-size:.8rem;font-weight:700}.column-filter-row{align-items:center;padding:.2rem 0;display:flex}\n/*$vite$:1*/')),document.head.appendChild(e)}}catch(o){console.error("vite-plugin-css-injected-by-js",o)}}();
2
+ !function(){var e=class{_state={};get state(){return this._state}_settings={};get settings(){return this._settings}_updateCb=()=>{throw new Error("UI not connected")};_update({...e}){for(const t of Object.keys(e))e[t]===this._state[t]&&delete e[t];return Object.assign(this._state,e),console.log("🎮⏩",e),Object.keys(e).length>0&&this._updateCb({...e}),e}_onConnect(){}connect(e){this._updateCb=e,this._onConnect(),console.log("🎮🔛",{initialState:{...this._state},settings:this._settings})}interaction(e){const{action:t,...n}=e,r=this._update(n);console.log("🎮⏪",{event:e,action:t,stateDiff:r}),(Object.keys(r).length>0||void 0!==t)&&this._onInteraction(r,t)}},t=3e5,n=[{label:"5 minutes",key:t},{label:"15 minutes",key:9e5},{label:"30 minutes",key:18e5},{label:"1 hour",key:36e5},{label:"3 hours",key:108e5}],r=[{label:"5 seconds",key:5e3},{label:"10 seconds",key:1e4},{label:"30 seconds",key:3e4},{label:"60 seconds",key:6e4}];function o(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function a(e){return e.toString().padStart(2,"0")}function s(e){const t=new Date(e);return`${a(t.getMonth()+1)}/${a(t.getDate())}/${t.getFullYear()}, ${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}`}function i(e,t){const n="relative"===e.timerangeType,r=n?function(e,t){const n=t.relativeTimerange.map(t=>`<ui5-option value="${t.key}"${e.relativeTimerange===t.key?" selected":""}>${t.label}</ui5-option>`).join(""),r=t.autorefresh.map(t=>`<ui5-option value="${t.key}"${e.autorefreshInterval===t.key?" selected":""}>${t.label}</ui5-option>`).join("");return`<ui5-select id="relativeTimerangeSelect">${n}</ui5-select>\n <span>Auto Refresh:</span>\n <ui5-select id="autorefreshSelect">\n <ui5-option value="none"${e.autorefresh?"":" selected"}>None</ui5-option>\n ${r}\n </ui5-select>`}(e,t):function(e){return`<ui5-datetime-picker id="absoluteFromPicker" value="${s(e.absoluteTimerangeFrom)}" placeholder="From"></ui5-datetime-picker>\n <ui5-datetime-picker id="absoluteToPicker" value="${s(e.absoluteTimerangeTo)}" placeholder="To"></ui5-datetime-picker>`}(e),a=e.errorMessage?`<ui5-message-strip id="errorStrip" design="Negative" hide-close-button>${o(e.errorMessage)}</ui5-message-strip>`:"";return`<ui5-input id="filterInput" value="${o(e.filter)}" placeholder="Filter expression..." style="flex:1;min-width:200px;"></ui5-input>\n <ui5-select id="timerangeTypeSelect">\n <ui5-option value="relative"${n?" selected":""}>Relative</ui5-option>\n <ui5-option value="absolute"${n?"":" selected"}>Absolute</ui5-option>\n </ui5-select>\n ${r}\n <ui5-button id="refreshNowBtn">Refresh now</ui5-button>\n ${a}`}var l={0:"&#128269;",1:"&#128172;",2:"&#9888;&#65039;",3:"&#10060;",4:"&#128163;"},c={0:"debug",1:"info",2:"warn",3:"error",4:"fatal"},u=["B","KB","MB","GB"];function d(e){return l[e]??"?"}function p(e){return e?new Date(e).toLocaleString():"—"}function g(e){let t=e,n=0;for(;t>=1024&&n<u.length-1;)t/=1024,n++;return`${0===n?t.toString():t.toFixed(1)} ${u[n]}`}function m(e){const t='<thead><tr>\n <th data-col="timestamp" class="col-clickable">Timestamp (local)</th>\n <th data-col="level" class="col-clickable">Level</th>\n <th data-col="source" class="col-clickable">Source</th>\n <th data-col="processId" class="col-clickable">PID</th>\n <th data-col="threadId" class="col-clickable">TID</th>\n <th data-col="pageId" class="col-clickable">Page ID</th>\n <th class="col-message">Message</th>\n</tr></thead>';return 0===e.length?`${t}<tbody><tr><td colspan="7" style="text-align:center;padding:1rem;color:var(--sapContent_LabelColor);">No log entries</td></tr></tbody>`:`${t}<tbody>${e.map((e,t)=>{const n=e.message.length>200?`${e.message.slice(0,200)}…`:e.message;return`<tr data-index="${t}">\n <td>${p(e.timestamp)}</td>\n <td>${d(e.level)}</td>\n <td>${e.source}</td>\n <td>${e.processId}</td>\n <td>${e.threadId}</td>\n <td>${e.pageId??""}</td>\n <td class="col-message">${r=n,r.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}</td>\n</tr>`;var r}).join("")}</tbody>`}function v(e,t){const n=JSON.stringify(t);return`<span class="log-details-actions">\n <ui5-button class="filter-add-btn" design="Transparent" data-field="${e}" data-value='${n}' data-op="===">&#10133;</ui5-button>\n <ui5-button class="filter-remove-btn" design="Transparent" data-field="${e}" data-value='${n}' data-op="!==">&#10134;</ui5-button>\n </span>`}function f(e,t,n=""){return`<div class="log-details-row">\n <span class="log-details-label">${e}</span>\n <span class="log-details-value">${t}</span>\n ${n}\n</div>`}function h(e,t="data"){return Object.entries(e).map(([e,n])=>{const r=`${t}.${e}`;return Array.isArray(n)?n.map((e,t)=>{const n=`${r}[${t}]`;return"object"==typeof e&&null!==e?h(e,n):f(n,b(String(e)),v(n,e))}).join(""):"object"==typeof n&&null!==n?h(n,r):f(r,b(String(n)),v(r,n))}).join("")}function b(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function y(e){const t=d(e.level),n=(r=e.level,c[r]??"unknown");var r;let o=f("timestamp",p(e.timestamp));var a;return o+=f("level",`${t} ${n}`,v("level",n)),o+=f("source",b(e.source),v("source",e.source)),o+=f("processId",String(e.processId),v("processId",e.processId)),o+=f("threadId",String(e.threadId),v("threadId",e.threadId)),void 0!==e.pageId&&(o+=f("pageId",String(e.pageId),v("pageId",e.pageId))),o+=f("message",b(e.message)),e.error&&(o+=(a=e.error,`<div class="log-details-row"><span class="log-details-section-label">error (JSON):</span></div>\n<div class="log-details-row"><pre class="log-details-error">${b(JSON.stringify(a,null,2))}</pre></div>`)),void 0!==e.data&&(o+='<div class="log-details-row"><span class="log-details-section-label">data (JSON):</span></div>',o+=h(e.data)),o}function S(e,t,n,r){const o=`${e} ${n} ${"string"==typeof t?`"${t}"`:String(t)}`;return r?`${r} && ${o}`:o}var $=new class extends e{constructor(){super(),this._state={timerangeType:"relative",relativeTimerange:t,absoluteTimerangeFrom:0,absoluteTimerangeTo:0,autorefresh:!1,autorefreshInterval:5e3,filter:"",errorMessage:"",logs:[],metrics:{inputSize:0,chunksCount:0,outputSize:0,minTimestamp:Number.MAX_SAFE_INTEGER,maxTimestamp:0,logCount:0,reading:!0}},this._settings={relativeTimerange:n,autorefresh:r}}async _executeQuery(e){this._update({errorMessage:""});const t=new URLSearchParams;for(const a of Object.keys(e))t.set(a,e[a].toString());const n=await fetch("/query?"+t.toString());if(!n.ok){const e=await n.text()||`${n.status} ${n.statusText}`;return void this._update({errorMessage:e})}const{metrics:r,logs:o}=await n.json();return{metrics:r,logs:o}}async _checkInitialQuery(){const e=await this._executeQuery({});if(!e)return;const{metrics:t,logs:n}=e,r=Date.now(),o={absoluteTimerangeFrom:t.minTimestamp,absoluteTimerangeTo:r,metrics:t,logs:n};t.minTimestamp<=r-3e5&&(o.timerangeType="absolute"),this._update(o)}_onConnect(){this._checkInitialQuery()}_onInteraction(e,t){("autorefresh"in e||"autorefreshInterval"in e)&&this._autorefresh(e),void 0!==t&&this[t]()}async refresh_now(){const e={};"absolute"===this._state.timerangeType?(e.from=this._state.absoluteTimerangeFrom,e.to=this._state.absoluteTimerangeTo):e.from=Date.now()-this._state.relativeTimerange,this._state.filter&&(e.filter=this._state.filter);const t=await this._executeQuery(e);t&&this._update(t)}_autorefreshIntervalId;_startAutorefresh(){this._autorefreshIntervalId=setInterval(()=>{this.refresh_now()},this._state.autorefreshInterval)}_stopAutorefresh(){clearInterval(this._autorefreshIntervalId),this._autorefreshIntervalId=void 0}_autorefresh({autorefresh:e}){!1===e?this._stopAutorefresh():(!0===e||this._stopAutorefresh(),this._startAutorefresh())}};function T(){const e=document.querySelector("#filterInput"),t=function(e,t){let n;return(...r)=>{clearTimeout(n),n=setTimeout(()=>e(...r),t)}}(e=>$.interaction({filter:e}),250);e?.addEventListener("input",e=>{const n=e.target;t(n.value)}),document.querySelector("#timerangeTypeSelect")?.addEventListener("change",e=>{const t=e.detail;$.interaction({timerangeType:t.selectedOption.value})}),document.querySelector("#relativeTimerangeSelect")?.addEventListener("change",e=>{const t=e.detail;$.interaction({relativeTimerange:Number(t.selectedOption.value)})}),document.querySelector("#autorefreshSelect")?.addEventListener("change",e=>{const t=e.detail.selectedOption.value;"none"===t?$.interaction({autorefresh:!1}):$.interaction({autorefresh:!0,autorefreshInterval:Number(t)})}),document.querySelector("#absoluteFromPicker")?.addEventListener("change",e=>{const t=e.target;t.dateValue&&$.interaction({absoluteTimerangeFrom:t.dateValue.getTime()})}),document.querySelector("#absoluteToPicker")?.addEventListener("change",e=>{const t=e.target;t.dateValue&&$.interaction({absoluteTimerangeTo:t.dateValue.getTime()})}),document.querySelector("#refreshNowBtn")?.addEventListener("click",()=>$.interaction({action:"refresh_now"}))}function _(e){e.addEventListener("click",e=>{const t=e.target.closest("th[data-col]");if(!t)return;const n=t.dataset.col;if(!n)return;const r=$.state.logs,o=document.querySelector("#columnFilterPopover"),a=document.querySelector("#columnFilterPopoverContent");if(!o||!a)return;if("timestamp"===n){if(0===r.length)return;const e=r.map(e=>e.timestamp),t=Math.min(...e),n=Math.max(...e);return void $.interaction({timerangeType:"absolute",absoluteTimerangeFrom:t,absoluteTimerangeTo:n})}a.innerHTML="level"===n?["debug","info","warn","error","fatal"].map(e=>`<div class="column-filter-row"><ui5-checkbox data-filter-value="${e}" text="${e}"></ui5-checkbox></div>`).join(""):function(e,t){return[...new Set(t.map(t=>t[e]))].toSorted().map(e=>{const t=void 0===e;return`<div class="column-filter-row"><ui5-checkbox data-filter-value='${t?"__undefined__":JSON.stringify(e)}' text="${t?"none":String(e)}"></ui5-checkbox></div>`}).join("")}(n,r);const s=document.querySelector("#columnFilterApply"),i=s?.cloneNode(!0);s&&i&&(s.replaceWith(i),i.addEventListener("click",()=>function(e){const t=document.querySelector("#columnFilterPopoverContent");if(!t)return;const n=[...t.querySelectorAll("ui5-checkbox")].filter(e=>!0===e.checked);if(0===n.length)return;const r=n.map(e=>{const t=e.dataset.filterValue??"null";if("__undefined__"!==t)try{return JSON.parse(t)}catch{return t}}),o=r.map(t=>S(e,t,"===","")),a=r.length>1?`(${o.join(" || ")})`:o[0],s=$.state.filter?`${$.state.filter} && ${a}`:a;$.interaction({filter:s});const i=document.querySelector("#filterInput");i&&(i.value=s),document.querySelector("#columnFilterPopover").open=!1}("level"===n?"level":n))),o.opener=t,o.open=!0})}function k(){T(),document.querySelector("#statusBtn")?.addEventListener("click",e=>{const t=document.querySelector("#metricsPopover"),n=document.querySelector("#metricsPopoverContent");t&&n&&(n.innerHTML=function(){const e=$.state.metrics;return`<div class="log-details-row"><span class="log-details-label">Status</span>\n <span>${e.reading?"Live (reading)":"Replay (complete)"}</span></div>\n <div class="log-details-row"><span class="log-details-label">Log count</span>\n <span>${e.logCount}</span></div>\n <div class="log-details-row"><span class="log-details-label">Input size</span>\n <span>${g(e.inputSize)}</span></div>\n <div class="log-details-row"><span class="log-details-label">Output size</span>\n <span>${g(e.outputSize)}</span></div>\n <div class="log-details-row"><span class="log-details-label">Chunks</span>\n <span>${e.chunksCount}</span></div>\n <div class="log-details-row"><span class="log-details-label">From</span>\n <span>${p(e.minTimestamp)}</span></div>\n <div class="log-details-row"><span class="log-details-label">To</span>\n <span>${p(e.maxTimestamp)}</span></div>`}(),t.opener=e.currentTarget,t.open=!0)});const e=document.querySelector("#logTable thead");e&&_(e);const t=document.querySelector("#logTable tbody");t&&I(t),document.querySelector("#logDetailsClose")?.addEventListener("click",()=>{const e=document.querySelector("#logDetailsPopover");e&&(e.open=!1)})}function I(e){e.addEventListener("click",e=>{const t=e.target.closest("tr[data-index]");if(!t)return;const n=Number(t.dataset.index),r=$.state.logs[n];if(!r)return;const o=document.querySelector("#logDetailsPopover"),a=document.querySelector("#logDetailsPopoverContent");o&&a&&(a.innerHTML=y(r),function(e){for(const t of e.querySelectorAll(".filter-add-btn, .filter-remove-btn"))t.addEventListener("click",()=>{const e=t,n=e.dataset.field??"",r=e.dataset.value??"null",o=e.dataset.op??"===";let a;try{a=JSON.parse(r)}catch{a=r}const s=S(n,a,o,$.state.filter);$.interaction({filter:s});const i=document.querySelector("#filterInput");i&&(i.value=s)})}(a),o.opener=t,o.open=!0)})}var w=["timerangeType","relativeTimerange","autorefresh","autorefreshInterval","absoluteTimerangeFrom","absoluteTimerangeTo"];function q(e){if(w.some(t=>t in e)&&function(){const e=document.querySelector("#toolbar");e&&(e.innerHTML=i($.state,$.settings),T())}(),"metrics"in e&&function(){const e=document.querySelector("#statusBtn");if(!e)return;const t=$.state.metrics.reading;e.textContent=t?"Status: Live":"Status: Replay",e.setAttribute("design",t?"Positive":"Neutral")}(),"logs"in e&&function(){const e=document.querySelector("#logTable");if(!e)return;e.innerHTML=m($.state.logs);const t=e.querySelector("thead");t&&_(t);const n=e.querySelector("tbody");n&&I(n)}(),"errorMessage"in e&&function(){const e=document.querySelector("#toolbar");if(!e)return;const t=document.querySelector("#errorStrip");$.state.errorMessage?t?t.textContent=$.state.errorMessage:e.insertAdjacentHTML("beforeend",`<ui5-message-strip id="errorStrip" design="Negative" hide-close-button>${$.state.errorMessage}</ui5-message-strip>`):t?.remove()}(),"filter"in e){const e=document.querySelector("#filterInput");e&&document.activeElement!==e&&(e.value=$.state.filter)}}document.addEventListener("DOMContentLoaded",()=>{!function(){const e=document.querySelector("#app");e&&e.insertAdjacentHTML("beforebegin",'<ui5-popover id="metricsPopover" header-text="Metrics" placement="Bottom">\n <div id="metricsPopoverContent" style="padding: 0.5rem;"></div>\n </ui5-popover>\n <ui5-popover id="logDetailsPopover" header-text="Log Details" placement="Bottom" style="max-width: 600px;">\n <div id="logDetailsPopoverContent" style="padding: 0.5rem;"></div>\n <div slot="footer" style="display: flex; justify-content: flex-end; padding: 0.5rem;">\n <ui5-button id="logDetailsClose" design="Transparent">Close</ui5-button>\n </div>\n </ui5-popover>\n <ui5-popover id="columnFilterPopover" placement="Bottom">\n <div id="columnFilterPopoverContent" style="padding: 0.5rem; min-width: 180px;"></div>\n <div slot="footer" style="display: flex; justify-content: flex-end; padding: 0.5rem;">\n <ui5-button id="columnFilterApply">Filter</ui5-button>\n </div>\n </ui5-popover>')}(),$.connect(q),function(){const e=document.querySelector("#app");if(!e)return;const{state:t,settings:n}=$;e.innerHTML=function(e){const t=e.reading;return`<div id="header">\n <h1>UI5 Test Runner Log Viewer</h1>\n <ui5-button id="statusBtn" design="${t?"Positive":"Neutral"}">Status: ${t?"Live":"Replay"}</ui5-button>\n</div>`}(t.metrics)+`<div id="toolbar">${i(t,n)}</div><div id="logTableWrapper"><table id="logTable">${m(t.logs)}</table></div>`,k()}()})}();
@@ -0,0 +1,28 @@
1
+ import { FileSystem, logger } from '../../platform/index.js';
2
+ const recursive = { recursive: true };
3
+ export const Folder = {
4
+ async clean(path) {
5
+ logger.debug({ source: 'job', message: `Cleaning folder: ${path}` });
6
+ try {
7
+ await FileSystem.stat(path);
8
+ await FileSystem.rm(path, recursive);
9
+ }
10
+ catch {
11
+ }
12
+ },
13
+ async create(path) {
14
+ logger.debug({ source: 'job', message: `Creating folder: ${path}` });
15
+ try {
16
+ await FileSystem.mkdir(path, recursive);
17
+ }
18
+ catch (error_) {
19
+ const error = new Error(`Failed to create folder: ${path}`);
20
+ error.cause = error_;
21
+ throw error;
22
+ }
23
+ },
24
+ async recreate(path) {
25
+ await Folder.clean(path);
26
+ await Folder.create(path);
27
+ }
28
+ };
@@ -0,0 +1,86 @@
1
+ import { Exit, FileSystem, assert } from '../../platform/index.js';
2
+ import { setTimeout } from 'node:timers/promises';
3
+ export class FramedStreamReader {
4
+ static create(fileName, pollIntervalMs = 500) {
5
+ return new this(fileName, pollIntervalMs);
6
+ }
7
+ _fileName;
8
+ _pollIntervalMs;
9
+ constructor(fileName, pollIntervalMs) {
10
+ this._fileName = fileName;
11
+ this._pollIntervalMs = pollIntervalMs;
12
+ }
13
+ *_extractFrames(buffer) {
14
+ let workingBuffer = buffer;
15
+ while (this._reading && workingBuffer.length >= 4) {
16
+ const size = workingBuffer.readUInt32BE();
17
+ if (size === 0) {
18
+ yield { type: 'end' };
19
+ }
20
+ if (workingBuffer.length < size + 4) {
21
+ yield { type: 'incomplete', remaining: workingBuffer };
22
+ return;
23
+ }
24
+ yield {
25
+ type: 'frame',
26
+ frame: workingBuffer.subarray(4, size + 4)
27
+ };
28
+ workingBuffer = Buffer.from(workingBuffer.subarray(size + 4));
29
+ }
30
+ yield { type: 'incomplete', remaining: workingBuffer };
31
+ }
32
+ _startPos = 0;
33
+ _reading = true;
34
+ _buffer = Buffer.alloc(0);
35
+ _task;
36
+ async *_read(end) {
37
+ const fileStream = FileSystem.createReadStream(this._fileName, {
38
+ start: this._startPos,
39
+ end,
40
+ highWaterMark: 64 * 1024
41
+ });
42
+ for await (const chunk of fileStream) {
43
+ assert(chunk instanceof Buffer);
44
+ this._buffer = Buffer.concat([this._buffer, chunk]);
45
+ this._startPos += chunk.length;
46
+ for (const result of this._extractFrames(this._buffer)) {
47
+ if (result.type === 'end') {
48
+ this._reading = false;
49
+ this._task?.[Symbol.dispose]();
50
+ return;
51
+ }
52
+ if (result.type === 'frame') {
53
+ yield result.frame;
54
+ }
55
+ else {
56
+ this._buffer = result.remaining;
57
+ }
58
+ }
59
+ }
60
+ }
61
+ async *read(signal) {
62
+ assert(this._task === undefined, 'read is already in progress');
63
+ this._task = Exit.registerAsyncTask({
64
+ name: `FramedStreamReader(${this._fileName})`,
65
+ stop: () => {
66
+ this._reading = false;
67
+ }
68
+ });
69
+ const { promise: abortSignal, resolve: triggerAbort } = Promise.withResolvers();
70
+ if (signal) {
71
+ signal.addEventListener('abort', () => {
72
+ triggerAbort();
73
+ this._reading = false;
74
+ });
75
+ }
76
+ while (this._reading) {
77
+ const stats = await FileSystem.stat(this._fileName);
78
+ if (stats.size > this._startPos) {
79
+ yield* this._read(stats.size - 1);
80
+ }
81
+ if (this._reading) {
82
+ await Promise.race([setTimeout(this._pollIntervalMs), abortSignal]);
83
+ }
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,27 @@
1
+ import { FileSystem } from '../../platform/index.js';
2
+ export class FramedStreamWriter {
3
+ static create(fileName) {
4
+ return new this(fileName);
5
+ }
6
+ _stream;
7
+ constructor(fileName) {
8
+ this._stream = FileSystem.createWriteStream(fileName);
9
+ }
10
+ async _write(buffer) {
11
+ const { promise, resolve, reject } = Promise.withResolvers();
12
+ this._stream.write(buffer, (error) => (error ? reject(error) : resolve()));
13
+ await promise;
14
+ }
15
+ async write(buffer) {
16
+ if (buffer.length > 0) {
17
+ const size = Buffer.alloc(4);
18
+ size.writeUInt32BE(buffer.length, 0);
19
+ await this._write(size);
20
+ await this._write(buffer);
21
+ }
22
+ }
23
+ async end() {
24
+ await this._write(Buffer.from([0, 0, 0, 0]));
25
+ this._stream.end();
26
+ }
27
+ }
@@ -0,0 +1,43 @@
1
+ export class ProgressBar {
2
+ static WIDTH = 10;
3
+ _value = 0;
4
+ get value() {
5
+ return this._value;
6
+ }
7
+ _max = 0;
8
+ get max() {
9
+ return this._max;
10
+ }
11
+ _label = '';
12
+ get label() {
13
+ return this._label;
14
+ }
15
+ update(attributes) {
16
+ this._value = attributes.data.value;
17
+ this._max = attributes.data.max;
18
+ this._label = attributes.message;
19
+ }
20
+ render(width) {
21
+ let spaceLeft = width;
22
+ let progressBar = [];
23
+ if (this._max !== 0) {
24
+ const ratio = this._value / this._max;
25
+ const filled = Math.floor(ProgressBar.WIDTH * Math.min(ratio, 1));
26
+ spaceLeft = width - ProgressBar.WIDTH - 7;
27
+ progressBar = [
28
+ '[',
29
+ ''.padEnd(filled, '#'),
30
+ ''.padEnd(ProgressBar.WIDTH - filled, '-'),
31
+ ']',
32
+ Math.floor(100 * ratio)
33
+ .toString()
34
+ .padStart(3, ' ')
35
+ .toString(),
36
+ '% '
37
+ ];
38
+ }
39
+ const { length: labelLength } = this._label;
40
+ const label = labelLength > spaceLeft ? `...${this._label.slice(Math.max(0, labelLength - spaceLeft + 3))}` : this._label;
41
+ return [...progressBar, label].join('');
42
+ }
43
+ }
@@ -0,0 +1,48 @@
1
+ import { createEmptyTestResults } from '../../types/CommonTestReportFormat.js';
2
+ const SUMMARY_FIELDS = ['tests', 'passed', 'failed', 'skipped', 'pending', 'other'];
3
+ export class TestReportBuilder {
4
+ _report;
5
+ _suites = {};
6
+ get report() {
7
+ return this._report;
8
+ }
9
+ constructor(reportId, generatedBy) {
10
+ this._report = {
11
+ reportFormat: 'CTRF',
12
+ specVersion: 'pre-1.0',
13
+ reportId,
14
+ timestamp: new Date().toISOString(),
15
+ generatedBy,
16
+ results: createEmptyTestResults()
17
+ };
18
+ this._report.results.summary.start = Date.now();
19
+ }
20
+ addSuite(suiteUrl, pageUrls) {
21
+ const parentUrls = this._suites[suiteUrl] ?? [];
22
+ for (const pageUrl of pageUrls) {
23
+ this._suites[pageUrl] = [...parentUrls, suiteUrl];
24
+ }
25
+ }
26
+ merge(url, testResults) {
27
+ const { name: toolName } = this._report.results.tool;
28
+ if (testResults.tool.name && toolName === '') {
29
+ this._report.results.tool = testResults.tool;
30
+ }
31
+ const { results } = this._report;
32
+ const suites = [...(this._suites[url] ?? []), url];
33
+ for (const test of testResults.tests) {
34
+ results.tests.push({
35
+ ...test,
36
+ suite: [...suites, ...(test.suite ?? [])]
37
+ });
38
+ }
39
+ for (const summaryField of SUMMARY_FIELDS) {
40
+ results.summary[summaryField] += testResults.summary[summaryField];
41
+ }
42
+ }
43
+ finalize() {
44
+ const { summary } = this._report.results;
45
+ summary.stop = Date.now();
46
+ summary.duration = summary.stop - summary.start;
47
+ }
48
+ }
@@ -0,0 +1,19 @@
1
+ export const memoize = (compute) => {
2
+ let cachedValue;
3
+ let cachedError;
4
+ return () => {
5
+ if (cachedError) {
6
+ throw cachedError;
7
+ }
8
+ if (cachedValue === undefined) {
9
+ try {
10
+ cachedValue = compute();
11
+ }
12
+ catch (error) {
13
+ cachedError = error;
14
+ throw error;
15
+ }
16
+ }
17
+ return cachedValue;
18
+ };
19
+ };
@@ -0,0 +1,8 @@
1
+ const literalPrototype = Object.getPrototypeOf({});
2
+ export const toPlainObject = (object) => {
3
+ const prototype = Object.getPrototypeOf(object);
4
+ if (Object.getPrototypeOf(object) === literalPrototype) {
5
+ return object;
6
+ }
7
+ return Object.assign({}, toPlainObject(prototype), object);
8
+ };
@@ -0,0 +1,59 @@
1
+ export const parallelize = async (processor, queue, options) => {
2
+ const { parallel = 1, on } = options ?? {};
3
+ const results = [];
4
+ let index = 0;
5
+ const context = {
6
+ stop(reason) {
7
+ context.stopRequested = true;
8
+ throw reason;
9
+ },
10
+ stopRequested: false
11
+ };
12
+ let active = 0;
13
+ const { promise, resolve } = Promise.withResolvers();
14
+ const fiber = async () => {
15
+ ++active;
16
+ while (!context.stopRequested && index < queue.length) {
17
+ const current = index++;
18
+ if (active < parallel && index < queue.length) {
19
+ void fiber();
20
+ }
21
+ const input = queue[current];
22
+ try {
23
+ on?.({
24
+ type: 'started',
25
+ index: current,
26
+ input
27
+ });
28
+ const output = await processor.call(context, input, current, queue);
29
+ results[current] = {
30
+ status: 'fulfilled',
31
+ value: output
32
+ };
33
+ on?.({
34
+ type: 'completed',
35
+ index: current,
36
+ input,
37
+ output
38
+ });
39
+ }
40
+ catch (error) {
41
+ on?.({
42
+ type: 'failed',
43
+ index: current,
44
+ input,
45
+ error
46
+ });
47
+ results[current] = {
48
+ status: 'rejected',
49
+ reason: error
50
+ };
51
+ }
52
+ }
53
+ if (--active === 0) {
54
+ resolve(results);
55
+ }
56
+ };
57
+ void fiber();
58
+ return promise;
59
+ };
@@ -0,0 +1,23 @@
1
+ export function split(string, ...lengthes) {
2
+ const result = [];
3
+ let from = 0;
4
+ for (const length of lengthes) {
5
+ result.push(string.slice(from, from + length));
6
+ from += length;
7
+ }
8
+ if (from < string.length) {
9
+ result.push(string.slice(from));
10
+ }
11
+ return result;
12
+ }
13
+ export const formatDuration = (ms) => {
14
+ if (ms <= 0) {
15
+ return '00:00';
16
+ }
17
+ if (ms < 1000) {
18
+ return '0.' + ms.toString().padStart(3, '0');
19
+ }
20
+ const seconds = Math.floor(ms / 1000);
21
+ const minutes = Math.floor(seconds / 60);
22
+ return minutes.toString().padStart(2, '0') + ':' + (seconds % 60).toString().padStart(2, '0');
23
+ };
@@ -0,0 +1,17 @@
1
+ export const toIError = (error) => {
2
+ if (!(error instanceof Error)) {
3
+ return toIError(new Error(JSON.stringify(error)));
4
+ }
5
+ const attributes = {
6
+ name: error.name,
7
+ message: error.message,
8
+ stack: error.stack
9
+ };
10
+ if (error.cause) {
11
+ attributes.cause = toIError(error.cause);
12
+ }
13
+ if (error instanceof AggregateError) {
14
+ attributes.errors = error.errors.map((item) => toIError(item));
15
+ }
16
+ return attributes;
17
+ };
package/package.json CHANGED
@@ -1,33 +1,54 @@
1
1
  {
2
2
  "name": "ui5-test-runner",
3
- "version": "5.13.1",
3
+ "version": "6.0.0-beta.2",
4
4
  "description": "Standalone test runner for UI5",
5
- "main": "index.js",
5
+ "main": "dist/cli.js",
6
+ "type": "module",
7
+ "files": [
8
+ "dist/"
9
+ ],
6
10
  "bin": {
7
- "ui5-test-runner": "./index.js"
11
+ "ui5-test-runner": "./dist/cli.js"
8
12
  },
9
13
  "publishConfig": {
10
14
  "access": "public",
11
15
  "provenance": true
12
16
  },
13
17
  "engines": {
14
- "node": ">=18"
18
+ "node": ">=24.11.1"
15
19
  },
16
20
  "scripts": {
17
- "lint": "standard --fix",
18
- "test": "npm run test:unit && npm run test:e2e",
21
+ "ts-run": "node --no-warnings --experimental-strip-types --import ./src/platform/js2ts.mjs",
22
+ "cli": "make precli && npm run ts-run -- src/cli.ts",
23
+ "test:cli1": "npm run cli -- --url https://ui5.sap.com/test-resources/sap/m/demokit/cart/webapp/test/testsuite.qunit.html --report-dir tmp",
24
+ "test:cli2": "npm run cli -- --url \"https://ui5.sap.com/test-resources/sap/m/demokit/cart/webapp/test/Test.qunit.html?testsuite=test-resources/sap/ui/demo/cart/testsuite.qunit&test=unit/unitTests\" --report-dir tmp",
25
+ "test:cli3": "npm run cli -- --url \"https://ui5.sap.com/test-resources/sap/m/demokit/cart/webapp/test/Test.qunit.html?testsuite=test-resources%2Fsap%2Fui%2Fdemo%2Fcart%2Ftestsuite.qunit&test=integration%2FopaTestsComponent#/categories\" --report-dir tmp",
26
+ "test:cli4": "npm run cli -- --url \"https://ui5.sap.com/test-resources/sap/m/demokit/cart/webapp/test/Test.qunit.html?testsuite=test-resources/sap/ui/demo/cart/testsuite.qunit&test=integration/opaTestsIFrame\" --report-dir tmp",
27
+ "test:cli5": "npm run cli -- --cwd test/sample.js",
28
+ "test:openui5": "npm run cli -- --url http://localhost:8000/test-resources/sap/ui/core/qunit/testsuite.qunit.html --parallel 4",
29
+ "test:openui5.uncaught": "npm run cli -- --url \"http://localhost:8000/resources/sap/ui/test/starter/Test.qunit.html?testsuite=test-resources/sap/ui/core/qunit/odata/v2/testsuite.odatav2.qunit&test=ODataV2TreeBindingFlat_MockSrv\"",
30
+ "lint": "dpdm src/cli.ts --circular --tree false --warning false --skip-dynamic-imports circular && eslint \"**/*.mjs\" \"./src/**/*.ts\" --fix --cache --cache-strategy content && tsc --build --noEmit",
31
+ "build:options": "node build/options.mjs > ./src/configuration/options.ts && npm run lint",
32
+ "build:agent": "vite build",
33
+ "build:ui:report": "vite build -c src/ui/report/vite.config.mjs",
34
+ "start:ui:report": "vite -c src/ui/report/vite.config.mjs",
35
+ "build:ui:log": "vite build -c src/ui/log/vite.config.mjs",
36
+ "build:ui:lib": "vite build -c src/ui/lib/vite.config.mjs",
37
+ "start:ui:log": "vite -c src/ui/log/vite.config.mjs",
38
+ "test": "npm run lint && npm run test:unit && npm run test:e2e",
19
39
  "test:samples": "npm run test:samples:js && npm run test:samples:ts",
20
40
  "test:samples:js": "npm run test:sample:js:legacy && npm run test:sample:js:coverage:legacy && npm run test:sample:js:legacy-remote && npm run test:sample:js:coverage:legacy-remote && npm run test:sample:js:remote && npm run test:sample:js:coverage:remote && npm run test:sample:js:basic-authent && npm run test:sample:js:legacy:split-opa && npm run test:sample:js:remote:split-opa",
21
41
  "test:coverall": "rimraf .nyc_output && jest --coverageDirectory .nyc_output --coverageReporters json && nyc --silent --no-clean npm run test:e2e && nyc merge .nyc_output .nyc_output/final/coverage.json && nyc report --temp-dir .nyc_output/final/ --report-dir coverage --branches 80 --functions 80 --lines 80 --statements 80",
22
- "test:unit": "jest",
42
+ "test:unit": "vitest run --coverage",
43
+ "test:unit:watch": "vitest",
23
44
  "test:unit:debug": "node --inspect node_modules/jest/bin/jest.js --runInBand --no-coverage",
24
- "pretest:e2e": "npm install -g puppeteer selenium-webdriver playwright webdriverio jsdom",
25
- "test:e2e": "node . --batch \"test/e2e/[\\w_]*\\.json\" --report-dir e2e --start \"node test/e2e/serve.js\" --start-wait-url http://localhost:8081 --start-wait-method HEAD --start-timeout 30s",
26
- "serve:e2e": "node test/e2e/serve.js",
27
- "test:e2e:legacy-only": "node . --batch \"test/e2e/JS_LEGACY_[\\w_]*\\.json\" --report-dir e2e --start serve:e2e --start-wait-url http://localhost:8081 --start-wait-method HEAD --start-timeout 30s --debug-verbose start handle --ci",
45
+ "pretest:e2e0": "npm install -g puppeteer selenium-webdriver playwright webdriverio",
46
+ "test:e2e0": "npm run cli -- --batch \"test/e2e/[\\w_]*\\.json\" --report-dir e2e --start \"node test/e2e/serve.js\" --start-wait-url http://localhost:8081 --start-wait-method HEAD --start-timeout 30s",
47
+ "test:e2e": "echo No E2E tests until the runner is ready",
28
48
  "test:report": "node ./src/defaults/report.js ./test/report && reserve --config ./test/report/reserve.json",
29
49
  "test:text-report": "node ./src/defaults/text-report.js ./test/report",
30
50
  "build:doc": "node build/doc",
51
+ "build": "make precli && npx tsc --project tsconfig.cli.json",
31
52
  "clean": "npm uninstall -g ui5-test-runner puppeteer nyc selenium-webdriver playwright webdriverio jsdom",
32
53
  "update": "ncu -i --format group",
33
54
  "semantic-release": "semantic-release"
@@ -45,52 +66,54 @@
45
66
  "coverage",
46
67
  "ui5"
47
68
  ],
48
- "author": "Arnaud Buchholz",
69
+ "author": "Arnaud Buchholz <arnaud.buchholz@free.fr>",
49
70
  "license": "MIT",
50
71
  "bugs": {
51
72
  "url": "https://github.com/ArnaudBuchholz/ui5-test-runner/issues"
52
73
  },
53
74
  "homepage": "https://github.com/ArnaudBuchholz/ui5-test-runner#readme",
54
75
  "dependencies": {
55
- "commander": "^12.1.0",
56
- "punybind": "^1.2.1",
57
- "punyexpr": "1.2.0",
58
- "reserve": "2.3.4"
76
+ "punyexpr": "1.3.1",
77
+ "reserve": "2.3.5"
59
78
  },
60
79
  "devDependencies": {
61
- "@openui5/types": "^1.143.1",
62
- "@semantic-release/npm": "^13.1.3",
63
- "@ui5/cli": "^4.0.38",
64
- "@ui5/middleware-code-coverage": "^2.0.2",
65
- "baseline-browser-mapping": "^2.9.11",
66
- "dotenv": "^16.5.0",
67
- "jest": "^29.7.0",
68
- "nock": "^14.0.10",
69
- "npm-check-updates": "^18.3.0",
70
- "nyc": "^17.1.0",
71
- "rimraf": "^6.1.2",
72
- "semantic-release": "^25.0.2",
73
- "standard": "^17.1.2",
74
- "typescript": "^5.9.3",
75
- "ui5-tooling-transpile": "^3.10.0"
76
- },
77
- "optionalDependencies": {
78
- "fsevents": "^2.3.3"
79
- },
80
- "overrides": {
81
- "axios": "1.7.4"
82
- },
83
- "standard": {
84
- "env": [
85
- "browser",
86
- "qunit",
87
- "node",
88
- "jest"
89
- ],
90
- "globals": [
91
- "sap",
92
- "opaTest",
93
- "normalizePath"
94
- ]
80
+ "@openui5/types": "^1.148.0",
81
+ "@stylistic/eslint-plugin": "^5.10.0",
82
+ "@stylistic/eslint-plugin-js": "^4.4.1",
83
+ "@types/node": "^24.12.2",
84
+ "@types/qunit": "^2.19.14",
85
+ "@ui5/cli": "^4.0.55",
86
+ "@ui5/middleware-code-coverage": "^2.0.3",
87
+ "@ui5/webcomponents": "^2.22.0",
88
+ "@ui5/webcomponents-fiori": "^2.22.0",
89
+ "@vitest/coverage-v8": "^4.1.8",
90
+ "baseline-browser-mapping": "^2.10.33",
91
+ "dotenv": "^17.4.2",
92
+ "dpdm": "^4.2.0",
93
+ "eslint": "^9.39.2",
94
+ "eslint-config-prettier": "^10.1.8",
95
+ "eslint-plugin-import": "^2.32.0",
96
+ "eslint-plugin-no-only-tests": "^3.4.0",
97
+ "eslint-plugin-prettier": "^5.5.6",
98
+ "eslint-plugin-security": "^4.0.0",
99
+ "eslint-plugin-sonarjs": "^4.0.3",
100
+ "eslint-plugin-unicorn": "^64.0.0",
101
+ "globals": "^17.6.0",
102
+ "jsdom": "^29.1.1",
103
+ "markdownlint-cli": "^0.48.0",
104
+ "npm-check-updates": "^22.2.1",
105
+ "puppeteer": "^25.1.0",
106
+ "qunit": "^2.26.0",
107
+ "rimraf": "^6.1.3",
108
+ "semantic-release": "^25.0.3",
109
+ "stylelint": "^17.12.0",
110
+ "stylelint-config-standard": "^40.0.0",
111
+ "terser": "^5.48.0",
112
+ "typescript": "^6.0.3",
113
+ "typescript-eslint": "^8.60.0",
114
+ "ui5-tooling-transpile": "^3.11.2",
115
+ "vite": "^8.0.16",
116
+ "vite-plugin-css-injected-by-js": "^5.0.1",
117
+ "vitest": "^4.1.8"
95
118
  }
96
119
  }
package/.releaserc DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "branches": [
3
- { "name": "5.x.y", "channel": "latest" }
4
- ]
5
- }