calabash-android 0.4.22.pre4 → 0.5.0.pre1
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.
- checksums.yaml +4 -4
- data/bin/calabash-android +66 -45
- data/lib/calabash-android/calabash_steps.rb +0 -8
- data/lib/calabash-android/canned_steps.md +2 -30
- data/lib/calabash-android/lib/TestServer.apk +0 -0
- data/lib/calabash-android/operations.rb +199 -23
- data/lib/calabash-android/removed_actions.txt +52 -0
- data/lib/calabash-android/steps/assert_steps.rb +9 -24
- data/lib/calabash-android/steps/check_box_steps.rb +2 -2
- data/lib/calabash-android/steps/context_menu_steps.rb +11 -4
- data/lib/calabash-android/steps/date_picker_steps.rb +2 -2
- data/lib/calabash-android/steps/enter_text_steps.rb +13 -13
- data/lib/calabash-android/steps/l10n_steps.rb +5 -5
- data/lib/calabash-android/steps/map_steps.rb +12 -12
- data/lib/calabash-android/steps/navigation_steps.rb +12 -12
- data/lib/calabash-android/steps/press_button_steps.rb +16 -12
- data/lib/calabash-android/steps/progress_steps.rb +19 -22
- data/lib/calabash-android/steps/search_steps.rb +2 -2
- data/lib/calabash-android/steps/spinner_steps.rb +10 -2
- data/lib/calabash-android/steps/time_picker_steps.rb +2 -2
- data/lib/calabash-android/version.rb +1 -1
- data/lib/calabash-android/wait_helpers.rb +29 -1
- data/test-server/instrumentation-backend/antlr/UIQuery.g +11 -11
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/CalabashInstrumentationTestRunner.java +3 -2
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/InstrumentationBackend.java +9 -4
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java +16 -12
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/application/Backdoor.java +55 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/LongPressCoordinate.java +19 -2
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptExecuter.java +105 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +27 -30
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java +27 -18
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/ComparisonOperator.java +7 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTPredicate.java +16 -4
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTWith.java +13 -6
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryUtils.java +94 -48
- metadata +5 -59
- data/lib/calabash-android/steps/additions_manual_steps.rb +0 -11
- data/lib/calabash-android/steps/app_steps.rb +0 -10
- data/lib/calabash-android/steps/list_steps.rb +0 -41
- data/lib/calabash-android/steps/rotation_steps.rb +0 -7
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonNumber.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonText.java +0 -27
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressImageButtonDescription.java +0 -39
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressImageButtonNumber.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/WaitForButton.java +0 -47
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/checkbox/ToggleCheckboxNumber.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressText.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuById.java +0 -26
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuByIndex.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuByText.java +0 -26
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/helpers/InspectCurrentDialog.java +0 -76
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListData.java +0 -85
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemProperties.java +0 -194
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemText.java +0 -136
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/LongPressListItems.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/PressListItems.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/scrolling/ScrollDown.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/scrolling/ScrollUp.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/search/EnterQueryByIndex.java +0 -29
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/SelectFromMenuByText.java +0 -24
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/GetSelectedSpinnerItemText.java +0 -36
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/SelectSpinnerItemByContentDescription.java +0 -43
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertGridViewContainsNoDuplicates.java +0 -72
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertText.java +0 -31
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertTextOfSpecificTextViewByContentDescription.java +0 -32
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextById.java +0 -30
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextByIndex.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextFieldByContentDescription.java +0 -33
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClickOnText.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextByContentDescription.java +0 -32
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextById.java +0 -33
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextByIndex.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/GetTextById.java +0 -42
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/AssertViewProperty.java +0 -141
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewByDescription.java +0 -46
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewById.java +0 -56
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetViewProperty.java +0 -101
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/HasView.java +0 -31
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/IsEnabled.java +0 -30
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/LongPressOnViewById.java +0 -34
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/Press.java +0 -89
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/SelectTab.java +0 -110
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/Wait.java +0 -24
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForDialogClose.java +0 -21
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForProgress.java +0 -47
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForScreen.java +0 -54
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForTab.java +0 -108
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForText.java +0 -37
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForView.java +0 -43
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForViewById.java +0 -58
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptOperation.java +0 -44
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/PressByCssSelector.java +0 -70
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetText.java +0 -64
|
@@ -11,58 +11,55 @@ import java.util.Map;
|
|
|
11
11
|
import sh.calaba.instrumentationbackend.InstrumentationBackend;
|
|
12
12
|
import sh.calaba.instrumentationbackend.actions.webview.CalabashChromeClient.WebFuture;
|
|
13
13
|
import sh.calaba.org.codehaus.jackson.map.ObjectMapper;
|
|
14
|
+
|
|
15
|
+
import android.os.Build;
|
|
14
16
|
import android.util.Log;
|
|
15
17
|
import android.webkit.ValueCallback;
|
|
16
18
|
import android.webkit.WebView;
|
|
17
19
|
|
|
18
20
|
public class QueryHelper {
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
|
|
21
23
|
@SuppressWarnings("unchecked")
|
|
22
24
|
public static Map<String, Object> findFirstVisibleRectangle(List<HashMap<String,Object>> elements) {
|
|
23
|
-
return (Map<String, Object>)findFirstVisibleElement(elements).get("rect");
|
|
25
|
+
return (Map<String, Object>)findFirstVisibleElement(elements).get("rect");
|
|
24
26
|
}
|
|
25
|
-
|
|
27
|
+
|
|
26
28
|
public static Map<String, Object> findFirstVisibleElement(List<HashMap<String,Object>> elements) {
|
|
27
29
|
//TODO: Should do something more intelligent
|
|
28
|
-
return (Map<String, Object>)elements.get(0);
|
|
30
|
+
return (Map<String, Object>)elements.get(0);
|
|
29
31
|
}
|
|
30
|
-
|
|
32
|
+
|
|
31
33
|
public static float translateCoordToScreen(int offset, float scale, Object point) {
|
|
32
34
|
return offset + ((Number)point).floatValue() *scale;
|
|
33
35
|
}
|
|
34
|
-
|
|
35
|
-
public static Map<String,
|
|
36
|
+
|
|
37
|
+
public static Map<String, Integer> translateRectToScreenCoordinates(WebView webView, Map<String, Integer> rectangle) {
|
|
36
38
|
try {
|
|
37
|
-
|
|
38
39
|
float scale = webView.getScale();
|
|
39
40
|
|
|
40
41
|
int[] webviewLocation = new int[2];
|
|
41
42
|
webView.getLocationOnScreen(webviewLocation);
|
|
42
43
|
//center_x, center_y
|
|
43
44
|
//left, top, width, height
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
result.put("
|
|
54
|
-
result.put("
|
|
55
|
-
|
|
56
|
-
result.put("center_y",center_y);
|
|
57
|
-
|
|
45
|
+
int center_x = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("center_x"));
|
|
46
|
+
int center_y = (int)translateCoordToScreen(webviewLocation[1], scale, rectangle.get("center_y"));
|
|
47
|
+
|
|
48
|
+
int x = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("left"));
|
|
49
|
+
int y = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("top"));
|
|
50
|
+
Map<String,Integer> result = new HashMap<String, Integer>(rectangle);
|
|
51
|
+
|
|
52
|
+
result.put("x", x);
|
|
53
|
+
result.put("y", y);
|
|
54
|
+
result.put("center_x", center_x);
|
|
55
|
+
result.put("center_y", center_y);
|
|
56
|
+
|
|
58
57
|
return result;
|
|
59
|
-
|
|
60
|
-
|
|
61
58
|
} catch (Exception e) {
|
|
62
59
|
throw new RuntimeException(e);
|
|
63
60
|
}
|
|
64
61
|
}
|
|
65
|
-
|
|
62
|
+
|
|
66
63
|
public static String toJsonString(Object o) {
|
|
67
64
|
//http://www.mkyong.com/java/how-to-convert-java-map-to-from-json-jackson/
|
|
68
65
|
try {
|
|
@@ -71,7 +68,7 @@ public class QueryHelper {
|
|
|
71
68
|
throw new RuntimeException(e);
|
|
72
69
|
}
|
|
73
70
|
}
|
|
74
|
-
|
|
71
|
+
|
|
75
72
|
|
|
76
73
|
private static String readJavascriptFromAsset(String scriptPath) {
|
|
77
74
|
StringBuffer script = new StringBuffer();
|
|
@@ -88,7 +85,7 @@ public class QueryHelper {
|
|
|
88
85
|
}
|
|
89
86
|
return script.toString();
|
|
90
87
|
}
|
|
91
|
-
|
|
88
|
+
|
|
92
89
|
public static WebFuture executeAsyncJavascriptInWebviews(WebView webView,
|
|
93
90
|
String scriptPath, String selector, String type) {
|
|
94
91
|
|
|
@@ -99,12 +96,12 @@ public class QueryHelper {
|
|
|
99
96
|
|
|
100
97
|
CalabashChromeClient chromeClient = CalabashChromeClient.prepareWebView(webView);
|
|
101
98
|
|
|
102
|
-
if (
|
|
103
|
-
|
|
99
|
+
if (Build.VERSION.SDK_INT < 19) { // Android 4.4
|
|
100
|
+
JavaScriptExecuter javaScriptExecuter = new JavaScriptExecuter(webView);
|
|
101
|
+
javaScriptExecuter.executeJavaScript("calabash_result = " + script + ";prompt('calabash:' + calabash_result);");
|
|
104
102
|
} else {
|
|
105
103
|
chromeClient.evaluateCalabashScript(script);
|
|
106
104
|
}
|
|
107
|
-
|
|
108
105
|
return chromeClient.getResult();
|
|
109
106
|
}
|
|
110
107
|
}
|
data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java
CHANGED
|
@@ -15,17 +15,18 @@ import android.widget.TextView;
|
|
|
15
15
|
public class ViewMapper {
|
|
16
16
|
|
|
17
17
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
18
|
-
public static Object extractDataFromView(View v) {
|
|
19
|
-
|
|
18
|
+
public static Object extractDataFromView(View v) {
|
|
19
|
+
|
|
20
20
|
Map data = new HashMap();
|
|
21
|
-
data.put("class", getClassNameForView(v));
|
|
21
|
+
data.put("class", getClassNameForView(v));
|
|
22
22
|
data.put("description", v.toString());
|
|
23
23
|
data.put("contentDescription", getContentDescriptionForView(v));
|
|
24
24
|
data.put("enabled", v.isEnabled());
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
data.put("id", getIdForView(v));
|
|
27
|
+
data.put("tag", getTagForView(v));
|
|
27
28
|
|
|
28
|
-
Map rect = getRectForView(v);
|
|
29
|
+
Map<String,Integer> rect = getRectForView(v);
|
|
29
30
|
|
|
30
31
|
data.put("rect", rect);
|
|
31
32
|
|
|
@@ -45,19 +46,20 @@ public class ViewMapper {
|
|
|
45
46
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
public static Map<String, Integer> getRectForView(View v) {
|
|
50
|
+
Map<String,Integer> rect = new HashMap<String,Integer>();
|
|
50
51
|
int[] location = new int[2];
|
|
51
52
|
v.getLocationOnScreen(location);
|
|
52
53
|
|
|
53
54
|
rect.put("x", location[0]);
|
|
54
55
|
rect.put("y", location[1]);
|
|
55
|
-
|
|
56
|
-
rect.put("center_x", location[0] + v.getWidth()/2.0);
|
|
57
|
-
rect.put("center_y", location[1] + v.getHeight()/2.0);
|
|
58
|
-
|
|
56
|
+
|
|
57
|
+
rect.put("center_x", (int)(location[0] + v.getWidth()/2.0));
|
|
58
|
+
rect.put("center_y", (int)(location[1] + v.getHeight()/2.0));
|
|
59
|
+
|
|
59
60
|
rect.put("width", v.getWidth());
|
|
60
61
|
rect.put("height", v.getHeight());
|
|
62
|
+
|
|
61
63
|
return rect;
|
|
62
64
|
}
|
|
63
65
|
|
|
@@ -82,26 +84,33 @@ public class ViewMapper {
|
|
|
82
84
|
return id;
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
public static String getTagForView(View v) {
|
|
88
|
+
if (v.getTag() instanceof String || v.getTag() instanceof Integer) {
|
|
89
|
+
return v.getTag().toString();
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
85
94
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
86
95
|
public static Object mapView(Object o) {
|
|
87
96
|
if (o instanceof View) {
|
|
88
97
|
return extractDataFromView((View) o);
|
|
89
|
-
}
|
|
90
|
-
else if (o instanceof Map) {
|
|
91
|
-
Map copy = new HashMap();
|
|
98
|
+
}
|
|
99
|
+
else if (o instanceof Map) {
|
|
100
|
+
Map copy = new HashMap();
|
|
92
101
|
for (Object e : ((Map) o).entrySet()) {
|
|
93
102
|
Map.Entry entry = (Entry) e;
|
|
94
103
|
Object value = entry.getValue();
|
|
95
104
|
if (value instanceof View) {
|
|
96
105
|
copy.put(entry.getKey(), UIQueryUtils.getId((View) value));
|
|
97
|
-
}
|
|
106
|
+
}
|
|
98
107
|
else {
|
|
99
108
|
copy.put(entry.getKey(),entry.getValue());
|
|
100
|
-
}
|
|
109
|
+
}
|
|
101
110
|
}
|
|
102
|
-
|
|
111
|
+
|
|
103
112
|
return copy;
|
|
104
|
-
}
|
|
113
|
+
}
|
|
105
114
|
else if (o instanceof CharSequence) {
|
|
106
115
|
return o.toString();
|
|
107
116
|
}
|
|
@@ -25,7 +25,13 @@ public enum ComparisonOperator implements UIQueryASTPredicateRelation {
|
|
|
25
25
|
if (firstValue == secondValue) {
|
|
26
26
|
return true;
|
|
27
27
|
}
|
|
28
|
-
return (firstValue != null) && firstValue.equals(secondValue);
|
|
28
|
+
return (firstValue != null) && firstValue.equals(secondValue);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
NOTEQUAL {
|
|
33
|
+
public boolean areRelated(Object firstValue, Object secondValue) {
|
|
34
|
+
return !EQUAL.areRelated(firstValue, secondValue);
|
|
29
35
|
}
|
|
30
36
|
},
|
|
31
37
|
|
|
@@ -80,6 +80,16 @@ public class UIQueryASTPredicate implements UIQueryAST {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
// there's no tag property for non Views, handle them all here
|
|
84
|
+
if (this.propertyName.equals("tag")) {
|
|
85
|
+
String tag = (o instanceof View ? UIQueryUtils.getTag((View) o) : null);
|
|
86
|
+
if (this.relation.areRelated(tag, this.valueToMatch)) {
|
|
87
|
+
return o;
|
|
88
|
+
} else {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
83
93
|
Method propertyAccessor = UIQueryUtils
|
|
84
94
|
.hasProperty(o, this.propertyName);
|
|
85
95
|
if (propertyAccessor == null) {
|
|
@@ -90,8 +100,8 @@ public class UIQueryASTPredicate implements UIQueryAST {
|
|
|
90
100
|
if (this.relation.areRelated(value, this.valueToMatch)) {
|
|
91
101
|
return o;
|
|
92
102
|
} else if (this.valueToMatch instanceof String
|
|
93
|
-
|
|
94
|
-
|
|
103
|
+
&& value != null
|
|
104
|
+
&& this.relation.areRelated(value.toString(), this.valueToMatch)) {
|
|
95
105
|
return o;
|
|
96
106
|
} else {
|
|
97
107
|
return null;
|
|
@@ -109,7 +119,7 @@ public class UIQueryASTPredicate implements UIQueryAST {
|
|
|
109
119
|
return new UIQueryASTPredicate(prop.getText(),
|
|
110
120
|
UIQueryASTPredicate.parseRelation(rel),
|
|
111
121
|
UIQueryUtils.parseValue(val));
|
|
112
|
-
|
|
122
|
+
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
private static UIQueryASTPredicateRelation parseRelation(CommonTree rel) {
|
|
@@ -120,7 +130,7 @@ public class UIQueryASTPredicate implements UIQueryAST {
|
|
|
120
130
|
caseSensitive = false;
|
|
121
131
|
relText = relText.substring(0,relText.length() - CASE_INSENSITIVE_SPEC.length());
|
|
122
132
|
}
|
|
123
|
-
|
|
133
|
+
|
|
124
134
|
if ("BEGINSWITH".equals(relText)) {
|
|
125
135
|
return new BeginsWithRelation(caseSensitive);
|
|
126
136
|
} else if ("ENDSWITH".equals(relText)) {
|
|
@@ -139,6 +149,8 @@ public class UIQueryASTPredicate implements UIQueryAST {
|
|
|
139
149
|
return ComparisonOperator.GREATERTHAN;
|
|
140
150
|
} else if (">=".equals(relText)) {
|
|
141
151
|
return ComparisonOperator.GREATERTHANOREQUAL;
|
|
152
|
+
} else if ("!=".equals(relText) || "<>".equals(relText)) {
|
|
153
|
+
return ComparisonOperator.NOTEQUAL;
|
|
142
154
|
} else {
|
|
143
155
|
throw new IllegalStateException("Unsupported Relation: " + relText);
|
|
144
156
|
}
|
|
@@ -63,13 +63,13 @@ public class UIQueryASTWith implements UIQueryAST {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return new PartialFutureList(visibilityFilteredResults);
|
|
66
|
+
|
|
67
|
+
return new PartialFutureList(futureResult);
|
|
69
68
|
}
|
|
70
69
|
});
|
|
71
70
|
|
|
72
|
-
List processedResult = new ArrayList(queryResult.size());
|
|
71
|
+
final List processedResult = new ArrayList(queryResult.size());
|
|
72
|
+
|
|
73
73
|
for (Object o : queryResult) {
|
|
74
74
|
if (o instanceof Map) {
|
|
75
75
|
Map m = (Map) o;
|
|
@@ -85,9 +85,16 @@ public class UIQueryASTWith implements UIQueryAST {
|
|
|
85
85
|
processedResult.add(o);
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
return processedResult;
|
|
89
|
-
|
|
90
88
|
|
|
89
|
+
List visibilityFilteredResults = (List) UIQueryUtils.evaluateSyncInMainThread(new Callable() {
|
|
90
|
+
|
|
91
|
+
@Override
|
|
92
|
+
public Object call() throws Exception {
|
|
93
|
+
return visibility.evaluateWithViews(processedResult, direction, visibility);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return visibilityFilteredResults;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
private boolean isDomQuery() {
|
|
@@ -30,6 +30,7 @@ import sh.calaba.org.codehaus.jackson.type.TypeReference;
|
|
|
30
30
|
import android.text.InputType;
|
|
31
31
|
import android.util.Log;
|
|
32
32
|
import android.view.View;
|
|
33
|
+
import android.view.ViewParent;
|
|
33
34
|
import android.webkit.WebView;
|
|
34
35
|
import android.widget.Button;
|
|
35
36
|
import android.widget.CheckBox;
|
|
@@ -47,7 +48,7 @@ public class UIQueryUtils {
|
|
|
47
48
|
|
|
48
49
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
49
50
|
public static List subviews(Object o) {
|
|
50
|
-
|
|
51
|
+
|
|
51
52
|
try {
|
|
52
53
|
Method getChild = o.getClass().getMethod("getChildAt", int.class);
|
|
53
54
|
getChild.setAccessible(true);
|
|
@@ -74,15 +75,15 @@ public class UIQueryUtils {
|
|
|
74
75
|
|
|
75
76
|
@SuppressWarnings({ "rawtypes" })
|
|
76
77
|
public static Future webViewSubViews(WebView o) {
|
|
77
|
-
|
|
78
|
+
|
|
78
79
|
Log.i("Calabash", "About to webViewSubViews");
|
|
79
|
-
|
|
80
|
+
|
|
80
81
|
|
|
81
82
|
WebFuture controls = QueryHelper.executeAsyncJavascriptInWebviews(o,
|
|
82
83
|
"calabash.js", "input,button","css");
|
|
83
|
-
|
|
84
|
+
|
|
84
85
|
return controls;
|
|
85
|
-
|
|
86
|
+
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
@@ -168,18 +169,44 @@ public class UIQueryUtils {
|
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
public static boolean isVisible(Object v) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
if (v instanceof Map) {
|
|
173
|
+
Map map = (Map)v;
|
|
174
|
+
Map<String,Integer> viewRect = (Map<String,Integer>)map.get("rect");
|
|
175
|
+
Map<String,Integer> parentViewRec = ViewMapper.getRectForView((WebView)map.get("webView"));
|
|
175
176
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
return isViewSufficientlyShown(viewRect, parentViewRec);
|
|
178
|
+
} else if (v instanceof View) {
|
|
179
|
+
View view = (View) v;
|
|
179
180
|
|
|
180
|
-
|
|
181
|
+
if (view.getHeight() == 0 || view.getWidth() == 0) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return view.isShown() && isViewSufficientlyShown(view);
|
|
186
|
+
} else {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
181
189
|
}
|
|
182
190
|
|
|
191
|
+
public static boolean isViewSufficientlyShown(Map<String,Integer> viewRect, Map<String,Integer> parentViewRect) {
|
|
192
|
+
int centerX = viewRect.get("center_x");
|
|
193
|
+
int centerY = viewRect.get("center_y");
|
|
194
|
+
|
|
195
|
+
int parentX = parentViewRect.get("x");
|
|
196
|
+
int parentY = parentViewRect.get("y");
|
|
197
|
+
int parentWidth = parentViewRect.get("width");
|
|
198
|
+
int parentHeight = parentViewRect.get("height");
|
|
199
|
+
int windowWidth = parentX + parentWidth;
|
|
200
|
+
int windowHeight = parentY + parentHeight;
|
|
201
|
+
|
|
202
|
+
return (windowWidth > centerX && parentX < centerX &&
|
|
203
|
+
windowHeight > centerY && parentY < centerY);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public static boolean isViewSufficientlyShown(View view) {
|
|
207
|
+
return isViewSufficientlyShown(view, view.getParent());
|
|
208
|
+
}
|
|
209
|
+
|
|
183
210
|
public static boolean isClickable(Object v) {
|
|
184
211
|
if (!(v instanceof View)) {
|
|
185
212
|
return true;
|
|
@@ -193,6 +220,10 @@ public class UIQueryUtils {
|
|
|
193
220
|
return ViewMapper.getIdForView(view);
|
|
194
221
|
}
|
|
195
222
|
|
|
223
|
+
public static String getTag(View view) {
|
|
224
|
+
return ViewMapper.getTagForView(view);
|
|
225
|
+
}
|
|
226
|
+
|
|
196
227
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
197
228
|
public static Future evaluateAsyncInMainThread(final Callable callable) throws Exception {
|
|
198
229
|
|
|
@@ -246,8 +277,8 @@ public class UIQueryUtils {
|
|
|
246
277
|
new TypeReference<List<HashMap<String, Object>>>() {
|
|
247
278
|
});
|
|
248
279
|
for (Map<String, Object> data : parsedResult) {
|
|
249
|
-
Map<String,
|
|
250
|
-
Map<String,
|
|
280
|
+
Map<String, Integer> rect = (Map<String, Integer>) data.get("rect");
|
|
281
|
+
Map<String, Integer> updatedRect = QueryHelper.translateRectToScreenCoordinates(webView, rect);
|
|
251
282
|
data.put("rect", updatedRect);
|
|
252
283
|
data.put("webView", webView);
|
|
253
284
|
}
|
|
@@ -301,7 +332,7 @@ public class UIQueryUtils {
|
|
|
301
332
|
}
|
|
302
333
|
|
|
303
334
|
/*
|
|
304
|
-
*
|
|
335
|
+
*
|
|
305
336
|
* {"rect"=>{"x"=>0, "y"=>0, "width"=>768, "height"=>1024},
|
|
306
337
|
* "hit-point"=>{"x"=>384, "y"=>512}, "id"=>"", "action"=>false,
|
|
307
338
|
* "enabled"=>1, "visible"=>1, "value"=>nil, "type"=>"[object UIAWindow]",
|
|
@@ -343,7 +374,7 @@ public class UIQueryUtils {
|
|
|
343
374
|
childrenArray.add(dumpRecursively(serializedChild,
|
|
344
375
|
childrenList));
|
|
345
376
|
}
|
|
346
|
-
|
|
377
|
+
|
|
347
378
|
}
|
|
348
379
|
|
|
349
380
|
parentView.put("children", childrenArray);
|
|
@@ -373,7 +404,7 @@ public class UIQueryUtils {
|
|
|
373
404
|
}
|
|
374
405
|
|
|
375
406
|
/*
|
|
376
|
-
*
|
|
407
|
+
*
|
|
377
408
|
"enabled" => true,
|
|
378
409
|
"visible" => true,
|
|
379
410
|
"children" => [],
|
|
@@ -412,16 +443,16 @@ public class UIQueryUtils {
|
|
|
412
443
|
if (viewOrMap == null) {
|
|
413
444
|
return null;
|
|
414
445
|
}
|
|
415
|
-
|
|
416
|
-
if (viewOrMap instanceof Map)
|
|
446
|
+
|
|
447
|
+
if (viewOrMap instanceof Map)
|
|
417
448
|
{
|
|
418
|
-
Map map = (Map) viewOrMap;
|
|
449
|
+
Map map = (Map) viewOrMap;
|
|
419
450
|
map.put("el", map);
|
|
420
451
|
|
|
421
452
|
Map rect = (Map) map.get("rect");
|
|
422
453
|
Map hitPoint = extractHitPointFromRect(rect);
|
|
423
|
-
|
|
424
|
-
map.put("hit-point", hitPoint);
|
|
454
|
+
|
|
455
|
+
map.put("hit-point", hitPoint);
|
|
425
456
|
map.put("enabled", true);
|
|
426
457
|
map.put("visible", true);
|
|
427
458
|
map.put("value", null);
|
|
@@ -430,36 +461,36 @@ public class UIQueryUtils {
|
|
|
430
461
|
map.put("label", null);
|
|
431
462
|
map.put("children", Collections.EMPTY_LIST);
|
|
432
463
|
String html = (String)map.get("html");
|
|
433
|
-
String nodeName = (String) map.get("nodeName");
|
|
434
|
-
if (nodeName != null && nodeName.toLowerCase().equals("input")) {
|
|
464
|
+
String nodeName = (String) map.get("nodeName");
|
|
465
|
+
if (nodeName != null && nodeName.toLowerCase().equals("input")) {
|
|
435
466
|
String domType = extractDomType(html);
|
|
436
467
|
if (isDomPasswordType(domType)) {
|
|
437
468
|
map.put("entry_types", Collections.singletonList("password"));
|
|
438
469
|
}
|
|
439
470
|
else if (isDomTextType(domType)) {
|
|
440
471
|
map.put("entry_types", Collections.singletonList("text"));
|
|
441
|
-
}
|
|
472
|
+
}
|
|
442
473
|
else {
|
|
443
|
-
map.put("entry_types", Collections.emptyList());
|
|
444
|
-
}
|
|
474
|
+
map.put("entry_types", Collections.emptyList());
|
|
475
|
+
}
|
|
445
476
|
map.put("value", extractAttribute(html, "value"));
|
|
446
477
|
map.put("type", "dom");
|
|
447
478
|
map.put("name", extractAttribute(html, "name"));
|
|
448
479
|
map.put("label", extractAttribute(html, "title"));
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
return map;
|
|
452
|
-
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return map;
|
|
483
|
+
|
|
453
484
|
}
|
|
454
|
-
else
|
|
485
|
+
else
|
|
455
486
|
{
|
|
456
487
|
Map m = new HashMap();
|
|
457
|
-
|
|
488
|
+
|
|
458
489
|
View view = (View) viewOrMap;
|
|
459
490
|
m.put("id", getId(view));
|
|
460
491
|
m.put("el", view);
|
|
461
492
|
|
|
462
|
-
Map rect = ViewMapper.getRectForView(view);
|
|
493
|
+
Map<String,Integer> rect = ViewMapper.getRectForView(view);
|
|
463
494
|
Map hitPoint = extractHitPointFromRect(rect);
|
|
464
495
|
|
|
465
496
|
m.put("rect", rect);
|
|
@@ -472,14 +503,29 @@ public class UIQueryUtils {
|
|
|
472
503
|
m.put("type", ViewMapper.getClassNameForView(view));
|
|
473
504
|
m.put("name", getNameForView(view));
|
|
474
505
|
m.put("label", ViewMapper.getContentDescriptionForView(view));
|
|
475
|
-
return m;
|
|
506
|
+
return m;
|
|
476
507
|
}
|
|
477
508
|
|
|
478
|
-
|
|
479
509
|
|
|
480
|
-
|
|
510
|
+
|
|
511
|
+
|
|
481
512
|
}
|
|
482
513
|
|
|
514
|
+
private static boolean isViewSufficientlyShown(View view, ViewParent viewParent) {
|
|
515
|
+
if (!(viewParent instanceof View)) return true;
|
|
516
|
+
|
|
517
|
+
View parent = (View)viewParent;
|
|
518
|
+
|
|
519
|
+
if (view.equals(parent) || parent == null) {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
Map<String,Integer> viewRect = ViewMapper.getRectForView(view);
|
|
524
|
+
Map<String,Integer> parentRect = ViewMapper.getRectForView(parent);
|
|
525
|
+
|
|
526
|
+
return isViewSufficientlyShown(viewRect, parentRect) && isViewSufficientlyShown(view, parent.getParent());
|
|
527
|
+
}
|
|
528
|
+
|
|
483
529
|
private static boolean isDomTextType(String domType) {
|
|
484
530
|
if (domType == null) {
|
|
485
531
|
return true;
|
|
@@ -487,25 +533,25 @@ public class UIQueryUtils {
|
|
|
487
533
|
return DOM_TEXT_TYPES.contains(domType);
|
|
488
534
|
}
|
|
489
535
|
|
|
490
|
-
private static boolean isDomPasswordType(String domType) {
|
|
536
|
+
private static boolean isDomPasswordType(String domType) {
|
|
491
537
|
return "password".equalsIgnoreCase(domType);
|
|
492
538
|
}
|
|
493
539
|
|
|
494
540
|
// naive implementation only works for (valid) input tags
|
|
495
541
|
public static String extractDomType(String input) {
|
|
496
|
-
return extractAttribute(input, "type");
|
|
542
|
+
return extractAttribute(input, "type");
|
|
497
543
|
}
|
|
498
|
-
|
|
544
|
+
|
|
499
545
|
public static String extractAttribute(String input, String attribute) {
|
|
500
546
|
String[] split = input.split(attribute+"=");
|
|
501
547
|
if (split.length == 1) {
|
|
502
|
-
split = input.split(attribute+" =");
|
|
548
|
+
split = input.split(attribute+" =");
|
|
503
549
|
}
|
|
504
550
|
if (split.length > 1) {
|
|
505
551
|
String lastPart = split[1];
|
|
506
552
|
if (lastPart == null) {
|
|
507
|
-
return null;
|
|
508
|
-
}
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
509
555
|
if (lastPart.charAt(0) == '"' || lastPart.charAt(0) == '\'') {
|
|
510
556
|
int endIndex = -1;
|
|
511
557
|
for (int i=1;i<lastPart.length();i++) {
|
|
@@ -514,15 +560,15 @@ public class UIQueryUtils {
|
|
|
514
560
|
break;
|
|
515
561
|
}
|
|
516
562
|
}
|
|
517
|
-
|
|
563
|
+
|
|
518
564
|
if (endIndex > 0) {
|
|
519
565
|
return lastPart.substring(1,endIndex);
|
|
520
566
|
}
|
|
521
|
-
|
|
522
|
-
}
|
|
567
|
+
|
|
568
|
+
}
|
|
523
569
|
}
|
|
524
570
|
return null;
|
|
525
|
-
|
|
571
|
+
|
|
526
572
|
}
|
|
527
573
|
|
|
528
574
|
|