Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release-distribution.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
tag_name: v${{ env.GITHUB_MILESTONE }}
body: |
Release notes:
https://github.com/TESTARtool/TESTAR_dev/wiki/TESTAR-release-notes
https://github.com/TESTARtool/TESTAR_dev/blob/master/CHANGELOG

Latest W7 version (2.5.0):
https://github.com/TESTARtool/TESTAR_dev/releases/download/v2.5.0/testar_w7_2.5.0.zip
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#TESTAR v2.7.17 (5-Dec-2025)
- Add allowInvisibleElements to appium-android
- Add AndroidDisplayed Tag property


#TESTAR v2.7.16 (28-Nov-2025)
- Add AndroidCapabilitiesFactory for creating appium capabilities
- Implement AndroidRoles
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ https://github.com/TESTARtool/TESTAR_dev/wiki/Development:-Increase-Java-memory
https://github.com/TESTARtool/TESTAR_dev/issues

## Release notes
https://github.com/TESTARtool/TESTAR_dev/wiki/TESTAR-release-notes
https://github.com/TESTARtool/TESTAR_dev/blob/master/CHANGELOG

## Required tools to create a windows.dll to update UIAutomation API
https://github.com/TESTARtool/TESTAR_dev/wiki/Development:-Update-Windows-UIAutomation-(windows.dll)
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.16
2.7.17
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ Result fromJsonObject(JsonObject json) {
cap.setCapability("appium:newCommandTimeout", getInt(json, "newCommandTimeout", 600));
cap.setCapability("appium:autoGrantPermissions", getBool(json, "autoGrantPermissions", false));

cap.setCapability("appium:settings[allowInvisibleElements]", getBool(json, "allowInvisibleElements", false));

String appiumUrl = defaultAppiumUrl;

// If the APK is already installed we use appPackage identifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public class AndroidElement extends TaggableBase implements Serializable {
boolean longclicklable;
boolean password;
boolean selected;
boolean displayed;

public AndroidElement(){ this(null); }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ else if (t.equals(AndroidTags.AndroidSelected)) {
else if (t.equals(AndroidTags.AndroidAccessibilityId)) {
ret = w.element.accessibilityID;
}
else if (t.equals(AndroidTags.AndroidDisplayed)) {
ret = w.element.displayed;
}
else if (t.equals(AndroidTags.AndroidXpath)) {
ret = w.element.xPath;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/***************************************************************************************************
*
* Copyright (c) 2020 - 2022 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2020 - 2022 Open Universiteit - www.ou.nl
* Copyright (c) 2020 - 2025 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2020 - 2025 Open Universiteit - www.ou.nl
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
Expand Down Expand Up @@ -186,6 +186,7 @@ private void XmlNodeDescend(AndroidElement parent, Node xmlNode) {
childElement.password = AndroidNodeParser.getBooleanAttribute(xmlNode, "password");
childElement.selected = AndroidNodeParser.getBooleanAttribute(xmlNode, "selected");
childElement.accessibilityID = AndroidNodeParser.getStringAttribute(xmlNode, "content-desc");
childElement.displayed = AndroidNodeParser.getBooleanAttribute(xmlNode, "displayed");

childElement.rect = androidBoundsRect(AndroidNodeParser.getStringAttribute(xmlNode, "bounds"));
childElement.bounds = androidBoundsRect(AndroidNodeParser.getStringAttribute(xmlNode, "bounds"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ private AndroidTags() {}

public static final Tag<String> AndroidAccessibilityId = from("AndroidAccessibilityId", String.class);

public static final Tag<Boolean> AndroidDisplayed = from("AndroidDisplayed", Boolean.class);

public static final Tag<String> AndroidXpath = from("AndroidXpath", String.class);

public static final Tag<String> AndroidAbstractActionId = from("AndroidAbstractActionId", String.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ private void displayWidgetInfo(Widget nodeWidget) {
boolean longClickableWidget = nodeWidget.get(AndroidTags.AndroidLongClickable);
boolean scrollableWidget = nodeWidget.get(AndroidTags.AndroidScrollable);
boolean selectedWidget = nodeWidget.get(AndroidTags.AndroidSelected);
boolean displayedWidget = nodeWidget.get(AndroidTags.AndroidDisplayed);
String xpathWidget = nodeWidget.get(AndroidTags.AndroidXpath);
String activityWidget = nodeWidget.get(AndroidTags.AndroidActivity);

Expand Down Expand Up @@ -387,6 +388,9 @@ private void displayWidgetInfo(Widget nodeWidget) {
infoPaneLeft.add(new JLabel("Selected: ")).setFont(new Font("SansSerif", Font.BOLD, fontSize));
infoPaneRight.add(new JLabel(String.valueOf(selectedWidget))).setFont(new Font("SansSerif", Font.PLAIN, fontSize));

infoPaneLeft.add(new JLabel("Displayed: ")).setFont(new Font("SansSerif", Font.BOLD, fontSize));
infoPaneRight.add(new JLabel(String.valueOf(selectedWidget))).setFont(new Font("SansSerif", Font.PLAIN, fontSize));

infoPaneLeft.add(new JLabel("Current Activity: ")).setFont(new Font("SansSerif", Font.BOLD, fontSize));
infoPaneRight.add(new JLabel(String.valueOf(activityWidget))).setFont(new Font("SansSerif", Font.PLAIN, fontSize));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"app": "suts/ApiDemos-debug.apk",
"automationName" : "UiAutomator2",
"newCommandTimeout": 600,
"autoGrantPermissions": false
"autoGrantPermissions": false,
"allowInvisibleElements": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"automationName" : "UiAutomator2",
"newCommandTimeout": 600,
"autoGrantPermissions": true,
"allowInvisibleElements": false,
"isEmulatorDocker": true,
"ipAddressAppium": 10.102.0.198
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"automationName" : "UiAutomator2",
"newCommandTimeout": 600,
"autoGrantPermissions": false,
"allowInvisibleElements": false,
"isApkInstalled": true
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"app": "suts/ApiDemos-debug.apk",
"automationName" : "UiAutomator2",
"newCommandTimeout": 600,
"autoGrantPermissions": false
"autoGrantPermissions": false,
"allowInvisibleElements": false
}
2 changes: 1 addition & 1 deletion testar/src/org/testar/monkey/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@

public class Main {

public static final String TESTAR_VERSION = "v2.7.16 (28-Nov-2025)";
public static final String TESTAR_VERSION = "v2.7.17 (5-Dec-2025)";

//public static final String TESTAR_DIR_PROPERTY = "DIRNAME"; //Use the OS environment to obtain TESTAR directory
public static final String SETTINGS_FILE = "test.settings";
Expand Down
6 changes: 4 additions & 2 deletions testar/src/org/testar/protocols/AndroidProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ protected boolean isClickable(Widget w) {
return false;
}
return w.get(AndroidTags.AndroidClickable, false)
&& w.get(AndroidTags.AndroidEnabled, false);
&& w.get(AndroidTags.AndroidEnabled, false)
&& w.get(AndroidTags.AndroidDisplayed, false);
}

@Override
Expand All @@ -106,7 +107,8 @@ protected boolean isTypeable(Widget w) {
return false;
}
return w.get(AndroidTags.AndroidEnabled, false)
&& w.get(AndroidTags.AndroidFocusable, false);
&& w.get(AndroidTags.AndroidFocusable, false)
&& w.get(AndroidTags.AndroidDisplayed, false);
}

protected boolean isScrollable(Widget w) {
Expand Down
27 changes: 21 additions & 6 deletions testar/test/org/testar/protocols/TestAndroidIsClickable.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static Collection<Object[]> data() {
@Parameterized.Parameter
public Role role;

private WidgetStub createWidget(Role role, boolean clickable, boolean enabled) {
private WidgetStub createWidget(Role role, boolean clickable, boolean enabled, boolean displayed) {
StateStub state = new StateStub();
WidgetStub widget = new WidgetStub();
state.addChild(widget);
Expand All @@ -59,40 +59,55 @@ private WidgetStub createWidget(Role role, boolean clickable, boolean enabled) {
widget.set(Tags.Role, role);
widget.set(AndroidTags.AndroidClickable, clickable);
widget.set(AndroidTags.AndroidEnabled, enabled);
widget.set(AndroidTags.AndroidDisplayed, displayed);

return widget;
}

@Test
public void isClickableRole() {
WidgetStub widget = createWidget(role, true, true);
WidgetStub widget = createWidget(role, true, true, true);
assertTrue("Expected clickable for role: " + role, androidProtocol.isClickable(widget));
}

@Test
public void notClickableRoleWhenClickableFalse() {
WidgetStub widget = createWidget(role, false, true);
WidgetStub widget = createWidget(role, false, true, true);
assertFalse("Expected NOT clickable when AndroidClickable=false for role: " + role,
androidProtocol.isClickable(widget));
}

@Test
public void notClickableRoleWhenDisabled() {
WidgetStub widget = createWidget(role, true, false);
WidgetStub widget = createWidget(role, true, false, true);
assertFalse("Expected NOT clickable when AndroidEnabled=false for role: " + role,
androidProtocol.isClickable(widget));
}

@Test
public void notClickableRoleWhenNotDisplayed() {
WidgetStub widget = createWidget(role, true, true, false);
assertFalse("Expected NOT clickable when AndroidDisplayed=false for role: " + role,
androidProtocol.isClickable(widget));
}

@Test
public void notClickableRoleWhenClickableFalseAndDisabled() {
WidgetStub widget = createWidget(role, false, false);
WidgetStub widget = createWidget(role, false, false, true);
assertFalse("Expected NOT clickable when AndroidClickable=false & AndroidEnabled=false for role: " + role,
androidProtocol.isClickable(widget));
}

@Test
public void notClickableRoleWhenClickableFalseDisabledAndNotDisplayed() {
WidgetStub widget = createWidget(role, false, false, false);
assertFalse("Expected NOT clickable when AndroidClickable=false, AndroidEnabled=false & AndroidDisplayed=false for role: " + role,
androidProtocol.isClickable(widget));
}

@Test
public void roleIsNotClickable() {
WidgetStub widget = createWidget(AndroidRoles.AndroidEditText, true, true);
WidgetStub widget = createWidget(AndroidRoles.AndroidEditText, true, true, true);
assertFalse("Expected NOT clickable for role: " + AndroidRoles.AndroidEditText, androidProtocol.isClickable(widget));
}

Expand Down
29 changes: 22 additions & 7 deletions testar/test/org/testar/protocols/TestAndroidIsTypeable.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static Collection<Object[]> data() {
@Parameterized.Parameter
public Role role;

private WidgetStub createWidget(Role role, boolean focusable, boolean enabled) {
private WidgetStub createWidget(Role role, boolean focusable, boolean enabled, boolean displayed) {
StateStub state = new StateStub();
WidgetStub widget = new WidgetStub();
state.addChild(widget);
Expand All @@ -59,40 +59,55 @@ private WidgetStub createWidget(Role role, boolean focusable, boolean enabled) {
widget.set(Tags.Role, role);
widget.set(AndroidTags.AndroidFocusable, focusable);
widget.set(AndroidTags.AndroidEnabled, enabled);
widget.set(AndroidTags.AndroidDisplayed, displayed);

return widget;
}

@Test
public void isTypeableRole() {
WidgetStub widget = createWidget(role, true, true);
WidgetStub widget = createWidget(role, true, true, true);
assertTrue("Expected typeable for role: " + role, androidProtocol.isTypeable(widget));
}

@Test
public void notTypeableRoleWhenFocusableFalse() {
WidgetStub widget = createWidget(role, false, true);
WidgetStub widget = createWidget(role, false, true, true);
assertFalse("Expected NOT typeable when AndroidFocusable=false for role: " + role,
androidProtocol.isTypeable(widget));
}

@Test
public void notTypeableRoleWhenDisabled() {
WidgetStub widget = createWidget(role, true, false);
WidgetStub widget = createWidget(role, true, false, true);
assertFalse("Expected NOT typeable when AndroidEnabled=false for role: " + role,
androidProtocol.isTypeable(widget));
}

@Test
public void notTypeableRoleWhenNotDisplayed() {
WidgetStub widget = createWidget(role, true, true, false);
assertFalse("Expected NOT typeable when AndroidDisplayed=false for role: " + role,
androidProtocol.isTypeable(widget));
}

@Test
public void notTypeableRoleWhenFocusableFalseAndDisabled() {
WidgetStub widget = createWidget(role, false, false);
assertFalse("Expected NOT typebale when AndroidFocusable=false & AndroidEnabled=false for role: " + role,
WidgetStub widget = createWidget(role, false, false, true);
assertFalse("Expected NOT typeable when AndroidFocusable=false & AndroidEnabled=false for role: " + role,
androidProtocol.isTypeable(widget));
}

@Test
public void notTypeableRoleWhenFocusableFalseDisabledAndNotDisplayed() {
WidgetStub widget = createWidget(role, false, false, false);
assertFalse("Expected NOT typeable when AndroidFocusable=false, AndroidEnabled=false & AndroidDisplayed=false for role: " + role,
androidProtocol.isTypeable(widget));
}

@Test
public void roleIsNotTypeable() {
WidgetStub widget = createWidget(AndroidRoles.AndroidButton, true, true);
WidgetStub widget = createWidget(AndroidRoles.AndroidButton, true, true, true);
assertFalse("Expected NOT typeable for role: " + AndroidRoles.AndroidButton, androidProtocol.isTypeable(widget));
}

Expand Down