@sap-ux/ui5-test-writer 0.9.8 → 0.9.11
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 +0 -15
- package/dist/fiori-elements-opa-writer.js +0 -29
- package/dist/types.d.ts +5 -1
- package/dist/utils/actionUtils.d.ts +19 -0
- package/dist/utils/actionUtils.js +41 -11
- package/dist/utils/listReportUtils.d.ts +54 -2
- package/dist/utils/listReportUtils.js +146 -29
- package/package.json +5 -5
- package/templates/v4/integration/ListReportJourney.js +26 -0
|
@@ -31,19 +31,4 @@ export declare function generateOPAFiles(basePath: string, opaConfig: {
|
|
|
31
31
|
* @returns the manifest object. An exception is thrown if the manifest cannot be read.
|
|
32
32
|
*/
|
|
33
33
|
export declare function readManifest(fs: Editor, basePath: string): Manifest;
|
|
34
|
-
/**
|
|
35
|
-
* Generate a page object file for a Fiori elements for OData V4 application.
|
|
36
|
-
* Note: this doesn't modify other existing files in the webapp/test folder.
|
|
37
|
-
*
|
|
38
|
-
* @param basePath - the absolute target path where the application will be generated
|
|
39
|
-
* @param pageObjectParameters - parameters for the page
|
|
40
|
-
* @param pageObjectParameters.targetKey - the key of the target in the manifest file corresponding to the page
|
|
41
|
-
* @param pageObjectParameters.appID - the appID. If not specified, will be read from the manifest in sap.app/id
|
|
42
|
-
* @param fs - an optional reference to a mem-fs editor
|
|
43
|
-
* @returns Reference to a mem-fs-editor
|
|
44
|
-
*/
|
|
45
|
-
export declare function generatePageObjectFile(basePath: string, pageObjectParameters: {
|
|
46
|
-
targetKey: string;
|
|
47
|
-
appID?: string;
|
|
48
|
-
}, fs?: Editor): Promise<Editor>;
|
|
49
34
|
//# sourceMappingURL=fiori-elements-opa-writer.d.ts.map
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateOPAFiles = generateOPAFiles;
|
|
4
4
|
exports.readManifest = readManifest;
|
|
5
|
-
exports.generatePageObjectFile = generatePageObjectFile;
|
|
6
5
|
const node_path_1 = require("node:path");
|
|
7
6
|
const node_fs_1 = require("node:fs");
|
|
8
7
|
const mem_fs_1 = require("mem-fs");
|
|
@@ -443,32 +442,4 @@ function writePageObject(pageConfig, rootTemplateDirPath, testOutDirPath, fs) {
|
|
|
443
442
|
globOptions: { dot: true }
|
|
444
443
|
});
|
|
445
444
|
}
|
|
446
|
-
/**
|
|
447
|
-
* Generate a page object file for a Fiori elements for OData V4 application.
|
|
448
|
-
* Note: this doesn't modify other existing files in the webapp/test folder.
|
|
449
|
-
*
|
|
450
|
-
* @param basePath - the absolute target path where the application will be generated
|
|
451
|
-
* @param pageObjectParameters - parameters for the page
|
|
452
|
-
* @param pageObjectParameters.targetKey - the key of the target in the manifest file corresponding to the page
|
|
453
|
-
* @param pageObjectParameters.appID - the appID. If not specified, will be read from the manifest in sap.app/id
|
|
454
|
-
* @param fs - an optional reference to a mem-fs editor
|
|
455
|
-
* @returns Reference to a mem-fs-editor
|
|
456
|
-
*/
|
|
457
|
-
async function generatePageObjectFile(basePath, pageObjectParameters, fs) {
|
|
458
|
-
const editor = fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
|
|
459
|
-
const manifest = readManifest(editor, basePath);
|
|
460
|
-
const { applicationType } = getAppTypeAndHideFilterBarFromManifest(manifest);
|
|
461
|
-
const pageConfig = createPageConfig(manifest, pageObjectParameters.targetKey, pageObjectParameters.appID);
|
|
462
|
-
if (pageConfig) {
|
|
463
|
-
const rootTemplateDirPath = (0, node_path_1.join)(__dirname, `../templates/${applicationType}`); // Only v4 is supported for the time being
|
|
464
|
-
const testOutDirPath = (0, node_path_1.join)(await (0, project_access_1.getWebappPath)(basePath), 'test');
|
|
465
|
-
writePageObject(pageConfig, rootTemplateDirPath, testOutDirPath, editor);
|
|
466
|
-
}
|
|
467
|
-
else {
|
|
468
|
-
throw new types_1.ValidationError((0, i18n_1.t)('error.cannotGeneratePageFile', {
|
|
469
|
-
targetKey: pageObjectParameters.targetKey
|
|
470
|
-
}));
|
|
471
|
-
}
|
|
472
|
-
return editor;
|
|
473
|
-
}
|
|
474
445
|
//# sourceMappingURL=fiori-elements-opa-writer.js.map
|
package/dist/types.d.ts
CHANGED
|
@@ -130,13 +130,17 @@ export type ListReportFeatures = {
|
|
|
130
130
|
};
|
|
131
131
|
deleteButton?: {
|
|
132
132
|
enabled?: boolean | string;
|
|
133
|
-
visible
|
|
133
|
+
visible?: boolean;
|
|
134
134
|
dynamicPath?: string;
|
|
135
135
|
};
|
|
136
136
|
filterBarItems?: string[];
|
|
137
137
|
tableColumns?: Record<string, Record<string, string | number | boolean>>;
|
|
138
138
|
toolBarActions?: ActionButtonState[];
|
|
139
139
|
isALP?: boolean;
|
|
140
|
+
semanticKey?: {
|
|
141
|
+
semanticKeyProperties?: string[];
|
|
142
|
+
missingFromFilterBar?: string[];
|
|
143
|
+
};
|
|
140
144
|
};
|
|
141
145
|
export interface ActionButtonState {
|
|
142
146
|
label: string;
|
|
@@ -95,6 +95,16 @@ export declare function analyzeDeleteRestrictions(restriction: DeleteRestriction
|
|
|
95
95
|
* @returns ButtonState indicating visibility and enabled state based on the Updatable value
|
|
96
96
|
*/
|
|
97
97
|
export declare function analyzeUpdateRestrictions(restriction: UpdateRestrictionsType | undefined): ButtonState;
|
|
98
|
+
/**
|
|
99
|
+
* Checks the visibility and enabled state of create and delete buttons for a given entity set
|
|
100
|
+
* by analyzing OData Capabilities annotations in the converted metadata.
|
|
101
|
+
*
|
|
102
|
+
* @param convertedMetadata The already-converted OData metadata
|
|
103
|
+
* @param entitySetName The name of the entity set to check
|
|
104
|
+
* @returns ButtonVisibilityResult containing the state of create and delete buttons
|
|
105
|
+
* @throws {Error} If entity set is not found
|
|
106
|
+
*/
|
|
107
|
+
export declare function checkButtonVisibilityFromMetadata(convertedMetadata: ConvertedMetadata, entitySetName: string): ButtonVisibilityResult;
|
|
98
108
|
/**
|
|
99
109
|
* Checks the visibility and enabled state of create and delete buttons for a given entity set
|
|
100
110
|
* by analyzing OData Capabilities annotations in the metadata.
|
|
@@ -115,6 +125,15 @@ export declare function checkButtonVisibility(metadataXml: string, entitySetName
|
|
|
115
125
|
* @throws {Error} If metadata cannot be parsed or entity set is not found
|
|
116
126
|
*/
|
|
117
127
|
export declare function checkEditVisibility(metadataXml: string, entitySetName: string): ButtonState;
|
|
128
|
+
/**
|
|
129
|
+
* Safely checks button visibility from already-converted metadata, with error handling.
|
|
130
|
+
*
|
|
131
|
+
* @param convertedMetadata The already-converted OData metadata
|
|
132
|
+
* @param entitySetName The name of the entity set
|
|
133
|
+
* @param log Optional logger instance
|
|
134
|
+
* @returns Button visibility result or undefined if error occurs
|
|
135
|
+
*/
|
|
136
|
+
export declare function safeCheckButtonVisibilityFromMetadata(convertedMetadata: ConvertedMetadata, entitySetName: string, log?: Logger): ButtonVisibilityResult | undefined;
|
|
118
137
|
/**
|
|
119
138
|
* Safely checks button visibility with error handling.
|
|
120
139
|
*
|
|
@@ -10,8 +10,10 @@ exports.analyzeRestrictionValue = analyzeRestrictionValue;
|
|
|
10
10
|
exports.analyzeInsertRestrictions = analyzeInsertRestrictions;
|
|
11
11
|
exports.analyzeDeleteRestrictions = analyzeDeleteRestrictions;
|
|
12
12
|
exports.analyzeUpdateRestrictions = analyzeUpdateRestrictions;
|
|
13
|
+
exports.checkButtonVisibilityFromMetadata = checkButtonVisibilityFromMetadata;
|
|
13
14
|
exports.checkButtonVisibility = checkButtonVisibility;
|
|
14
15
|
exports.checkEditVisibility = checkEditVisibility;
|
|
16
|
+
exports.safeCheckButtonVisibilityFromMetadata = safeCheckButtonVisibilityFromMetadata;
|
|
15
17
|
exports.safeCheckButtonVisibility = safeCheckButtonVisibility;
|
|
16
18
|
exports.safeCheckEditVisibility = safeCheckEditVisibility;
|
|
17
19
|
const edmx_parser_1 = require("@sap-ux/edmx-parser");
|
|
@@ -215,6 +217,27 @@ function analyzeUpdateRestrictions(restriction) {
|
|
|
215
217
|
const value = restriction ? restriction['Updatable'] : undefined;
|
|
216
218
|
return analyzeRestrictionValue(value);
|
|
217
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Checks the visibility and enabled state of create and delete buttons for a given entity set
|
|
222
|
+
* by analyzing OData Capabilities annotations in the converted metadata.
|
|
223
|
+
*
|
|
224
|
+
* @param convertedMetadata The already-converted OData metadata
|
|
225
|
+
* @param entitySetName The name of the entity set to check
|
|
226
|
+
* @returns ButtonVisibilityResult containing the state of create and delete buttons
|
|
227
|
+
* @throws {Error} If entity set is not found
|
|
228
|
+
*/
|
|
229
|
+
function checkButtonVisibilityFromMetadata(convertedMetadata, entitySetName) {
|
|
230
|
+
const entitySet = convertedMetadata.entitySets.find((es) => es.name === entitySetName);
|
|
231
|
+
if (!entitySet) {
|
|
232
|
+
throw new Error(`Entity set '${entitySetName}' not found in metadata`);
|
|
233
|
+
}
|
|
234
|
+
const insertRestrictions = entitySet.annotations?.Capabilities?.InsertRestrictions;
|
|
235
|
+
const deleteRestrictions = entitySet.annotations?.Capabilities?.DeleteRestrictions;
|
|
236
|
+
return {
|
|
237
|
+
create: analyzeInsertRestrictions(insertRestrictions),
|
|
238
|
+
delete: analyzeDeleteRestrictions(deleteRestrictions)
|
|
239
|
+
};
|
|
240
|
+
}
|
|
218
241
|
/**
|
|
219
242
|
* Checks the visibility and enabled state of create and delete buttons for a given entity set
|
|
220
243
|
* by analyzing OData Capabilities annotations in the metadata.
|
|
@@ -226,17 +249,7 @@ function analyzeUpdateRestrictions(restriction) {
|
|
|
226
249
|
*/
|
|
227
250
|
function checkButtonVisibility(metadataXml, entitySetName) {
|
|
228
251
|
try {
|
|
229
|
-
|
|
230
|
-
const entitySet = convertedMetadata.entitySets.find((es) => es.name === entitySetName);
|
|
231
|
-
if (!entitySet) {
|
|
232
|
-
throw new Error(`Entity set '${entitySetName}' not found in metadata`);
|
|
233
|
-
}
|
|
234
|
-
const insertRestrictions = entitySet.annotations?.Capabilities?.InsertRestrictions;
|
|
235
|
-
const deleteRestrictions = entitySet.annotations?.Capabilities?.DeleteRestrictions;
|
|
236
|
-
return {
|
|
237
|
-
create: analyzeInsertRestrictions(insertRestrictions),
|
|
238
|
-
delete: analyzeDeleteRestrictions(deleteRestrictions)
|
|
239
|
-
};
|
|
252
|
+
return checkButtonVisibilityFromMetadata((0, annotation_converter_1.convert)((0, edmx_parser_1.parse)(metadataXml)), entitySetName);
|
|
240
253
|
}
|
|
241
254
|
catch (error) {
|
|
242
255
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -267,6 +280,23 @@ function checkEditVisibility(metadataXml, entitySetName) {
|
|
|
267
280
|
throw new Error(`Failed to analyze edit visibility: ${errorMessage}`);
|
|
268
281
|
}
|
|
269
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Safely checks button visibility from already-converted metadata, with error handling.
|
|
285
|
+
*
|
|
286
|
+
* @param convertedMetadata The already-converted OData metadata
|
|
287
|
+
* @param entitySetName The name of the entity set
|
|
288
|
+
* @param log Optional logger instance
|
|
289
|
+
* @returns Button visibility result or undefined if error occurs
|
|
290
|
+
*/
|
|
291
|
+
function safeCheckButtonVisibilityFromMetadata(convertedMetadata, entitySetName, log) {
|
|
292
|
+
try {
|
|
293
|
+
return checkButtonVisibilityFromMetadata(convertedMetadata, entitySetName);
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
log?.debug(`Failed to check button visibility: ${error instanceof Error ? error.message : String(error)}`);
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
270
300
|
/**
|
|
271
301
|
* Safely checks button visibility with error handling.
|
|
272
302
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Logger } from '@sap-ux/logger';
|
|
2
2
|
import type { TreeAggregations, TreeModel } from '@sap/ux-specification/dist/types/src/parser';
|
|
3
3
|
import type { ActionButtonsResult, ActionButtonState, ButtonState, FEV4ManifestTarget, ListReportFeatures } from '../types';
|
|
4
|
+
import type { ConvertedMetadata } from '@sap-ux/vocabularies-types';
|
|
4
5
|
import { safeCheckButtonVisibility } from './actionUtils';
|
|
5
6
|
import type { PageWithModelV4 } from '@sap/ux-specification/dist/types/src/parser/application';
|
|
6
7
|
import type { Manifest } from '@sap-ux/project-access';
|
|
@@ -20,13 +21,22 @@ export declare function buildButtonState(buttonState?: ButtonState): {
|
|
|
20
21
|
/**
|
|
21
22
|
* Safely checks action button states with error handling.
|
|
22
23
|
*
|
|
23
|
-
* @param
|
|
24
|
+
* @param convertedMetadata - The already-converted OData metadata
|
|
24
25
|
* @param entitySetName - The name of the entity set
|
|
25
26
|
* @param actionNames - List of action names to check
|
|
26
27
|
* @param log - Optional logger instance
|
|
27
28
|
* @returns Array of action button states or empty array if error occurs
|
|
28
29
|
*/
|
|
29
|
-
export declare function safeCheckActionButtonStates(
|
|
30
|
+
export declare function safeCheckActionButtonStates(convertedMetadata: ConvertedMetadata, entitySetName: string, actionNames: string[], log?: Logger): ActionButtonState[];
|
|
31
|
+
/**
|
|
32
|
+
* Safely gets semantic key properties with error handling.
|
|
33
|
+
*
|
|
34
|
+
* @param convertedMetadata - The already-converted OData metadata
|
|
35
|
+
* @param entitySetName - The name of the entity set
|
|
36
|
+
* @param log - Optional logger instance
|
|
37
|
+
* @returns Array of semantic key properties or undefined if error occurs
|
|
38
|
+
*/
|
|
39
|
+
export declare function safeGetSemanticKeyProperties(convertedMetadata: ConvertedMetadata, entitySetName: string, log?: Logger): string[] | undefined;
|
|
30
40
|
/**
|
|
31
41
|
* Returns true when a ListReport manifest target is configured as an Analytical List Page.
|
|
32
42
|
* ALP targets have a `views.paths` array where at least one entry contains a `primary` array,
|
|
@@ -69,6 +79,16 @@ export declare function getToolBarActions(pageModel: TreeModel): TreeAggregation
|
|
|
69
79
|
* @returns - an array of filter field names
|
|
70
80
|
*/
|
|
71
81
|
export declare function getFilterFieldNames(pageModel: TreeModel, log?: Logger): string[];
|
|
82
|
+
/**
|
|
83
|
+
* Checks the state of action buttons defined in UI.LineItem annotations for a given entity set.
|
|
84
|
+
*
|
|
85
|
+
* @param convertedMetadata The already-converted OData metadata
|
|
86
|
+
* @param entitySetName The name of the entity set to check
|
|
87
|
+
* @param actionNames Optional list of action names to filter (e.g., ['Check', 'deductDiscount']). If not provided, returns all actions.
|
|
88
|
+
* @returns ActionButtonsResult containing the list of action buttons and their states
|
|
89
|
+
* @throws {Error} If entity set is not found
|
|
90
|
+
*/
|
|
91
|
+
export declare function checkActionButtonStatesFromMetadata(convertedMetadata: ConvertedMetadata, entitySetName: string, actionNames?: string[]): ActionButtonsResult;
|
|
72
92
|
/**
|
|
73
93
|
* Checks the state of action buttons defined in UI.LineItem annotations for a given entity set.
|
|
74
94
|
*
|
|
@@ -94,4 +114,36 @@ export declare function getToolBarActionNames(pageModel: TreeModel, log?: Logger
|
|
|
94
114
|
* @returns An array of toolbar action descriptions.
|
|
95
115
|
*/
|
|
96
116
|
export declare function getToolBarActionItems(toolBarActionsAgg: TreeAggregations): string[];
|
|
117
|
+
/**
|
|
118
|
+
* Checks whether all SemanticKey properties for a given entity set appear as filter fields in the filter bar.
|
|
119
|
+
* Returns false if the semantic key is absent, empty, or no semantic key properties are present as filters.
|
|
120
|
+
*
|
|
121
|
+
* @param pageModel - The tree model containing filter bar definitions (from ux-specification)
|
|
122
|
+
* @param metadataXml - The OData metadata XML content as a string
|
|
123
|
+
* @param entitySetName - The name of the entity set to inspect
|
|
124
|
+
* @param log - optional logger instance
|
|
125
|
+
* @returns true if every SemanticKey property appears in the filter bar, false otherwise
|
|
126
|
+
*/
|
|
127
|
+
export declare function isSemanticKeyInFilterBar(pageModel: TreeModel, metadataXml: string, entitySetName: string, log?: Logger): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Retrieves the SemanticKey PropertyPath values for a given entity set from already-converted metadata.
|
|
130
|
+
*
|
|
131
|
+
* @param convertedMetadata - The already-converted OData metadata
|
|
132
|
+
* @param entitySetName - The name of the entity set to inspect
|
|
133
|
+
* @param resolveLabels - when true, each property name is replaced with its Common.Label value (falls back to the property name when no label is defined). Use this when comparing against getFilterFieldNames(), which also returns labels.
|
|
134
|
+
* @returns An array of PropertyPath string values (or their labels) from the SemanticKey annotation, or an empty array if not found
|
|
135
|
+
* @throws {Error} If the entity set is not found
|
|
136
|
+
*/
|
|
137
|
+
export declare function getSemanticKeyPropertiesFromMetadata(convertedMetadata: ConvertedMetadata, entitySetName: string, resolveLabels?: boolean): string[];
|
|
138
|
+
/**
|
|
139
|
+
* Retrieves the SemanticKey PropertyPath values for a given entity set from OData metadata XML.
|
|
140
|
+
* Returns the values of all PropertyPath entries in the SAP Common SemanticKey annotation on the entity type.
|
|
141
|
+
*
|
|
142
|
+
* @param metadataXml - The OData metadata XML content as a string
|
|
143
|
+
* @param entitySetName - The name of the entity set to inspect
|
|
144
|
+
* @param resolveLabels - when true, each property name is replaced with its Common.Label value (falls back to the property name when no label is defined). Use this when comparing against getFilterFieldNames(), which also returns labels.
|
|
145
|
+
* @returns An array of PropertyPath string values (or their labels) from the SemanticKey annotation, or an empty array if not found
|
|
146
|
+
* @throws {Error} If the metadata cannot be parsed or the entity set is not found
|
|
147
|
+
*/
|
|
148
|
+
export declare function getSemanticKeyProperties(metadataXml: string, entitySetName: string, resolveLabels?: boolean): string[];
|
|
97
149
|
//# sourceMappingURL=listReportUtils.d.ts.map
|
|
@@ -3,14 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.safeCheckButtonVisibility = exports.safeCheckEditVisibility = exports.checkButtonVisibility = void 0;
|
|
4
4
|
exports.buildButtonState = buildButtonState;
|
|
5
5
|
exports.safeCheckActionButtonStates = safeCheckActionButtonStates;
|
|
6
|
+
exports.safeGetSemanticKeyProperties = safeGetSemanticKeyProperties;
|
|
6
7
|
exports.isALPManifestTarget = isALPManifestTarget;
|
|
7
8
|
exports.isALPFromManifest = isALPFromManifest;
|
|
8
9
|
exports.getListReportFeatures = getListReportFeatures;
|
|
9
10
|
exports.getToolBarActions = getToolBarActions;
|
|
10
11
|
exports.getFilterFieldNames = getFilterFieldNames;
|
|
12
|
+
exports.checkActionButtonStatesFromMetadata = checkActionButtonStatesFromMetadata;
|
|
11
13
|
exports.checkActionButtonStates = checkActionButtonStates;
|
|
12
14
|
exports.getToolBarActionNames = getToolBarActionNames;
|
|
13
15
|
exports.getToolBarActionItems = getToolBarActionItems;
|
|
16
|
+
exports.isSemanticKeyInFilterBar = isSemanticKeyInFilterBar;
|
|
17
|
+
exports.getSemanticKeyPropertiesFromMetadata = getSemanticKeyPropertiesFromMetadata;
|
|
18
|
+
exports.getSemanticKeyProperties = getSemanticKeyProperties;
|
|
14
19
|
const modelUtils_1 = require("./modelUtils");
|
|
15
20
|
const edmx_parser_1 = require("@sap-ux/edmx-parser");
|
|
16
21
|
const annotation_converter_1 = require("@sap-ux/annotation-converter");
|
|
@@ -35,21 +40,38 @@ function buildButtonState(buttonState) {
|
|
|
35
40
|
/**
|
|
36
41
|
* Safely checks action button states with error handling.
|
|
37
42
|
*
|
|
38
|
-
* @param
|
|
43
|
+
* @param convertedMetadata - The already-converted OData metadata
|
|
39
44
|
* @param entitySetName - The name of the entity set
|
|
40
45
|
* @param actionNames - List of action names to check
|
|
41
46
|
* @param log - Optional logger instance
|
|
42
47
|
* @returns Array of action button states or empty array if error occurs
|
|
43
48
|
*/
|
|
44
|
-
function safeCheckActionButtonStates(
|
|
49
|
+
function safeCheckActionButtonStates(convertedMetadata, entitySetName, actionNames, log) {
|
|
45
50
|
try {
|
|
46
|
-
return
|
|
51
|
+
return checkActionButtonStatesFromMetadata(convertedMetadata, entitySetName, actionNames).actions;
|
|
47
52
|
}
|
|
48
53
|
catch (error) {
|
|
49
54
|
log?.debug(`Failed to check action button states: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
55
|
return [];
|
|
51
56
|
}
|
|
52
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Safely gets semantic key properties with error handling.
|
|
60
|
+
*
|
|
61
|
+
* @param convertedMetadata - The already-converted OData metadata
|
|
62
|
+
* @param entitySetName - The name of the entity set
|
|
63
|
+
* @param log - Optional logger instance
|
|
64
|
+
* @returns Array of semantic key properties or undefined if error occurs
|
|
65
|
+
*/
|
|
66
|
+
function safeGetSemanticKeyProperties(convertedMetadata, entitySetName, log) {
|
|
67
|
+
try {
|
|
68
|
+
return getSemanticKeyPropertiesFromMetadata(convertedMetadata, entitySetName, true);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
log?.debug(`Failed to get semantic key properties: ${error instanceof Error ? error.message : String(error)}`);
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
53
75
|
/**
|
|
54
76
|
* Returns true when a ListReport manifest target is configured as an Analytical List Page.
|
|
55
77
|
* ALP targets have a `views.paths` array where at least one entry contains a `primary` array,
|
|
@@ -89,20 +111,38 @@ function isALPFromManifest(manifest, targetKey) {
|
|
|
89
111
|
* @returns feature data extracted from the List Report page model
|
|
90
112
|
*/
|
|
91
113
|
function getListReportFeatures(listReportPage, log, metadata, manifest) {
|
|
92
|
-
const buttonVisibility = metadata && listReportPage.entitySet
|
|
93
|
-
? (0, actionUtils_1.safeCheckButtonVisibility)(metadata, listReportPage.entitySet, log)
|
|
94
|
-
: undefined;
|
|
95
114
|
const toolbarActions = getToolBarActionNames(listReportPage.model, log);
|
|
115
|
+
const filterBarItems = getFilterFieldNames(listReportPage.model, log);
|
|
116
|
+
let buttonVisibility;
|
|
117
|
+
let semanticKeyProperties;
|
|
118
|
+
let toolBarActions = [];
|
|
119
|
+
if (metadata && listReportPage.entitySet) {
|
|
120
|
+
const entitySetName = listReportPage.entitySet;
|
|
121
|
+
try {
|
|
122
|
+
const convertedMetadata = (0, annotation_converter_1.convert)((0, edmx_parser_1.parse)(metadata));
|
|
123
|
+
buttonVisibility = (0, actionUtils_1.safeCheckButtonVisibilityFromMetadata)(convertedMetadata, entitySetName, log);
|
|
124
|
+
semanticKeyProperties = safeGetSemanticKeyProperties(convertedMetadata, entitySetName, log);
|
|
125
|
+
toolBarActions = safeCheckActionButtonStates(convertedMetadata, entitySetName, toolbarActions, log);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
log?.debug(`Failed to parse metadata: ${error instanceof Error ? error.message : String(error)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const missingKeys = semanticKeyProperties?.length && filterBarItems.length
|
|
132
|
+
? semanticKeyProperties.filter((key) => !filterBarItems.includes(key))
|
|
133
|
+
: undefined;
|
|
96
134
|
return {
|
|
97
135
|
name: listReportPage.name,
|
|
98
136
|
createButton: buildButtonState(buttonVisibility?.create),
|
|
99
137
|
deleteButton: buildButtonState(buttonVisibility?.delete),
|
|
100
|
-
filterBarItems
|
|
138
|
+
filterBarItems,
|
|
101
139
|
tableColumns: (0, modelUtils_1.getTableColumnData)(listReportPage.model, log),
|
|
102
|
-
toolBarActions
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
140
|
+
toolBarActions,
|
|
141
|
+
isALP: manifest ? isALPFromManifest(manifest, listReportPage.name) : false,
|
|
142
|
+
semanticKey: {
|
|
143
|
+
semanticKeyProperties,
|
|
144
|
+
missingFromFilterBar: missingKeys?.length ? missingKeys : undefined
|
|
145
|
+
}
|
|
106
146
|
};
|
|
107
147
|
}
|
|
108
148
|
/**
|
|
@@ -141,6 +181,34 @@ function getFilterFieldNames(pageModel, log) {
|
|
|
141
181
|
}
|
|
142
182
|
return filterBarItems;
|
|
143
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Checks the state of action buttons defined in UI.LineItem annotations for a given entity set.
|
|
186
|
+
*
|
|
187
|
+
* @param convertedMetadata The already-converted OData metadata
|
|
188
|
+
* @param entitySetName The name of the entity set to check
|
|
189
|
+
* @param actionNames Optional list of action names to filter (e.g., ['Check', 'deductDiscount']). If not provided, returns all actions.
|
|
190
|
+
* @returns ActionButtonsResult containing the list of action buttons and their states
|
|
191
|
+
* @throws {Error} If entity set is not found
|
|
192
|
+
*/
|
|
193
|
+
function checkActionButtonStatesFromMetadata(convertedMetadata, entitySetName, actionNames) {
|
|
194
|
+
const entitySet = convertedMetadata.entitySets.find((es) => es.name === entitySetName);
|
|
195
|
+
if (!entitySet) {
|
|
196
|
+
throw new Error(`Entity set '${entitySetName}' not found in metadata`);
|
|
197
|
+
}
|
|
198
|
+
const entityType = entitySet.entityType;
|
|
199
|
+
if (!entityType) {
|
|
200
|
+
throw new Error(`Entity type not found for entity set '${entitySetName}'`);
|
|
201
|
+
}
|
|
202
|
+
const lineItemAnnotation = entityType.annotations?.UI?.LineItem;
|
|
203
|
+
if (!lineItemAnnotation || !Array.isArray(lineItemAnnotation)) {
|
|
204
|
+
return { actions: [], entityType: entityType.name };
|
|
205
|
+
}
|
|
206
|
+
const dataFieldForActions = lineItemAnnotation.filter((item) => item.$Type === 'com.sap.vocabularies.UI.v1.DataFieldForAction');
|
|
207
|
+
const actions = actionNames
|
|
208
|
+
? findActionStates(dataFieldForActions, actionNames, convertedMetadata)
|
|
209
|
+
: extractAllActionStates(dataFieldForActions, convertedMetadata);
|
|
210
|
+
return { actions, entityType: entityType.name };
|
|
211
|
+
}
|
|
144
212
|
/**
|
|
145
213
|
* Checks the state of action buttons defined in UI.LineItem annotations for a given entity set.
|
|
146
214
|
*
|
|
@@ -152,24 +220,7 @@ function getFilterFieldNames(pageModel, log) {
|
|
|
152
220
|
*/
|
|
153
221
|
function checkActionButtonStates(metadataXml, entitySetName, actionNames) {
|
|
154
222
|
try {
|
|
155
|
-
|
|
156
|
-
const entitySet = convertedMetadata.entitySets.find((es) => es.name === entitySetName);
|
|
157
|
-
if (!entitySet) {
|
|
158
|
-
throw new Error(`Entity set '${entitySetName}' not found in metadata`);
|
|
159
|
-
}
|
|
160
|
-
const entityType = entitySet.entityType;
|
|
161
|
-
if (!entityType) {
|
|
162
|
-
throw new Error(`Entity type not found for entity set '${entitySetName}'`);
|
|
163
|
-
}
|
|
164
|
-
const lineItemAnnotation = entityType.annotations?.UI?.LineItem;
|
|
165
|
-
if (!lineItemAnnotation || !Array.isArray(lineItemAnnotation)) {
|
|
166
|
-
return { actions: [], entityType: entityType.name };
|
|
167
|
-
}
|
|
168
|
-
const dataFieldForActions = lineItemAnnotation.filter((item) => item.$Type === 'com.sap.vocabularies.UI.v1.DataFieldForAction');
|
|
169
|
-
const actions = actionNames
|
|
170
|
-
? findActionStates(dataFieldForActions, actionNames, convertedMetadata)
|
|
171
|
-
: extractAllActionStates(dataFieldForActions, convertedMetadata);
|
|
172
|
-
return { actions, entityType: entityType.name };
|
|
223
|
+
return checkActionButtonStatesFromMetadata((0, annotation_converter_1.convert)((0, edmx_parser_1.parse)(metadataXml)), entitySetName, actionNames);
|
|
173
224
|
}
|
|
174
225
|
catch (error) {
|
|
175
226
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -249,4 +300,70 @@ function extractItemDescriptions(aggregations) {
|
|
|
249
300
|
}
|
|
250
301
|
return [];
|
|
251
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Checks whether all SemanticKey properties for a given entity set appear as filter fields in the filter bar.
|
|
305
|
+
* Returns false if the semantic key is absent, empty, or no semantic key properties are present as filters.
|
|
306
|
+
*
|
|
307
|
+
* @param pageModel - The tree model containing filter bar definitions (from ux-specification)
|
|
308
|
+
* @param metadataXml - The OData metadata XML content as a string
|
|
309
|
+
* @param entitySetName - The name of the entity set to inspect
|
|
310
|
+
* @param log - optional logger instance
|
|
311
|
+
* @returns true if every SemanticKey property appears in the filter bar, false otherwise
|
|
312
|
+
*/
|
|
313
|
+
function isSemanticKeyInFilterBar(pageModel, metadataXml, entitySetName, log) {
|
|
314
|
+
try {
|
|
315
|
+
const semanticKeys = getSemanticKeyProperties(metadataXml, entitySetName, true);
|
|
316
|
+
if (!semanticKeys.length) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
const filterFields = getFilterFieldNames(pageModel, log);
|
|
320
|
+
return semanticKeys.every((key) => filterFields.includes(key));
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
log?.debug(`Failed to check semantic key in filter bar: ${error instanceof Error ? error.message : String(error)}`);
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Retrieves the SemanticKey PropertyPath values for a given entity set from already-converted metadata.
|
|
329
|
+
*
|
|
330
|
+
* @param convertedMetadata - The already-converted OData metadata
|
|
331
|
+
* @param entitySetName - The name of the entity set to inspect
|
|
332
|
+
* @param resolveLabels - when true, each property name is replaced with its Common.Label value (falls back to the property name when no label is defined). Use this when comparing against getFilterFieldNames(), which also returns labels.
|
|
333
|
+
* @returns An array of PropertyPath string values (or their labels) from the SemanticKey annotation, or an empty array if not found
|
|
334
|
+
* @throws {Error} If the entity set is not found
|
|
335
|
+
*/
|
|
336
|
+
function getSemanticKeyPropertiesFromMetadata(convertedMetadata, entitySetName, resolveLabels = false) {
|
|
337
|
+
const entitySet = convertedMetadata.entitySets.find((es) => es.name === entitySetName);
|
|
338
|
+
if (!entitySet) {
|
|
339
|
+
throw new Error(`Entity set '${entitySetName}' not found in metadata`);
|
|
340
|
+
}
|
|
341
|
+
const semanticKey = entitySet.entityType.annotations?.Common?.SemanticKey;
|
|
342
|
+
if (!semanticKey) {
|
|
343
|
+
return [];
|
|
344
|
+
}
|
|
345
|
+
const propertyNames = semanticKey.map((entry) => entry.value).filter((v) => typeof v === 'string');
|
|
346
|
+
if (!resolveLabels) {
|
|
347
|
+
return propertyNames;
|
|
348
|
+
}
|
|
349
|
+
return propertyNames.map((propName) => {
|
|
350
|
+
const property = entitySet.entityType.entityProperties.find((p) => p.name === propName);
|
|
351
|
+
const label = property?.annotations?.Common?.Label;
|
|
352
|
+
const labelStr = label !== undefined && label !== null ? String(label) : '';
|
|
353
|
+
return labelStr || propName;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Retrieves the SemanticKey PropertyPath values for a given entity set from OData metadata XML.
|
|
358
|
+
* Returns the values of all PropertyPath entries in the SAP Common SemanticKey annotation on the entity type.
|
|
359
|
+
*
|
|
360
|
+
* @param metadataXml - The OData metadata XML content as a string
|
|
361
|
+
* @param entitySetName - The name of the entity set to inspect
|
|
362
|
+
* @param resolveLabels - when true, each property name is replaced with its Common.Label value (falls back to the property name when no label is defined). Use this when comparing against getFilterFieldNames(), which also returns labels.
|
|
363
|
+
* @returns An array of PropertyPath string values (or their labels) from the SemanticKey annotation, or an empty array if not found
|
|
364
|
+
* @throws {Error} If the metadata cannot be parsed or the entity set is not found
|
|
365
|
+
*/
|
|
366
|
+
function getSemanticKeyProperties(metadataXml, entitySetName, resolveLabels = false) {
|
|
367
|
+
return getSemanticKeyPropertiesFromMetadata((0, annotation_converter_1.convert)((0, edmx_parser_1.parse)(metadataXml)), entitySetName, resolveLabels);
|
|
368
|
+
}
|
|
252
369
|
//# sourceMappingURL=listReportUtils.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.9.
|
|
4
|
+
"version": "0.9.11",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/SAP/open-ux-tools.git",
|
|
@@ -27,11 +27,11 @@
|
|
|
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.9.
|
|
31
|
-
"@sap-ux/logger": "0.9.0",
|
|
32
|
-
"@sap-ux/fiori-generator-shared": "0.15.3",
|
|
30
|
+
"@sap-ux/ui5-application-writer": "1.9.2",
|
|
33
31
|
"@sap-ux/project-access": "1.38.1",
|
|
34
|
-
"@sap-ux/preview-middleware": "0.26.
|
|
32
|
+
"@sap-ux/preview-middleware": "0.26.8",
|
|
33
|
+
"@sap-ux/fiori-generator-shared": "0.15.4",
|
|
34
|
+
"@sap-ux/logger": "0.9.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/ejs": "3.1.5",
|
|
@@ -38,6 +38,32 @@ sap.ui.define([
|
|
|
38
38
|
<%_ }); -%>
|
|
39
39
|
});
|
|
40
40
|
<%_ } -%>
|
|
41
|
+
<%_ if (semanticKey && semanticKey.missingFromFilterBar && semanticKey.missingFromFilterBar.length > 0) { %>
|
|
42
|
+
opaTest("Add semantic key properties to filter bar", function (Given, When, Then) {
|
|
43
|
+
Then.onThe<%- startLR%>.onFilterBar().iOpenFilterAdaptation();
|
|
44
|
+
<%_ semanticKey.missingFromFilterBar.forEach(function(property) { _%>
|
|
45
|
+
When.onThe<%- startLR%>.onFilterBar().iAddAdaptationFilterField("<%- property %>");
|
|
46
|
+
<%_ }); -%>
|
|
47
|
+
Then.onThe<%- startLR%>.onFilterBar().iConfirmFilterAdaptation();
|
|
48
|
+
<%_ semanticKey.missingFromFilterBar.forEach(function(property) { _%>
|
|
49
|
+
Then.onThe<%- startLR%>.onFilterBar().iCheckFilterField("<%- property %>");
|
|
50
|
+
<%_ }); -%>
|
|
51
|
+
<%_ semanticKey.missingFromFilterBar.forEach(function(property) { _%>
|
|
52
|
+
// Then.onThe<%- startLR%>.onFilterBar().iChangeFilterField("<%- property %>");
|
|
53
|
+
<%_ }); -%>
|
|
54
|
+
// Then.onThe<%- startLR%>.onFilterBar().iExecuteSearch();
|
|
55
|
+
// Then.onThe<%- startLR%>.onTable().iCheckRows();
|
|
56
|
+
// Then.onThe<%- startLR%>.onTable().iSelectRows(0);
|
|
57
|
+
// Then.onThe<%- startLR%>.onTable().iCheckAction("<Action Name>", { enabled: true });
|
|
58
|
+
});
|
|
59
|
+
<%_ } -%>
|
|
60
|
+
|
|
61
|
+
// Note: this test will only work if the ListReport page has a search field and shows data that matches the search term. Please ensure that the test data and search term are set up accordingly.
|
|
62
|
+
// opaTest("Perform a global search and check the result", function (Given, When, Then) {
|
|
63
|
+
// When.onThe<%- startLR%>.onFilterBar().iChangeSearchField("Search Term");
|
|
64
|
+
// When.onThe<%- startLR%>.onFilterBar().iExecuteSearch();
|
|
65
|
+
// Then.onThe<%- startLR%>.onTable().iCheckRows();
|
|
66
|
+
// });
|
|
41
67
|
|
|
42
68
|
<%_ if ((toolBarActions && toolBarActions.length > 0 ) || (tableColumns && Object.keys(tableColumns).length > 0)) { -%>
|
|
43
69
|
opaTest("Check table columns and actions", function (Given, When, Then) {
|