@sap-ux/preview-middleware 0.17.22 → 0.17.24

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 (69) hide show
  1. package/README.md +1 -1
  2. package/dist/base/flp.d.ts +95 -1
  3. package/dist/base/flp.js +277 -159
  4. package/dist/client/adp/api-handler.js +153 -153
  5. package/dist/client/adp/command-executor.js +75 -75
  6. package/dist/client/adp/control-utils.js +44 -44
  7. package/dist/client/adp/controllers/BaseDialog.controller.js +187 -187
  8. package/dist/client/adp/controllers/ControllerExtension.controller.js +213 -213
  9. package/dist/client/adp/controllers/ExtensionPoint.controller.js +138 -138
  10. package/dist/client/adp/controllers/FileExistsDialog.controller.js +66 -66
  11. package/dist/client/adp/dialog-factory.js +122 -122
  12. package/dist/client/adp/init-dialogs.js +100 -100
  13. package/dist/client/adp/quick-actions/common/add-controller-to-page.js +55 -55
  14. package/dist/client/adp/quick-actions/common/create-page-action.js +50 -50
  15. package/dist/client/adp/quick-actions/common/op-add-custom-section.js +36 -36
  16. package/dist/client/adp/quick-actions/common/op-add-header-field.js +48 -48
  17. package/dist/client/adp/quick-actions/common/utils.js +18 -18
  18. package/dist/client/adp/quick-actions/control-types.js +21 -21
  19. package/dist/client/adp/quick-actions/dialog-enablement-validator.js +24 -24
  20. package/dist/client/adp/quick-actions/enablement-validator.js +4 -4
  21. package/dist/client/adp/quick-actions/fe-v2/change-table-columns.js +101 -101
  22. package/dist/client/adp/quick-actions/fe-v2/create-table-action.js +70 -70
  23. package/dist/client/adp/quick-actions/fe-v2/create-table-custom-column.js +96 -96
  24. package/dist/client/adp/quick-actions/fe-v2/lr-enable-semantic-date-range-filter-bar.js +78 -78
  25. package/dist/client/adp/quick-actions/fe-v2/lr-enable-table-filtering.js +77 -77
  26. package/dist/client/adp/quick-actions/fe-v2/lr-enable-variant-management.js +69 -69
  27. package/dist/client/adp/quick-actions/fe-v2/lr-toggle-clear-filter-bar.js +58 -58
  28. package/dist/client/adp/quick-actions/fe-v2/op-enable-empty-row-mode.js +93 -93
  29. package/dist/client/adp/quick-actions/fe-v2/op-enable-variant-management.js +81 -81
  30. package/dist/client/adp/quick-actions/fe-v2/registry.js +75 -75
  31. package/dist/client/adp/quick-actions/fe-v2/utils.js +95 -95
  32. package/dist/client/adp/quick-actions/fe-v4/change-table-columns.js +73 -73
  33. package/dist/client/adp/quick-actions/fe-v4/create-table-action.js +49 -49
  34. package/dist/client/adp/quick-actions/fe-v4/create-table-custom-column.js +46 -46
  35. package/dist/client/adp/quick-actions/fe-v4/enable-variant-management.js +81 -81
  36. package/dist/client/adp/quick-actions/fe-v4/lr-enable-semantic-date-range-filter-bar.js +55 -55
  37. package/dist/client/adp/quick-actions/fe-v4/lr-enable-table-filtering.js +82 -82
  38. package/dist/client/adp/quick-actions/fe-v4/lr-toggle-clear-filter-bar.js +52 -52
  39. package/dist/client/adp/quick-actions/fe-v4/op-enable-empty-row-mode.js +89 -89
  40. package/dist/client/adp/quick-actions/fe-v4/registry.js +58 -58
  41. package/dist/client/adp/quick-actions/fe-v4/utils.js +47 -47
  42. package/dist/client/adp/quick-actions/load.js +44 -44
  43. package/dist/client/adp/quick-actions/quick-action-base.js +53 -53
  44. package/dist/client/adp/utils.js +160 -160
  45. package/dist/client/cpe/changes/index.js +10 -10
  46. package/dist/client/cpe/changes/validator.js +39 -39
  47. package/dist/client/cpe/documentation.js +164 -164
  48. package/dist/client/cpe/feature-service.js +36 -36
  49. package/dist/client/cpe/logger.js +30 -30
  50. package/dist/client/cpe/outline/editable.js +37 -37
  51. package/dist/client/cpe/outline/nodes.js +222 -222
  52. package/dist/client/cpe/quick-actions/quick-action-definition.js +4 -4
  53. package/dist/client/cpe/quick-actions/registry.js +143 -143
  54. package/dist/client/cpe/quick-actions/utils.js +92 -92
  55. package/dist/client/cpe/types.js +4 -4
  56. package/dist/client/cpe/ui5-utils.js +33 -33
  57. package/dist/client/cpe/utils.js +138 -138
  58. package/dist/client/flp/WorkspaceConnector.js +86 -86
  59. package/dist/client/flp/common.js +28 -28
  60. package/dist/client/flp/enableFakeConnector.js +83 -83
  61. package/dist/client/flp/initConnectors.js +30 -30
  62. package/dist/client/flp/initRta.js +178 -178
  63. package/dist/client/i18n.js +56 -56
  64. package/dist/client/utils/application.js +32 -32
  65. package/dist/client/utils/core.js +68 -68
  66. package/dist/client/utils/error.js +19 -19
  67. package/dist/client/utils/fe-v4.js +118 -118
  68. package/dist/client/utils/version.js +102 -102
  69. package/package.json +4 -4
package/dist/base/flp.js CHANGED
@@ -4,10 +4,11 @@ exports.FlpSandbox = void 0;
4
4
  exports.initAdp = initAdp;
5
5
  const mem_fs_1 = require("mem-fs");
6
6
  const mem_fs_editor_1 = require("mem-fs-editor");
7
- const ejs_1 = require("ejs");
8
7
  const fs_1 = require("fs");
9
- const path_1 = require("path");
8
+ const ejs_1 = require("ejs");
10
9
  const express_1 = require("express");
10
+ const path_1 = require("path");
11
+ const project_access_1 = require("@sap-ux/project-access");
11
12
  const adp_tooling_1 = require("@sap-ux/adp-tooling");
12
13
  const btp_utils_1 = require("@sap-ux/btp-utils");
13
14
  const feature_toggle_1 = require("@sap-ux/feature-toggle");
@@ -30,6 +31,7 @@ class FlpSandbox {
30
31
  rta;
31
32
  test;
32
33
  router;
34
+ fs;
33
35
  /**
34
36
  * Constructor setting defaults and keeping reference to workspace resources.
35
37
  *
@@ -173,6 +175,61 @@ class FlpSandbox {
173
175
  this.templateConfig.apps[appName].applicationDependencies = this.adp.descriptor;
174
176
  }
175
177
  }
178
+ /**
179
+ * Handler for the GET requests to the runtime adaptation editor in developer mode.
180
+ *
181
+ * @param res the response
182
+ * @param rta runtime adaptation configuration
183
+ * @param previewUrl the url of the preview
184
+ * @private
185
+ */
186
+ async editorGetHandlerDeveloperMode(res, rta, previewUrl) {
187
+ const scenario = rta.options?.scenario;
188
+ let templatePreviewUrl = `${previewUrl}?sap-ui-xx-viewCache=false&fiori-tools-rta-mode=forAdaptation&sap-ui-rta-skip-flex-validation=true&sap-ui-xx-condense-changes=true#${this.config.intent.object}-${this.config.intent.action}`;
189
+ if (scenario === 'ADAPTATION_PROJECT') {
190
+ templatePreviewUrl = templatePreviewUrl.replace('?', `?sap-ui-layer=${rta.layer}&`);
191
+ }
192
+ const template = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/flp/editor.html'), 'utf-8');
193
+ const features = feature_toggle_1.FeatureToggleAccess.getAllFeatureToggles();
194
+ const envPort = process.env.FIORI_TOOLS_LIVERELOAD_PORT;
195
+ let livereloadPort = envPort ? parseInt(envPort, 10) : DEFAULT_LIVERELOAD_PORT;
196
+ livereloadPort = isNaN(livereloadPort) ? DEFAULT_LIVERELOAD_PORT : livereloadPort;
197
+ const envLivereloadUrl = (0, btp_utils_1.isAppStudio)() ? await (0, btp_utils_1.exposePort)(livereloadPort) : undefined;
198
+ const html = (0, ejs_1.render)(template, {
199
+ previewUrl: templatePreviewUrl,
200
+ telemetry: rta.options?.telemetry ?? false,
201
+ appName: rta.options?.appName,
202
+ scenario,
203
+ livereloadPort,
204
+ livereloadUrl: envLivereloadUrl,
205
+ features: JSON.stringify(features)
206
+ });
207
+ this.sendResponse(res, 'text/html', 200, html);
208
+ }
209
+ /**
210
+ * Handler for the GET requests to the runtime adaptation editor.
211
+ *
212
+ * @param req the request
213
+ * @param res the response
214
+ * @param rta runtime adaptation configuration
215
+ * @param previewUrl the url of the preview
216
+ * @param editor editor configuration
217
+ * @private
218
+ */
219
+ async editorGetHandler(req, res, rta, previewUrl, editor) {
220
+ if (!req.query['fiori-tools-rta-mode']) {
221
+ // Redirect to the same URL but add the necessary parameter
222
+ const params = structuredClone(req.query);
223
+ params['sap-ui-xx-viewCache'] = 'false';
224
+ params['fiori-tools-rta-mode'] = 'true';
225
+ params['sap-ui-rta-skip-flex-validation'] = 'true';
226
+ params['sap-ui-xx-condense-changes'] = 'true';
227
+ res.redirect(302, `${previewUrl}?${new URLSearchParams(params)}`);
228
+ return;
229
+ }
230
+ const html = (await this.generateSandboxForEditor(req, rta, editor)).replace('</body>', `</body>\n<!-- livereload disabled for editor </body>-->`);
231
+ this.sendResponse(res, 'text/html', 200, html);
232
+ }
176
233
  /**
177
234
  * Add additional routes for configured editors.
178
235
  *
@@ -186,27 +243,7 @@ class FlpSandbox {
186
243
  previewUrl = `${previewUrl}.inner.html`;
187
244
  editor.pluginScript ??= 'open/ux/preview/client/cpe/init';
188
245
  this.router.get(editor.path, async (_req, res) => {
189
- const scenario = rta.options?.scenario;
190
- let templatePreviewUrl = `${previewUrl}?sap-ui-xx-viewCache=false&fiori-tools-rta-mode=forAdaptation&sap-ui-rta-skip-flex-validation=true&sap-ui-xx-condense-changes=true#${this.config.intent.object}-${this.config.intent.action}`;
191
- if (scenario === 'ADAPTATION_PROJECT') {
192
- templatePreviewUrl = templatePreviewUrl.replace('?', `?sap-ui-layer=${rta.layer}&`);
193
- }
194
- const template = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/flp/editor.html'), 'utf-8');
195
- const features = feature_toggle_1.FeatureToggleAccess.getAllFeatureToggles();
196
- const envPort = process.env.FIORI_TOOLS_LIVERELOAD_PORT;
197
- let livereloadPort = envPort ? parseInt(envPort, 10) : DEFAULT_LIVERELOAD_PORT;
198
- livereloadPort = isNaN(livereloadPort) ? DEFAULT_LIVERELOAD_PORT : livereloadPort;
199
- const envLivereloadUrl = (0, btp_utils_1.isAppStudio)() ? await (0, btp_utils_1.exposePort)(livereloadPort) : undefined;
200
- const html = (0, ejs_1.render)(template, {
201
- previewUrl: templatePreviewUrl,
202
- telemetry: rta.options?.telemetry ?? false,
203
- appName: rta.options?.appName,
204
- scenario,
205
- livereloadPort,
206
- livereloadUrl: envLivereloadUrl,
207
- features: JSON.stringify(features)
208
- });
209
- this.sendResponse(res, 'text/html', 200, html);
246
+ await this.editorGetHandlerDeveloperMode(res, rta, previewUrl);
210
247
  });
211
248
  let path = (0, path_1.dirname)(editor.path);
212
249
  if (!path.endsWith('/')) {
@@ -215,21 +252,45 @@ class FlpSandbox {
215
252
  this.router.use(`${path}editor`, (0, express_1.static)(cpe));
216
253
  }
217
254
  this.router.get(previewUrl, async (req, res) => {
218
- if (!req.query['fiori-tools-rta-mode']) {
219
- // Redirect to the same URL but add the necessary parameter
220
- const params = structuredClone(req.query);
221
- params['sap-ui-xx-viewCache'] = 'false';
222
- params['fiori-tools-rta-mode'] = 'true';
223
- params['sap-ui-rta-skip-flex-validation'] = 'true';
224
- params['sap-ui-xx-condense-changes'] = 'true';
225
- res.redirect(302, `${previewUrl}?${new URLSearchParams(params)}`);
226
- return;
227
- }
228
- const html = (await this.generateSandboxForEditor(req, rta, editor)).replace('</body>', `</body>\n<!-- livereload disabled for editor </body>-->`);
229
- this.sendResponse(res, 'text/html', 200, html);
255
+ await this.editorGetHandler(req, res, rta, previewUrl, editor);
230
256
  });
231
257
  }
232
258
  }
259
+ /**
260
+ * Handler for the GET requests to the FLP.
261
+ *
262
+ * @param req the request
263
+ * @param res the response
264
+ * @param next the next function
265
+ * @private
266
+ */
267
+ async flpGetHandler(req, res, next) {
268
+ // connect API (karma test runner) has no request query property
269
+ if ('query' in req && 'redirect' in res && !req.query['sap-ui-xx-viewCache']) {
270
+ // Redirect to the same URL but add the necessary parameter
271
+ const params = structuredClone(req.query);
272
+ params['sap-ui-xx-viewCache'] = 'false';
273
+ res.redirect(302, `${this.config.path}?${new URLSearchParams(params)}`);
274
+ return;
275
+ }
276
+ await this.setApplicationDependencies();
277
+ // inform the user if a html file exists on the filesystem
278
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
279
+ const file = await this.project.byPath(this.config.path);
280
+ if (file) {
281
+ this.logger.info(`HTML file returned at ${this.config.path} is loaded from the file system.`);
282
+ next();
283
+ }
284
+ else {
285
+ const ui5Version = await this.getUi5Version(
286
+ //use protocol from request header referer as fallback for connect API (karma test runner)
287
+ 'protocol' in req
288
+ ? req.protocol
289
+ : req.headers.referer?.substring(0, req.headers.referer.indexOf(':')) ?? 'http', req.headers.host, 'ui5-patched-router' in req ? req['ui5-patched-router']?.baseUrl : undefined);
290
+ const html = (0, ejs_1.render)(this.getSandboxTemplate(ui5Version.major), this.templateConfig);
291
+ this.sendResponse(res, 'text/html', 200, html);
292
+ }
293
+ }
233
294
  /**
234
295
  * Add routes for html and scripts required for a local FLP.
235
296
  */
@@ -237,33 +298,9 @@ class FlpSandbox {
237
298
  // register static client sources
238
299
  this.router.use(config_1.PREVIEW_URL.client.path, (0, express_1.static)(config_1.PREVIEW_URL.client.local));
239
300
  // add route for the sandbox html
240
- this.router.get(this.config.path, (async (req, res, next) => {
241
- // connect API (karma test runner) has no request query property
242
- if ('query' in req && 'redirect' in res && !req.query['sap-ui-xx-viewCache']) {
243
- // Redirect to the same URL but add the necessary parameter
244
- const params = structuredClone(req.query);
245
- params['sap-ui-xx-viewCache'] = 'false';
246
- res.redirect(302, `${this.config.path}?${new URLSearchParams(params)}`);
247
- return;
248
- }
249
- await this.setApplicationDependencies();
250
- // inform the user if a html file exists on the filesystem
251
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
252
- const file = await this.project.byPath(this.config.path);
253
- if (file) {
254
- this.logger.info(`HTML file returned at ${this.config.path} is loaded from the file system.`);
255
- next();
256
- }
257
- else {
258
- const ui5Version = await this.getUi5Version(
259
- //use protocol from request header referer as fallback for connect API (karma test runner)
260
- 'protocol' in req
261
- ? req.protocol
262
- : req.headers.referer?.substring(0, req.headers.referer.indexOf(':')) ?? 'http', req.headers.host, 'ui5-patched-router' in req ? req['ui5-patched-router']?.baseUrl : undefined);
263
- const html = (0, ejs_1.render)(this.getSandboxTemplate(ui5Version.major), this.templateConfig);
264
- this.sendResponse(res, 'text/html', 200, html);
265
- }
266
- }));
301
+ this.router.get(this.config.path, async (req, res, next) => {
302
+ await this.flpGetHandler(req, res, next);
303
+ });
267
304
  }
268
305
  /**
269
306
  * Read the UI5 version.
@@ -338,8 +375,10 @@ class FlpSandbox {
338
375
  for (const app of this.config.apps) {
339
376
  let manifest;
340
377
  if (app.local) {
341
- manifest = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(app.local, 'webapp/manifest.json'), 'utf-8'));
342
- this.router.use(app.target, (0, express_1.static)((0, path_1.join)(app.local, 'webapp')));
378
+ this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
379
+ const webappPath = await (0, project_access_1.getWebappPath)(app.local, this.fs);
380
+ manifest = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(webappPath, 'manifest.json'), 'utf-8'));
381
+ this.router.use(app.target, (0, express_1.static)(webappPath));
343
382
  this.logger.info(`Serving additional application at ${app.target} from ${app.local}`);
344
383
  }
345
384
  else if (app.componentId) {
@@ -360,53 +399,125 @@ class FlpSandbox {
360
399
  }
361
400
  }
362
401
  /**
363
- * Create required routes for flex.
402
+ * Handler for flex changes GET requests.
403
+ *
404
+ * @param res the response
405
+ * @private
364
406
  */
365
- createFlexHandler() {
366
- const fs = (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
367
- const api = `${config_1.PREVIEW_URL.api}/changes`;
368
- this.router.use(api, (0, express_1.json)());
369
- this.router.get(api, (async (_req, res) => {
370
- const changes = await (0, flex_1.readChanges)(this.project, this.logger);
407
+ async flexGetHandler(res) {
408
+ const changes = await (0, flex_1.readChanges)(this.project, this.logger);
409
+ if (this.onChangeRequest) {
410
+ this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
411
+ for (const change of Object.values(changes)) {
412
+ await this.onChangeRequest('read', change, this.fs, this.logger);
413
+ }
414
+ }
415
+ this.sendResponse(res, 'application/json', 200, JSON.stringify(changes));
416
+ }
417
+ /**
418
+ * Handler for flex changes POST requests.
419
+ *
420
+ * @param req the request
421
+ * @param res the response
422
+ * @private
423
+ */
424
+ async flexPostHandler(req, res) {
425
+ this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
426
+ try {
427
+ const change = req.body;
371
428
  if (this.onChangeRequest) {
372
- for (const change of Object.values(changes)) {
373
- await this.onChangeRequest('read', change, fs, this.logger);
374
- }
429
+ await this.onChangeRequest('write', change, this.fs, this.logger);
375
430
  }
376
- this.sendResponse(res, 'application/json', 200, JSON.stringify(changes));
377
- }));
378
- this.router.post(api, (async (req, res) => {
379
- try {
380
- const change = req.body;
381
- if (this.onChangeRequest) {
382
- await this.onChangeRequest('write', change, fs, this.logger);
383
- }
384
- const { success, message } = (0, flex_1.writeChange)(change, this.utils.getProject().getSourcePath(), fs, this.logger);
385
- if (success) {
386
- fs.commit(() => this.sendResponse(res, 'text/plain', 200, message ?? ''));
387
- }
388
- else {
389
- this.sendResponse(res, 'text/plain', 400, 'INVALID_DATA');
390
- }
431
+ const { success, message } = (0, flex_1.writeChange)(change, this.utils.getProject().getSourcePath(), this.fs, this.logger);
432
+ if (success) {
433
+ this.fs.commit(() => this.sendResponse(res, 'text/plain', 200, message ?? ''));
391
434
  }
392
- catch (error) {
393
- this.sendResponse(res, 'text/plain', 500, error.message);
435
+ else {
436
+ this.sendResponse(res, 'text/plain', 400, 'INVALID_DATA');
394
437
  }
395
- }));
396
- this.router.delete(api, (async (req, res) => {
397
- try {
398
- const { success, message } = (0, flex_1.deleteChange)(req.body, this.utils.getProject().getSourcePath(), this.logger);
399
- if (success) {
400
- this.sendResponse(res, 'text/plain', 200, message ?? '');
401
- }
402
- else {
403
- this.sendResponse(res, 'text/plain', 400, 'INVALID_DATA');
404
- }
438
+ }
439
+ catch (error) {
440
+ this.sendResponse(res, 'text/plain', 500, error.message);
441
+ }
442
+ }
443
+ /**
444
+ * Handler for flex changes DELETE requests.
445
+ *
446
+ * @param req the request
447
+ * @param res the response
448
+ * @private
449
+ */
450
+ async flexDeleteHandler(req, res) {
451
+ try {
452
+ const { success, message } = (0, flex_1.deleteChange)(req.body, this.utils.getProject().getSourcePath(), this.logger);
453
+ if (success) {
454
+ this.sendResponse(res, 'text/plain', 200, message ?? '');
405
455
  }
406
- catch (error) {
407
- this.sendResponse(res, 'text/plain', 500, error.message);
456
+ else {
457
+ this.sendResponse(res, 'text/plain', 400, 'INVALID_DATA');
408
458
  }
409
- }));
459
+ }
460
+ catch (error) {
461
+ this.sendResponse(res, 'text/plain', 500, error.message);
462
+ }
463
+ }
464
+ /**
465
+ * Create required routes for flex.
466
+ */
467
+ createFlexHandler() {
468
+ const api = `${config_1.PREVIEW_URL.api}/changes`;
469
+ this.router.use(api, (0, express_1.json)());
470
+ this.router.get(api, async (_req, res) => {
471
+ await this.flexGetHandler(res);
472
+ });
473
+ this.router.post(api, async (req, res) => {
474
+ await this.flexPostHandler(req, res);
475
+ });
476
+ this.router.delete(api, async (req, res) => {
477
+ await this.flexDeleteHandler(req, res);
478
+ });
479
+ }
480
+ /**
481
+ * Handler for the GET requests to the HTML of the test suite.
482
+ *
483
+ * @param res the response
484
+ * @param testsuite the test suite template
485
+ * @param config the test configuration
486
+ * @private
487
+ */
488
+ async testSuiteHtmlGetHandler(res, testsuite, config) {
489
+ this.logger.debug(`Serving test route: ${config.path}`);
490
+ const templateConfig = {
491
+ basePath: this.templateConfig.basePath,
492
+ initPath: config.init
493
+ };
494
+ const html = (0, ejs_1.render)(testsuite, templateConfig);
495
+ this.sendResponse(res, 'text/html', 200, html);
496
+ }
497
+ /**
498
+ * Handler for the GET requests to the JS of the test suite.
499
+ *
500
+ * @param res the response
501
+ * @param next the next function
502
+ * @param config the test configuration
503
+ * @param initTemplate the test runner template
504
+ * @param testPaths the paths to the test files
505
+ * @private
506
+ */
507
+ async testSuiteJsGetHandler(res, next, config, initTemplate, testPaths) {
508
+ const files = await this.project.byGlob(config.init.replace('.js', '.[jt]s'));
509
+ if (files?.length > 0) {
510
+ this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
511
+ next();
512
+ }
513
+ else {
514
+ this.logger.debug(`Serving test route: ${config.init}`);
515
+ const templateConfig = {
516
+ testPaths: testPaths
517
+ };
518
+ const js = (0, ejs_1.render)(initTemplate, templateConfig);
519
+ this.sendResponse(res, 'application/javascript', 200, js);
520
+ }
410
521
  }
411
522
  /**
412
523
  * If it is part of TestConfig, create a test suite for the test configurations.
@@ -425,18 +536,11 @@ class FlpSandbox {
425
536
  return;
426
537
  }
427
538
  const testsuite = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/testsuite.qunit.html'), 'utf-8');
428
- const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/testsuite.qunit.js'), 'utf-8');
429
539
  const config = (0, test_1.mergeTestConfigDefaults)(testsuiteConfig);
430
540
  this.logger.debug(`Add route for ${config.path}`);
431
- this.router.get(config.path, (async (_req, res, _next) => {
432
- this.logger.debug(`Serving test route: ${config.path}`);
433
- const templateConfig = {
434
- basePath: this.templateConfig.basePath,
435
- initPath: config.init
436
- };
437
- const html = (0, ejs_1.render)(testsuite, templateConfig);
438
- this.sendResponse(res, 'text/html', 200, html);
439
- }));
541
+ this.router.get(config.path, async (_req, res) => {
542
+ await this.testSuiteHtmlGetHandler(res, testsuite, config);
543
+ });
440
544
  if (testsuiteConfig.init !== undefined) {
441
545
  this.logger.debug(`Skip serving testsuite init script in favor of provided script: ${testsuiteConfig.init}`);
442
546
  return;
@@ -449,22 +553,11 @@ class FlpSandbox {
449
553
  const mergedConfig = (0, test_1.mergeTestConfigDefaults)(testConfig);
450
554
  testPaths.push(path_1.posix.relative(path_1.posix.dirname(config.path), mergedConfig.path));
451
555
  }
556
+ const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/testsuite.qunit.js'), 'utf-8');
452
557
  this.logger.debug(`Add route for ${config.init}`);
453
- this.router.get(config.init, (async (_req, res, next) => {
454
- const files = await this.project.byGlob(config.init.replace('.js', '.[jt]s'));
455
- if (files?.length > 0) {
456
- this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
457
- next();
458
- }
459
- else {
460
- this.logger.debug(`Serving test route: ${config.init}`);
461
- const templateConfig = {
462
- testPaths: testPaths
463
- };
464
- const js = (0, ejs_1.render)(initTemplate, templateConfig);
465
- this.sendResponse(res, 'application/javascript', 200, js);
466
- }
467
- }));
558
+ this.router.get(config.init, async (_req, res, next) => {
559
+ await this.testSuiteJsGetHandler(res, next, config, initTemplate, testPaths);
560
+ });
468
561
  }
469
562
  /**
470
563
  * Send a response with the given content type, status and body.
@@ -483,6 +576,53 @@ class FlpSandbox {
483
576
  res.write(body);
484
577
  res.end();
485
578
  }
579
+ /**
580
+ * Handler for the GET requests to the HTML of the test runner.
581
+ *
582
+ * @param res the response
583
+ * @param next the next function
584
+ * @param config test configuration
585
+ * @param htmlTemplate the test runner template
586
+ * @param id application id from manifest
587
+ */
588
+ async testRunnerHtmlGetHandler(res, next, config, htmlTemplate, id) {
589
+ this.logger.debug(`Serving test route: ${config.path}`);
590
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
591
+ const file = await this.project.byPath(config.path);
592
+ if (file) {
593
+ this.logger.warn(`HTML file returned at ${config.path} is loaded from the file system.`);
594
+ next();
595
+ }
596
+ else {
597
+ const templateConfig = (0, config_1.createTestTemplateConfig)(config, id, this.templateConfig.ui5.theme);
598
+ const html = (0, ejs_1.render)(htmlTemplate, templateConfig);
599
+ this.sendResponse(res, 'text/html', 200, html);
600
+ }
601
+ }
602
+ /**
603
+ * Handler for the GET requests to the JS of the test runner.
604
+ *
605
+ * @param res the response
606
+ * @param next the next function
607
+ * @param config test configuration
608
+ * @param initTemplate the test runner template
609
+ * @param ns namespace for the test files
610
+ * @private
611
+ */
612
+ async testRunnerJsGetHandler(res, next, config, initTemplate, ns) {
613
+ this.logger.debug(`Serving test init script: ${config.init}`);
614
+ const files = await this.project.byGlob(config.init.replace('.js', '.[jt]s'));
615
+ if (files?.length > 0) {
616
+ this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
617
+ next();
618
+ }
619
+ else {
620
+ const testFiles = await this.project.byGlob(config.pattern);
621
+ const templateConfig = { tests: (0, test_1.generateImportList)(ns, testFiles) };
622
+ const js = (0, ejs_1.render)(initTemplate, templateConfig);
623
+ this.sendResponse(res, 'application/javascript', 200, js);
624
+ }
625
+ }
486
626
  /**
487
627
  * Add routes for html and scripts required for a local test FLP.
488
628
  *
@@ -492,45 +632,23 @@ class FlpSandbox {
492
632
  addTestRoutes(configs, id) {
493
633
  const ns = id.replace(/\./g, '/');
494
634
  const htmlTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/qunit.html'), 'utf-8');
495
- const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/qunit.js'), 'utf-8');
496
635
  for (const testConfig of configs) {
497
636
  const config = (0, test_1.mergeTestConfigDefaults)(testConfig);
498
637
  this.logger.debug(`Add route for ${config.path}`);
499
638
  // add route for the *.qunit.html
500
- this.router.get(config.path, (async (_req, res, next) => {
501
- this.logger.debug(`Serving test route: ${config.path}`);
502
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
503
- const file = await this.project.byPath(config.path);
504
- if (file) {
505
- this.logger.warn(`HTML file returned at ${config.path} is loaded from the file system.`);
506
- next();
507
- }
508
- else {
509
- const templateConfig = (0, config_1.createTestTemplateConfig)(config, id, this.templateConfig.ui5.theme);
510
- const html = (0, ejs_1.render)(htmlTemplate, templateConfig);
511
- this.sendResponse(res, 'text/html', 200, html);
512
- }
513
- }));
639
+ this.router.get(config.path, async (_req, res, next) => {
640
+ await this.testRunnerHtmlGetHandler(res, next, config, htmlTemplate, id);
641
+ });
514
642
  if (testConfig.init !== undefined) {
515
643
  this.logger.debug(`Skip serving test init script in favor of provided script: ${testConfig.init}`);
516
644
  continue;
517
645
  }
518
646
  // add route for the init file
647
+ const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/qunit.js'), 'utf-8');
519
648
  this.logger.debug(`Add route for ${config.init}`);
520
- this.router.get(config.init, (async (_req, res, next) => {
521
- this.logger.debug(`Serving test init script: ${config.init}`);
522
- const files = await this.project.byGlob(config.init.replace('.js', '.[jt]s'));
523
- if (files?.length > 0) {
524
- this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
525
- next();
526
- }
527
- else {
528
- const testFiles = await this.project.byGlob(config.pattern);
529
- const templateConfig = { tests: (0, test_1.generateImportList)(ns, testFiles) };
530
- const js = (0, ejs_1.render)(initTemplate, templateConfig);
531
- this.sendResponse(res, 'application/javascript', 200, js);
532
- }
533
- }));
649
+ this.router.get(config.init, async (_req, res, next) => {
650
+ await this.testRunnerJsGetHandler(res, next, config, initTemplate, ns);
651
+ });
534
652
  }
535
653
  }
536
654
  }
@@ -539,7 +657,7 @@ exports.FlpSandbox = FlpSandbox;
539
657
  * Creates an attribute string that can be added to an HTML element.
540
658
  *
541
659
  * @param attributes map with attributes and their values
542
- * @param indent indentation thats inserted before each attribute
660
+ * @param indent indentation that's inserted before each attribute
543
661
  * @param prefix value that should be added at the start of to all attribute names
544
662
  * @returns attribute string
545
663
  */