@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
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { t } from '../i18n.js';
|
|
3
|
+
import { MAX_FILE_CONTENT_LENGTH, escapeRegex, findBracedBlock, insertAfterLastImport } from './fileWritingUtils.js';
|
|
4
|
+
/** Relative path from the test output directory to OpaJourneyTypes.d.ts */
|
|
5
|
+
const OPA_JOURNEY_TYPES_FILE = join('integration', 'types', 'OpaJourneyTypes.d.ts');
|
|
6
|
+
/** Frameworks the splicer knows how to render entries for. */
|
|
7
|
+
const SUPPORTED_FRAMEWORKS = new Set(['ListReport', 'ObjectPage']);
|
|
8
|
+
/**
|
|
9
|
+
* Filter `pages` down to those whose generator-owned custom-actions/assertions import
|
|
10
|
+
* is not yet present (matched against `../pages/<fileName>` with the `.gen` suffix).
|
|
11
|
+
*
|
|
12
|
+
* @param fileContent - the existing OpaJourneyTypes.d.ts content
|
|
13
|
+
* @param pages - candidate pages to splice in
|
|
14
|
+
* @returns the subset of pages that need to be added
|
|
15
|
+
*/
|
|
16
|
+
function findPagesToAdd(fileContent, pages) {
|
|
17
|
+
return pages.filter((page) => {
|
|
18
|
+
const importPattern = new RegExp(String.raw `from\s+"\.\./pages/${escapeRegex(page.fileName)}"`);
|
|
19
|
+
return !importPattern.test(fileContent);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build the framework-import lines (ListReport / ObjectPage / TemplatePage) that need to be
|
|
24
|
+
* added to the file, skipping any already imported.
|
|
25
|
+
*
|
|
26
|
+
* @param fileContent - the existing OpaJourneyTypes.d.ts content
|
|
27
|
+
* @param pages - the new pages being added
|
|
28
|
+
* @returns the list of framework-import lines to insert
|
|
29
|
+
*/
|
|
30
|
+
function buildMissingFrameworkImports(fileContent, pages) {
|
|
31
|
+
const lines = [];
|
|
32
|
+
const templates = new Set(pages.map((page) => page.template).filter((template) => Boolean(template)));
|
|
33
|
+
if (templates.has('ListReport') && !fileContent.includes('from "sap/fe/test/ListReport"')) {
|
|
34
|
+
lines.push(`import type { actions as ListReportActions, assertions as ListReportAssertions } from "sap/fe/test/ListReport";`);
|
|
35
|
+
}
|
|
36
|
+
if (templates.has('ObjectPage') && !fileContent.includes('from "sap/fe/test/ObjectPage"')) {
|
|
37
|
+
lines.push(`import type { actions as ObjectPageActions, assertions as ObjectPageAssertions } from "sap/fe/test/ObjectPage";`);
|
|
38
|
+
}
|
|
39
|
+
if ((templates.has('ListReport') || templates.has('ObjectPage')) &&
|
|
40
|
+
!fileContent.includes('from "sap/fe/test/TemplatePage"')) {
|
|
41
|
+
lines.push(`import type { actions as TemplatePageActions, assertions as TemplatePageAssertions } from "sap/fe/test/TemplatePage";`);
|
|
42
|
+
}
|
|
43
|
+
return lines;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build the per-page import line for a page's generator-owned custom actions/assertions.
|
|
47
|
+
*
|
|
48
|
+
* @param page - the page to render
|
|
49
|
+
* @returns the import line
|
|
50
|
+
*/
|
|
51
|
+
function buildPageCustomImportLine(page) {
|
|
52
|
+
return (`import type { actions as ${page.targetKey}GeneratedCustomActions, ` +
|
|
53
|
+
`assertions as ${page.targetKey}GeneratedCustomAssertions } from "../pages/${page.fileName}";`);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build the new entry to insert into the `When`/`Then` type union for a single page.
|
|
57
|
+
*
|
|
58
|
+
* @param page - the page to render
|
|
59
|
+
* @param mode - whether to render the entry for the `When` (actions) or `Then` (assertions) union
|
|
60
|
+
* @param indent - leading whitespace for the new line
|
|
61
|
+
* @returns the source line, or undefined if the page's framework is not supported
|
|
62
|
+
*/
|
|
63
|
+
function buildPageUnionEntry(page, mode, indent) {
|
|
64
|
+
if (!page.template || !SUPPORTED_FRAMEWORKS.has(page.template)) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
const frameworkSuffix = mode === 'actions' ? 'Actions' : 'Assertions';
|
|
68
|
+
const customSuffix = mode === 'actions' ? 'CustomActions' : 'CustomAssertions';
|
|
69
|
+
return (`${indent}onThe${page.targetKey}Generated: Opa5 & ${page.template}${frameworkSuffix} & TemplatePage${frameworkSuffix} & ` +
|
|
70
|
+
`typeof ${page.targetKey}Generated${customSuffix};`);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Insert new `onThe<targetKey>Generated` member lines into the named exported type union,
|
|
74
|
+
* preserving the indentation of the first existing member.
|
|
75
|
+
*
|
|
76
|
+
* @param content - the file content
|
|
77
|
+
* @param exportName - the type union to update (`When` or `Then`)
|
|
78
|
+
* @param newEntries - the new union member lines to insert
|
|
79
|
+
* @returns the updated content (or unchanged if the type union or its closing brace can't be found)
|
|
80
|
+
*/
|
|
81
|
+
function insertIntoTypeUnion(content, exportName, newEntries) {
|
|
82
|
+
if (newEntries.length === 0) {
|
|
83
|
+
return content;
|
|
84
|
+
}
|
|
85
|
+
const block = findBracedBlock(content, new RegExp(String.raw `export\s+type\s+${exportName}\b[^=]*=\s*[^{]*\{`));
|
|
86
|
+
if (!block) {
|
|
87
|
+
return content;
|
|
88
|
+
}
|
|
89
|
+
const { openBraceIdx, closeBraceIdx } = block;
|
|
90
|
+
const body = content.slice(openBraceIdx + 1, closeBraceIdx);
|
|
91
|
+
const indentMatch = /^([ \t]+)\S/m.exec(body);
|
|
92
|
+
const indent = indentMatch ? indentMatch[1] : ' ';
|
|
93
|
+
const insertion = newEntries.map((line) => line.replace(/^\s*/, indent)).join('\n');
|
|
94
|
+
// Insert before the closing brace, with a leading newline so the new lines sit on their own.
|
|
95
|
+
const head = content.slice(0, closeBraceIdx);
|
|
96
|
+
const tail = content.slice(closeBraceIdx);
|
|
97
|
+
return `${head.trimEnd()}\n${insertion}\n${tail}`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Splice new journey entries into an existing `OpaJourneyTypes.d.ts`: framework imports,
|
|
101
|
+
* per-page custom actions/assertions imports, and `onThe<targetKey>Generated` members in
|
|
102
|
+
* the `When` and `Then` unions. Pages already imported are skipped; all other content is preserved.
|
|
103
|
+
*
|
|
104
|
+
* @param fileContent - the full content of the OpaJourneyTypes.d.ts file
|
|
105
|
+
* @param pages - pages to add
|
|
106
|
+
* @returns the updated file content, or the original content unchanged if nothing was added
|
|
107
|
+
*/
|
|
108
|
+
export function spliceJourneysIntoOpaJourneyTypes(fileContent, pages) {
|
|
109
|
+
if (fileContent.length > MAX_FILE_CONTENT_LENGTH) {
|
|
110
|
+
return fileContent;
|
|
111
|
+
}
|
|
112
|
+
const toAdd = findPagesToAdd(fileContent, pages);
|
|
113
|
+
if (toAdd.length === 0) {
|
|
114
|
+
return fileContent;
|
|
115
|
+
}
|
|
116
|
+
const newImportLines = [
|
|
117
|
+
...buildMissingFrameworkImports(fileContent, toAdd),
|
|
118
|
+
...toAdd
|
|
119
|
+
.filter((page) => page.template && SUPPORTED_FRAMEWORKS.has(page.template))
|
|
120
|
+
.map((page) => buildPageCustomImportLine(page))
|
|
121
|
+
];
|
|
122
|
+
const whenEntries = toAdd
|
|
123
|
+
.map((page) => buildPageUnionEntry(page, 'actions', ''))
|
|
124
|
+
.filter((entry) => entry !== undefined);
|
|
125
|
+
const thenEntries = toAdd
|
|
126
|
+
.map((page) => buildPageUnionEntry(page, 'assertions', ''))
|
|
127
|
+
.filter((entry) => entry !== undefined);
|
|
128
|
+
let result = insertAfterLastImport(fileContent, newImportLines);
|
|
129
|
+
result = insertIntoTypeUnion(result, 'When', whenEntries);
|
|
130
|
+
result = insertIntoTypeUnion(result, 'Then', thenEntries);
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Read `OpaJourneyTypes.d.ts` from the project, splice entries for new pages, and write
|
|
135
|
+
* the result back. Pages already present are skipped. If the file does not exist or
|
|
136
|
+
* cannot be read, logs a warning and returns without writing.
|
|
137
|
+
*
|
|
138
|
+
* @param pages - pages whose journeys should be reflected in OpaJourneyTypes.d.ts
|
|
139
|
+
* @param testOutDirPath - path to the test output directory (`.../webapp/test`)
|
|
140
|
+
* @param fs - mem-fs-editor instance used to read and write the file
|
|
141
|
+
* @param log - optional logger instance used to surface warnings when the file
|
|
142
|
+
* cannot be read or updated
|
|
143
|
+
* @returns true if the file was written, false otherwise
|
|
144
|
+
*/
|
|
145
|
+
export function addJourneysToOpaJourneyTypes(pages, testOutDirPath, fs, log) {
|
|
146
|
+
if (pages.length === 0) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
const filePath = join(testOutDirPath, OPA_JOURNEY_TYPES_FILE);
|
|
151
|
+
const content = fs.read(filePath);
|
|
152
|
+
if (content.length > MAX_FILE_CONTENT_LENGTH) {
|
|
153
|
+
log?.warn(t('warn.cannotUpdateOpaJourneyTypes'));
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
const updated = spliceJourneysIntoOpaJourneyTypes(content, pages);
|
|
157
|
+
if (updated !== content) {
|
|
158
|
+
fs.write(filePath, updated);
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
log?.warn(t('warn.cannotUpdateOpaJourneyTypes'));
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=opaJourneyTypesUtils.js.map
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* all other content (formatting, comments, whitespace) is preserved exactly.
|
|
5
5
|
*/
|
|
6
6
|
import type { Editor } from 'mem-fs-editor';
|
|
7
|
-
import {
|
|
8
|
-
import type { TestConfig as PreviewMiddlewareTestConfig } from '@sap-ux/preview-middleware';
|
|
7
|
+
import type { Logger } from '@sap-ux/logger';
|
|
9
8
|
/**
|
|
10
9
|
* Splices new module paths into the sap.ui.require array of the content string.
|
|
11
10
|
* Entries that are already present are skipped. All other content is preserved exactly.
|
|
@@ -19,7 +18,7 @@ import type { TestConfig as PreviewMiddlewareTestConfig } from '@sap-ux/preview-
|
|
|
19
18
|
*/
|
|
20
19
|
export declare function spliceModulesIntoQUnitContent(fileContent: string, moduleNames: string[]): string;
|
|
21
20
|
/**
|
|
22
|
-
* Reads opaTests.qunit.js from webapp/test/
|
|
21
|
+
* Reads opaTests.qunit.js from webapp/test/integration and extracts the html
|
|
23
22
|
* launch target (path, query parameters, and hash fragment) from the launchUrl
|
|
24
23
|
* line, e.g. `test/flpSandbox.html?sap-ui-xx-viewCache=false#myApp-tile`.
|
|
25
24
|
* Returns undefined if the file cannot be read or the pattern is not found.
|
|
@@ -29,14 +28,6 @@ export declare function spliceModulesIntoQUnitContent(fileContent: string, modul
|
|
|
29
28
|
* @returns the html target string, or undefined if not found
|
|
30
29
|
*/
|
|
31
30
|
export declare function readHtmlTargetFromQUnitJs(testPath: string, fs: Editor): string | undefined;
|
|
32
|
-
/**
|
|
33
|
-
* Appends `/webapp/test/integration_old` to the project's `.gitignore`.
|
|
34
|
-
* Creates the file if it does not exist. Skips if the entry is already present.
|
|
35
|
-
*
|
|
36
|
-
* @param basePath - project root (contains .gitignore)
|
|
37
|
-
* @param fs - mem-fs-editor instance used to read and write the file
|
|
38
|
-
*/
|
|
39
|
-
export declare function addIntegrationOldToGitignore(basePath: string, fs: Editor): Promise<void>;
|
|
40
31
|
/**
|
|
41
32
|
* Reads opaTests.qunit.js from the project, adds module paths to the
|
|
42
33
|
* sap.ui.require array, and writes the updated content back.
|
|
@@ -46,86 +37,9 @@ export declare function addIntegrationOldToGitignore(basePath: string, fs: Edito
|
|
|
46
37
|
* @param filePaths - module paths to add (e.g. ["myApp/test/integration/SomeJourney"])
|
|
47
38
|
* @param projectPath - path to the test output directory (`.../webapp/test`)
|
|
48
39
|
* @param fs - mem-fs-editor instance used to read and write the file
|
|
40
|
+
* @param log - optional logger instance used to surface warnings when the file
|
|
41
|
+
* cannot be read or updated
|
|
42
|
+
* @returns true if the file was written, false otherwise
|
|
49
43
|
*/
|
|
50
|
-
export declare function addPathsToQUnitJs(filePaths: string[], projectPath: string, fs: Editor):
|
|
51
|
-
/**
|
|
52
|
-
* Page entry to splice into an existing JourneyRunner.js / JourneyRunner.ts.
|
|
53
|
-
*/
|
|
54
|
-
export interface JourneyRunnerPage {
|
|
55
|
-
/** The page's targetKey, used as both the variable name and `onThe<targetKey>` key */
|
|
56
|
-
targetKey: string;
|
|
57
|
-
/** The app module path prefix (e.g. "project1/test/integration/pages") */
|
|
58
|
-
appPath: string;
|
|
59
|
-
/** The framework page template (`'ListReport'` or `'ObjectPage'`); used by the TS splicer to construct `new <FW>(definition, Custom<Page>)`. */
|
|
60
|
-
template?: string;
|
|
61
|
-
/** The app id (sap.app.id from the manifest); only needed by the TS splicer. */
|
|
62
|
-
appID?: string;
|
|
63
|
-
/** The component id (defined in the target section); only needed by the TS splicer. */
|
|
64
|
-
componentID?: string;
|
|
65
|
-
/** The entity set name (if the page uses an entitySet rather than a contextPath); only needed by the TS splicer. */
|
|
66
|
-
entitySet?: string;
|
|
67
|
-
/** The context path (if the page uses a contextPath rather than an entitySet); only needed by the TS splicer. */
|
|
68
|
-
contextPath?: string;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Splices new page entries into the three locations of an existing JourneyRunner.js:
|
|
72
|
-
* - the sap.ui.define dependency array
|
|
73
|
-
* - the function parameter list
|
|
74
|
-
* - the pages object literal
|
|
75
|
-
*
|
|
76
|
-
* Pages already present (detected by their module path in the define array) are skipped.
|
|
77
|
-
* All other content — formatting, comments, whitespace — is preserved exactly.
|
|
78
|
-
*
|
|
79
|
-
* Note: files exceeding MAX_FILE_CONTENT_LENGTH characters are returned unchanged to prevent
|
|
80
|
-
* ReDoS on crafted inputs. Valid generated files are well within this limit.
|
|
81
|
-
*
|
|
82
|
-
* @param fileContent - the full content of the JourneyRunner.js file
|
|
83
|
-
* @param pages - pages to add
|
|
84
|
-
* @returns the updated file content, or the original content unchanged if nothing was added
|
|
85
|
-
*/
|
|
86
|
-
export declare function splicePageIntoJourneyRunner(fileContent: string, pages: JourneyRunnerPage[]): string;
|
|
87
|
-
/**
|
|
88
|
-
* Splices new page entries into an existing TypeScript JourneyRunner.ts:
|
|
89
|
-
* - adds a default-import line after the last existing page import
|
|
90
|
-
* - adds an entry inside the `pages: { ... }` object literal
|
|
91
|
-
*
|
|
92
|
-
* Pages already present (detected by their import line) are skipped.
|
|
93
|
-
* All other content — formatting, comments, whitespace — is preserved exactly.
|
|
94
|
-
*
|
|
95
|
-
* Note: files exceeding MAX_FILE_CONTENT_LENGTH characters are returned unchanged to prevent
|
|
96
|
-
* ReDoS on crafted inputs. Valid generated files are well within this limit.
|
|
97
|
-
*
|
|
98
|
-
* @param fileContent - the full content of the JourneyRunner.ts file
|
|
99
|
-
* @param pages - pages to add
|
|
100
|
-
* @returns the updated file content, or the original content unchanged if nothing was added
|
|
101
|
-
*/
|
|
102
|
-
export declare function splicePageIntoJourneyRunnerTs(fileContent: string, pages: JourneyRunnerPage[]): string;
|
|
103
|
-
/**
|
|
104
|
-
* Reads JourneyRunner from the project, adds new page entries, and writes the updated
|
|
105
|
-
* content back. Pages already present are skipped. Both AMD (`.js`) and ES module
|
|
106
|
-
* (`.ts`) variants are supported and dispatched on `dotFileExtension`.
|
|
107
|
-
*
|
|
108
|
-
* @param pages - pages to add
|
|
109
|
-
* @param testOutDirPath - path to the test output directory (`.../webapp/test`)
|
|
110
|
-
* @param fs - mem-fs-editor instance used to read and write the file
|
|
111
|
-
* @param dotFileExtension - file extension of the JourneyRunner ('.ts' or '.js'); defaults to '.js'
|
|
112
|
-
*/
|
|
113
|
-
export declare function addPagesToJourneyRunner(pages: JourneyRunnerPage[], testOutDirPath: string, fs: Editor, dotFileExtension?: DotFileExtension): void;
|
|
114
|
-
/**
|
|
115
|
-
* Returns true if any UI5 yaml file in the project contains a `fiori-tools-preview`
|
|
116
|
-
* middleware whose `test` array includes an entry with `framework: OPA5`.
|
|
117
|
-
*
|
|
118
|
-
* @param basePath - project root directory
|
|
119
|
-
* @returns true when OPA5 is configured in a preview middleware, false otherwise
|
|
120
|
-
*/
|
|
121
|
-
export declare function hasVirtualOPA5(basePath: string): Promise<boolean>;
|
|
122
|
-
/**
|
|
123
|
-
* Updates the fiori-tools-preview middleware in ui5-mock.yaml to support virtual OPA test endpoints.
|
|
124
|
-
* Adds test framework entries to ui5-mock.yaml.
|
|
125
|
-
*
|
|
126
|
-
* @param basePath - the absolute target path of the application
|
|
127
|
-
* @param testFrameworks - the test framework entries to add to ui5-mock.yaml
|
|
128
|
-
* @param fs - the memfs editor instance
|
|
129
|
-
*/
|
|
130
|
-
export declare function addVirtualTestConfig(basePath: string, testFrameworks: PreviewMiddlewareTestConfig[], fs: Editor): Promise<void>;
|
|
44
|
+
export declare function addPathsToQUnitJs(filePaths: string[], projectPath: string, fs: Editor, log?: Logger): boolean;
|
|
131
45
|
//# sourceMappingURL=opaQUnitUtils.d.ts.map
|