@sap-ux/preview-middleware 0.17.22 → 0.17.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -188,7 +188,7 @@ return flp.router
188
188
 
189
189
 
190
190
  ## [Migration](#migration)
191
- If you have no custom modifications in the local Fiori Launchpad sandbox files (`webapp/test/flpSandbox.html` or `webapp/test/flpSandboxMockserver.html`), the conversion is finished.
191
+ If you have no custom modifications in the local Fiori Launchpad sandbox files (`<webapp>/test/flpSandbox.html` or `<webapp>/test/flpSandboxMockserver.html`), the conversion is finished.
192
192
 
193
193
  If you have custom modifications in the local Fiori Launchpad sandbox files, you need to migrate them into a custom .js or .ts file (depending on your setup) and integrate this file as a custom `init` script into the configuration options of the middleware.
194
194
 
@@ -3,7 +3,7 @@ import type { Editor as MemFsEditor } from 'mem-fs-editor';
3
3
  import type { Router } from 'express';
4
4
  import type { Logger, ToolsLogger } from '@sap-ux/logger';
5
5
  import type { MiddlewareUtils } from '@ui5/server';
6
- import type { Manifest } from '@sap-ux/project-access';
6
+ import { type Manifest } from '@sap-ux/project-access';
7
7
  import { AdpPreview, type AdpPreviewConfig, type CommonChangeProperties, type OperationType } from '@sap-ux/adp-tooling';
8
8
  import type { FlpConfig, MiddlewareConfig, RtaConfig, TestConfig } from '../types';
9
9
  import { type TemplateConfig } from './config';
@@ -29,6 +29,7 @@ export declare class FlpSandbox {
29
29
  readonly rta?: RtaConfig;
30
30
  readonly test?: TestConfig[];
31
31
  readonly router: EnhancedRouter;
32
+ private fs;
32
33
  /**
33
34
  * Constructor setting defaults and keeping reference to workspace resources.
34
35
  *
@@ -77,12 +78,41 @@ export declare class FlpSandbox {
77
78
  * @returns Promise that resolves when the application dependencies are set
78
79
  */
79
80
  private setApplicationDependencies;
81
+ /**
82
+ * Handler for the GET requests to the runtime adaptation editor in developer mode.
83
+ *
84
+ * @param res the response
85
+ * @param rta runtime adaptation configuration
86
+ * @param previewUrl the url of the preview
87
+ * @private
88
+ */
89
+ private editorGetHandlerDeveloperMode;
90
+ /**
91
+ * Handler for the GET requests to the runtime adaptation editor.
92
+ *
93
+ * @param req the request
94
+ * @param res the response
95
+ * @param rta runtime adaptation configuration
96
+ * @param previewUrl the url of the preview
97
+ * @param editor editor configuration
98
+ * @private
99
+ */
100
+ private editorGetHandler;
80
101
  /**
81
102
  * Add additional routes for configured editors.
82
103
  *
83
104
  * @param rta runtime authoring configuration
84
105
  */
85
106
  private addEditorRoutes;
107
+ /**
108
+ * Handler for the GET requests to the FLP.
109
+ *
110
+ * @param req the request
111
+ * @param res the response
112
+ * @param next the next function
113
+ * @private
114
+ */
115
+ private flpGetHandler;
86
116
  /**
87
117
  * Add routes for html and scripts required for a local FLP.
88
118
  */
@@ -120,10 +150,53 @@ export declare class FlpSandbox {
120
150
  * Add additional routes for apps also to be shown in the local FLP.
121
151
  */
122
152
  private addRoutesForAdditionalApps;
153
+ /**
154
+ * Handler for flex changes GET requests.
155
+ *
156
+ * @param res the response
157
+ * @private
158
+ */
159
+ private flexGetHandler;
160
+ /**
161
+ * Handler for flex changes POST requests.
162
+ *
163
+ * @param req the request
164
+ * @param res the response
165
+ * @private
166
+ */
167
+ private flexPostHandler;
168
+ /**
169
+ * Handler for flex changes DELETE requests.
170
+ *
171
+ * @param req the request
172
+ * @param res the response
173
+ * @private
174
+ */
175
+ private flexDeleteHandler;
123
176
  /**
124
177
  * Create required routes for flex.
125
178
  */
126
179
  private createFlexHandler;
180
+ /**
181
+ * Handler for the GET requests to the HTML of the test suite.
182
+ *
183
+ * @param res the response
184
+ * @param testsuite the test suite template
185
+ * @param config the test configuration
186
+ * @private
187
+ */
188
+ private testSuiteHtmlGetHandler;
189
+ /**
190
+ * Handler for the GET requests to the JS of the test suite.
191
+ *
192
+ * @param res the response
193
+ * @param next the next function
194
+ * @param config the test configuration
195
+ * @param initTemplate the test runner template
196
+ * @param testPaths the paths to the test files
197
+ * @private
198
+ */
199
+ private testSuiteJsGetHandler;
127
200
  /**
128
201
  * If it is part of TestConfig, create a test suite for the test configurations.
129
202
  *
@@ -142,6 +215,27 @@ export declare class FlpSandbox {
142
215
  * @private
143
216
  */
144
217
  private sendResponse;
218
+ /**
219
+ * Handler for the GET requests to the HTML of the test runner.
220
+ *
221
+ * @param res the response
222
+ * @param next the next function
223
+ * @param config test configuration
224
+ * @param htmlTemplate the test runner template
225
+ * @param id application id from manifest
226
+ */
227
+ private testRunnerHtmlGetHandler;
228
+ /**
229
+ * Handler for the GET requests to the JS of the test runner.
230
+ *
231
+ * @param res the response
232
+ * @param next the next function
233
+ * @param config test configuration
234
+ * @param initTemplate the test runner template
235
+ * @param ns namespace for the test files
236
+ * @private
237
+ */
238
+ private testRunnerJsGetHandler;
145
239
  /**
146
240
  * Add routes for html and scripts required for a local test FLP.
147
241
  *
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
  */
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Apreview-middleware"
11
11
  },
12
- "version": "0.17.22",
12
+ "version": "0.17.23",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -26,9 +26,9 @@
26
26
  "mem-fs": "2.1.0",
27
27
  "mem-fs-editor": "9.4.0",
28
28
  "@sap-ux/logger": "0.6.0",
29
- "@sap-ux/feature-toggle": "0.2.3",
30
29
  "@sap-ux/btp-utils": "1.0.1",
31
30
  "@sap-ux/adp-tooling": "0.12.125",
31
+ "@sap-ux/feature-toggle": "0.2.3",
32
32
  "@sap-ux/control-property-editor-sources": "npm:@sap-ux/control-property-editor@0.5.35",
33
33
  "@sap-ux/project-access": "1.29.5"
34
34
  },