@sap-ux/ui5-test-writer 0.7.101 → 0.7.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/fiori-elements-opa-writer.d.ts +3 -2
- package/dist/fiori-elements-opa-writer.js +114 -56
- package/dist/types.d.ts +14 -0
- package/dist/utils/flpSandboxUtils.d.ts +17 -0
- package/dist/utils/flpSandboxUtils.js +40 -0
- package/dist/utils/opaQUnitUtils.d.ts +54 -0
- package/dist/utils/opaQUnitUtils.js +184 -0
- package/package.json +3 -3
- package/templates/v4/integration/ObjectPageJourney.js +4 -0
|
@@ -21,13 +21,14 @@ export declare function readManifest(fs: Editor, basePath: string): Manifest;
|
|
|
21
21
|
* @param metadata - optional metadata for the OPA test generation
|
|
22
22
|
* @param fs - an optional reference to a mem-fs editor
|
|
23
23
|
* @param log - optional logger instance
|
|
24
|
+
* @param standalone - opa test generation run standalone, not during app generation
|
|
24
25
|
* @returns Reference to a mem-fs-editor
|
|
25
26
|
*/
|
|
26
27
|
export declare function generateOPAFiles(basePath: string, opaConfig: {
|
|
27
28
|
scriptName?: string;
|
|
28
29
|
appID?: string;
|
|
29
30
|
htmlTarget?: string;
|
|
30
|
-
}, metadata?: string, fs?: Editor, log?: Logger): Promise<Editor>;
|
|
31
|
+
}, metadata?: string, fs?: Editor, log?: Logger, standalone?: boolean): Promise<Editor>;
|
|
31
32
|
/**
|
|
32
33
|
* Generate a page object file for a Fiori elements for OData V4 application.
|
|
33
34
|
* Note: this doesn't modify other existing files in the webapp/test folder.
|
|
@@ -42,5 +43,5 @@ export declare function generateOPAFiles(basePath: string, opaConfig: {
|
|
|
42
43
|
export declare function generatePageObjectFile(basePath: string, pageObjectParameters: {
|
|
43
44
|
targetKey: string;
|
|
44
45
|
appID?: string;
|
|
45
|
-
}, fs?: Editor): Editor
|
|
46
|
+
}, fs?: Editor): Promise<Editor>;
|
|
46
47
|
//# sourceMappingURL=fiori-elements-opa-writer.d.ts.map
|
|
@@ -4,12 +4,14 @@ exports.readManifest = readManifest;
|
|
|
4
4
|
exports.generateOPAFiles = generateOPAFiles;
|
|
5
5
|
exports.generatePageObjectFile = generatePageObjectFile;
|
|
6
6
|
const node_path_1 = require("node:path");
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
7
8
|
const mem_fs_1 = require("mem-fs");
|
|
8
9
|
const mem_fs_editor_1 = require("mem-fs-editor");
|
|
9
10
|
const types_1 = require("./types");
|
|
10
11
|
const i18n_1 = require("./i18n");
|
|
11
12
|
const project_access_1 = require("@sap-ux/project-access");
|
|
12
13
|
const modelUtils_1 = require("./utils/modelUtils");
|
|
14
|
+
const opaQUnitUtils_1 = require("./utils/opaQUnitUtils");
|
|
13
15
|
/**
|
|
14
16
|
* Reads the manifest for an app.
|
|
15
17
|
*
|
|
@@ -192,6 +194,89 @@ function findLROP(pages, manifest) {
|
|
|
192
194
|
}
|
|
193
195
|
return { pageLR, pageOP };
|
|
194
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Writes common test files, page objects, and the first journey file.
|
|
199
|
+
*
|
|
200
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
201
|
+
* @param rootCommonTemplateDirPath - template root directory for common files
|
|
202
|
+
*/
|
|
203
|
+
function writeCommonAndPageFiles(writeContext, rootCommonTemplateDirPath) {
|
|
204
|
+
const { config, rootV4TemplateDirPath, testOutDirPath, editor, journeyParams } = writeContext;
|
|
205
|
+
// Common test files
|
|
206
|
+
editor.copyTpl((0, node_path_1.join)(rootCommonTemplateDirPath), testOutDirPath,
|
|
207
|
+
// unit tests are not added for Fiori elements app
|
|
208
|
+
{ appId: config.appID }, undefined, {
|
|
209
|
+
globOptions: { dot: true }
|
|
210
|
+
});
|
|
211
|
+
// Pages files (one for each page in the app)
|
|
212
|
+
config.pages.forEach((page) => {
|
|
213
|
+
writePageObject(page, rootV4TemplateDirPath, testOutDirPath, editor);
|
|
214
|
+
});
|
|
215
|
+
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'FirstJourney.js'), (0, node_path_1.join)(testOutDirPath, 'integration', `${config.opaJourneyFileName}.js`), journeyParams, undefined, {
|
|
216
|
+
globOptions: { dot: true }
|
|
217
|
+
});
|
|
218
|
+
// Journey Runner
|
|
219
|
+
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'pages', 'JourneyRunner.js'), (0, node_path_1.join)(testOutDirPath, 'integration', 'pages', 'JourneyRunner.js'), config, undefined, {
|
|
220
|
+
globOptions: { dot: true }
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Writes journey files for list report, object pages and FPM pages.
|
|
225
|
+
*
|
|
226
|
+
* @param appFeatures - object containing feature data for list report, object pages, and FPM
|
|
227
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
228
|
+
* @param isStandalone - whether the generation is run in standalone mode (not during app generation)
|
|
229
|
+
* @param hasJourneyRunner - whether a JourneyRunner.js already exists (standalone upgrade path)
|
|
230
|
+
* @param virtualOPA5Configured - whether virtual OPA5 is configured
|
|
231
|
+
*/
|
|
232
|
+
function writeJourneyFiles(appFeatures, writeContext, isStandalone, hasJourneyRunner = false, virtualOPA5Configured = false) {
|
|
233
|
+
const { config, rootV4TemplateDirPath, testOutDirPath, editor, journeyParams } = writeContext;
|
|
234
|
+
const generatedJourneyPages = [];
|
|
235
|
+
if (appFeatures.listReport?.name) {
|
|
236
|
+
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'ListReportJourney.js'), (0, node_path_1.join)(testOutDirPath, 'integration', `${appFeatures.listReport.name}Journey.js`), {
|
|
237
|
+
...journeyParams,
|
|
238
|
+
...appFeatures.listReport
|
|
239
|
+
}, undefined, {
|
|
240
|
+
globOptions: { dot: true }
|
|
241
|
+
});
|
|
242
|
+
generatedJourneyPages.push(appFeatures.listReport.name);
|
|
243
|
+
}
|
|
244
|
+
if (appFeatures.objectPages && appFeatures.objectPages.length > 0) {
|
|
245
|
+
appFeatures.objectPages.forEach((objectPage) => {
|
|
246
|
+
if (objectPage.name) {
|
|
247
|
+
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'ObjectPageJourney.js'), (0, node_path_1.join)(testOutDirPath, 'integration', `${objectPage.name}Journey.js`), {
|
|
248
|
+
...journeyParams,
|
|
249
|
+
...objectPage,
|
|
250
|
+
isStandalone
|
|
251
|
+
}, undefined, {
|
|
252
|
+
globOptions: { dot: true }
|
|
253
|
+
});
|
|
254
|
+
generatedJourneyPages.push(objectPage.name);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
if (appFeatures.fpm?.name) {
|
|
259
|
+
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'FPMJourney.js'), (0, node_path_1.join)(testOutDirPath, 'integration', `${appFeatures.fpm.name}Journey.js`), {
|
|
260
|
+
...journeyParams,
|
|
261
|
+
...appFeatures.fpm
|
|
262
|
+
}, undefined, {
|
|
263
|
+
globOptions: { dot: true }
|
|
264
|
+
});
|
|
265
|
+
generatedJourneyPages.push(appFeatures.fpm.name);
|
|
266
|
+
}
|
|
267
|
+
if (!virtualOPA5Configured) {
|
|
268
|
+
if (hasJourneyRunner) {
|
|
269
|
+
(0, opaQUnitUtils_1.addPathsToQUnitJs)(generatedJourneyPages.map((page) => {
|
|
270
|
+
return `${config.appPath}/test/integration/${page}Journey`;
|
|
271
|
+
}), testOutDirPath, editor);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'opaTests.*.*'), (0, node_path_1.join)(testOutDirPath, 'integration'), { ...config, generatedJourneyPages }, undefined, {
|
|
275
|
+
globOptions: { dot: true }
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
195
280
|
/**
|
|
196
281
|
* Writes a page object in a mem-fs-editor.
|
|
197
282
|
*
|
|
@@ -201,7 +286,7 @@ function findLROP(pages, manifest) {
|
|
|
201
286
|
* @param fs - a reference to a mem-fs editor
|
|
202
287
|
*/
|
|
203
288
|
function writePageObject(pageConfig, rootTemplateDirPath, testOutDirPath, fs) {
|
|
204
|
-
fs.copyTpl((0, node_path_1.join)(rootTemplateDirPath,
|
|
289
|
+
fs.copyTpl((0, node_path_1.join)(rootTemplateDirPath, 'integration', 'pages', `${pageConfig.template}.js`), (0, node_path_1.join)(testOutDirPath, 'integration', 'pages', `${pageConfig.targetKey}.js`), pageConfig, undefined, {
|
|
205
290
|
globOptions: { dot: true }
|
|
206
291
|
});
|
|
207
292
|
}
|
|
@@ -217,78 +302,51 @@ function writePageObject(pageConfig, rootTemplateDirPath, testOutDirPath, fs) {
|
|
|
217
302
|
* @param metadata - optional metadata for the OPA test generation
|
|
218
303
|
* @param fs - an optional reference to a mem-fs editor
|
|
219
304
|
* @param log - optional logger instance
|
|
305
|
+
* @param standalone - opa test generation run standalone, not during app generation
|
|
220
306
|
* @returns Reference to a mem-fs-editor
|
|
221
307
|
*/
|
|
222
|
-
async function generateOPAFiles(basePath, opaConfig, metadata, fs, log) {
|
|
308
|
+
async function generateOPAFiles(basePath, opaConfig, metadata, fs, log, standalone = false) {
|
|
223
309
|
const editor = fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
|
|
224
310
|
const manifest = readManifest(editor, basePath);
|
|
225
311
|
const { applicationType, hideFilterBar } = getAppTypeAndHideFilterBarFromManifest(manifest);
|
|
226
312
|
const config = createConfig(manifest, opaConfig, hideFilterBar);
|
|
227
313
|
const rootCommonTemplateDirPath = (0, node_path_1.join)(__dirname, '../templates/common');
|
|
228
314
|
const rootV4TemplateDirPath = (0, node_path_1.join)(__dirname, `../templates/${applicationType}`); // Only v4 is supported for the time being
|
|
229
|
-
const testOutDirPath = (0, node_path_1.join)(basePath, '
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
// unit tests are not added for Fiori elements app
|
|
233
|
-
{ appId: config.appID }, undefined, {
|
|
234
|
-
globOptions: { dot: true }
|
|
235
|
-
});
|
|
236
|
-
// Pages files (one for each page in the app)
|
|
237
|
-
config.pages.forEach((page) => {
|
|
238
|
-
writePageObject(page, rootV4TemplateDirPath, testOutDirPath, editor);
|
|
239
|
-
});
|
|
315
|
+
const testOutDirPath = (0, node_path_1.join)(await (0, project_access_1.getWebappPath)(basePath), 'test');
|
|
316
|
+
// Access ux-specification to get feature data for OPA test generation
|
|
317
|
+
const appFeatures = await (0, modelUtils_1.getAppFeatures)(basePath, editor, log, metadata);
|
|
240
318
|
// OPA Journey file
|
|
241
319
|
const startPages = config.pages.filter((page) => page.isStartup).map((page) => page.targetKey);
|
|
242
320
|
const LROP = findLROP(config.pages, manifest);
|
|
243
|
-
// Access ux-specification to get feature data for OPA test generation
|
|
244
|
-
const { listReport, objectPages, fpm } = await (0, modelUtils_1.getAppFeatures)(basePath, editor, log, metadata);
|
|
245
321
|
const journeyParams = {
|
|
246
322
|
startPages,
|
|
247
323
|
startLR: LROP.pageLR?.targetKey,
|
|
248
324
|
navigatedOP: LROP.pageOP?.targetKey,
|
|
249
325
|
hideFilterBar: config.hideFilterBar
|
|
250
326
|
};
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}, undefined, {
|
|
270
|
-
globOptions: { dot: true }
|
|
271
|
-
});
|
|
272
|
-
generatedJourneyPages.push(objectPage.name);
|
|
273
|
-
});
|
|
327
|
+
const writeContext = { config, rootV4TemplateDirPath, testOutDirPath, editor, journeyParams };
|
|
328
|
+
if (standalone) {
|
|
329
|
+
const hasJourneyRunner = (0, node_fs_1.existsSync)((0, node_path_1.join)(testOutDirPath, 'integration', 'pages', 'JourneyRunner.js'));
|
|
330
|
+
const virtualOPA5Configured = await (0, opaQUnitUtils_1.hasVirtualOPA5)(basePath);
|
|
331
|
+
if (hasJourneyRunner) {
|
|
332
|
+
writeJourneyFiles(appFeatures, writeContext, true, true, virtualOPA5Configured);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
editor.move((0, node_path_1.join)(testOutDirPath, 'integration', '**'), (0, node_path_1.join)(testOutDirPath, 'integration_old'));
|
|
336
|
+
await (0, opaQUnitUtils_1.addIntegrationOldToGitignore)(basePath, editor);
|
|
337
|
+
const htmlTarget = (0, opaQUnitUtils_1.readHtmlTargetFromQUnitJs)(testOutDirPath, editor) ?? config.htmlTarget;
|
|
338
|
+
const standaloneConfig = { ...config, htmlTarget };
|
|
339
|
+
const standaloneWriteContext = { ...writeContext, config: standaloneConfig };
|
|
340
|
+
if (!virtualOPA5Configured) {
|
|
341
|
+
writeCommonAndPageFiles(standaloneWriteContext, rootCommonTemplateDirPath);
|
|
342
|
+
}
|
|
343
|
+
writeJourneyFiles(appFeatures, standaloneWriteContext, true, true, virtualOPA5Configured);
|
|
344
|
+
}
|
|
274
345
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
...fpm
|
|
279
|
-
}, undefined, {
|
|
280
|
-
globOptions: { dot: true }
|
|
281
|
-
});
|
|
282
|
-
generatedJourneyPages.push(fpm.name);
|
|
346
|
+
else {
|
|
347
|
+
writeCommonAndPageFiles(writeContext, rootCommonTemplateDirPath);
|
|
348
|
+
writeJourneyFiles(appFeatures, writeContext, false);
|
|
283
349
|
}
|
|
284
|
-
// Integration (OPA) test files - version-specific
|
|
285
|
-
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'opaTests.*.*'), (0, node_path_1.join)(testOutDirPath, 'integration'), { ...config, generatedJourneyPages }, undefined, {
|
|
286
|
-
globOptions: { dot: true }
|
|
287
|
-
});
|
|
288
|
-
// Journey Runner
|
|
289
|
-
editor.copyTpl((0, node_path_1.join)(rootV4TemplateDirPath, 'integration', 'pages', 'JourneyRunner.js'), (0, node_path_1.join)(testOutDirPath, 'integration', 'pages', 'JourneyRunner.js'), config, undefined, {
|
|
290
|
-
globOptions: { dot: true }
|
|
291
|
-
});
|
|
292
350
|
return editor;
|
|
293
351
|
}
|
|
294
352
|
/**
|
|
@@ -302,14 +360,14 @@ async function generateOPAFiles(basePath, opaConfig, metadata, fs, log) {
|
|
|
302
360
|
* @param fs - an optional reference to a mem-fs editor
|
|
303
361
|
* @returns Reference to a mem-fs-editor
|
|
304
362
|
*/
|
|
305
|
-
function generatePageObjectFile(basePath, pageObjectParameters, fs) {
|
|
363
|
+
async function generatePageObjectFile(basePath, pageObjectParameters, fs) {
|
|
306
364
|
const editor = fs || (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
|
|
307
365
|
const manifest = readManifest(editor, basePath);
|
|
308
366
|
const { applicationType } = getAppTypeAndHideFilterBarFromManifest(manifest);
|
|
309
367
|
const pageConfig = createPageConfig(manifest, pageObjectParameters.targetKey, pageObjectParameters.appID);
|
|
310
368
|
if (pageConfig) {
|
|
311
369
|
const rootTemplateDirPath = (0, node_path_1.join)(__dirname, `../templates/${applicationType}`); // Only v4 is supported for the time being
|
|
312
|
-
const testOutDirPath = (0, node_path_1.join)(basePath, '
|
|
370
|
+
const testOutDirPath = (0, node_path_1.join)(await (0, project_access_1.getWebappPath)(basePath), 'test');
|
|
313
371
|
writePageObject(pageConfig, rootTemplateDirPath, testOutDirPath, editor);
|
|
314
372
|
}
|
|
315
373
|
else {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Editor } from 'mem-fs-editor';
|
|
1
2
|
export declare const SupportedPageTypes: {
|
|
2
3
|
[id: string]: string;
|
|
3
4
|
};
|
|
@@ -20,6 +21,12 @@ export type FEV4OPAConfig = {
|
|
|
20
21
|
hideFilterBar: boolean;
|
|
21
22
|
filterBarItems?: string[];
|
|
22
23
|
};
|
|
24
|
+
export type JourneyParams = {
|
|
25
|
+
startPages: string[];
|
|
26
|
+
startLR: string | undefined;
|
|
27
|
+
navigatedOP: string | undefined;
|
|
28
|
+
hideFilterBar: boolean;
|
|
29
|
+
};
|
|
23
30
|
export type FEV4ManifestTarget = {
|
|
24
31
|
type?: string;
|
|
25
32
|
name?: string;
|
|
@@ -135,6 +142,13 @@ export type AppFeatures = {
|
|
|
135
142
|
objectPages?: ObjectPageFeatures[];
|
|
136
143
|
fpm?: FPMFeatures;
|
|
137
144
|
};
|
|
145
|
+
export type WriteContext = {
|
|
146
|
+
config: FEV4OPAConfig;
|
|
147
|
+
rootV4TemplateDirPath: string;
|
|
148
|
+
testOutDirPath: string;
|
|
149
|
+
editor: Editor;
|
|
150
|
+
journeyParams: JourneyParams;
|
|
151
|
+
};
|
|
138
152
|
export type FormField = {
|
|
139
153
|
fieldGroupQualifier?: string;
|
|
140
154
|
field?: string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility for reading the FLP sandbox HTML file and extracting the
|
|
3
|
+
* application hash (intent) from the sap-ushell-config applications object.
|
|
4
|
+
*/
|
|
5
|
+
import type { Editor } from 'mem-fs-editor';
|
|
6
|
+
/**
|
|
7
|
+
* Reads an FLP sandbox HTML file and extracts the first application key
|
|
8
|
+
* from the `sap-ushell-config` `applications` object.
|
|
9
|
+
*
|
|
10
|
+
* @param htmlRelativePath - path to the HTML file relative to `webapp/`
|
|
11
|
+
* (e.g. `test/flpSandbox.html`)
|
|
12
|
+
* @param webappPath - path to the webapp directory
|
|
13
|
+
* @param fs - mem-fs-editor instance used to read the file
|
|
14
|
+
* @returns the application key (e.g. `fincashbankmanage-tile`), or undefined
|
|
15
|
+
*/
|
|
16
|
+
export declare function readHashFromFlpSandbox(htmlRelativePath: string, webappPath: string, fs: Editor): string | undefined;
|
|
17
|
+
//# sourceMappingURL=flpSandboxUtils.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility for reading the FLP sandbox HTML file and extracting the
|
|
4
|
+
* application hash (intent) from the sap-ushell-config applications object.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.readHashFromFlpSandbox = readHashFromFlpSandbox;
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
/**
|
|
10
|
+
* Regex to extract the first application key from the sap-ushell-config
|
|
11
|
+
* `applications` block. Matches patterns like:
|
|
12
|
+
*
|
|
13
|
+
* applications: {
|
|
14
|
+
* "fincashbankmanage-tile": {
|
|
15
|
+
*
|
|
16
|
+
* Captures the quoted key (e.g. `fincashbankmanage-tile`).
|
|
17
|
+
*/
|
|
18
|
+
const APPLICATIONS_KEY_REGEX = /applications\s*:\s*\{[^"]*"([^"]+)"\s*:/;
|
|
19
|
+
/**
|
|
20
|
+
* Reads an FLP sandbox HTML file and extracts the first application key
|
|
21
|
+
* from the `sap-ushell-config` `applications` object.
|
|
22
|
+
*
|
|
23
|
+
* @param htmlRelativePath - path to the HTML file relative to `webapp/`
|
|
24
|
+
* (e.g. `test/flpSandbox.html`)
|
|
25
|
+
* @param webappPath - path to the webapp directory
|
|
26
|
+
* @param fs - mem-fs-editor instance used to read the file
|
|
27
|
+
* @returns the application key (e.g. `fincashbankmanage-tile`), or undefined
|
|
28
|
+
*/
|
|
29
|
+
function readHashFromFlpSandbox(htmlRelativePath, webappPath, fs) {
|
|
30
|
+
try {
|
|
31
|
+
const filePath = (0, node_path_1.join)(webappPath, htmlRelativePath);
|
|
32
|
+
const content = fs.read(filePath);
|
|
33
|
+
const match = APPLICATIONS_KEY_REGEX.exec(content);
|
|
34
|
+
return match?.[1];
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=flpSandboxUtils.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility for reading and updating a generated opaTests.qunit.js file.
|
|
3
|
+
* The file is modified in-place: only the sap.ui.require array is changed;
|
|
4
|
+
* all other content (formatting, comments, whitespace) is preserved exactly.
|
|
5
|
+
*/
|
|
6
|
+
import type { Editor } from 'mem-fs-editor';
|
|
7
|
+
/**
|
|
8
|
+
* Splices new module paths into the sap.ui.require array of the content string.
|
|
9
|
+
* Entries that are already present are skipped. All other content is preserved exactly.
|
|
10
|
+
*
|
|
11
|
+
* @param fileContent - the full content of the opaTests.qunit.js file
|
|
12
|
+
* @param moduleNames - module paths to add (e.g. ["myApp/test/integration/SomeJourney"])
|
|
13
|
+
* @returns the updated file content, or the original content unchanged if nothing was added
|
|
14
|
+
*/
|
|
15
|
+
export declare function spliceModulesIntoQUnitContent(fileContent: string, moduleNames: string[]): string;
|
|
16
|
+
/**
|
|
17
|
+
* Reads opaTests.qunit.js from webapp/test/integration_old and extracts the html
|
|
18
|
+
* launch target (path, query parameters, and hash fragment) from the launchUrl
|
|
19
|
+
* line, e.g. `test/flpSandbox.html?sap-ui-xx-viewCache=false#myApp-tile`.
|
|
20
|
+
* Returns undefined if the file cannot be read or the pattern is not found.
|
|
21
|
+
*
|
|
22
|
+
* @param testPath - path to the test output directory (`.../webapp/test`)
|
|
23
|
+
* @param fs - mem-fs-editor instance used to read the file
|
|
24
|
+
* @returns the html target string, or undefined if not found
|
|
25
|
+
*/
|
|
26
|
+
export declare function readHtmlTargetFromQUnitJs(testPath: string, fs: Editor): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Appends `/webapp/test/integration_old` to the project's `.gitignore`.
|
|
29
|
+
* Creates the file if it does not exist. Skips if the entry is already present.
|
|
30
|
+
*
|
|
31
|
+
* @param basePath - project root (contains .gitignore)
|
|
32
|
+
* @param fs - mem-fs-editor instance used to read and write the file
|
|
33
|
+
*/
|
|
34
|
+
export declare function addIntegrationOldToGitignore(basePath: string, fs: Editor): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Reads opaTests.qunit.js from the project, adds module paths to the
|
|
37
|
+
* sap.ui.require array, and writes the updated content back.
|
|
38
|
+
* Entries that are already present are skipped.
|
|
39
|
+
* All other file content is preserved exactly.
|
|
40
|
+
*
|
|
41
|
+
* @param filePaths - module paths to add (e.g. ["myApp/test/integration/SomeJourney"])
|
|
42
|
+
* @param projectPath - path to the test output directory (`.../webapp/test`)
|
|
43
|
+
* @param fs - mem-fs-editor instance used to read and write the file
|
|
44
|
+
*/
|
|
45
|
+
export declare function addPathsToQUnitJs(filePaths: string[], projectPath: string, fs: Editor): void;
|
|
46
|
+
/**
|
|
47
|
+
* Returns true if any UI5 yaml file in the project contains a `fiori-tools-preview`
|
|
48
|
+
* middleware whose `test` array includes an entry with `framework: OPA5`.
|
|
49
|
+
*
|
|
50
|
+
* @param basePath - project root directory
|
|
51
|
+
* @returns true when OPA5 is configured in a preview middleware, false otherwise
|
|
52
|
+
*/
|
|
53
|
+
export declare function hasVirtualOPA5(basePath: string): Promise<boolean>;
|
|
54
|
+
//# sourceMappingURL=opaQUnitUtils.d.ts.map
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Utility for reading and updating a generated opaTests.qunit.js file.
|
|
4
|
+
* The file is modified in-place: only the sap.ui.require array is changed;
|
|
5
|
+
* all other content (formatting, comments, whitespace) is preserved exactly.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.spliceModulesIntoQUnitContent = spliceModulesIntoQUnitContent;
|
|
9
|
+
exports.readHtmlTargetFromQUnitJs = readHtmlTargetFromQUnitJs;
|
|
10
|
+
exports.addIntegrationOldToGitignore = addIntegrationOldToGitignore;
|
|
11
|
+
exports.addPathsToQUnitJs = addPathsToQUnitJs;
|
|
12
|
+
exports.hasVirtualOPA5 = hasVirtualOPA5;
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const flpSandboxUtils_1 = require("./flpSandboxUtils");
|
|
15
|
+
const project_access_1 = require("@sap-ux/project-access");
|
|
16
|
+
/** Relative path from the test output directory to opaTests.qunit.js */
|
|
17
|
+
const OPA_QUNIT_FILE = (0, node_path_1.join)('integration', 'opaTests.qunit.js');
|
|
18
|
+
/**
|
|
19
|
+
* The regex matches the opening bracket of the sap.ui.require array and
|
|
20
|
+
* captures everything up to (but not including) the closing bracket followed
|
|
21
|
+
* by `], function`. This lets us splice new entries in without disturbing
|
|
22
|
+
* any other part of the file.
|
|
23
|
+
*
|
|
24
|
+
* Matches:
|
|
25
|
+
* sap.ui.require(\n [\n "a",\n "b",\n ], function
|
|
26
|
+
* ^^^^^^^^^^^^^^^^^
|
|
27
|
+
* captured as group 1
|
|
28
|
+
*
|
|
29
|
+
* The `d` flag enables `match.indices` so we can read the capture group's
|
|
30
|
+
* exact start/end positions without fragile string searching.
|
|
31
|
+
*/
|
|
32
|
+
const SAP_UI_REQUIRE_ARRAY_REGEX = /sap\.ui\.require\s*\(\s*\[([\s\S]*?)\]\s*,\s*function/d;
|
|
33
|
+
/**
|
|
34
|
+
* Splices new module paths into the sap.ui.require array of the content string.
|
|
35
|
+
* Entries that are already present are skipped. All other content is preserved exactly.
|
|
36
|
+
*
|
|
37
|
+
* @param fileContent - the full content of the opaTests.qunit.js file
|
|
38
|
+
* @param moduleNames - module paths to add (e.g. ["myApp/test/integration/SomeJourney"])
|
|
39
|
+
* @returns the updated file content, or the original content unchanged if nothing was added
|
|
40
|
+
*/
|
|
41
|
+
function spliceModulesIntoQUnitContent(fileContent, moduleNames) {
|
|
42
|
+
const match = SAP_UI_REQUIRE_ARRAY_REGEX.exec(fileContent);
|
|
43
|
+
if (!match) {
|
|
44
|
+
return fileContent;
|
|
45
|
+
}
|
|
46
|
+
const arrayBody = match[1]; // everything between `[` and `]`
|
|
47
|
+
// Collect existing quoted entries so we don't add duplicates
|
|
48
|
+
const existingEntries = new Set();
|
|
49
|
+
const entryRegex = /"([^"]+)"/g;
|
|
50
|
+
let entryMatch;
|
|
51
|
+
while ((entryMatch = entryRegex.exec(arrayBody)) !== null) {
|
|
52
|
+
existingEntries.add(entryMatch[1]);
|
|
53
|
+
}
|
|
54
|
+
const toAdd = moduleNames.filter((name) => !existingEntries.has(name));
|
|
55
|
+
if (toAdd.length === 0) {
|
|
56
|
+
return fileContent;
|
|
57
|
+
}
|
|
58
|
+
// Detect the indentation used by the existing entries (e.g. four spaces)
|
|
59
|
+
const indentMatch = /^([ \t]+)"/m.exec(arrayBody);
|
|
60
|
+
const indent = indentMatch ? indentMatch[1] : ' ';
|
|
61
|
+
// Build the lines to insert, each terminated with a trailing comma
|
|
62
|
+
const newLines = toAdd.map((name) => `${indent}"${name}",`).join('\n');
|
|
63
|
+
// Insert just before the closing `]` using the capture group's end index.
|
|
64
|
+
const insertPosition = match.indices?.[1]?.[1];
|
|
65
|
+
if (insertPosition === undefined) {
|
|
66
|
+
return fileContent;
|
|
67
|
+
}
|
|
68
|
+
const before = fileContent.slice(0, insertPosition);
|
|
69
|
+
const after = fileContent.slice(insertPosition);
|
|
70
|
+
const leadingNewline = arrayBody.endsWith('\n') ? '' : '\n';
|
|
71
|
+
return `${before}${leadingNewline}${newLines}\n${after}`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Regex to extract the html launch target from a `launchUrl` line of the form:
|
|
75
|
+
* sap.ui.require.toUrl('...') + '/some/path.html?params#hash'
|
|
76
|
+
* Captures the path/query/hash portion after the closing `') + '`.
|
|
77
|
+
*/
|
|
78
|
+
const LAUNCH_URL_REGEX = /\.toUrl\s*\([^)]+\)\s*\+\s*'([^']+)'/;
|
|
79
|
+
/**
|
|
80
|
+
* Reads opaTests.qunit.js from webapp/test/integration_old and extracts the html
|
|
81
|
+
* launch target (path, query parameters, and hash fragment) from the launchUrl
|
|
82
|
+
* line, e.g. `test/flpSandbox.html?sap-ui-xx-viewCache=false#myApp-tile`.
|
|
83
|
+
* Returns undefined if the file cannot be read or the pattern is not found.
|
|
84
|
+
*
|
|
85
|
+
* @param testPath - path to the test output directory (`.../webapp/test`)
|
|
86
|
+
* @param fs - mem-fs-editor instance used to read the file
|
|
87
|
+
* @returns the html target string, or undefined if not found
|
|
88
|
+
*/
|
|
89
|
+
function readHtmlTargetFromQUnitJs(testPath, fs) {
|
|
90
|
+
try {
|
|
91
|
+
const integrationOldDir = (0, node_path_1.join)(testPath, 'integration_old');
|
|
92
|
+
let filePath = (0, node_path_1.join)(integrationOldDir, 'opaTests.qunit.js');
|
|
93
|
+
if (!fs.exists(filePath)) {
|
|
94
|
+
filePath = (0, node_path_1.join)(integrationOldDir, 'Opa.qunit.js');
|
|
95
|
+
}
|
|
96
|
+
const content = fs.read(filePath);
|
|
97
|
+
const match = LAUNCH_URL_REGEX.exec(content);
|
|
98
|
+
const launchUrl = match?.[1].replace(/^\//, '');
|
|
99
|
+
if (!launchUrl) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
// If the launch URL already contains a hash fragment, use it as-is
|
|
103
|
+
if (launchUrl.includes('#')) {
|
|
104
|
+
return launchUrl;
|
|
105
|
+
}
|
|
106
|
+
// No hash fragment — read the referenced HTML file to extract the
|
|
107
|
+
// application key from the sap-ushell-config applications object
|
|
108
|
+
const htmlPath = launchUrl.split('?')[0];
|
|
109
|
+
const hash = (0, flpSandboxUtils_1.readHashFromFlpSandbox)(htmlPath, (0, node_path_1.join)(testPath, '..'), fs);
|
|
110
|
+
return hash ? `${launchUrl}#${hash}` : launchUrl;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** The gitignore entry added for the moved integration test folder */
|
|
117
|
+
const INTEGRATION_OLD_GITIGNORE_ENTRY = '/webapp/test/integration_old';
|
|
118
|
+
/**
|
|
119
|
+
* Appends `/webapp/test/integration_old` to the project's `.gitignore`.
|
|
120
|
+
* Creates the file if it does not exist. Skips if the entry is already present.
|
|
121
|
+
*
|
|
122
|
+
* @param basePath - project root (contains .gitignore)
|
|
123
|
+
* @param fs - mem-fs-editor instance used to read and write the file
|
|
124
|
+
*/
|
|
125
|
+
async function addIntegrationOldToGitignore(basePath, fs) {
|
|
126
|
+
const filePath = (0, node_path_1.join)(basePath, '.gitignore');
|
|
127
|
+
const existing = fs.exists(filePath) ? fs.read(filePath) : '';
|
|
128
|
+
const lines = existing.split('\n');
|
|
129
|
+
if (lines.some((line) => line.trim() === INTEGRATION_OLD_GITIGNORE_ENTRY)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const updated = existing.endsWith('\n') || existing === ''
|
|
133
|
+
? `${existing}${INTEGRATION_OLD_GITIGNORE_ENTRY}\n`
|
|
134
|
+
: `${existing}\n${INTEGRATION_OLD_GITIGNORE_ENTRY}\n`;
|
|
135
|
+
fs.write(filePath, updated);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Reads opaTests.qunit.js from the project, adds module paths to the
|
|
139
|
+
* sap.ui.require array, and writes the updated content back.
|
|
140
|
+
* Entries that are already present are skipped.
|
|
141
|
+
* All other file content is preserved exactly.
|
|
142
|
+
*
|
|
143
|
+
* @param filePaths - module paths to add (e.g. ["myApp/test/integration/SomeJourney"])
|
|
144
|
+
* @param projectPath - path to the test output directory (`.../webapp/test`)
|
|
145
|
+
* @param fs - mem-fs-editor instance used to read and write the file
|
|
146
|
+
*/
|
|
147
|
+
function addPathsToQUnitJs(filePaths, projectPath, fs) {
|
|
148
|
+
try {
|
|
149
|
+
const filePath = (0, node_path_1.join)(projectPath, OPA_QUNIT_FILE);
|
|
150
|
+
const content = fs.read(filePath);
|
|
151
|
+
const updated = spliceModulesIntoQUnitContent(content, filePaths);
|
|
152
|
+
if (updated !== content) {
|
|
153
|
+
fs.write(filePath, updated);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// If the file doesn't exist or can't be read, do nothing
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Returns true if any UI5 yaml file in the project contains a `fiori-tools-preview`
|
|
162
|
+
* middleware whose `test` array includes an entry with `framework: OPA5`.
|
|
163
|
+
*
|
|
164
|
+
* @param basePath - project root directory
|
|
165
|
+
* @returns true when OPA5 is configured in a preview middleware, false otherwise
|
|
166
|
+
*/
|
|
167
|
+
async function hasVirtualOPA5(basePath) {
|
|
168
|
+
const yamlFileNames = await (0, project_access_1.getAllUi5YamlFileNames)(basePath);
|
|
169
|
+
for (const fileName of yamlFileNames) {
|
|
170
|
+
try {
|
|
171
|
+
const ui5Config = await (0, project_access_1.readUi5Yaml)(basePath, fileName);
|
|
172
|
+
const previewMiddleware = ui5Config.findCustomMiddleware('fiori-tools-preview');
|
|
173
|
+
const testEntries = previewMiddleware?.configuration?.test;
|
|
174
|
+
if (testEntries?.some((entry) => entry.framework === 'OPA5')) {
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
// Skip yaml files that cannot be read
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=opaQUnitUtils.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap-ux/ui5-test-writer",
|
|
3
3
|
"description": "SAP UI5 tests writer",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.103",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/SAP/open-ux-tools.git",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"@sap/ux-specification": "1.144.0",
|
|
28
28
|
"@sap-ux/edmx-parser": "0.10.0",
|
|
29
29
|
"@sap-ux/annotation-converter": "0.10.21",
|
|
30
|
-
"@sap-ux/ui5-application-writer": "1.8.
|
|
30
|
+
"@sap-ux/ui5-application-writer": "1.8.5",
|
|
31
31
|
"@sap-ux/logger": "0.8.5",
|
|
32
|
-
"@sap-ux/project-access": "1.35.
|
|
32
|
+
"@sap-ux/project-access": "1.35.20"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/ejs": "3.1.5",
|
|
@@ -66,8 +66,12 @@ sap.ui.define([
|
|
|
66
66
|
Then.onThe<%- name%>.iCheckNumberOfSections(<%- bodySections.length %>);
|
|
67
67
|
<% } -%>
|
|
68
68
|
<% bodySections.forEach(function(section) { -%>
|
|
69
|
+
<% if (!isStandalone) { -%>
|
|
70
|
+
<% if (bodySections.length > 1) { -%>
|
|
69
71
|
When.onThe<%- name%>.iPressSectionIconTabFilterButton("<%- section.id %>");
|
|
72
|
+
<% } -%>
|
|
70
73
|
Then.onThe<%- name%>.iCheckSection({ section: "<%- section.id %>" });
|
|
74
|
+
<% } -%>
|
|
71
75
|
<% if (section?.subSections?.length > 0) { -%>
|
|
72
76
|
<% section.subSections.forEach(function(subSection) { -%>
|
|
73
77
|
//When.onThe<%- name%>.iGoToSection({ section: "<%- section.id %>", subSection: "<%- subSection.id %>" });
|