@sap-ux/ui5-test-writer 1.1.13 → 1.2.0
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.js +360 -143
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/translations/ui5-test-writer.i18n.json +10 -0
- package/dist/types.d.ts +10 -0
- package/dist/utils/fileWritingUtils.d.ts +55 -0
- package/dist/utils/fileWritingUtils.js +103 -0
- package/dist/utils/journeyRunnerUtils.d.ts +64 -0
- package/dist/utils/journeyRunnerUtils.js +251 -0
- package/dist/utils/opaJourneyTypesUtils.d.ts +27 -0
- package/dist/utils/opaJourneyTypesUtils.js +167 -0
- package/dist/utils/opaQUnitUtils.d.ts +6 -92
- package/dist/utils/opaQUnitUtils.js +20 -374
- package/dist/utils/virtualOpaUtils.d.ts +21 -0
- package/dist/utils/virtualOpaUtils.js +51 -0
- package/package.json +2 -1
- package/templates/v4/integration/FPMJourney.js +3 -3
- package/templates/v4/integration/FirstJourney.ts +5 -5
- package/templates/v4/integration/ListReportJourney.js +25 -25
- package/templates/v4/integration/ListReportJourney.ts +25 -25
- package/templates/v4/integration/ObjectPageJourney.js +37 -37
- package/templates/v4/integration/ObjectPageJourney.ts +38 -38
- package/templates/v4/integration/opaTests.qunit.js +5 -2
- package/templates/v4/integration/pages/FPM.js +17 -0
- package/templates/v4/integration/pages/JourneyRunner.js +6 -6
- package/templates/v4/integration/pages/JourneyRunner.ts +21 -12
- package/templates/v4/integration/pages/ListReport.js +17 -0
- package/templates/v4/integration/pages/ObjectPage.js +17 -0
- package/templates/v4/integration/types/OpaJourneyTypes.d.ts +5 -5
|
@@ -7,7 +7,10 @@ import { SupportedPageTypes, ValidationError, DotFileExtension } from './types.j
|
|
|
7
7
|
import { t } from './i18n.js';
|
|
8
8
|
import { FileName, DirName, getWebappPath, updatePackageScript } from '@sap-ux/project-access';
|
|
9
9
|
import { getAppFeatures } from './utils/modelUtils.js';
|
|
10
|
-
import {
|
|
10
|
+
import { addPathsToQUnitJs, readHtmlTargetFromQUnitJs } from './utils/opaQUnitUtils.js';
|
|
11
|
+
import { addPagesToJourneyRunner } from './utils/journeyRunnerUtils.js';
|
|
12
|
+
import { hasVirtualOPA5, addVirtualTestConfig } from './utils/virtualOpaUtils.js';
|
|
13
|
+
import { addJourneysToOpaJourneyTypes } from './utils/opaJourneyTypesUtils.js';
|
|
11
14
|
import { getPackageScripts } from '@sap-ux/fiori-generator-shared';
|
|
12
15
|
import { readHashFromFlpSandbox } from './utils/flpSandboxUtils.js';
|
|
13
16
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -51,77 +54,203 @@ export async function generateOPAFiles(basePath, options, metadata, fs, log, sta
|
|
|
51
54
|
};
|
|
52
55
|
const writeContext = {
|
|
53
56
|
config,
|
|
57
|
+
basePath,
|
|
58
|
+
rootCommonTemplateDirPath,
|
|
54
59
|
rootV4TemplateDirPath,
|
|
55
60
|
testOutDirPath,
|
|
56
61
|
editor,
|
|
62
|
+
log,
|
|
57
63
|
journeyParams,
|
|
58
|
-
dotFileExtension
|
|
64
|
+
dotFileExtension,
|
|
65
|
+
modifiedFiles: []
|
|
59
66
|
};
|
|
60
|
-
// The active context is the one used to actually emit files. In standalone mode without an
|
|
61
|
-
// existing JourneyRunner it is replaced with the resolved standalone context (which may
|
|
62
|
-
// override fields like `htmlTarget`); otherwise it stays as the original `writeContext`.
|
|
63
|
-
let activeContext = writeContext;
|
|
64
67
|
if (standalone) {
|
|
65
|
-
|
|
66
|
-
const virtualOPA5Configured = await hasVirtualOPA5(basePath);
|
|
67
|
-
if (hasJourneyRunner) {
|
|
68
|
-
writeJourneyFiles(appFeatures, writeContext, true, true, virtualOPA5Configured);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
activeContext = await resolveStandaloneWriteContext(basePath, testOutDirPath, writeContext, editor);
|
|
72
|
-
if (!virtualOPA5Configured) {
|
|
73
|
-
writeCommonAndPageFiles(activeContext, rootCommonTemplateDirPath);
|
|
74
|
-
}
|
|
75
|
-
writeJourneyFiles(appFeatures, activeContext, true, hasJourneyRunner, virtualOPA5Configured);
|
|
76
|
-
}
|
|
68
|
+
await generateOPAFilesForExistingApp(writeContext, appFeatures);
|
|
77
69
|
}
|
|
78
70
|
else {
|
|
79
|
-
|
|
80
|
-
writeCommonAndPageFiles(writeContext, rootCommonTemplateDirPath, useVirtualPreviewEndpoints);
|
|
81
|
-
writeJourneyFiles(appFeatures, writeContext, false, false, useVirtualPreviewEndpoints);
|
|
82
|
-
if (useVirtualPreviewEndpoints) {
|
|
83
|
-
await addVirtualTestConfig(basePath, [{ framework: 'OPA5', path: '/test/integration/opaTests.qunit.html' }, { framework: 'Testsuite' }], editor);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (enableTypeScript) {
|
|
87
|
-
writeOpaJourneyTypes(activeContext);
|
|
71
|
+
await generateOPAFilesForNewApp(writeContext, appFeatures);
|
|
88
72
|
}
|
|
89
73
|
return editor;
|
|
90
74
|
}
|
|
91
75
|
/**
|
|
92
|
-
*
|
|
93
|
-
* Moves any existing integration folder to integration_old, or adds the int-test script
|
|
94
|
-
* and resolves the htmlTarget from flpSandbox.html if present.
|
|
76
|
+
* Generate OPA test files for an existing Fiori elements for OData V4 application.
|
|
95
77
|
*
|
|
96
|
-
* @param
|
|
97
|
-
* @param
|
|
98
|
-
* @param writeContext - shared write context to base the resolved context on
|
|
99
|
-
* @param editor - a reference to a mem-fs editor
|
|
100
|
-
* @returns a new WriteContext with the resolved htmlTarget
|
|
78
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
79
|
+
* @param appFeatures - object containing feature data for list report, object pages, and FPM, used for generating the journey files
|
|
101
80
|
*/
|
|
102
|
-
async function
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
81
|
+
async function generateOPAFilesForExistingApp(writeContext, appFeatures) {
|
|
82
|
+
const virtualOPA5Configured = await hasVirtualOPA5(writeContext.basePath);
|
|
83
|
+
const standaloneWriteContext = await resolveStandaloneWriteContext(writeContext);
|
|
84
|
+
const generatedPages = writePageFiles(standaloneWriteContext);
|
|
85
|
+
const generatedJourneys = writeJourneyFiles(appFeatures, standaloneWriteContext);
|
|
86
|
+
handleJourneyRunner(standaloneWriteContext, generatedPages);
|
|
87
|
+
if (virtualOPA5Configured) {
|
|
88
|
+
await addVirtualOpa5Config(standaloneWriteContext);
|
|
108
89
|
}
|
|
109
90
|
else {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
91
|
+
handleOpaTestsStartupFiles(standaloneWriteContext, generatedJourneys);
|
|
92
|
+
}
|
|
93
|
+
if (standaloneWriteContext.dotFileExtension === DotFileExtension.TS) {
|
|
94
|
+
handleOPAJourneyTypes(standaloneWriteContext, generatedPages);
|
|
95
|
+
}
|
|
96
|
+
logGeneratedAndModifiedFiles(standaloneWriteContext, generatedJourneys, generatedPages);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Generate OPA test files for a newly generated Fiori elements for OData V4 application.
|
|
100
|
+
*
|
|
101
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
102
|
+
* @param appFeatures - object containing feature data for list report, object pages, and FPM, used for generating the journey files
|
|
103
|
+
*/
|
|
104
|
+
async function generateOPAFilesForNewApp(writeContext, appFeatures) {
|
|
105
|
+
const generatedPages = writePageFiles(writeContext);
|
|
106
|
+
writeJourneyRunner(writeContext);
|
|
107
|
+
const generatedJourneys = writeJourneyFiles(appFeatures, writeContext);
|
|
108
|
+
if (writeContext.config.useVirtualPreviewEndpoints) {
|
|
109
|
+
await addVirtualOpa5Config(writeContext);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
handleOpaTestsStartupFiles(writeContext, generatedJourneys);
|
|
113
|
+
}
|
|
114
|
+
if (writeContext.dotFileExtension === DotFileExtension.TS) {
|
|
115
|
+
writeOpaJourneyTypes(writeContext);
|
|
116
|
+
}
|
|
117
|
+
logGeneratedAndModifiedFiles(writeContext, generatedJourneys, generatedPages);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Log a summary of all files the generator produced or updated, grouped into journeys, pages,
|
|
121
|
+
* and other modified files (JourneyRunner, qunit harness, type definitions, etc.).
|
|
122
|
+
*
|
|
123
|
+
* @param writeContext - shared write context (provides logger, file extension, and modifiedFiles accumulator)
|
|
124
|
+
* @param generatedJourneys - feature names for which a `<name>Journey.gen.<ext>` file was written
|
|
125
|
+
* @param generatedPages - page objects written under `pages/`
|
|
126
|
+
*/
|
|
127
|
+
function logGeneratedAndModifiedFiles(writeContext, generatedJourneys, generatedPages) {
|
|
128
|
+
const { log, dotFileExtension, modifiedFiles, incompatibleTestSetup } = writeContext;
|
|
129
|
+
if (!log?.info) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
logGeneratedJourneyFiles(log, generatedJourneys, dotFileExtension);
|
|
133
|
+
logGeneratedPageFiles(log, generatedPages, dotFileExtension);
|
|
134
|
+
logModifiedFiles(log, modifiedFiles);
|
|
135
|
+
// In an incompatible existing setup, the qunit/testsuite files are not touched, so the
|
|
136
|
+
// generated `.gen` Journeys/Pages must be wired in by the app owner.
|
|
137
|
+
if (incompatibleTestSetup && (generatedJourneys.length > 0 || generatedPages.length > 0)) {
|
|
138
|
+
log.info(t('info.manualIntegrationRequired'));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Log the generated journey files (one per line) under a "Generated Journeys:" heading.
|
|
143
|
+
*
|
|
144
|
+
* @param log - logger instance to use for logging
|
|
145
|
+
* @param generatedJourneys - feature names for which a `<name>Journey.gen.<ext>` file was written
|
|
146
|
+
* @param dotFileExtension - the journey file extension (`.js` or `.ts`)
|
|
147
|
+
*/
|
|
148
|
+
function logGeneratedJourneyFiles(log, generatedJourneys, dotFileExtension) {
|
|
149
|
+
if (generatedJourneys.length === 0) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const lines = generatedJourneys.map((journey) => ` ${journey}Journey.gen${dotFileExtension}`);
|
|
153
|
+
log.info?.(['Generated Journeys:', ...lines].join('\n'));
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Log the generated page files (one per line) under a "Generated Pages:" heading.
|
|
157
|
+
*
|
|
158
|
+
* @param log - logger instance to use for logging
|
|
159
|
+
* @param generatedPages - page objects written under `pages/`
|
|
160
|
+
* @param dotFileExtension - the page file extension (`.js` or `.ts`)
|
|
161
|
+
*/
|
|
162
|
+
function logGeneratedPageFiles(log, generatedPages, dotFileExtension) {
|
|
163
|
+
if (generatedPages.length === 0) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const lines = generatedPages.map((page) => ` pages/${page.fileName}${dotFileExtension}`);
|
|
167
|
+
log.info?.(['Generated Pages:', ...lines].join('\n'));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Log the additional files updated during generation (one per line) under a "Modified files:" heading.
|
|
171
|
+
*
|
|
172
|
+
* @param log - logger instance to use for logging
|
|
173
|
+
* @param modifiedFiles - paths (relative to the test output dir) of files that were written or spliced
|
|
174
|
+
*/
|
|
175
|
+
function logModifiedFiles(log, modifiedFiles) {
|
|
176
|
+
if (modifiedFiles.length === 0) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const lines = modifiedFiles.map((file) => ` ${file}`);
|
|
180
|
+
log.info?.(['Modified files:', ...lines].join('\n'));
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Resolve the standalone-mode write context: detect preexisting integration tests and an
|
|
184
|
+
* incompatible legacy setup, and resolve the htmlTarget from flpSandbox.html if present.
|
|
185
|
+
*
|
|
186
|
+
* @param writeContext - shared write context to base the resolved context on
|
|
187
|
+
* @returns a new WriteContext with the resolved values for the standalone generation
|
|
188
|
+
*/
|
|
189
|
+
async function resolveStandaloneWriteContext(writeContext) {
|
|
190
|
+
const hasPreexistingTests = existsSync(join(writeContext.testOutDirPath, 'integration'));
|
|
191
|
+
if (hasPreexistingTests) {
|
|
192
|
+
return {
|
|
193
|
+
...writeContext,
|
|
194
|
+
hasPreexistingTests: true,
|
|
195
|
+
incompatibleTestSetup: hasIncompatibleTestSetup(writeContext.testOutDirPath),
|
|
196
|
+
config: {
|
|
197
|
+
...writeContext.config,
|
|
198
|
+
htmlTarget: readHtmlTargetFromQUnitJs(writeContext.testOutDirPath, writeContext.editor) ??
|
|
199
|
+
writeContext.config.htmlTarget
|
|
115
200
|
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// app has no integration tests yet
|
|
204
|
+
return await resolveWriteContextForMissingIntegrationFolder(writeContext);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Resolve the standalone-mode write context for the case where the integration folder is
|
|
208
|
+
* missing entirely: there are no OPA tests yet, the int-test package script may need to be
|
|
209
|
+
* added, and the htmlTarget is resolved from flpSandbox.html if present.
|
|
210
|
+
*
|
|
211
|
+
* @param writeContext - shared write context to base the resolved context on
|
|
212
|
+
* @returns a new WriteContext with the resolved values for the standalone generation
|
|
213
|
+
*/
|
|
214
|
+
async function resolveWriteContextForMissingIntegrationFolder(writeContext) {
|
|
215
|
+
const hasIntTestScript = checkScriptInPackageJson(writeContext.editor, writeContext.basePath, 'int-test');
|
|
216
|
+
if (!hasIntTestScript) {
|
|
217
|
+
const script = getPackageScripts({ localOnly: false, addTest: true })['int-test'];
|
|
218
|
+
if (script) {
|
|
219
|
+
await updatePackageScript(writeContext.basePath, 'int-test', script, writeContext.editor);
|
|
220
|
+
writeContext.modifiedFiles.push('package.json');
|
|
116
221
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
222
|
+
}
|
|
223
|
+
let htmlTarget = writeContext.config.htmlTarget;
|
|
224
|
+
if (existsSync(join(writeContext.testOutDirPath, 'flpSandbox.html'))) {
|
|
225
|
+
const hashFromFlpSandbox = readHashFromFlpSandbox(join('test', 'flpSandbox.html'), await getWebappPath(writeContext.basePath), writeContext.editor);
|
|
226
|
+
if (hashFromFlpSandbox) {
|
|
227
|
+
htmlTarget = `test/flpSandbox.html#${hashFromFlpSandbox}`;
|
|
122
228
|
}
|
|
123
229
|
}
|
|
124
|
-
return {
|
|
230
|
+
return {
|
|
231
|
+
...writeContext,
|
|
232
|
+
hasPreexistingTests: false,
|
|
233
|
+
config: { ...writeContext.config, htmlTarget }
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Checks for incompatible test setup — the integration folder exists but no own JourneyRunner.js / .ts file is present.
|
|
238
|
+
*
|
|
239
|
+
* @param testOutDirPath - path to the test output directory (`.../webapp/test`)
|
|
240
|
+
* @returns true if the test setup is incompatible, false otherwise
|
|
241
|
+
*/
|
|
242
|
+
function hasIncompatibleTestSetup(testOutDirPath) {
|
|
243
|
+
return !hasJourneyRunnerFile(testOutDirPath);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Checks whether the existing test setup contains its own JourneyRunner.js or JourneyRunner.ts file.
|
|
247
|
+
*
|
|
248
|
+
* @param testOutDirPath - path to the test output directory (`.../webapp/test`)
|
|
249
|
+
* @returns true if the JourneyRunner.js or JourneyRunner.ts file exists, false otherwise
|
|
250
|
+
*/
|
|
251
|
+
function hasJourneyRunnerFile(testOutDirPath) {
|
|
252
|
+
const pagesDir = join(testOutDirPath, 'integration', 'pages');
|
|
253
|
+
return existsSync(join(pagesDir, 'JourneyRunner.js')) || existsSync(join(pagesDir, 'JourneyRunner.ts'));
|
|
125
254
|
}
|
|
126
255
|
/**
|
|
127
256
|
* Checks whether a script with the given name exists in the package.json.
|
|
@@ -217,7 +346,8 @@ function createPageConfig(manifest, targetKey, forcedAppID) {
|
|
|
217
346
|
targetKey,
|
|
218
347
|
componentID: target.id,
|
|
219
348
|
template: SupportedPageTypes[target.name],
|
|
220
|
-
isStartup: false
|
|
349
|
+
isStartup: false,
|
|
350
|
+
fileName: targetKey + '.gen'
|
|
221
351
|
};
|
|
222
352
|
if (target.options.settings.contextPath) {
|
|
223
353
|
pageConfig.contextPath = target.options.settings.contextPath;
|
|
@@ -248,7 +378,8 @@ function createConfig(manifest, options, hideFilterBar) {
|
|
|
248
378
|
pages: [],
|
|
249
379
|
opaJourneyFileName: options.scriptName ?? 'FirstJourney',
|
|
250
380
|
htmlTarget: options.htmlTarget ?? 'index.html',
|
|
251
|
-
hideFilterBar
|
|
381
|
+
hideFilterBar,
|
|
382
|
+
useVirtualPreviewEndpoints: options.useVirtualPreviewEndpoints ?? false
|
|
252
383
|
};
|
|
253
384
|
// Identify startup targets from the routes
|
|
254
385
|
const appRoutes = (manifest['sap.ui5']?.routing?.routes ?? []);
|
|
@@ -319,32 +450,43 @@ function findLROP(pages, manifest) {
|
|
|
319
450
|
return { pageLR, pageOP };
|
|
320
451
|
}
|
|
321
452
|
/**
|
|
322
|
-
* Writes common test files
|
|
453
|
+
* Writes the common test files for the Fiori elements app.
|
|
323
454
|
*
|
|
324
455
|
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
325
|
-
* @param rootCommonTemplateDirPath - template root directory for common files
|
|
326
|
-
* @param useVirtualPreviewEndpoints - when true, testsuite harness files are served virtually; skip writing them to disk
|
|
327
456
|
*/
|
|
328
|
-
function
|
|
329
|
-
const { config, rootV4TemplateDirPath, testOutDirPath, editor, journeyParams, dotFileExtension } = writeContext;
|
|
457
|
+
function writeTestsuiteFiles(writeContext) {
|
|
330
458
|
// Common test files (testsuite served virtually when useVirtualPreviewEndpoints is enabled)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
{ appId: config.appID }, undefined, {
|
|
335
|
-
globOptions: { dot: true }
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
config.pages.forEach((page) => {
|
|
339
|
-
writePageObject(page, rootV4TemplateDirPath, testOutDirPath, editor, dotFileExtension);
|
|
340
|
-
});
|
|
341
|
-
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', `FirstJourney${dotFileExtension}`), join(testOutDirPath, 'integration', `${config.opaJourneyFileName}${dotFileExtension}`), { ...journeyParams, appPath: config.appPath }, undefined, {
|
|
459
|
+
writeContext.editor.copyTpl(join(writeContext.rootCommonTemplateDirPath), writeContext.testOutDirPath,
|
|
460
|
+
// unit tests are not added for Fiori elements app
|
|
461
|
+
{ appId: writeContext.config.appID }, undefined, {
|
|
342
462
|
globOptions: { dot: true }
|
|
343
463
|
});
|
|
344
|
-
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Writes common test files, page objects, and the first journey file.
|
|
467
|
+
*
|
|
468
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
469
|
+
* @returns an array of the written page objects with their targetKey and appPath
|
|
470
|
+
*/
|
|
471
|
+
function writePageFiles(writeContext) {
|
|
472
|
+
const { config, rootV4TemplateDirPath, testOutDirPath, editor } = writeContext;
|
|
473
|
+
const writtenPages = [];
|
|
474
|
+
config.pages.forEach((page) => {
|
|
475
|
+
writtenPages.push(writePageObject(page, rootV4TemplateDirPath, testOutDirPath, editor, writeContext.dotFileExtension));
|
|
476
|
+
});
|
|
477
|
+
return writtenPages;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Writes the JourneyRunner file.
|
|
481
|
+
*
|
|
482
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
483
|
+
*/
|
|
484
|
+
function writeJourneyRunner(writeContext) {
|
|
485
|
+
const { config, rootV4TemplateDirPath, testOutDirPath, editor, dotFileExtension, modifiedFiles } = writeContext;
|
|
345
486
|
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', 'pages', `JourneyRunner${dotFileExtension}`), join(testOutDirPath, 'integration', 'pages', `JourneyRunner${dotFileExtension}`), config, undefined, {
|
|
346
487
|
globOptions: { dot: true }
|
|
347
488
|
});
|
|
489
|
+
modifiedFiles.push(`integration/pages/JourneyRunner${dotFileExtension}`);
|
|
348
490
|
}
|
|
349
491
|
/**
|
|
350
492
|
* Writes the OpaJourneyTypes.d.ts type definition file used by generated TypeScript OPA tests.
|
|
@@ -352,89 +494,43 @@ function writeCommonAndPageFiles(writeContext, rootCommonTemplateDirPath, useVir
|
|
|
352
494
|
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
353
495
|
*/
|
|
354
496
|
function writeOpaJourneyTypes(writeContext) {
|
|
355
|
-
const { config, rootV4TemplateDirPath, testOutDirPath, editor } = writeContext;
|
|
497
|
+
const { config, rootV4TemplateDirPath, testOutDirPath, editor, modifiedFiles } = writeContext;
|
|
356
498
|
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', 'types', 'OpaJourneyTypes.d.ts'), join(testOutDirPath, 'integration', 'types', 'OpaJourneyTypes.d.ts'), config, undefined, {
|
|
357
499
|
globOptions: { dot: true }
|
|
358
500
|
});
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Checks whether a page object file already exists for the given feature name.
|
|
362
|
-
* Both `.ts` and `.js` extensions are checked to avoid creating duplicate page objects
|
|
363
|
-
* when regenerating in a different language than the existing tests use.
|
|
364
|
-
* If neither exists, finds the matching page config and writes the file.
|
|
365
|
-
*
|
|
366
|
-
* @param featureName - the feature/page name (equals the manifest targetKey)
|
|
367
|
-
* @param config - the OPA config containing all page configurations
|
|
368
|
-
* @param rootV4TemplateDirPath - template root directory for v4 templates
|
|
369
|
-
* @param testOutDirPath - output test directory (.../webapp/test)
|
|
370
|
-
* @param editor - a reference to a mem-fs editor
|
|
371
|
-
* @param dotFileExtension - file extension ('.ts' or '.js')
|
|
372
|
-
* @returns JourneyRunnerPage if the page was newly created, undefined otherwise
|
|
373
|
-
*/
|
|
374
|
-
function ensurePageExists(featureName, config, rootV4TemplateDirPath, testOutDirPath, editor, dotFileExtension) {
|
|
375
|
-
const pagesDir = join(testOutDirPath, 'integration', 'pages');
|
|
376
|
-
if (editor.exists(join(pagesDir, `${featureName}${DotFileExtension.TS}`)) ||
|
|
377
|
-
editor.exists(join(pagesDir, `${featureName}${DotFileExtension.JS}`))) {
|
|
378
|
-
return undefined;
|
|
379
|
-
}
|
|
380
|
-
const pageConfig = config.pages.find((p) => p.targetKey === featureName);
|
|
381
|
-
if (pageConfig) {
|
|
382
|
-
writePageObject(pageConfig, rootV4TemplateDirPath, testOutDirPath, editor, dotFileExtension);
|
|
383
|
-
return {
|
|
384
|
-
targetKey: featureName,
|
|
385
|
-
appPath: config.appPath,
|
|
386
|
-
template: pageConfig.template,
|
|
387
|
-
appID: config.appID,
|
|
388
|
-
componentID: pageConfig.componentID,
|
|
389
|
-
entitySet: pageConfig.entitySet,
|
|
390
|
-
contextPath: pageConfig.contextPath
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
return undefined;
|
|
501
|
+
modifiedFiles.push('integration/types/OpaJourneyTypes.d.ts');
|
|
394
502
|
}
|
|
395
503
|
/**
|
|
396
504
|
* Writes journey files for list report, object pages and FPM pages.
|
|
397
505
|
*
|
|
398
506
|
* @param appFeatures - object containing feature data for list report, object pages, and FPM
|
|
399
507
|
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
400
|
-
* @
|
|
401
|
-
* @param hasJourneyRunner - whether a JourneyRunner already exists (standalone upgrade path)
|
|
402
|
-
* @param virtualOPA5Configured - whether virtual OPA5 is configured
|
|
508
|
+
* @returns an array of feature names for which journey files were generated
|
|
403
509
|
*/
|
|
404
|
-
function writeJourneyFiles(appFeatures, writeContext
|
|
510
|
+
function writeJourneyFiles(appFeatures, writeContext) {
|
|
405
511
|
const { config, rootV4TemplateDirPath, testOutDirPath, editor, journeyParams, dotFileExtension } = writeContext;
|
|
406
|
-
const
|
|
407
|
-
const newPages = [];
|
|
512
|
+
const generatedJourneys = [];
|
|
408
513
|
if (appFeatures.listReport?.name) {
|
|
409
|
-
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', `ListReportJourney${dotFileExtension}`), join(testOutDirPath, 'integration', `${appFeatures.listReport.name}Journey${dotFileExtension}`), {
|
|
514
|
+
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', `ListReportJourney${dotFileExtension}`), join(testOutDirPath, 'integration', `${appFeatures.listReport.name}Journey.gen${dotFileExtension}`), {
|
|
410
515
|
...journeyParams,
|
|
411
516
|
...appFeatures.listReport,
|
|
412
517
|
appPath: config.appPath
|
|
413
518
|
}, undefined, {
|
|
414
519
|
globOptions: { dot: true }
|
|
415
520
|
});
|
|
416
|
-
|
|
417
|
-
const lrPage = ensurePageExists(appFeatures.listReport.name, config, rootV4TemplateDirPath, testOutDirPath, editor, dotFileExtension);
|
|
418
|
-
if (lrPage) {
|
|
419
|
-
newPages.push(lrPage);
|
|
420
|
-
}
|
|
521
|
+
generatedJourneys.push(appFeatures.listReport.name);
|
|
421
522
|
}
|
|
422
523
|
if (appFeatures.objectPages && appFeatures.objectPages.length > 0) {
|
|
423
524
|
appFeatures.objectPages.forEach((objectPage) => {
|
|
424
525
|
if (objectPage.name) {
|
|
425
|
-
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', `ObjectPageJourney${dotFileExtension}`), join(testOutDirPath, 'integration', `${objectPage.name}Journey${dotFileExtension}`), {
|
|
526
|
+
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', `ObjectPageJourney${dotFileExtension}`), join(testOutDirPath, 'integration', `${objectPage.name}Journey.gen${dotFileExtension}`), {
|
|
426
527
|
...journeyParams,
|
|
427
528
|
...objectPage,
|
|
428
|
-
isStandalone,
|
|
429
529
|
appPath: config.appPath
|
|
430
530
|
}, undefined, {
|
|
431
531
|
globOptions: { dot: true }
|
|
432
532
|
});
|
|
433
|
-
|
|
434
|
-
const opPage = ensurePageExists(objectPage.name, config, rootV4TemplateDirPath, testOutDirPath, editor, dotFileExtension);
|
|
435
|
-
if (opPage) {
|
|
436
|
-
newPages.push(opPage);
|
|
437
|
-
}
|
|
533
|
+
generatedJourneys.push(objectPage.name);
|
|
438
534
|
}
|
|
439
535
|
});
|
|
440
536
|
}
|
|
@@ -446,33 +542,142 @@ function writeJourneyFiles(appFeatures, writeContext, isStandalone, hasJourneyRu
|
|
|
446
542
|
// an LR-OP-FPM mix with `enableTypeScript` would crash in `writePageObject`
|
|
447
543
|
// when trying to load the missing `FPM.ts` template.
|
|
448
544
|
// Future work: add FPM.ts/FPMJourney.ts templates and switch to `dotFileExtension`.
|
|
449
|
-
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', 'FPMJourney.js'), join(testOutDirPath, 'integration', `${appFeatures.fpm.name}Journey.js`), {
|
|
545
|
+
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', 'FPMJourney.js'), join(testOutDirPath, 'integration', `${appFeatures.fpm.name}Journey.gen.js`), {
|
|
450
546
|
...journeyParams,
|
|
451
547
|
...appFeatures.fpm
|
|
452
548
|
}, undefined, {
|
|
453
549
|
globOptions: { dot: true }
|
|
454
550
|
});
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
551
|
+
generatedJourneys.push(appFeatures.fpm.name);
|
|
552
|
+
}
|
|
553
|
+
if (generatedJourneys.length === 0 && !writeContext.hasPreexistingTests) {
|
|
554
|
+
writeFallbackJourney(writeContext);
|
|
555
|
+
}
|
|
556
|
+
return generatedJourneys;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Writes the fallback `FirstJourney.js` starter file when no dynamically generated journeys
|
|
560
|
+
* were produced.
|
|
561
|
+
*
|
|
562
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
563
|
+
*/
|
|
564
|
+
function writeFallbackJourney(writeContext) {
|
|
565
|
+
const { config, rootV4TemplateDirPath, testOutDirPath, editor, journeyParams, dotFileExtension } = writeContext;
|
|
566
|
+
editor.copyTpl(join(rootV4TemplateDirPath, 'integration', `FirstJourney${dotFileExtension}`), join(testOutDirPath, 'integration', `${config.opaJourneyFileName}${dotFileExtension}`), journeyParams, undefined, {
|
|
567
|
+
globOptions: { dot: true }
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Update the `OpaJourneyTypes.d.ts` type-definition file used by generated TypeScript OPA tests.
|
|
572
|
+
*
|
|
573
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
574
|
+
* @param generatedPages - pages whose journeys should be reflected in the type definitions
|
|
575
|
+
*/
|
|
576
|
+
function handleOPAJourneyTypes(writeContext, generatedPages) {
|
|
577
|
+
if (writeContext.incompatibleTestSetup) {
|
|
578
|
+
writeContext.log?.info(t('info.opaJourneyTypesNotUpdated'));
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (writeContext.hasPreexistingTests) {
|
|
582
|
+
const written = addJourneysToOpaJourneyTypes(generatedPages, writeContext.testOutDirPath, writeContext.editor, writeContext.log);
|
|
583
|
+
if (written) {
|
|
584
|
+
writeContext.modifiedFiles.push('integration/types/OpaJourneyTypes.d.ts');
|
|
459
585
|
}
|
|
460
586
|
}
|
|
461
|
-
|
|
462
|
-
|
|
587
|
+
else {
|
|
588
|
+
writeOpaJourneyTypes(writeContext);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Handles JourneyRunner File.
|
|
593
|
+
* If there is already a JourneyRunner file, it is updated with the generated pages, otherwise a new JourneyRunner file is written.
|
|
594
|
+
*
|
|
595
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
596
|
+
* @param generatedPages - an array of page objects that were generated, each containing a targetKey and appPath
|
|
597
|
+
*/
|
|
598
|
+
function handleJourneyRunner(writeContext, generatedPages) {
|
|
599
|
+
if (writeContext.incompatibleTestSetup) {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
else if (writeContext.hasPreexistingTests) {
|
|
603
|
+
updatePagesInJourneyRunner(writeContext, generatedPages);
|
|
463
604
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
605
|
+
else {
|
|
606
|
+
writeJourneyRunner(writeContext);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Ensures that there is a page object file for each generated journey and adds the pages to the JourneyRunner.js file if they were newly created.
|
|
611
|
+
*
|
|
612
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
613
|
+
* @param generatedPages - an array of page objects that were generated, each containing a targetKey and appPath
|
|
614
|
+
*/
|
|
615
|
+
function updatePagesInJourneyRunner(writeContext, generatedPages) {
|
|
616
|
+
const { testOutDirPath, editor, log, dotFileExtension, modifiedFiles } = writeContext;
|
|
617
|
+
if (generatedPages.length > 0) {
|
|
618
|
+
const written = addPagesToJourneyRunner(generatedPages, testOutDirPath, editor, dotFileExtension, log);
|
|
619
|
+
if (written) {
|
|
620
|
+
modifiedFiles.push(`integration/pages/JourneyRunner${dotFileExtension}`);
|
|
469
621
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Configures `ui5-mock.yaml` to serve the OPA harness virtually so the qunit/testsuite files
|
|
626
|
+
* do not need to be written to disk. Used when virtual OPA5 is configured for the app.
|
|
627
|
+
*
|
|
628
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
629
|
+
*/
|
|
630
|
+
async function addVirtualOpa5Config(writeContext) {
|
|
631
|
+
await addVirtualTestConfig(writeContext.basePath, [{ framework: 'OPA5', path: '/test/integration/opaTests.qunit.html' }, { framework: 'Testsuite' }], writeContext.editor);
|
|
632
|
+
writeContext.modifiedFiles.push('ui5-mock.yaml');
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Handles the opaTests.qunit.html, opaTests.qunit.js, and testsuite.qunit.* files for non-virtual setups.
|
|
636
|
+
* For virtual OPA5 setups, call `addVirtualOpa5Config` instead.
|
|
637
|
+
*
|
|
638
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
639
|
+
* @param generatedJourneys - an array of feature names for which journey files were generated
|
|
640
|
+
*/
|
|
641
|
+
function handleOpaTestsStartupFiles(writeContext, generatedJourneys = []) {
|
|
642
|
+
if (writeContext.incompatibleTestSetup) {
|
|
643
|
+
writeContext.log?.info(t('info.incompatibleTestSetupSkipped'));
|
|
644
|
+
}
|
|
645
|
+
else if (writeContext.hasPreexistingTests) {
|
|
646
|
+
// update existing opaTests.qunit.js only in a compatible setup, as long as virtual OPA5 is not used
|
|
647
|
+
const written = updateReferencesInOpaTestsStartupFiles(writeContext, generatedJourneys);
|
|
648
|
+
if (written) {
|
|
649
|
+
writeContext.modifiedFiles.push('integration/opaTests.qunit.js');
|
|
474
650
|
}
|
|
475
651
|
}
|
|
652
|
+
else {
|
|
653
|
+
// new app or missing integration folder: write all files
|
|
654
|
+
writeOpaTestsStartupFiles(writeContext, generatedJourneys);
|
|
655
|
+
writeTestsuiteFiles(writeContext);
|
|
656
|
+
writeContext.modifiedFiles.push('integration/opaTests.qunit.html', 'integration/opaTests.qunit.js', 'testsuite.qunit.html', 'testsuite.qunit.js');
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Writes the opaTests.qunit.html and opaTests.qunit.js files to the test folder. The files are copied from the common templates, which are used for both new app generation and standalone generation in case of an incompatible existing test setup or when virtual OPA5 is used.
|
|
661
|
+
*
|
|
662
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
663
|
+
* @param generatedJourneys - an array of feature names for which journey files were generated, used for conditionally adding the test configuration for the virtual OPA5 setup
|
|
664
|
+
*/
|
|
665
|
+
function writeOpaTestsStartupFiles(writeContext, generatedJourneys = []) {
|
|
666
|
+
writeContext.editor.copyTpl(join(writeContext.rootV4TemplateDirPath, 'integration', 'opaTests.*.*'), join(writeContext.testOutDirPath, 'integration'), { ...writeContext.config, generatedJourneys }, undefined, {
|
|
667
|
+
globOptions: { dot: true }
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Updates the references in the opaTests.qunit.js file to the generated journey files and adds the test configuration for virtual OPA5 in case it's used.
|
|
672
|
+
*
|
|
673
|
+
* @param writeContext - shared write context (config, paths, editor, journey params)
|
|
674
|
+
* @param generatedJourneys - an array of feature names for which journey files were generated, used for conditionally adding the test configuration for the virtual OPA5 setup
|
|
675
|
+
* @returns true if the file was written, false otherwise
|
|
676
|
+
*/
|
|
677
|
+
function updateReferencesInOpaTestsStartupFiles(writeContext, generatedJourneys = []) {
|
|
678
|
+
return addPathsToQUnitJs(generatedJourneys.map((page) => {
|
|
679
|
+
return `${writeContext.config.appPath}/test/integration/${page}Journey.gen`;
|
|
680
|
+
}), writeContext.testOutDirPath, writeContext.editor, writeContext.log);
|
|
476
681
|
}
|
|
477
682
|
/**
|
|
478
683
|
* Writes a page object in a mem-fs-editor.
|
|
@@ -482,12 +687,24 @@ function writeJourneyFiles(appFeatures, writeContext, isStandalone, hasJourneyRu
|
|
|
482
687
|
* @param testOutDirPath - output test directory (.../webapp/test)
|
|
483
688
|
* @param fs - a reference to a mem-fs editor
|
|
484
689
|
* @param dotFileExtension - file extension ('.ts' or '.js')
|
|
690
|
+
* @returns path to the written page object
|
|
485
691
|
*/
|
|
486
692
|
function writePageObject(pageConfig, rootTemplateDirPath, testOutDirPath, fs, dotFileExtension) {
|
|
487
693
|
// FPM has no .ts template; force .js regardless of the configured extension
|
|
488
694
|
const ext = pageConfig.template === 'FPM' ? DotFileExtension.JS : dotFileExtension;
|
|
489
|
-
fs.copyTpl(join(rootTemplateDirPath, 'integration', 'pages', `${pageConfig.template}${ext}`), join(testOutDirPath, 'integration', 'pages', `${pageConfig.targetKey}${ext}`), pageConfig, undefined, {
|
|
695
|
+
fs.copyTpl(join(rootTemplateDirPath, 'integration', 'pages', `${pageConfig.template}${ext}`), join(testOutDirPath, 'integration', 'pages', `${pageConfig.targetKey}.gen${ext}`), pageConfig, undefined, {
|
|
490
696
|
globOptions: { dot: true }
|
|
491
697
|
});
|
|
698
|
+
return {
|
|
699
|
+
targetKey: pageConfig.targetKey,
|
|
700
|
+
appPath: pageConfig.appPath,
|
|
701
|
+
fileName: `${pageConfig.targetKey}.gen`,
|
|
702
|
+
dotFileExtension: ext,
|
|
703
|
+
template: pageConfig.template,
|
|
704
|
+
appID: pageConfig.appID,
|
|
705
|
+
componentID: pageConfig.componentID,
|
|
706
|
+
entitySet: pageConfig.entitySet,
|
|
707
|
+
contextPath: pageConfig.contextPath
|
|
708
|
+
};
|
|
492
709
|
}
|
|
493
710
|
//# sourceMappingURL=fiori-elements-opa-writer.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { generateOPAFiles } from './fiori-elements-opa-writer.js';
|
|
2
2
|
export { generateFreestyleOPAFiles } from './fiori-freestyle-opa-writer.js';
|
|
3
|
-
export { addVirtualTestConfig } from './utils/
|
|
3
|
+
export { addVirtualTestConfig } from './utils/virtualOpaUtils.js';
|
|
4
4
|
export type { OPAGenerationOptions } from './types.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { generateOPAFiles } from './fiori-elements-opa-writer.js';
|
|
2
2
|
export { generateFreestyleOPAFiles } from './fiori-freestyle-opa-writer.js';
|
|
3
|
-
export { addVirtualTestConfig } from './utils/
|
|
3
|
+
export { addVirtualTestConfig } from './utils/virtualOpaUtils.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|