Skip to content

Commit c420fd4

Browse files
committed
Update widget-element description logic
1 parent 3031bad commit c420fd4

4 files changed

Lines changed: 171 additions & 41 deletions

File tree

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Move ExtendedOracles logic to DefaultProtocol
88
- Remove reflective process-listener handle
99
- Fix ExtendedSettingsFile default value
10+
- Update widget-element description logic
1011

1112

1213
#TESTAR v2.7.23 (5-Mar-2026)

webdriver/src/org/testar/monkey/alayer/webdriver/WdElement.java

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -233,32 +233,70 @@ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFound
233233
* Check web element parameters and try to find an appropriate one to act as description
234234
*/
235235
public String getElementDescription() {
236-
if(name != null && !name.isEmpty()) {
237-
return name;
238-
}
239-
else if(textContent != null && !textContent.isEmpty()) {
240-
return textContent;
241-
}
242-
else if(id != null && !id.isEmpty()) {
243-
return id;
244-
}
245-
else if(placeholder != null && !placeholder.isEmpty()) {
246-
return placeholder;
247-
}
248-
else if(value != null && !value.isEmpty()) {
249-
return value;
250-
}
251-
else if(tagName != null && !tagName.isEmpty()) {
252-
return tagName;
253-
}
254-
else if(title != null && !title.isEmpty()) {
255-
return title;
256-
}
257-
else if(href != null && !href.isEmpty()) {
258-
return href;
259-
}
236+
// Role/tag context: "button", "input", "a", etc.
237+
String roleDescription = normalizeDescription(tagName);
238+
239+
// Visible/accessible semantic labels
240+
String semanticDescription = "";
241+
242+
if (hasText(innerText)) {
243+
semanticDescription = normalizeDescription(innerText);
244+
}
245+
else if (hasText(textContent)) {
246+
semanticDescription = normalizeDescription(textContent);
247+
}
248+
else if (hasText(getAttribute("aria-label"))) {
249+
semanticDescription = normalizeDescription(getAttribute("aria-label"));
250+
}
251+
else if (hasText(getAttribute("aria-labelledby"))) {
252+
semanticDescription = normalizeDescription(getAttribute("aria-labelledby"));
253+
}
254+
else if (hasText(placeholder)) {
255+
semanticDescription = normalizeDescription(placeholder);
256+
}
257+
else if (hasText(title)) {
258+
semanticDescription = normalizeDescription(title);
259+
}
260+
else if (hasText(alt)) {
261+
semanticDescription = normalizeDescription(alt);
262+
}
263+
else if (hasText(value)) {
264+
semanticDescription = normalizeDescription(value);
265+
}
266+
else if (hasText(name)) {
267+
semanticDescription = normalizeDescription(name);
268+
}
269+
270+
// Use technical properties if semantic descriptions are empty
271+
if (semanticDescription.isEmpty() && hasText(id)) {
272+
semanticDescription = normalizeDescription(id);
273+
}
274+
else if (semanticDescription.isEmpty() && hasText(href)) {
275+
semanticDescription = normalizeDescription(href);
276+
}
277+
278+
// If these combined description still empty, return css classes
279+
if (roleDescription.isEmpty() && semanticDescription.isEmpty()) {
280+
return String.join("_", cssClasses);
281+
}
282+
// Else return the combined role_semantic description
283+
return roleDescription + "_" + semanticDescription;
284+
}
285+
286+
private boolean hasText(String value) {
287+
return value != null && !value.trim().isEmpty();
288+
}
289+
290+
private String normalizeDescription(String value) {
291+
String description = value == null ? "" : value.trim().toLowerCase();
292+
description = description.replaceAll("\\s+", "_");
293+
description = description.replaceAll("[^a-z0-9_./-]", "");
294+
description = description.replaceAll("_+", "_");
295+
return description;
296+
}
260297

261-
return String.join(",", cssClasses);
298+
private String getAttribute(String key) {
299+
return (attributeMap == null) ? "" : attributeMap.getOrDefault(key, "");
262300
}
263301

264302
private void setName() {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package org.testar.monkey.alayer.webdriver;
2+
3+
import org.junit.Assert;
4+
import org.junit.Before;
5+
import org.junit.Test;
6+
7+
import java.util.Arrays;
8+
import java.util.HashMap;
9+
10+
public class TestWdElementDescription {
11+
12+
private WdRootElement root;
13+
14+
@Before
15+
public void setUp() {
16+
root = new WdRootElement();
17+
}
18+
19+
@Test
20+
public void test_role_with_semantic_description() {
21+
WdElement element = newElement();
22+
element.tagName = "A";
23+
element.innerText = "Buy This!";
24+
25+
Assert.assertEquals("a_buy_this", element.getElementDescription());
26+
}
27+
28+
@Test
29+
public void test_semantic_priority() {
30+
WdElement element = newElement();
31+
element.tagName = "button";
32+
element.innerText = "Submit";
33+
element.textContent = "Secondary";
34+
35+
Assert.assertEquals("button_submit", element.getElementDescription());
36+
}
37+
38+
@Test
39+
public void test_semantic_aria_label() {
40+
WdElement element = newElement();
41+
element.tagName = "input";
42+
element.attributeMap.put("aria-label", "Search Product");
43+
44+
Assert.assertEquals("input_search_product", element.getElementDescription());
45+
}
46+
47+
@Test
48+
public void test_fallback_to_id() {
49+
WdElement element = newElement();
50+
element.tagName = "div";
51+
element.id = "Main-Section";
52+
53+
Assert.assertEquals("div_main-section", element.getElementDescription());
54+
}
55+
56+
@Test
57+
public void test_fallback_to_href() {
58+
WdElement element = newElement();
59+
element.tagName = "a";
60+
element.href = "/page.htm";
61+
62+
Assert.assertEquals("a_/page.htm", element.getElementDescription());
63+
}
64+
65+
@Test
66+
public void test_css_classes_when_no_descriptions() {
67+
WdElement element = newElement();
68+
element.cssClasses = Arrays.asList("btn", "primary");
69+
70+
Assert.assertEquals("btn_primary", element.getElementDescription());
71+
}
72+
73+
@Test
74+
public void test_normalization_on_semantic_description() {
75+
WdElement element = newElement();
76+
element.tagName = "button";
77+
element.innerText = " Save 50% NOW! ";
78+
79+
Assert.assertEquals("button_save_50_now", element.getElementDescription());
80+
}
81+
82+
private WdElement newElement() {
83+
WdElement element = new WdElement(root, root);
84+
element.attributeMap = new HashMap<>();
85+
return element;
86+
}
87+
}

webdriver/test/org/testar/monkey/alayer/webdriver/TestWebdriverRemoteActions.java

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ public void test_create_WdRemoteClickAction() {
5656
Assert.isTrue(remoteClickAction.get(Tags.OriginWidget).equals(childWdWidget));
5757
Assert.isTrue(remoteClickAction.get(Tags.Role).equals(WdActionRoles.RemoteClick));
5858
Assert.isTrue(remoteClickAction.get(Tags.Desc).equals("Remote click " + "Widget Description"));
59-
Assert.isTrue(remoteClickAction.toShortString().equals("Remote click " + childWdElement.name));
60-
Assert.isTrue(remoteClickAction.toParametersString().equals("Remote click " + childWdElement.name));
61-
Assert.isTrue(remoteClickAction.toString(new Role[0]).equals("Remote click " + childWdElement.name));
62-
Assert.isTrue(remoteClickAction.toString().equals("Remote click " + childWdElement.name));
59+
String elementDescription = childWdElement.getElementDescription();
60+
Assert.isTrue(remoteClickAction.toShortString().equals("Remote click " + elementDescription));
61+
Assert.isTrue(remoteClickAction.toParametersString().equals("Remote click " + elementDescription));
62+
Assert.isTrue(remoteClickAction.toString(new Role[0]).equals("Remote click " + elementDescription));
63+
Assert.isTrue(remoteClickAction.toString().equals("Remote click " + elementDescription));
6364

6465
// Verify that run the action invokes the remoteWebElement click event
6566
remoteClickAction.run(Mockito.mock(SUT.class), Mockito.mock(State.class), 1);
@@ -80,10 +81,11 @@ public void test_create_WdRemoteScrollClickAction() {
8081
Assert.isTrue(remoteScrollClickAction.get(Tags.OriginWidget).equals(childWdWidget));
8182
Assert.isTrue(remoteScrollClickAction.get(Tags.Role).equals(WdActionRoles.RemoteScrollClick));
8283
Assert.isTrue(remoteScrollClickAction.get(Tags.Desc).equals("Remote scroll and click " + "Widget Description"));
83-
Assert.isTrue(remoteScrollClickAction.toShortString().equals("Remote scroll and click " + childWdElement.name));
84-
Assert.isTrue(remoteScrollClickAction.toParametersString().equals("Remote scroll and click " + childWdElement.name));
85-
Assert.isTrue(remoteScrollClickAction.toString(new Role[0]).equals("Remote scroll and click " + childWdElement.name));
86-
Assert.isTrue(remoteScrollClickAction.toString().equals("Remote scroll and click " + childWdElement.name));
84+
String elementDescription = childWdElement.getElementDescription();
85+
Assert.isTrue(remoteScrollClickAction.toShortString().equals("Remote scroll and click " + elementDescription));
86+
Assert.isTrue(remoteScrollClickAction.toParametersString().equals("Remote scroll and click " + elementDescription));
87+
Assert.isTrue(remoteScrollClickAction.toString(new Role[0]).equals("Remote scroll and click " + elementDescription));
88+
Assert.isTrue(remoteScrollClickAction.toString().equals("Remote scroll and click " + elementDescription));
8789

8890
// Verify that run the action invokes the remoteWebElement click event
8991
remoteScrollClickAction.run(Mockito.mock(SUT.class), Mockito.mock(State.class), 1);
@@ -105,10 +107,11 @@ public void test_create_WdRemoteTypeAction() {
105107
Assert.isTrue(remoteTypeAction.get(Tags.OriginWidget).equals(childWdWidget));
106108
Assert.isTrue(remoteTypeAction.get(Tags.Role).equals(WdActionRoles.RemoteType));
107109
Assert.isTrue(remoteTypeAction.get(Tags.Desc).equals("Remote type " + typedText + " to widget " + "Widget Description"));
108-
Assert.isTrue(remoteTypeAction.toShortString().equals("Remote type " + typedText + " " + childWdElement.name));
109-
Assert.isTrue(remoteTypeAction.toParametersString().equals("Remote type " + typedText + " " + childWdElement.name));
110-
Assert.isTrue(remoteTypeAction.toString(new Role[0]).equals("Remote type " + typedText + " " + childWdElement.name));
111-
Assert.isTrue(remoteTypeAction.toString().equals("Remote type " + typedText + " " + childWdElement.name));
110+
String elementDescription = childWdElement.getElementDescription();
111+
Assert.isTrue(remoteTypeAction.toShortString().equals("Remote type " + typedText + " " + elementDescription));
112+
Assert.isTrue(remoteTypeAction.toParametersString().equals("Remote type " + typedText + " " + elementDescription));
113+
Assert.isTrue(remoteTypeAction.toString(new Role[0]).equals("Remote type " + typedText + " " + elementDescription));
114+
Assert.isTrue(remoteTypeAction.toString().equals("Remote type " + typedText + " " + elementDescription));
112115

113116
// Verify that run the action invokes the remoteWebElement sendKeys event
114117
remoteTypeAction.run(Mockito.mock(SUT.class), Mockito.mock(State.class), 1);
@@ -130,10 +133,11 @@ public void test_create_WdRemoteScrollTypeAction() {
130133
Assert.isTrue(remoteScrollTypeAction.get(Tags.OriginWidget).equals(childWdWidget));
131134
Assert.isTrue(remoteScrollTypeAction.get(Tags.Role).equals(WdActionRoles.RemoteScrollType));
132135
Assert.isTrue(remoteScrollTypeAction.get(Tags.Desc).equals("Remote scroll and type " + typedText + " to widget " + "Widget Description"));
133-
Assert.isTrue(remoteScrollTypeAction.toShortString().equals("Remote scroll and type " + typedText + " " + childWdElement.name));
134-
Assert.isTrue(remoteScrollTypeAction.toParametersString().equals("Remote scroll and type " + typedText + " " + childWdElement.name));
135-
Assert.isTrue(remoteScrollTypeAction.toString(new Role[0]).equals("Remote scroll and type " + typedText + " " + childWdElement.name));
136-
Assert.isTrue(remoteScrollTypeAction.toString().equals("Remote scroll and type " + typedText + " " + childWdElement.name));
136+
String elementDescription = childWdElement.getElementDescription();
137+
Assert.isTrue(remoteScrollTypeAction.toShortString().equals("Remote scroll and type " + typedText + " " + elementDescription));
138+
Assert.isTrue(remoteScrollTypeAction.toParametersString().equals("Remote scroll and type " + typedText + " " + elementDescription));
139+
Assert.isTrue(remoteScrollTypeAction.toString(new Role[0]).equals("Remote scroll and type " + typedText + " " + elementDescription));
140+
Assert.isTrue(remoteScrollTypeAction.toString().equals("Remote scroll and type " + typedText + " " + elementDescription));
137141

138142
// Verify that run the action invokes the remoteWebElement sendKeys event
139143
remoteScrollTypeAction.run(Mockito.mock(SUT.class), Mockito.mock(State.class), 1);

0 commit comments

Comments
 (0)