calabash-android 0.4.22.pre1 → 0.4.22.pre3
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/Gemfile.lock +4 -4
- data/lib/calabash-android/lib/TestServer.apk +0 -0
- data/lib/calabash-android/operations.rb +10 -0
- data/lib/calabash-android/version.rb +1 -1
- data/lib/calabash-android/wait_helpers.rb +101 -17
- data/test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/SoloEnhanced.java +4 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/CalabashInstrumentationTestRunner.java +3 -3
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/InstrumentationBackend.java +25 -5
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/KeyboardEnterText.java +62 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d221e4c80dd7613507106fb29b003b973f7bb90
|
4
|
+
data.tar.gz: 00acef8ea096b2fadd7d4d78a3351fdc14e080f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca7532fbf81f589c0a34b889db471ac9ce0730240dcd2cfde663271f937319e0784194575d4feb1993271f1c3936cc88be175fe4a2114507ee1113901ba0e0e7
|
7
|
+
data.tar.gz: 1e5a8fceb981f4508120066a950ffde01fbb2744f1b501429162f2a36609ebc0c54f171f450b6ccf4647d3ba1ab9f521e3206e3bf73a1ccc6d1aeeee08d3d651
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
calabash-android (0.4.
|
4
|
+
calabash-android (0.4.22.pre1)
|
5
5
|
awesome_print
|
6
6
|
cucumber
|
7
7
|
escape (~> 0.0.4)
|
@@ -17,7 +17,7 @@ GEM
|
|
17
17
|
specs:
|
18
18
|
awesome_print (1.2.0)
|
19
19
|
builder (3.2.2)
|
20
|
-
cucumber (1.3.
|
20
|
+
cucumber (1.3.11)
|
21
21
|
builder (>= 2.1.2)
|
22
22
|
diff-lcs (>= 1.1.3)
|
23
23
|
gherkin (~> 2.12)
|
@@ -30,7 +30,7 @@ GEM
|
|
30
30
|
httpclient (2.3.4.1)
|
31
31
|
json (1.8.1)
|
32
32
|
mime-types (1.25.1)
|
33
|
-
multi_json (1.
|
33
|
+
multi_json (1.9.0)
|
34
34
|
multi_test (0.0.3)
|
35
35
|
rake (10.1.0)
|
36
36
|
rest-client (1.6.7)
|
@@ -40,7 +40,7 @@ GEM
|
|
40
40
|
slowhandcuke (0.0.3)
|
41
41
|
cucumber
|
42
42
|
thor (0.18.1)
|
43
|
-
xamarin-test-cloud (0.9.
|
43
|
+
xamarin-test-cloud (0.9.29)
|
44
44
|
bundler (>= 1.3.0, < 2.0)
|
45
45
|
json
|
46
46
|
mime-types (< 2.0)
|
Binary file
|
@@ -722,6 +722,16 @@ module Operations
|
|
722
722
|
performAction("touch_coordinate", center_x, center_y)
|
723
723
|
end
|
724
724
|
|
725
|
+
def keyboard_enter_text(text, options = {})
|
726
|
+
performAction('keyboard_enter_text', text)
|
727
|
+
end
|
728
|
+
|
729
|
+
def enter_text(uiquery, text, options = {})
|
730
|
+
touch(uiquery, options)
|
731
|
+
sleep 0.5
|
732
|
+
keyboard_enter_text(text, options)
|
733
|
+
end
|
734
|
+
|
725
735
|
def find_coordinate(uiquery)
|
726
736
|
raise "Cannot find nil" unless uiquery
|
727
737
|
|
@@ -7,26 +7,32 @@ module Calabash
|
|
7
7
|
class WaitError < RuntimeError
|
8
8
|
end
|
9
9
|
|
10
|
+
# 'post_timeout' is the time to wait after a wait function returns true
|
11
|
+
DEFAULT_OPTS = {
|
12
|
+
:timeout => 30,
|
13
|
+
:retry_frequency => 0.3,
|
14
|
+
:post_timeout => 0,
|
15
|
+
:timeout_message => 'Timed out waiting...',
|
16
|
+
:screenshot_on_error => true
|
17
|
+
}.freeze
|
10
18
|
|
11
|
-
def wait_for(options_or_timeout=
|
12
|
-
{:timeout => 10,
|
13
|
-
:retry_frequency => 0.2,
|
14
|
-
:post_timeout => 0.1,
|
15
|
-
:timeout_message => "Timed out waiting...",
|
16
|
-
:screenshot_on_error => true}, &block)
|
19
|
+
def wait_for(options_or_timeout=DEFAULT_OPTS, &block)
|
17
20
|
#note Hash is preferred, number acceptable for backwards compat
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
default_timeout = 30
|
22
|
+
timeout = options_or_timeout || default_timeout
|
23
|
+
post_timeout=0
|
24
|
+
retry_frequency=0.3
|
21
25
|
timeout_message = nil
|
22
26
|
screenshot_on_error = true
|
23
27
|
|
24
28
|
if options_or_timeout.is_a?(Hash)
|
25
|
-
timeout = options_or_timeout[:timeout] ||
|
26
|
-
retry_frequency = options_or_timeout[:retry_frequency] ||
|
27
|
-
post_timeout = options_or_timeout[:post_timeout] ||
|
29
|
+
timeout = options_or_timeout[:timeout] || default_timeout
|
30
|
+
retry_frequency = options_or_timeout[:retry_frequency] || retry_frequency
|
31
|
+
post_timeout = options_or_timeout[:post_timeout] || post_timeout
|
28
32
|
timeout_message = options_or_timeout[:timeout_message]
|
29
|
-
|
33
|
+
if options_or_timeout.key?(:screenshot_on_error)
|
34
|
+
screenshot_on_error = options_or_timeout[:screenshot_on_error]
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
32
38
|
begin
|
@@ -35,12 +41,31 @@ module Calabash
|
|
35
41
|
end
|
36
42
|
sleep(post_timeout) if post_timeout > 0
|
37
43
|
rescue WaitError => e
|
38
|
-
|
44
|
+
msg = timeout_message || e
|
45
|
+
if screenshot_on_error
|
46
|
+
sleep(retry_frequency)
|
47
|
+
return screenshot_and_retry(msg, &block)
|
48
|
+
else
|
49
|
+
raise wait_error(msg)
|
50
|
+
end
|
39
51
|
rescue Exception => e
|
40
52
|
handle_error_with_options(e, nil, screenshot_on_error)
|
41
53
|
end
|
42
54
|
end
|
43
55
|
|
56
|
+
def screenshot_and_retry(msg, &block)
|
57
|
+
path = screenshot
|
58
|
+
res = yield
|
59
|
+
# Validate after taking screenshot
|
60
|
+
if res
|
61
|
+
FileUtils.rm_f(path)
|
62
|
+
return res
|
63
|
+
else
|
64
|
+
embed(path, 'image/png', msg)
|
65
|
+
raise wait_error(msg)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
44
69
|
def wait_poll(opts, &block)
|
45
70
|
test = opts[:until]
|
46
71
|
if test.nil?
|
@@ -58,16 +83,21 @@ module Calabash
|
|
58
83
|
end
|
59
84
|
end
|
60
85
|
|
61
|
-
#options for wait_for apply
|
86
|
+
#options for wait_for apply
|
62
87
|
def wait_for_elements_exist(elements_arr, options={})
|
88
|
+
if elements_arr.is_a?(String) || elements_arr.is_a?(Symbol)
|
89
|
+
elements_arr = [elements_arr.to_s]
|
90
|
+
end
|
63
91
|
options[:timeout_message] = options[:timeout_message] || "Timeout waiting for elements: #{elements_arr.join(",")}"
|
64
92
|
wait_for(options) do
|
65
93
|
elements_arr.all? { |q| element_exists(q) }
|
66
94
|
end
|
67
95
|
end
|
68
|
-
|
69
|
-
#options for wait_for apply
|
96
|
+
#options for wait_for apply
|
70
97
|
def wait_for_elements_do_not_exist(elements_arr, options={})
|
98
|
+
if elements_arr.is_a?(String)
|
99
|
+
elements_arr = [elements_arr]
|
100
|
+
end
|
71
101
|
options[:timeout_message] = options[:timeout_message] || "Timeout waiting for no elements matching: #{elements_arr.join(",")}"
|
72
102
|
wait_for(options) do
|
73
103
|
elements_arr.none? { |q| element_exists(q) }
|
@@ -86,6 +116,60 @@ module Calabash
|
|
86
116
|
end
|
87
117
|
end
|
88
118
|
|
119
|
+
def wait_error(msg)
|
120
|
+
(msg.is_a?(String) ? WaitError.new(msg) : msg)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Performs a lambda action until the element (a query string) appears.
|
124
|
+
# The default action is to do nothing.
|
125
|
+
#
|
126
|
+
# Raises an error if no uiquery is specified. Same options as wait_for
|
127
|
+
# which are timeout, retry frequency, post_timeout, timeout_message, and
|
128
|
+
# screenshot on error.
|
129
|
+
#
|
130
|
+
# Example usage:
|
131
|
+
# until_element_exists("Button", :action => lambda { swipe("up") })
|
132
|
+
def until_element_exists(uiquery, opts = {})
|
133
|
+
extra_opts = { :until_exists => uiquery, :action => lambda { ; } }
|
134
|
+
opts = DEFAULT_OPTS.merge(extra_opts).merge(opts)
|
135
|
+
wait_poll(opts) do
|
136
|
+
opts[:action].call
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Performs a lambda action until the element (a query string) disappears.
|
141
|
+
# The default action is to do nothing.
|
142
|
+
#
|
143
|
+
# Raises an error if no uiquery is specified. Same options as wait_for
|
144
|
+
# which are timeout, retry frequency, post_timeout, timeout_message, and
|
145
|
+
# screenshot on error.
|
146
|
+
#
|
147
|
+
# Example usage:
|
148
|
+
# until_element_does_not_exist("Button", :action => lambda { swipe("up") })
|
149
|
+
def until_element_does_not_exist(uiquery, opts = {})
|
150
|
+
condition = lambda { element_exists(uiquery) ? false : true }
|
151
|
+
extra_opts = { :until => condition, :action => lambda { ; } }
|
152
|
+
opts = DEFAULT_OPTS.merge(extra_opts).merge(opts)
|
153
|
+
wait_poll(opts) do
|
154
|
+
opts[:action].call
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Performs a lambda action once the element exists.
|
159
|
+
# The default behavior is to touch the specified element.
|
160
|
+
#
|
161
|
+
# Raises an error if no uiquery is specified. Same options as wait_for
|
162
|
+
# which are timeout, retry frequency, post_timeout, timeout_message, and
|
163
|
+
# screenshot on error.
|
164
|
+
#
|
165
|
+
# Example usage: when_element_exists("Button", :timeout => 10)
|
166
|
+
def when_element_exists(uiquery, opts = {})
|
167
|
+
action = { :action => lambda { touch uiquery } }
|
168
|
+
opts = DEFAULT_OPTS.merge(action).merge(opts)
|
169
|
+
wait_for_elements_exist([uiquery], opts)
|
170
|
+
opts[:action].call
|
171
|
+
end
|
172
|
+
|
89
173
|
|
90
174
|
end
|
91
175
|
end
|
@@ -12,7 +12,7 @@ public class CalabashInstrumentationTestRunner extends InstrumentationTestRunner
|
|
12
12
|
@Override
|
13
13
|
public void onCreate(Bundle arguments) {
|
14
14
|
try {
|
15
|
-
Context context = getTargetContext
|
15
|
+
Context context = getTargetContext();
|
16
16
|
Class<?> c = Class.forName("mono.MonoPackageManager");
|
17
17
|
Method method = c.getDeclaredMethod ("LoadApplication", Context.class, String.class, String[].class);
|
18
18
|
method.invoke (null, context, null, new String[]{context.getApplicationInfo ().sourceDir});
|
@@ -28,8 +28,8 @@ public class CalabashInstrumentationTestRunner extends InstrumentationTestRunner
|
|
28
28
|
InstrumentationBackend.extras = arguments;
|
29
29
|
|
30
30
|
try {
|
31
|
-
InstrumentationBackend.mainActivity =
|
32
|
-
} catch (
|
31
|
+
InstrumentationBackend.mainActivity = arguments.getString("main_activity");
|
32
|
+
} catch (Exception e) {
|
33
33
|
throw new RuntimeException(e);
|
34
34
|
}
|
35
35
|
|
@@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|
24
24
|
|
25
25
|
public class InstrumentationBackend extends ActivityInstrumentationTestCase2<Activity> {
|
26
26
|
public static String testPackage;
|
27
|
-
public static
|
27
|
+
public static String mainActivity;
|
28
28
|
public static Bundle extras;
|
29
29
|
|
30
30
|
private static final String TAG = "InstrumentationBackend";
|
@@ -34,16 +34,36 @@ public class InstrumentationBackend extends ActivityInstrumentationTestCase2<Act
|
|
34
34
|
public static PublicViewFetcher viewFetcher;
|
35
35
|
public static Actions actions;
|
36
36
|
|
37
|
-
@SuppressWarnings({ "deprecation", "unchecked" })
|
38
37
|
public InstrumentationBackend() {
|
39
|
-
super(
|
38
|
+
super(null);
|
39
|
+
}
|
40
|
+
|
41
|
+
@Override
|
42
|
+
public Activity getActivity() {
|
43
|
+
try {
|
44
|
+
setMainActivity(Class.forName(mainActivity).asSubclass(Activity.class));
|
45
|
+
return super.getActivity();
|
46
|
+
} catch (ClassNotFoundException e) {
|
47
|
+
throw new RuntimeException(e);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
private void setMainActivity(Class<? extends Activity> mainActivity) {
|
52
|
+
try {
|
53
|
+
Field mActivityClass = ActivityInstrumentationTestCase2.class.getDeclaredField("mActivityClass");
|
54
|
+
mActivityClass.setAccessible(true);
|
55
|
+
mActivityClass.set(this, mainActivity);
|
56
|
+
} catch (Exception e) {
|
57
|
+
throw new RuntimeException(e);
|
58
|
+
}
|
40
59
|
}
|
41
60
|
|
42
61
|
@Override
|
43
62
|
protected void setUp() throws Exception {
|
44
63
|
super.setUp();
|
45
|
-
Intent i = new Intent();
|
46
|
-
i.setClassName(testPackage, mainActivity
|
64
|
+
Intent i = new Intent(Intent.ACTION_MAIN);
|
65
|
+
i.setClassName(testPackage, mainActivity);
|
66
|
+
i.addCategory("android.intent.category.LAUNCHER");
|
47
67
|
i.putExtras(extras);
|
48
68
|
setActivityIntent(i);
|
49
69
|
|
@@ -0,0 +1,62 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.actions.text;
|
2
|
+
|
3
|
+
import android.app.Activity;
|
4
|
+
import android.content.Context;
|
5
|
+
import android.view.View;
|
6
|
+
import android.view.inputmethod.InputConnection;
|
7
|
+
import android.view.inputmethod.InputMethodManager;
|
8
|
+
|
9
|
+
import java.lang.Character;
|
10
|
+
import java.lang.reflect.Field;
|
11
|
+
|
12
|
+
import sh.calaba.instrumentationbackend.InstrumentationBackend;
|
13
|
+
import sh.calaba.instrumentationbackend.Result;
|
14
|
+
import sh.calaba.instrumentationbackend.actions.Action;
|
15
|
+
|
16
|
+
public class KeyboardEnterText implements Action {
|
17
|
+
@Override
|
18
|
+
public Result execute(String... args) {
|
19
|
+
if (args.length != 1) {
|
20
|
+
return Result.failedResult("This action takes one argument ([String] text).");
|
21
|
+
}
|
22
|
+
|
23
|
+
final InputConnection inputConnection = getInputConnection();
|
24
|
+
|
25
|
+
final String textToEnter = args[0];
|
26
|
+
InstrumentationBackend.solo.runOnMainSync(new Runnable() {
|
27
|
+
@Override
|
28
|
+
public void run() {
|
29
|
+
for (char c : textToEnter.toCharArray()) {
|
30
|
+
inputConnection.commitText(Character.toString(c), 0);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
});
|
34
|
+
|
35
|
+
return Result.successResult();
|
36
|
+
}
|
37
|
+
|
38
|
+
@Override
|
39
|
+
public String key() {
|
40
|
+
return "keyboard_enter_text";
|
41
|
+
}
|
42
|
+
|
43
|
+
InputConnection getInputConnection() {
|
44
|
+
Activity currentActivity = InstrumentationBackend.solo.getCurrentActivity();
|
45
|
+
final View view = currentActivity.getCurrentFocus();
|
46
|
+
|
47
|
+
Context context = view.getContext();
|
48
|
+
|
49
|
+
if (context == null) {
|
50
|
+
context = currentActivity.getApplicationContext();
|
51
|
+
}
|
52
|
+
|
53
|
+
try {
|
54
|
+
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
55
|
+
Field servedInputConnectionField = InputMethodManager.class.getDeclaredField("mServedInputConnection");
|
56
|
+
servedInputConnectionField.setAccessible(true);
|
57
|
+
return (InputConnection)servedInputConnectionField.get(inputMethodManager);
|
58
|
+
} catch (Exception e) {
|
59
|
+
throw new RuntimeException(e);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calabash-android
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.22.
|
4
|
+
version: 0.4.22.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonas Maturana Larsen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
@@ -399,6 +399,7 @@ files:
|
|
399
399
|
- test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextById.java
|
400
400
|
- test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextByIndex.java
|
401
401
|
- test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/GetTextById.java
|
402
|
+
- test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/KeyboardEnterText.java
|
402
403
|
- test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetDateByContentDescription.java
|
403
404
|
- test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetDateByIndex.java
|
404
405
|
- test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetTimeByContentDescription.java
|