@sap-ux/ui5-test-writer 1.2.17 → 1.2.19

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/types.d.ts CHANGED
@@ -108,6 +108,8 @@ export type ObjectPageNavigationParents = {
108
108
  };
109
109
  export type SectionFormField = {
110
110
  property: string;
111
+ connectedFields?: string;
112
+ fieldGroup?: string;
111
113
  };
112
114
  export type TableColumn = {
113
115
  header?: string;
@@ -177,14 +177,10 @@ function buildPageEntry(page, pageIndent, innerIndent) {
177
177
  const framework = page.template ?? 'ListReport';
178
178
  const innerProps = [
179
179
  `${innerIndent} appId: "${page.appID ?? ''}"`,
180
- `${innerIndent} componentId: "${page.componentID ?? ''}"`
180
+ `${innerIndent} componentId: "${page.componentID ?? ''}"`,
181
+ `${innerIndent} entitySet: "${page.entitySet ?? ''}"`,
182
+ `${innerIndent} contextPath: "${page.contextPath ?? ''}"`
181
183
  ];
182
- if (page.entitySet) {
183
- innerProps.push(`${innerIndent} entitySet: "${page.entitySet}"`);
184
- }
185
- if (page.contextPath) {
186
- innerProps.push(`${innerIndent} contextPath: "${page.contextPath}"`);
187
- }
188
184
  return [
189
185
  `${pageIndent}onThe${page.targetKey}Generated: new ${framework}(`,
190
186
  `${innerIndent}{`,
@@ -107,4 +107,14 @@ export declare function getSelectionFieldItems(selectionFieldsAgg: TreeAggregati
107
107
  * @returns An array of filter field descriptions.
108
108
  */
109
109
  export declare function getFilterFields(pageModel: TreeModel): TreeAggregations;
110
+ /**
111
+ * Parses a `DataFieldForAnnotation::<property>::<targetAnnotation>` style identifier.
112
+ *
113
+ * @param name - aggregation key or `field.name` from the spec model
114
+ * @returns the parsed property and target annotation, or undefined for non-annotation entries
115
+ */
116
+ export declare function parseDataFieldForAnnotationName(name: string | undefined): {
117
+ property: string;
118
+ targetAnnotation: string;
119
+ } | undefined;
110
120
  //# sourceMappingURL=modelUtils.d.ts.map
@@ -174,4 +174,25 @@ export function getFilterFields(pageModel) {
174
174
  const selectionFieldsAggregations = getAggregations(selectionFields);
175
175
  return selectionFieldsAggregations;
176
176
  }
177
+ /**
178
+ * Parses a `DataFieldForAnnotation::<property>::<targetAnnotation>` style identifier.
179
+ *
180
+ * @param name - aggregation key or `field.name` from the spec model
181
+ * @returns the parsed property and target annotation, or undefined for non-annotation entries
182
+ */
183
+ export function parseDataFieldForAnnotationName(name) {
184
+ if (!name) {
185
+ return undefined;
186
+ }
187
+ const segments = name.split('::');
188
+ if (segments.length < 3 || segments[0] !== 'DataFieldForAnnotation') {
189
+ return undefined;
190
+ }
191
+ const property = segments[1];
192
+ const targetAnnotation = segments[2];
193
+ if (!property || !targetAnnotation) {
194
+ return undefined;
195
+ }
196
+ return { property, targetAnnotation };
197
+ }
177
198
  //# sourceMappingURL=modelUtils.js.map
@@ -1,4 +1,4 @@
1
- import { getAggregations } from './modelUtils.js';
1
+ import { getAggregations, parseDataFieldForAnnotationName } from './modelUtils.js';
2
2
  import { extractTableColumnsFromNode } from './tableUtils.js';
3
3
  import { PageTypeV4 } from '@sap/ux-specification/dist/types/src/common/page.js';
4
4
  import { parse } from '@sap-ux/edmx-parser';
@@ -133,7 +133,7 @@ function extractObjectPageBodySectionsData(objectPage, convertedMetadata, schema
133
133
  const sections = getAggregations(sectionsAggregation);
134
134
  Object.entries(sections).forEach(([sectionKey, section]) => {
135
135
  const sectionId = getSectionIdentifier(section) ?? sectionKey;
136
- const subSections = extractBodySubSectionsData(section, sectionId);
136
+ const subSections = extractBodySubSectionsData(section, sectionId, convertedMetadata, objectPage.entitySet);
137
137
  const navigationProperty = getNavigationPropertyFromKey(sectionKey);
138
138
  const isTable = isTableSection(section);
139
139
  const sectionData = {
@@ -142,7 +142,9 @@ function extractObjectPageBodySectionsData(objectPage, convertedMetadata, schema
142
142
  isTable,
143
143
  custom: !!section.custom,
144
144
  order: section?.order ?? -1,
145
- fields: section.custom || isTable ? [] : extractFormFields(section),
145
+ fields: section.custom || isTable
146
+ ? []
147
+ : extractFormFields(section, convertedMetadata, objectPage.entitySet),
146
148
  tableColumns: section.custom || !isTable ? {} : extractTableColumnsFromNode(section),
147
149
  subSections,
148
150
  actions: !section.custom && convertedMetadata && schemaNamespace
@@ -215,9 +217,11 @@ function extractSectionActions(section, convertedMetadata, schemaNamespace) {
215
217
  *
216
218
  * @param section - body section entry from the application model
217
219
  * @param parentSectionId - identifier of the parent section (used as fallback key prefix)
220
+ * @param convertedMetadata - optional converted OData metadata for drilling into ConnectedFields / FieldGroup wrappers
221
+ * @param entitySetName - the entity set the section is bound to (used to locate the entity type)
218
222
  * @returns array of sub-section feature data
219
223
  */
220
- function extractBodySubSectionsData(section, parentSectionId) {
224
+ function extractBodySubSectionsData(section, parentSectionId, convertedMetadata, entitySetName) {
221
225
  const subSections = [];
222
226
  const subSectionsAggregation = getAggregations(section)['subSections'];
223
227
  const subSectionItems = getAggregations(subSectionsAggregation);
@@ -230,7 +234,7 @@ function extractBodySubSectionsData(section, parentSectionId) {
230
234
  isTable,
231
235
  custom: !!subSection.custom,
232
236
  order: subSection?.order ?? -1, // put a negative order number to signal that order was not in spec
233
- fields: subSection.custom || isTable ? [] : extractFormFields(subSection),
237
+ fields: subSection.custom || isTable ? [] : extractFormFields(subSection, convertedMetadata, entitySetName),
234
238
  tableColumns: subSection.custom || !isTable ? {} : extractTableColumnsFromNode(subSection)
235
239
  });
236
240
  });
@@ -240,9 +244,11 @@ function extractBodySubSectionsData(section, parentSectionId) {
240
244
  * Extracts form field property paths from a body sub-section's form aggregation.
241
245
  *
242
246
  * @param subSection - body sub-section entry from the application model
247
+ * @param convertedMetadata - optional converted OData metadata for drilling into ConnectedFields / FieldGroup wrappers
248
+ * @param entitySetName - the entity set the sub-section is bound to (used to locate the entity type)
243
249
  * @returns array of form field property paths for use with iCheckField({ property })
244
250
  */
245
- function extractFormFields(subSection) {
251
+ function extractFormFields(subSection, convertedMetadata, entitySetName) {
246
252
  const fields = [];
247
253
  const formAggregation = getAggregations(subSection)['form'];
248
254
  if (!formAggregation) {
@@ -250,14 +256,71 @@ function extractFormFields(subSection) {
250
256
  }
251
257
  const fieldsAggregation = getAggregations(formAggregation)['fields'];
252
258
  const fieldItems = getAggregations(fieldsAggregation);
253
- Object.values(fieldItems).forEach((field) => {
254
- const property = field.schema?.keys?.find((key) => key.name === 'Value')?.value;
255
- if (property) {
256
- fields.push({ property });
259
+ const entityType = convertedMetadata && entitySetName ? resolveEntityType(convertedMetadata, entitySetName) : undefined;
260
+ Object.values(fieldItems).forEach((fieldItem) => {
261
+ const annotationParts = parseDataFieldForAnnotationName(fieldItem.name);
262
+ const valueProperty = fieldItem.schema?.keys?.find((key) => key.name === 'Value')?.value;
263
+ const baseProperty = valueProperty ?? annotationParts?.property;
264
+ if (!baseProperty) {
265
+ return;
266
+ }
267
+ if (annotationParts) {
268
+ const qualifier = annotationParts.targetAnnotation;
269
+ if (annotationParts.property === 'ConnectedFields' && entityType) {
270
+ resolveConnectedFieldsInnerProperties(entityType, qualifier).forEach((property) => {
271
+ fields.push({ property, connectedFields: qualifier });
272
+ });
273
+ }
274
+ else if (annotationParts.property === 'FieldGroup' && entityType) {
275
+ resolveFieldGroupInnerProperties(entityType, qualifier).forEach((property) => {
276
+ fields.push({ property, fieldGroup: qualifier });
277
+ });
278
+ }
279
+ // ConnectedFields/FieldGroup without metadata: skip
280
+ // Unknown annotation wrapper type: skip
281
+ }
282
+ else {
283
+ fields.push({ property: baseProperty });
257
284
  }
258
285
  });
259
286
  return fields;
260
287
  }
288
+ /**
289
+ * Resolves the inner `Value` paths of a `@UI.ConnectedFields#<qualifier>` annotation.
290
+ *
291
+ * @param entityType - the entity type carrying the annotation
292
+ * @param qualifier - the annotation qualifier
293
+ * @returns the inner DataField property paths
294
+ */
295
+ function resolveConnectedFieldsInnerProperties(entityType, qualifier) {
296
+ const annotation = entityType.annotations?.UI?.[`ConnectedFields#${qualifier}`];
297
+ const dictionary = annotation?.Data ?? {};
298
+ return Object.values(dictionary)
299
+ .map((dataField) => dataField?.Value?.path)
300
+ .filter((path) => Boolean(path));
301
+ }
302
+ /**
303
+ * Resolves the inner `Value` paths of a `@UI.FieldGroup#<qualifier>` annotation.
304
+ *
305
+ * @param entityType - the entity type carrying the annotation
306
+ * @param qualifier - the annotation qualifier
307
+ * @returns the inner DataField property paths
308
+ */
309
+ function resolveFieldGroupInnerProperties(entityType, qualifier) {
310
+ const annotation = entityType.annotations?.UI?.[`FieldGroup#${qualifier}`];
311
+ const dataFields = annotation?.Data ?? [];
312
+ return dataFields.map((dataField) => dataField?.Value?.path).filter((path) => Boolean(path));
313
+ }
314
+ /**
315
+ * Looks up the entity type for the given entity set name in the converted metadata.
316
+ *
317
+ * @param convertedMetadata - the converted OData metadata
318
+ * @param entitySetName - the entity set name
319
+ * @returns the entity type, or undefined if not found
320
+ */
321
+ function resolveEntityType(convertedMetadata, entitySetName) {
322
+ return convertedMetadata.entitySets.find((es) => es.name === entitySetName)?.entityType;
323
+ }
261
324
  /**
262
325
  * Extracts the OData navigation property from a spec model section key.
263
326
  * Section keys for table sections follow the pattern `_NavProperty::@annotation`, so the
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": "1.2.17",
4
+ "version": "1.2.19",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -34,7 +34,7 @@ sap.ui.define([
34
34
  <%_ }); -%>
35
35
  <%_ } -%>
36
36
  <%_ if (tableColumns && Object.keys(tableColumns).length > 0) { _%>
37
- Then.onThe<%- pageName %>Generated.onTable().iCheckColumns(<%- Object.keys(tableColumns).length %>, <%- JSON.stringify(tableColumns) %>);
37
+ Then.onThe<%- pageName %>Generated.onTable().iCheckColumns(undefined, <%- JSON.stringify(tableColumns) %>);
38
38
  <%_ } %>
39
39
  <%_ }); -%>
40
40
  });
@@ -26,11 +26,13 @@ sap.ui.define([
26
26
 
27
27
  opaTest("Navigate to <%- name%>ObjectPage", function (Given, When, Then) {
28
28
  Given.iStartMyApp();
29
- <% if (!hideFilterBar) { %>
29
+ <% if(navigationParents.parentLRName) { -%>
30
+ <% if (!hideFilterBar) { -%>
30
31
  When.onThe<%- navigationParents.parentLRName%>Generated.onFilterBar().iExecuteSearch();
31
- <% } %>
32
+ <% } -%>
32
33
  Then.onThe<%- navigationParents.parentLRName%>Generated.onTable().iCheckRows();
33
34
  When.onThe<%- navigationParents.parentLRName%>Generated.onTable().iPressRow(0);
35
+ <% } -%>
34
36
  <% if(navigationParents.parentOPName) { %>
35
37
  Then.onThe<%- navigationParents.parentOPName%>Generated.iSeeThisPage();
36
38
  Then.onThe<%- navigationParents.parentOPName%>Generated.onTable({ property: "<%- navigationParents.parentOPTableSection %>" }).iCheckRows();
@@ -127,21 +129,21 @@ sap.ui.define([
127
129
  Then.onThe<%- name%>Generated.iCheckSubSection({ section: "<%- subSection.id %>" });
128
130
  <% if (subSection.fields && subSection.fields.length > 0) { -%>
129
131
  <% subSection.fields.forEach(function(field) { -%>
130
- Then.onThe<%- name%>Generated.onForm({ section: "<%- subSection.id %>" }).iCheckField({ property: "<%- field.property %>" });
132
+ Then.onThe<%- name%>Generated.onForm({ section: "<%- subSection.id %>" }).iCheckField({ property: "<%- field.property %>"<% if (field.connectedFields) { %>, connectedFields: "<%- field.connectedFields %>"<% } %><% if (field.fieldGroup) { %>, fieldGroup: "<%- field.fieldGroup %>"<% } %> });
131
133
  <% }) -%>
132
134
  <% } -%>
133
135
  <% if (subSection.tableColumns && Object.keys(subSection.tableColumns).length > 0 && subSection.navigationProperty) { -%>
134
- Then.onThe<%- name%>Generated.onTable({ property: "<%- subSection.navigationProperty %>" }).iCheckColumns(<%- JSON.stringify(subSection.tableColumns) %>);
136
+ Then.onThe<%- name%>Generated.onTable({ property: "<%- subSection.navigationProperty %>" }).iCheckColumns(undefined, <%- JSON.stringify(subSection.tableColumns) %>);
135
137
  <% } -%>
136
138
  <% }) -%>
137
139
  <% } else { -%>
138
140
  <% if (section.fields && section.fields.length > 0) { -%>
139
141
  <% section.fields.forEach(function(field) { -%>
140
- Then.onThe<%- name%>Generated.onForm({ section: "<%- section.id %>" }).iCheckField({ property: "<%- field.property %>" });
142
+ Then.onThe<%- name%>Generated.onForm({ section: "<%- section.id %>" }).iCheckField({ property: "<%- field.property %>"<% if (field.connectedFields) { %>, connectedFields: "<%- field.connectedFields %>"<% } %><% if (field.fieldGroup) { %>, fieldGroup: "<%- field.fieldGroup %>"<% } %> });
141
143
  <% }) -%>
142
144
  <% } -%>
143
145
  <% if (section.tableColumns && Object.keys(section.tableColumns).length > 0 && section.navigationProperty) { -%>
144
- Then.onThe<%- name%>Generated.onTable({ property: "<%- section.navigationProperty %>" }).iCheckColumns(<%- JSON.stringify(section.tableColumns) %>);
146
+ Then.onThe<%- name%>Generated.onTable({ property: "<%- section.navigationProperty %>" }).iCheckColumns(undefined, <%- JSON.stringify(section.tableColumns) %>);
145
147
  <% } -%>
146
148
  <% } -%>
147
149
  <% }) -%>
@@ -45,11 +45,13 @@ function journey() {
45
45
 
46
46
  opaTest("Navigate to <%- name%>ObjectPage", function (Given: Given, When: When, Then: Then) {
47
47
  Given.iStartMyApp();
48
- <% if (!hideFilterBar) { %>
48
+ <% if(navigationParents.parentLRName) { -%>
49
+ <% if (!hideFilterBar) { -%>
49
50
  When.onThe<%- navigationParents.parentLRName%>Generated.onFilterBar().iExecuteSearch();
50
- <% } %>
51
+ <% } -%>
51
52
  Then.onThe<%- navigationParents.parentLRName%>Generated.onTable("").iCheckRows();
52
53
  When.onThe<%- navigationParents.parentLRName%>Generated.onTable("").iPressRow(0);
54
+ <% } -%>
53
55
  <% if(navigationParents.parentOPName) { %>
54
56
  Then.onThe<%- navigationParents.parentOPName%>Generated.iSeeThisPage();
55
57
  Then.onThe<%- navigationParents.parentOPName%>Generated.onTable({ property: "<%- navigationParents.parentOPTableSection %>" }).iCheckRows();
@@ -146,21 +148,21 @@ function journey() {
146
148
  Then.onThe<%- name%>Generated.iCheckSubSection({ section: "<%- subSection.id %>" });
147
149
  <% if (subSection.fields && subSection.fields.length > 0) { -%>
148
150
  <% subSection.fields.forEach(function(field) { -%>
149
- Then.onThe<%- name%>Generated.onForm({ section: "<%- subSection.id %>" } as unknown as FormIdentifier).iCheckField({ property: "<%- field.property %>" });
151
+ Then.onThe<%- name%>Generated.onForm({ section: "<%- subSection.id %>" } as unknown as FormIdentifier).iCheckField({ property: "<%- field.property %>"<% if (field.connectedFields) { %>, connectedFields: "<%- field.connectedFields %>"<% } %><% if (field.fieldGroup) { %>, fieldGroup: "<%- field.fieldGroup %>"<% } %> });
150
152
  <% }) -%>
151
153
  <% } -%>
152
154
  <% if (subSection.tableColumns && Object.keys(subSection.tableColumns).length > 0 && subSection.navigationProperty) { -%>
153
- Then.onThe<%- name%>Generated.onTable({ property: "<%- subSection.navigationProperty %>" }).iCheckColumns(<%- JSON.stringify(subSection.tableColumns) %>);
155
+ Then.onThe<%- name%>Generated.onTable({ property: "<%- subSection.navigationProperty %>" }).iCheckColumns(undefined, <%- JSON.stringify(subSection.tableColumns) %>);
154
156
  <% } -%>
155
157
  <% }) -%>
156
158
  <% } else { -%>
157
159
  <% if (section.fields && section.fields.length > 0) { -%>
158
160
  <% section.fields.forEach(function(field) { -%>
159
- Then.onThe<%- name%>Generated.onForm({ section: "<%- section.id %>" } as unknown as FormIdentifier).iCheckField({ property: "<%- field.property %>" });
161
+ Then.onThe<%- name%>Generated.onForm({ section: "<%- section.id %>" } as unknown as FormIdentifier).iCheckField({ property: "<%- field.property %>"<% if (field.connectedFields) { %>, connectedFields: "<%- field.connectedFields %>"<% } %><% if (field.fieldGroup) { %>, fieldGroup: "<%- field.fieldGroup %>"<% } %> });
160
162
  <% }) -%>
161
163
  <% } -%>
162
164
  <% if (section.tableColumns && Object.keys(section.tableColumns).length > 0 && section.navigationProperty) { -%>
163
- Then.onThe<%- name%>Generated.onTable({ property: "<%- section.navigationProperty %>" }).iCheckColumns(<%- JSON.stringify(section.tableColumns) %>);
165
+ Then.onThe<%- name%>Generated.onTable({ property: "<%- section.navigationProperty %>" }).iCheckColumns(undefined, <%- JSON.stringify(section.tableColumns) %>);
164
166
  <% } -%>
165
167
  <% } -%>
166
168
  <% }) -%>
@@ -10,26 +10,17 @@ import ObjectPage from "sap/fe/test/ObjectPage";
10
10
  const runner = new JourneyRunner({
11
11
  launchUrl: sap.ui.require.toUrl("<%- appPath %>") + "/<%- htmlTarget %>",
12
12
  pages: {
13
- <%- pages.map((page) => {
14
- const innerProps = [
15
- ' appId: "' + page.appID + '"',
16
- ' componentId: "' + page.componentID + '"'
17
- ];
18
- if (page.entitySet) {
19
- innerProps.push(' entitySet: "' + page.entitySet + '"');
20
- }
21
- if (page.contextPath) {
22
- innerProps.push(' contextPath: "' + page.contextPath + '"');
23
- }
24
- return (
25
- ' onThe' + page.targetKey + 'Generated: new ' + page.template + '(\n' +
26
- ' {\n' +
27
- innerProps.join(',\n') + '\n' +
28
- ' },\n' +
29
- ' Custom' + page.targetKey + 'Generated\n' +
30
- ' )'
31
- );
32
- }).join(',\n') %>
13
+ <%- pages.map((page) =>
14
+ ' onThe' + page.targetKey + 'Generated: new ' + page.template + '(\n' +
15
+ ' {\n' +
16
+ ' appId: "' + page.appID + '",\n' +
17
+ ' componentId: "' + page.componentID + '",\n' +
18
+ ' entitySet: "' + (page.entitySet || '') + '",\n' +
19
+ ' contextPath: "' + (page.contextPath || '') + '"\n' +
20
+ ' },\n' +
21
+ ' Custom' + page.targetKey + 'Generated\n' +
22
+ ' )'
23
+ ).join(',\n') %>
33
24
  },
34
25
  async: true
35
26
  });