From 0d2bc327c996191343a8b0f67426e6656bbb91d9 Mon Sep 17 00:00:00 2001 From: ferpasri Date: Mon, 1 Dec 2025 12:17:34 +0100 Subject: [PATCH 1/4] Add allowInvisibleElements appium setting --- .../monkey/alayer/android/AndroidCapabilitiesFactory.java | 2 ++ .../settings/android_generic/DesiredCapabilities.json | 3 ++- .../android_generic/DesiredCapabilitiesDockerEmulator.json | 1 + .../settings/android_generic/DesiredCapabilitiesInstalled.json | 1 + .../DesiredCapabilities.json | 3 ++- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/android/src/org/testar/monkey/alayer/android/AndroidCapabilitiesFactory.java b/android/src/org/testar/monkey/alayer/android/AndroidCapabilitiesFactory.java index df4dd2bce..aff154c6e 100644 --- a/android/src/org/testar/monkey/alayer/android/AndroidCapabilitiesFactory.java +++ b/android/src/org/testar/monkey/alayer/android/AndroidCapabilitiesFactory.java @@ -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 diff --git a/testar/resources/settings/android_generic/DesiredCapabilities.json b/testar/resources/settings/android_generic/DesiredCapabilities.json index 0e0c0e883..fd52a6b6d 100644 --- a/testar/resources/settings/android_generic/DesiredCapabilities.json +++ b/testar/resources/settings/android_generic/DesiredCapabilities.json @@ -4,5 +4,6 @@ "app": "suts/ApiDemos-debug.apk", "automationName" : "UiAutomator2", "newCommandTimeout": 600, - "autoGrantPermissions": false + "autoGrantPermissions": false, + "allowInvisibleElements": false } diff --git a/testar/resources/settings/android_generic/DesiredCapabilitiesDockerEmulator.json b/testar/resources/settings/android_generic/DesiredCapabilitiesDockerEmulator.json index c0ecc2bb1..cf4d1f2da 100644 --- a/testar/resources/settings/android_generic/DesiredCapabilitiesDockerEmulator.json +++ b/testar/resources/settings/android_generic/DesiredCapabilitiesDockerEmulator.json @@ -5,6 +5,7 @@ "automationName" : "UiAutomator2", "newCommandTimeout": 600, "autoGrantPermissions": true, + "allowInvisibleElements": false, "isEmulatorDocker": true, "ipAddressAppium": 10.102.0.198 } diff --git a/testar/resources/settings/android_generic/DesiredCapabilitiesInstalled.json b/testar/resources/settings/android_generic/DesiredCapabilitiesInstalled.json index f1c187ddf..b7d753aa6 100644 --- a/testar/resources/settings/android_generic/DesiredCapabilitiesInstalled.json +++ b/testar/resources/settings/android_generic/DesiredCapabilitiesInstalled.json @@ -6,5 +6,6 @@ "automationName" : "UiAutomator2", "newCommandTimeout": 600, "autoGrantPermissions": false, + "allowInvisibleElements": false, "isApkInstalled": true } diff --git a/testar/resources/workflow/settings/test_gradle_workflow_android_generic/DesiredCapabilities.json b/testar/resources/workflow/settings/test_gradle_workflow_android_generic/DesiredCapabilities.json index e4e253cbb..e2131e06b 100644 --- a/testar/resources/workflow/settings/test_gradle_workflow_android_generic/DesiredCapabilities.json +++ b/testar/resources/workflow/settings/test_gradle_workflow_android_generic/DesiredCapabilities.json @@ -4,5 +4,6 @@ "app": "suts/ApiDemos-debug.apk", "automationName" : "UiAutomator2", "newCommandTimeout": 600, - "autoGrantPermissions": false + "autoGrantPermissions": false, + "allowInvisibleElements": false } From c443144573c64e372261b7142448b553d55956ec Mon Sep 17 00:00:00 2001 From: ferpasri Date: Mon, 1 Dec 2025 12:18:39 +0100 Subject: [PATCH 2/4] Add android is displayed logic --- .../org/testar/monkey/alayer/android/AndroidElement.java | 1 + .../src/org/testar/monkey/alayer/android/AndroidState.java | 3 +++ .../testar/monkey/alayer/android/AndroidStateFetcher.java | 5 +++-- .../org/testar/monkey/alayer/android/enums/AndroidTags.java | 2 ++ .../android/spy_visualization/TreeVisualizationAndroid.java | 4 ++++ testar/src/org/testar/protocols/AndroidProtocol.java | 6 ++++-- 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/android/src/org/testar/monkey/alayer/android/AndroidElement.java b/android/src/org/testar/monkey/alayer/android/AndroidElement.java index 4b2290cbd..493ae00e2 100644 --- a/android/src/org/testar/monkey/alayer/android/AndroidElement.java +++ b/android/src/org/testar/monkey/alayer/android/AndroidElement.java @@ -78,6 +78,7 @@ public class AndroidElement extends TaggableBase implements Serializable { boolean longclicklable; boolean password; boolean selected; + boolean displayed; public AndroidElement(){ this(null); } diff --git a/android/src/org/testar/monkey/alayer/android/AndroidState.java b/android/src/org/testar/monkey/alayer/android/AndroidState.java index 876dfd7bb..69bc35db6 100644 --- a/android/src/org/testar/monkey/alayer/android/AndroidState.java +++ b/android/src/org/testar/monkey/alayer/android/AndroidState.java @@ -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; } diff --git a/android/src/org/testar/monkey/alayer/android/AndroidStateFetcher.java b/android/src/org/testar/monkey/alayer/android/AndroidStateFetcher.java index 5eeb4e12c..fc66933ca 100644 --- a/android/src/org/testar/monkey/alayer/android/AndroidStateFetcher.java +++ b/android/src/org/testar/monkey/alayer/android/AndroidStateFetcher.java @@ -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: @@ -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")); diff --git a/android/src/org/testar/monkey/alayer/android/enums/AndroidTags.java b/android/src/org/testar/monkey/alayer/android/enums/AndroidTags.java index 2047823d7..77b02b648 100644 --- a/android/src/org/testar/monkey/alayer/android/enums/AndroidTags.java +++ b/android/src/org/testar/monkey/alayer/android/enums/AndroidTags.java @@ -74,6 +74,8 @@ private AndroidTags() {} public static final Tag AndroidAccessibilityId = from("AndroidAccessibilityId", String.class); + public static final Tag AndroidDisplayed = from("AndroidDisplayed", Boolean.class); + public static final Tag AndroidXpath = from("AndroidXpath", String.class); public static final Tag AndroidAbstractActionId = from("AndroidAbstractActionId", String.class); diff --git a/android/src/org/testar/monkey/alayer/android/spy_visualization/TreeVisualizationAndroid.java b/android/src/org/testar/monkey/alayer/android/spy_visualization/TreeVisualizationAndroid.java index 2d97a9388..745b82ec7 100644 --- a/android/src/org/testar/monkey/alayer/android/spy_visualization/TreeVisualizationAndroid.java +++ b/android/src/org/testar/monkey/alayer/android/spy_visualization/TreeVisualizationAndroid.java @@ -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); @@ -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)); diff --git a/testar/src/org/testar/protocols/AndroidProtocol.java b/testar/src/org/testar/protocols/AndroidProtocol.java index 1ac135ca2..196cfbe7c 100644 --- a/testar/src/org/testar/protocols/AndroidProtocol.java +++ b/testar/src/org/testar/protocols/AndroidProtocol.java @@ -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 @@ -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) { From 10f16faad837ffb9993232d7c7b916e02cba0583 Mon Sep 17 00:00:00 2001 From: ferpasri Date: Mon, 1 Dec 2025 19:37:00 +0100 Subject: [PATCH 3/4] Adapt clickable and typeable tests --- .../protocols/TestAndroidIsClickable.java | 27 +++++++++++++---- .../protocols/TestAndroidIsTypeable.java | 29 ++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/testar/test/org/testar/protocols/TestAndroidIsClickable.java b/testar/test/org/testar/protocols/TestAndroidIsClickable.java index 5a5720f1c..4f6eb8efe 100644 --- a/testar/test/org/testar/protocols/TestAndroidIsClickable.java +++ b/testar/test/org/testar/protocols/TestAndroidIsClickable.java @@ -50,7 +50,7 @@ public static Collection 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); @@ -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)); } diff --git a/testar/test/org/testar/protocols/TestAndroidIsTypeable.java b/testar/test/org/testar/protocols/TestAndroidIsTypeable.java index a02ba8d87..6aad43500 100644 --- a/testar/test/org/testar/protocols/TestAndroidIsTypeable.java +++ b/testar/test/org/testar/protocols/TestAndroidIsTypeable.java @@ -50,7 +50,7 @@ public static Collection 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); @@ -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)); } From 2a3a697409135b9c615e6e74db9d91486c56caab Mon Sep 17 00:00:00 2001 From: ferpasri Date: Mon, 1 Dec 2025 19:50:06 +0100 Subject: [PATCH 4/4] Update changelog links and versions --- .github/workflows/release-distribution.yml | 2 +- CHANGELOG | 5 +++++ README.md | 2 +- VERSION | 2 +- testar/src/org/testar/monkey/Main.java | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-distribution.yml b/.github/workflows/release-distribution.yml index f5ce20dfb..879c893e4 100644 --- a/.github/workflows/release-distribution.yml +++ b/.github/workflows/release-distribution.yml @@ -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 diff --git a/CHANGELOG b/CHANGELOG index 621a343e6..286d80126 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/README.md b/README.md index 0bac7ba0f..75add0464 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/VERSION b/VERSION index 1ab525692..addd93e5d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.7.16 \ No newline at end of file +2.7.17 \ No newline at end of file diff --git a/testar/src/org/testar/monkey/Main.java b/testar/src/org/testar/monkey/Main.java index ac1febeaf..3ce08281f 100644 --- a/testar/src/org/testar/monkey/Main.java +++ b/testar/src/org/testar/monkey/Main.java @@ -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";