calabash-android 0.4.22.pre1 → 0.4.22.pre3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|