@sap_oss/wdio-qmate-service 3.6.2 → 3.7.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/CLAUDE.md +83 -0
- package/lib/reuse/modules/ui5/table.d.ts +13 -7
- package/lib/reuse/modules/ui5/table.js +32 -16
- package/lib/reuse/modules/ui5/table.js.map +1 -1
- package/lib/reuse/modules/util/data.d.ts +1 -0
- package/lib/reuse/modules/util/data.js +23 -6
- package/lib/reuse/modules/util/data.js.map +1 -1
- package/lib/scripts/locators/qmateLocator.js +62 -23
- package/lib/scripts/locators/qmateLocator.js.map +1 -1
- package/lib/scripts/locators/qmateLocatorSrc/filters/AncestorFilter.js +5 -0
- package/lib/scripts/locators/qmateLocatorSrc/filters/AncestorFilter.js.map +1 -1
- package/lib/scripts/locators/qmateLocatorSrc/filters/BaseFilter.d.ts +2 -2
- package/lib/scripts/locators/qmateLocatorSrc/filters/BaseFilter.js +7 -2
- package/lib/scripts/locators/qmateLocatorSrc/filters/BaseFilter.js.map +1 -1
- package/lib/scripts/locators/qmateLocatorSrc/filters/ChildFilter.js +5 -0
- package/lib/scripts/locators/qmateLocatorSrc/filters/ChildFilter.js.map +1 -1
- package/lib/scripts/locators/qmateLocatorSrc/filters/DescendantFilter.js +6 -0
- package/lib/scripts/locators/qmateLocatorSrc/filters/DescendantFilter.js.map +1 -1
- package/lib/scripts/locators/qmateLocatorSrc/filters/ElementFilter.js +13 -10
- package/lib/scripts/locators/qmateLocatorSrc/filters/ElementFilter.js.map +1 -1
- package/lib/scripts/locators/qmateLocatorSrc/filters/PropertiesFilter.js +4 -3
- package/lib/scripts/locators/qmateLocatorSrc/filters/PropertiesFilter.js.map +1 -1
- package/lib/scripts/locators/qmateLocatorSrc/filters/SiblingFilter.js +5 -0
- package/lib/scripts/locators/qmateLocatorSrc/filters/SiblingFilter.js.map +1 -1
- package/lib/scripts/stats/createUsage.js +1 -5
- package/lib/scripts/stats/createUsage.js.map +1 -1
- package/lib/scripts/stats/getUserId.js +1 -5
- package/lib/scripts/stats/getUserId.js.map +1 -1
- package/lib/scripts/stats/updateUsage.js +1 -5
- package/lib/scripts/stats/updateUsage.js.map +1 -1
- package/package.json +1 -1
- package/reuseApi.json +3 -3
- package/test/core/functional/locators/ancestorProperties.test.js +63 -0
- package/test/core/functional/locators/childProperties.test.js +48 -0
- package/test/core/functional/locators/descendantProperties.test.js +60 -0
- package/test/core/functional/locators/siblingProperties.test.js +52 -0
- package/test/reuse/ui5/date/pickRange.spec.js +3 -3
- package/test/reuse/ui5/table/openItemByIndex.spec.js +32 -0
- package/test/reuse/ui5/table/openItemByValues.spec.js +32 -0
- package/test/reuse/ui5/userInteraction/clickTab.spec.js +1 -1
- package/test/reuse/util/data/data/getSecureData.secure.json +1 -0
- package/test/reuse/util/data/getSecureData1.spec.js +37 -2
|
@@ -107,4 +107,64 @@ describe("webdriver.io page locator test", function () {
|
|
|
107
107
|
.rejects.toThrowError(/No visible elements found/);
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
it("should access element by elementProperties and multiple descendantProperties as array - AND (happy case)", async function () {
|
|
111
|
+
await browser.navigateTo(`${BASE_URL}/#/entity/sap.m.Button/sample/sap.m.sample.Button`);
|
|
112
|
+
await handleCookiesConsent();
|
|
113
|
+
await util.browser.switchToIframe("[id='sampleFrame']");
|
|
114
|
+
|
|
115
|
+
// The toolbar contains both a "Default" button and a "Reject" button as descendants - both must match
|
|
116
|
+
const selector = {
|
|
117
|
+
"elementProperties": {
|
|
118
|
+
"viewName": "sap.m.sample.Button.Page",
|
|
119
|
+
"metadata": "sap.m.Toolbar"
|
|
120
|
+
},
|
|
121
|
+
"descendantProperties": [
|
|
122
|
+
{ "viewName": "sap.m.sample.Button.Page", "metadata": "sap.m.Button", "text": "Default" },
|
|
123
|
+
{ "viewName": "sap.m.sample.Button.Page", "metadata": "sap.m.Button", "text": "Reject" }
|
|
124
|
+
]
|
|
125
|
+
};
|
|
126
|
+
const elem = await browser.uiControl(selector);
|
|
127
|
+
await expect(elem).toBeDisplayed();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("should fail when one entry of descendantProperties array does not match - AND (unhappy case)", async function () {
|
|
131
|
+
await browser.navigateTo(`${BASE_URL}/#/entity/sap.m.Button/sample/sap.m.sample.Button`);
|
|
132
|
+
await handleCookiesConsent();
|
|
133
|
+
await util.browser.switchToIframe("[id='sampleFrame']");
|
|
134
|
+
|
|
135
|
+
// Second entry has a non-existent text - AND logic means the whole selector fails
|
|
136
|
+
const selector = {
|
|
137
|
+
"elementProperties": {
|
|
138
|
+
"viewName": "sap.m.sample.Button.Page",
|
|
139
|
+
"metadata": "sap.m.Toolbar"
|
|
140
|
+
},
|
|
141
|
+
"descendantProperties": [
|
|
142
|
+
{ "viewName": "sap.m.sample.Button.Page", "metadata": "sap.m.Button", "text": "Default" },
|
|
143
|
+
{ "viewName": "sap.m.sample.Button.Page", "metadata": "sap.m.Button", "text": "this-button-does-not-exist" }
|
|
144
|
+
]
|
|
145
|
+
};
|
|
146
|
+
await expect(browser.uiControl(selector, 0, 1000))
|
|
147
|
+
.rejects.toThrowError(/No visible elements found/);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should return multiple elements when multiple parents each satisfy array descendantProperties - AND (multiple results)", async function () {
|
|
151
|
+
await browser.navigateTo(`${BASE_URL}/#/entity/sap.m.Button/sample/sap.m.sample.Button`);
|
|
152
|
+
await handleCookiesConsent();
|
|
153
|
+
await util.browser.switchToIframe("[id='sampleFrame']");
|
|
154
|
+
|
|
155
|
+
// Multiple FlexItemData elements exist on this page (one per button).
|
|
156
|
+
// Using a single-entry array exercises the array code path and should return all FlexItemData with a Button descendant.
|
|
157
|
+
const selector = {
|
|
158
|
+
"elementProperties": {
|
|
159
|
+
"viewName": "sap.m.sample.Button.Page",
|
|
160
|
+
"metadata": "sap.m.FlexItemData"
|
|
161
|
+
},
|
|
162
|
+
"descendantProperties": [
|
|
163
|
+
{ "viewName": "sap.m.sample.Button.Page", "metadata": "sap.m.Button" }
|
|
164
|
+
]
|
|
165
|
+
};
|
|
166
|
+
const elems = await browser.uiControls(selector);
|
|
167
|
+
expect(elems.length).toBeGreaterThan(1);
|
|
168
|
+
});
|
|
169
|
+
|
|
110
170
|
});
|
|
@@ -112,6 +112,58 @@ describe("webdriver.io page locator test", function () {
|
|
|
112
112
|
};
|
|
113
113
|
await expect(browser.uiControl(wrongProperties)).rejects.toThrowError(/No visible elements found/);
|
|
114
114
|
});
|
|
115
|
+
|
|
116
|
+
it("should access element by elementProperties and multiple siblingProperties as array - AND (happy case)", async function () {
|
|
117
|
+
// The AC list item has CSA as a sibling, and also has other StandardListItem siblings - both conditions must match
|
|
118
|
+
const selector = {
|
|
119
|
+
"elementProperties": {
|
|
120
|
+
"viewName": "sap.ui.demo.cart.view.Home",
|
|
121
|
+
"metadata": "sap.m.StandardListItem",
|
|
122
|
+
"bindingContextPath": "/ProductCategories*'AC')"
|
|
123
|
+
},
|
|
124
|
+
"siblingProperties": [
|
|
125
|
+
{ "viewName": "sap.ui.demo.cart.view.Home", "metadata": "sap.m.StandardListItem", "bindingContextPath": "/ProductCategories*'CSA')" },
|
|
126
|
+
{ "viewName": "sap.ui.demo.cart.view.Home", "metadata": "sap.m.StandardListItem" }
|
|
127
|
+
]
|
|
128
|
+
};
|
|
129
|
+
const elem = await browser.uiControl(selector);
|
|
130
|
+
await expect(elem).toBeDisplayed();
|
|
131
|
+
await expect(elem).toBeClickable();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it("should fail when one entry of siblingProperties array does not match - AND (unhappy case)", async function () {
|
|
135
|
+
// Second entry points to a non-existent sibling - AND logic means the whole selector fails
|
|
136
|
+
const selector = {
|
|
137
|
+
"elementProperties": {
|
|
138
|
+
"viewName": "sap.ui.demo.cart.view.Home",
|
|
139
|
+
"metadata": "sap.m.StandardListItem",
|
|
140
|
+
"bindingContextPath": "/ProductCategories*'AC')"
|
|
141
|
+
},
|
|
142
|
+
"siblingProperties": [
|
|
143
|
+
{ "viewName": "sap.ui.demo.cart.view.Home", "metadata": "sap.m.StandardListItem", "bindingContextPath": "/ProductCategories*'CSA')" },
|
|
144
|
+
{ "viewName": "sap.ui.demo.cart.view.Home", "metadata": "sap.m.StandardListItem", "bindingContextPath": "/ProductCategories*'THIS-DOES-NOT-EXIST')" }
|
|
145
|
+
]
|
|
146
|
+
};
|
|
147
|
+
await expect(browser.uiControl(selector, 0, 1000))
|
|
148
|
+
.rejects.toThrowError(/No visible elements found/);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should return multiple elements when multiple elements each satisfy array siblingProperties - AND (multiple results)", async function () {
|
|
152
|
+
// All category items (except AC and CSA themselves) have both AC and CSA as siblings - returns multiple items
|
|
153
|
+
const selector = {
|
|
154
|
+
"elementProperties": {
|
|
155
|
+
"viewName": "sap.ui.demo.cart.view.Home",
|
|
156
|
+
"metadata": "sap.m.StandardListItem"
|
|
157
|
+
},
|
|
158
|
+
"siblingProperties": [
|
|
159
|
+
{ "viewName": "sap.ui.demo.cart.view.Home", "metadata": "sap.m.StandardListItem", "bindingContextPath": "/ProductCategories*'CSA')" },
|
|
160
|
+
{ "viewName": "sap.ui.demo.cart.view.Home", "metadata": "sap.m.StandardListItem", "bindingContextPath": "/ProductCategories*'AC')" }
|
|
161
|
+
]
|
|
162
|
+
};
|
|
163
|
+
const elems = await browser.uiControls(selector);
|
|
164
|
+
expect(elems.length).toBeGreaterThan(1);
|
|
165
|
+
});
|
|
166
|
+
|
|
115
167
|
});
|
|
116
168
|
|
|
117
169
|
|
|
@@ -40,7 +40,7 @@ describe("date - pickRange - when DateRangeSelection do not have any value", fun
|
|
|
40
40
|
|
|
41
41
|
const startRange = getBorderOfRange(start);
|
|
42
42
|
const endRange = getBorderOfRange(end);
|
|
43
|
-
const rangeAsString = `${startRange}
|
|
43
|
+
const rangeAsString = `${startRange} – ${endRange}`;
|
|
44
44
|
|
|
45
45
|
common.assertion.expectEqual(arrivedRange, rangeAsString);
|
|
46
46
|
});
|
|
@@ -77,7 +77,7 @@ describe("date - pickRange - with index as 2", function () {
|
|
|
77
77
|
|
|
78
78
|
const startRange = getBorderOfRange(start);
|
|
79
79
|
const endRange = getBorderOfRange(end);
|
|
80
|
-
const rangeAsString = `${startRange}
|
|
80
|
+
const rangeAsString = `${startRange} – ${endRange}`;
|
|
81
81
|
|
|
82
82
|
common.assertion.expectEqual(arrivedRange, rangeAsString);
|
|
83
83
|
});
|
|
@@ -123,7 +123,7 @@ describe("date - pickRange - with icon as selector", function () {
|
|
|
123
123
|
|
|
124
124
|
const startRange = getBorderOfRange(start);
|
|
125
125
|
const endRange = getBorderOfRange(end);
|
|
126
|
-
const rangeAsString = `${startRange}
|
|
126
|
+
const rangeAsString = `${startRange} – ${endRange}`;
|
|
127
127
|
|
|
128
128
|
common.assertion.expectEqual(arrivedRange, rangeAsString);
|
|
129
129
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { BASE_URL } = require("../../../../src/reuse/constants.ts");
|
|
3
|
+
const { handleCookiesConsent } = require("../../../helper/utils.js");
|
|
3
4
|
const smartTableSelector = {
|
|
4
5
|
"elementProperties": {
|
|
5
6
|
"viewName": "sap.suite.ui.generic.template.ListReport.view.ListReport",
|
|
@@ -14,6 +15,12 @@ const goButtonSelector = {
|
|
|
14
15
|
"id": "*listReportFilter-btnGo"
|
|
15
16
|
}
|
|
16
17
|
};
|
|
18
|
+
const mTableSelector = {
|
|
19
|
+
"elementProperties": {
|
|
20
|
+
"metadata": "sap.m.Table",
|
|
21
|
+
"id": "*--productsTable"
|
|
22
|
+
}
|
|
23
|
+
};
|
|
17
24
|
|
|
18
25
|
describe("table - openItemByIndex - smartTable - open first item", function () {
|
|
19
26
|
|
|
@@ -82,4 +89,29 @@ describe("table - openItemByIndex - smartTable - unhappy case - try to open not
|
|
|
82
89
|
it("Execution & Verification", async function () {
|
|
83
90
|
await expect(ui5.table.openItemByIndex(smartTableSelector, 10)).rejects.toThrow(/No item found with index 10/);
|
|
84
91
|
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("table - openItemByIndex - mTable - with no arrow icon", function () {
|
|
95
|
+
|
|
96
|
+
it("Preparation", async function () {
|
|
97
|
+
const url = `${BASE_URL}/#/entity/sap.m.Table/sample/sap.m.sample.TableNavigated`;
|
|
98
|
+
await common.navigation.navigateToUrl(url);
|
|
99
|
+
await handleCookiesConsent();
|
|
100
|
+
await util.browser.switchToIframe("[id='sampleFrame']");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("Execution", async function () {
|
|
104
|
+
await ui5.table.openItemByIndex(mTableSelector, 0);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("Verification", async function () {
|
|
108
|
+
const selector = {
|
|
109
|
+
"elementProperties": {
|
|
110
|
+
"metadata": "sap.m.ColumnListItem",
|
|
111
|
+
"id": "*productsTable-0"
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const navigationState = await ui5.element.getPropertyValue(selector, "navigated");
|
|
115
|
+
expect(navigationState).toEqual(true);
|
|
116
|
+
});
|
|
85
117
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { BASE_URL } = require("../../../../src/reuse/constants.ts");
|
|
3
|
+
const { handleCookiesConsent } = require("../../../helper/utils.js");
|
|
3
4
|
const smartTableSelector = {
|
|
4
5
|
"elementProperties": {
|
|
5
6
|
"viewName": "sap.suite.ui.generic.template.ListReport.view.ListReport",
|
|
@@ -14,6 +15,12 @@ const goButtonSelector = {
|
|
|
14
15
|
"id": "*listReportFilter-btnGo"
|
|
15
16
|
}
|
|
16
17
|
};
|
|
18
|
+
const mTableSelector = {
|
|
19
|
+
"elementProperties": {
|
|
20
|
+
"metadata": "sap.m.Table",
|
|
21
|
+
"id": "*--productsTable"
|
|
22
|
+
}
|
|
23
|
+
};
|
|
17
24
|
|
|
18
25
|
describe("table - openItemByValues - smartTable - single value as a String", function () {
|
|
19
26
|
|
|
@@ -100,4 +107,29 @@ describe("table - openItemByValues - smartTable - multiple values as an Array -
|
|
|
100
107
|
});
|
|
101
108
|
|
|
102
109
|
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("table - openItemByValues - mTable - when no arrow icon", function () {
|
|
113
|
+
|
|
114
|
+
it("Preparation", async function () {
|
|
115
|
+
const url = `${BASE_URL}/#/entity/sap.m.Table/sample/sap.m.sample.TableNavigated`;
|
|
116
|
+
await common.navigation.navigateToUrl(url);
|
|
117
|
+
await handleCookiesConsent();
|
|
118
|
+
await util.browser.switchToIframe("[id='sampleFrame']");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("Execution", async function () {
|
|
122
|
+
await ui5.table.openItemByValues(mTableSelector, "Notebook Basic 15");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("Verification", async function () {
|
|
126
|
+
const selector = {
|
|
127
|
+
"elementProperties": {
|
|
128
|
+
"metadata": "sap.m.ColumnListItem",
|
|
129
|
+
"id": "*productsTable-0"
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const navigationState = await ui5.element.getPropertyValue(selector, "navigated");
|
|
133
|
+
expect(navigationState).toEqual(true);
|
|
134
|
+
});
|
|
103
135
|
});
|
|
@@ -58,7 +58,7 @@ describe("userInteraction - clickTab - multiple select values", function () {
|
|
|
58
58
|
title: "Summary"
|
|
59
59
|
},
|
|
60
60
|
ancestorProperties: {
|
|
61
|
-
metadata: "sap.
|
|
61
|
+
metadata: "sap.ui.documentation.ObjectPageSection",
|
|
62
62
|
viewName: "sap.ui.documentation.sdk.view.SubApiDetail",
|
|
63
63
|
title: "Events"
|
|
64
64
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"test": {
|
|
6
6
|
"plainValue": "PLAIN_VALUE",
|
|
7
7
|
"number": 42,
|
|
8
|
+
"shortHex": "deadbeef12345678",
|
|
8
9
|
"inner": {
|
|
9
10
|
"value": "7090bcc6097140bdf6e68850582b5e94bbd4ec52d0db5c83ac7b9c1cf4c771e2b467b8cab402f27d6bf7ba1737ec081aff24bb437e80f734ad385fa28cdbe765b630774df1021c5020515d714753c1fce0119d9a7360cd802ac536060b33976a564a590c0f61a83e7d83b02ea917f0eba8ef34f36c5898bd49013dc5756dbb3b775f1df9b99c552f1d6c44fdf8b0635e69d4c884a5226a29b573b7975e8ac564481a3e8870ccef8dbff66e167b67bac9ec3155dc0e3c41460b03d9ab6ab58f061aa67b4216b0f719fb37225c5e51b3cdd38c4597c0fe9c48e5400390a61271649e3eda26c011dfca6a22cab1b7f8ed54bc37883013f203a117d3893dab3f5f42bbb63bf9566114df3e1aff43758a98d1e8cddc0b2a5c9b7076e6b6ce8d02864514b8af3a8b8d5f789c910c2af37305ad73b5bf9a3403299416a4278108987b80f33f82f6f2ad812518fbeb5eca565a52d8dea18976dc4d895c3c5a22693c70e9"
|
|
10
11
|
}
|
|
@@ -23,13 +23,19 @@ describe("data - getSecureData - default source", function () {
|
|
|
23
23
|
common.assertion.expectEqual(dataAct, dataExp);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
it("Verification 4 -
|
|
26
|
+
it("Verification 4 - short hex value is not decrypted", function () {
|
|
27
|
+
const dataExp = "deadbeef12345678";
|
|
28
|
+
const dataAct = data.test.shortHex;
|
|
29
|
+
common.assertion.expectEqual(dataAct, dataExp);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("Verification 5 - nested value", function () {
|
|
27
33
|
const dataExp = "TEST";
|
|
28
34
|
const dataAct = data.test.inner.value;
|
|
29
35
|
common.assertion.expectEqual(dataAct, dataExp);
|
|
30
36
|
});
|
|
31
37
|
|
|
32
|
-
it("Verification
|
|
38
|
+
it("Verification 6 - alternatives from different keys", function () {
|
|
33
39
|
const dataExp = "super-duper-sensitive-pw";
|
|
34
40
|
const dataAct = data.alternatives;
|
|
35
41
|
common.assertion.expectEqual(dataAct, dataExp);
|
|
@@ -51,6 +57,35 @@ describe("data - getSecureData - custom source", function () {
|
|
|
51
57
|
});
|
|
52
58
|
});
|
|
53
59
|
|
|
60
|
+
describe("data - getSecureData - base64 encoded hex value", function () {
|
|
61
|
+
let data;
|
|
62
|
+
|
|
63
|
+
it("Execution", function () {
|
|
64
|
+
const options = { useBase64Input: true };
|
|
65
|
+
data = util.data.getSecureData("decrypt.base64", "data", options);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("Verification - base64 encoded hex value is decrypted", function () {
|
|
69
|
+
const dataExp = "super-duper-sensitive-pw";
|
|
70
|
+
const dataAct = data.password;
|
|
71
|
+
common.assertion.expectEqual(dataAct, dataExp);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
describe("data - getSecureData - base64 encoded hex value auto-detected (no options)", function () {
|
|
76
|
+
let data;
|
|
77
|
+
|
|
78
|
+
it("Execution", function () {
|
|
79
|
+
data = util.data.getSecureData("decrypt.base64", "data");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("Verification - base64 encoded hex value is decrypted via fallback auto-detection", function () {
|
|
83
|
+
const dataExp = "super-duper-sensitive-pw";
|
|
84
|
+
const dataAct = data.password;
|
|
85
|
+
common.assertion.expectEqual(dataAct, dataExp);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
54
89
|
// =================================== KEEP DISABLED FOR PIPELINE EXECUTION ===================================
|
|
55
90
|
// Can't be executed in pipeline because file is missing. Add the following to "data" folder to execute locally:
|
|
56
91
|
|