calabash-android 0.3.8 → 0.4.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -66,6 +66,9 @@ Finds a input field by index and blanks its value.
66
66
  Then /^I clear "([^\"]*)"$/ do |name|
67
67
  Finds a input field with matching content description and blanks its value.
68
68
 
69
+ Then /^I clear input field with id "([^\"]*)"$/ do |view_id|
70
+ Finds the input field with id `view_id` and clears the text from it.
71
+
69
72
  Then /^I select "([^\"]*)" from "([^\"]*)"$/ do |item_text, spinner_content_description|
70
73
  Finds the Spinner by 'spinner_content_description' and selects the item with the matching 'item_text'
71
74
 
@@ -53,6 +53,10 @@ module Operations
53
53
  default_device.wake_up()
54
54
  end
55
55
 
56
+ def clear_app_data
57
+ default_device.clear_app_data
58
+ end
59
+
56
60
  def start_test_server_in_background
57
61
  default_device.start_test_server_in_background()
58
62
  end
@@ -92,14 +96,16 @@ module Operations
92
96
  end
93
97
 
94
98
  def query(uiquery, *args)
95
- raise "Currently queries are only supported for webviews" unless uiquery.start_with? "webView"
96
-
97
- uiquery.slice!(0, "webView".length)
98
- if uiquery =~ /(css|xpath):\s*(.*)/
99
- r = performAction("query", $1, $2)
100
- JSON.parse(r["message"])
99
+ if uiquery.start_with? "webView"
100
+ uiquery.slice!(0, "webView".length)
101
+ if uiquery =~ /(css|xpath):\s*(.*)/
102
+ r = performAction("query", $1, $2)
103
+ JSON.parse(r["message"])
104
+ else
105
+ raise "Invalid query #{uiquery}"
106
+ end
101
107
  else
102
- raise "Invalid query #{uiquery}"
108
+ JSON.parse(http("/query", {"query" => uiquery}))
103
109
  end
104
110
  end
105
111
 
@@ -298,6 +304,11 @@ module Operations
298
304
  end
299
305
  end
300
306
 
307
+ def clear_app_data
308
+ cmd = "#{adb_command} shell am instrument sh.calaba.android.test/sh.calaba.instrumentationbackend.ClearAppData"
309
+ raise "Could not clear data" unless system(cmd)
310
+ end
311
+
301
312
  def start_test_server_in_background
302
313
  raise "Will not start test server because of previous failures." if Cucumber.wants_to_quit
303
314
 
@@ -371,7 +382,19 @@ module Operations
371
382
  end
372
383
 
373
384
  def touch(uiquery,options={})
374
- ni
385
+ if uiquery.instance_of? String
386
+ elements = query(uiquery, options)
387
+ raise "No elements found" if elements.empty?
388
+ element = elements.first
389
+ else
390
+ element = uiquery
391
+ end
392
+
393
+ performAction("touch_coordinate", element["frame"]["x"], element["frame"]["y"])
394
+ end
395
+
396
+ def http(options, data=nil)
397
+ default_device.http(options, data)
375
398
  end
376
399
 
377
400
  def html(q)
@@ -481,11 +504,6 @@ module Operations
481
504
  ni
482
505
  end
483
506
 
484
- def http(options, data=nil)
485
- ni
486
- end
487
-
488
-
489
507
  def url_for( verb )
490
508
  ni
491
509
  end
@@ -18,6 +18,10 @@ Then /^I clear input field number (\d+)$/ do |number|
18
18
  performAction('clear_numbered_field',number)
19
19
  end
20
20
 
21
+ Then /^I clear input field with id "([^\"]*)"$/ do |view_id|
22
+ performAction('clear_id_field', view_id)
23
+ end
24
+
21
25
  Then /^I enter text "([^\"]*)" into field with id "([^\"]*)"$/ do |text, view_id|
22
26
  performAction('enter_text_into_id_field', text, view_id)
23
27
  end
@@ -5,4 +5,3 @@ end
5
5
  Then /^I rotate the device to portrait$/ do
6
6
  rotate_phone(0)
7
7
  end
8
-
@@ -1,5 +1,5 @@
1
1
  module Calabash
2
2
  module Android
3
- VERSION = "0.3.8"
3
+ VERSION = "0.4.0.pre1"
4
4
  end
5
5
  end
@@ -18,6 +18,7 @@
18
18
  </application>
19
19
  <uses-sdk android:minSdkVersion="4" />
20
20
  <instrumentation android:targetPackage="#targetPackage#" android:name="sh.calaba.instrumentationbackend.CalabashInstrumentationTestRunner" />
21
+ <instrumentation android:targetPackage="#targetPackage#" android:name="sh.calaba.instrumentationbackend.ClearAppData" />
21
22
 
22
23
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
23
24
  <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
@@ -0,0 +1,11 @@
1
+ package com.jayway.android.robotium.solo;
2
+
3
+ import android.app.Activity;
4
+ import android.app.Instrumentation;
5
+
6
+ public class PublicViewFetcher extends ViewFetcher {
7
+
8
+ public PublicViewFetcher(Instrumentation instrumentation, Activity activity) {
9
+ super(new ActivityUtils(instrumentation, activity, new Sleeper()));
10
+ }
11
+ }
@@ -0,0 +1,48 @@
1
+ package sh.calaba.instrumentationbackend;
2
+
3
+ import android.content.Context;
4
+ import android.os.Bundle;
5
+ import android.test.InstrumentationTestRunner;
6
+ import sh.calaba.instrumentationbackend.actions.HttpServer;
7
+
8
+ import java.io.File;
9
+ import java.lang.reflect.Method;
10
+
11
+ public class ClearAppData extends InstrumentationTestRunner {
12
+ @Override
13
+ public void onCreate(Bundle arguments) {
14
+ if (externalCacheDir() != null) {
15
+ delete(externalCacheDir().getParentFile());
16
+ }
17
+ if (cacheDir() != null) {
18
+ delete(cacheDir().getParentFile());
19
+ }
20
+ }
21
+
22
+ //If provided a file will delete it.
23
+ //If provided a directory will recursively delete files but preserve directories
24
+ private void delete(File file_or_directory) {
25
+ if (file_or_directory == null) {
26
+ return;
27
+ }
28
+
29
+ if (file_or_directory.isDirectory()) {
30
+ if (file_or_directory.listFiles() != null) {
31
+ for(File f : file_or_directory.listFiles()) {
32
+ delete(f);
33
+ }
34
+ }
35
+ } else {
36
+ file_or_directory.delete();
37
+ }
38
+ }
39
+
40
+ private File externalCacheDir() {
41
+ return getTargetContext().getExternalCacheDir();
42
+ }
43
+
44
+ private File cacheDir() {
45
+ return getTargetContext().getCacheDir();
46
+ }
47
+
48
+ }
@@ -2,6 +2,7 @@ package sh.calaba.instrumentationbackend;
2
2
 
3
3
  import android.Manifest;
4
4
  import android.content.pm.PackageManager;
5
+ import com.jayway.android.robotium.solo.PublicViewFetcher;
5
6
  import sh.calaba.instrumentationbackend.actions.Actions;
6
7
  import sh.calaba.instrumentationbackend.actions.HttpServer;
7
8
  import android.app.Activity;
@@ -21,6 +22,7 @@ public class InstrumentationBackend extends ActivityInstrumentationTestCase2 {
21
22
 
22
23
  public static Instrumentation instrumentation;
23
24
  public static SoloEnhanced solo;
25
+ public static PublicViewFetcher viewFetcher;
24
26
  public static Actions actions;
25
27
 
26
28
  public InstrumentationBackend() {
@@ -32,6 +34,7 @@ public class InstrumentationBackend extends ActivityInstrumentationTestCase2 {
32
34
  super.setUp();
33
35
 
34
36
  solo = new SoloEnhanced(getInstrumentation(), this.getActivity());
37
+ viewFetcher = new PublicViewFetcher(getInstrumentation(), this.getActivity());
35
38
  actions = new Actions(getInstrumentation(), this);
36
39
  instrumentation = getInstrumentation();
37
40
  }
@@ -1,6 +1,7 @@
1
1
  package sh.calaba.instrumentationbackend.actions;
2
2
 
3
3
  import java.io.*;
4
+ import java.util.Map;
4
5
  import java.util.Properties;
5
6
  import java.util.List;
6
7
  import java.util.concurrent.locks.Condition;
@@ -16,9 +17,12 @@ import android.view.View;
16
17
  import sh.calaba.instrumentationbackend.Command;
17
18
  import sh.calaba.instrumentationbackend.InstrumentationBackend;
18
19
  import sh.calaba.instrumentationbackend.Result;
20
+ import sh.calaba.instrumentationbackend.query.QueryResult;
21
+ import sh.calaba.instrumentationbackend.query.Query;
19
22
  import sh.calaba.org.codehaus.jackson.map.DeserializationConfig.Feature;
20
23
  import sh.calaba.org.codehaus.jackson.map.ObjectMapper;
21
24
  import android.util.Log;
25
+ import sh.calaba.org.codehaus.jackson.type.TypeReference;
22
26
 
23
27
  public class HttpServer extends NanoHTTPD {
24
28
  private static final String TAG = "InstrumentationBackend";
@@ -67,6 +71,17 @@ public class HttpServer extends NanoHTTPD {
67
71
  if (uri.endsWith("/ping")) {
68
72
  return new NanoHTTPD.Response( HTTP_OK, MIME_HTML, "pong");
69
73
 
74
+ } else if (uri.endsWith("/query")) {
75
+ try {
76
+ String commandString = params.getProperty("json");
77
+ ObjectMapper mapper = new ObjectMapper();
78
+ Map<String, String> command = mapper.readValue(commandString, new TypeReference<Map<String, String>>() {});
79
+ QueryResult result = new Query(command.get("query")).execute();
80
+ return new NanoHTTPD.Response( HTTP_OK, MIME_HTML, result.asJson());
81
+ } catch (IOException e) {
82
+ e.printStackTrace();
83
+ return new Response(HTTP_INTERNALERROR, MIME_PLAINTEXT, "Could not parse arguments as JSON");
84
+ }
70
85
  } else if (uri.endsWith("/kill")) {
71
86
  lock.lock();
72
87
  try {
@@ -0,0 +1,43 @@
1
+ package sh.calaba.instrumentationbackend.actions.activity;
2
+
3
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
4
+ import sh.calaba.instrumentationbackend.Result;
5
+ import sh.calaba.instrumentationbackend.actions.Action;
6
+
7
+ public class SetActivityOrientation implements Action {
8
+
9
+ @Override
10
+ public Result execute(String... args) {
11
+ if (args.length == 0) {
12
+ throw new IllegalArgumentException("No orientation provided. Use 'landscape' or 'portrait'");
13
+ }
14
+ String orientation = args[0].toLowerCase();
15
+
16
+ if (orientation != "landscape" && orientation != "portrait") {
17
+ throw new IllegalArgumentException("Invalid orientation '" + orientation + "'. Use 'landscape' or 'portrait'");
18
+ }
19
+
20
+ if (orientation == "landscape") {
21
+ InstrumentationBackend.solo.setActivityOrientation(0);
22
+ } else {
23
+ InstrumentationBackend.solo.setActivityOrientation(1);
24
+ }
25
+ // Wait 100ms for orientation change to happen.
26
+ sleep(100);
27
+
28
+ return Result.successResult();
29
+ }
30
+
31
+ private void sleep(long time) {
32
+ try {
33
+ Thread.sleep(time);
34
+ } catch (Exception e) {
35
+ throw new RuntimeException(e);
36
+ }
37
+ }
38
+
39
+ @Override
40
+ public String key() {
41
+ return "set_activity_orientation";
42
+ }
43
+ }
@@ -0,0 +1,39 @@
1
+ package sh.calaba.instrumentationbackend.actions.map;
2
+
3
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
4
+ import sh.calaba.instrumentationbackend.Result;
5
+ import sh.calaba.instrumentationbackend.actions.Action;
6
+
7
+ public class SetOrientation implements Action {
8
+
9
+ @Override
10
+ public Result execute(String... args) {
11
+ String orientation = "";
12
+ if (args != null && args.length >= 1) {
13
+ orientation = args[0].toLowerCase();
14
+ }
15
+
16
+ int changed = -1;
17
+
18
+ if( "landscape".contentEquals(orientation) ) {
19
+ changed = 0;
20
+ } else if( "portrait".contentEquals(orientation) ) {
21
+ changed = 1;
22
+ }
23
+
24
+ if (changed != -1) {
25
+ InstrumentationBackend.solo.setActivityOrientation(changed);
26
+ // Wait 100ms for orientation to happen.
27
+ try { Thread.sleep(100); } catch (Exception e) {}
28
+ // setActivityOrientation returns void so assume success.
29
+ return Result.successResult();
30
+ }
31
+
32
+ return new Result(false, "Requested invalid orientation: '" + orientation + "' Expected 'landscape' or 'portrait'.");
33
+ }
34
+
35
+ @Override
36
+ public String key() {
37
+ return "set_orientation";
38
+ }
39
+ }
@@ -0,0 +1,28 @@
1
+ package sh.calaba.instrumentationbackend.actions.gestures;
2
+
3
+
4
+ import android.view.Display;
5
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
6
+ import sh.calaba.instrumentationbackend.Result;
7
+ import sh.calaba.instrumentationbackend.actions.Action;
8
+
9
+
10
+ public class TouchCoordinates implements Action {
11
+
12
+ @Override
13
+ public Result execute(String... args) {
14
+ Display display = InstrumentationBackend.solo.getCurrentActivity().getWindowManager().getDefaultDisplay();
15
+
16
+ float x = Float.parseFloat(args[0]);
17
+ float y = Float.parseFloat(args[1]);
18
+
19
+ InstrumentationBackend.solo.clickOnScreen(x, y);
20
+ return Result.successResult();
21
+ }
22
+
23
+ @Override
24
+ public String key() {
25
+ return "touch_coordinate";
26
+ }
27
+
28
+ }
@@ -0,0 +1,90 @@
1
+ package sh.calaba.instrumentationbackend.query;
2
+
3
+ import android.content.res.Resources;
4
+ import android.view.View;
5
+ import android.widget.Button;
6
+ import android.widget.CheckBox;
7
+ import android.widget.TextView;
8
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
9
+
10
+ import java.util.ArrayList;
11
+ import java.util.HashMap;
12
+ import java.util.List;
13
+ import java.util.Map;
14
+
15
+ import static sh.calaba.instrumentationbackend.InstrumentationBackend.*;
16
+
17
+ public class Query {
18
+
19
+ private String queryString;
20
+
21
+ public Query(String queryString) {
22
+ System.out.println("CREATED QUERY: " + queryString);
23
+ this.queryString = queryString;
24
+ }
25
+
26
+
27
+ public QueryResult execute() {
28
+ List<Map<?,?>> result = new ArrayList<Map<?, ?>>();
29
+ for (View v : allVisibleViews()) {
30
+
31
+ if (!v.isShown() ) {
32
+ continue;
33
+ }
34
+
35
+ if (queryString != null) {
36
+ if (!queryString.isEmpty()) {
37
+ if (!queryString.equalsIgnoreCase(v.getClass().getSimpleName())) {
38
+ continue;
39
+ }
40
+ }
41
+ }
42
+
43
+ System.out.println(v.getClass().getSimpleName().toString());
44
+ Map view = new HashMap();
45
+ view.put("class", v.getClass().getSimpleName());
46
+ view.put("description", v.toString());
47
+ view.put("contentDescription", v.getContentDescription());
48
+ view.put("enabled", v.isEnabled());
49
+ String id = null;
50
+ try {
51
+ id = InstrumentationBackend.solo.getCurrentActivity().getResources().getResourceEntryName(v.getId());
52
+ } catch (Resources.NotFoundException e) {
53
+ System.out.println("Resource not found for " + v.getId() + ". Moving on.");
54
+ }
55
+ view.put("id", id);
56
+
57
+ Map frame = new HashMap();
58
+ int[] location = new int[2];
59
+ v.getLocationOnScreen(location);
60
+
61
+ frame.put("x", location[0]);
62
+ frame.put("y", location[1]);
63
+ frame.put("width", v.getWidth());
64
+ frame.put("height", v.getHeight());
65
+
66
+ view.put("frame", frame);
67
+
68
+ if (v instanceof Button) {
69
+ Button b = (Button)v;
70
+ view.put("text", b.getText().toString());
71
+ }
72
+ if (v instanceof CheckBox) {
73
+ CheckBox c = (CheckBox)v;
74
+ view.put("checked", c.isChecked());
75
+ }
76
+ if (v instanceof TextView) {
77
+ TextView t = (TextView)v;
78
+ view.put("text", t.getText().toString());
79
+ }
80
+
81
+ result.add(view);
82
+ }
83
+ return new QueryResult(result);
84
+ }
85
+
86
+
87
+ public List<View> allVisibleViews() {
88
+ return viewFetcher.getAllViews(false);
89
+ }
90
+ }
@@ -0,0 +1,27 @@
1
+ package sh.calaba.instrumentationbackend.query;
2
+
3
+ import sh.calaba.org.codehaus.jackson.map.ObjectMapper;
4
+
5
+ import java.io.IOException;
6
+ import java.util.List;
7
+
8
+ public class QueryResult {
9
+
10
+ private List result;
11
+
12
+ public QueryResult(List result) {
13
+
14
+ this.result = result;
15
+ }
16
+
17
+
18
+ public String asJson() {
19
+ ObjectMapper mapper = new ObjectMapper();
20
+
21
+ try {
22
+ return mapper.writeValueAsString(result);
23
+ } catch (IOException e) {
24
+ throw new RuntimeException("Could not convert result to json", e);
25
+ }
26
+ }
27
+ }
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calabash-android
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
5
- prerelease:
4
+ version: 0.4.0.pre1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jonas Maturana Larsen
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-07 00:00:00.000000000 Z
12
+ date: 2012-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cucumber
@@ -169,8 +169,10 @@ files:
169
169
  - test-server/instrumentation-backend/res/layout/main.xml
170
170
  - test-server/instrumentation-backend/res/values/strings.xml
171
171
  - test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/MapViewUtils.java
172
+ - test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/PublicViewFetcher.java
172
173
  - test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/SoloEnhanced.java
173
174
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/CalabashInstrumentationTestRunner.java
175
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/ClearAppData.java
174
176
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Command.java
175
177
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/InstrumentationBackend.java
176
178
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java
@@ -181,6 +183,8 @@ files:
181
183
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java
182
184
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/NanoHTTPD.java
183
185
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/NullAction.java
186
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/SetActivityOrientation.java
187
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/activity/SetOrientation.java
184
188
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonNumber.java
185
189
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonText.java
186
190
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressImageButtonDescription.java
@@ -194,6 +198,7 @@ files:
194
198
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/ClickOnScreen.java
195
199
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/Drag.java
196
200
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/Swipe.java
201
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/TouchCoordinates.java
197
202
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/helpers/InspectCurrentDialog.java
198
203
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/helpers/ListActions.java
199
204
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/l10n/L10nHelper.java
@@ -274,6 +279,8 @@ files:
274
279
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetPropertyByCssSelector.java
275
280
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetText.java
276
281
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Touch.java
282
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Query.java
283
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/QueryResult.java
277
284
  - test-server/instrumentation-backend/src/sh/calaba/org/codehaus/jackson/Base64Variant.java
278
285
  - test-server/instrumentation-backend/src/sh/calaba/org/codehaus/jackson/Base64Variants.java
279
286
  - test-server/instrumentation-backend/src/sh/calaba/org/codehaus/jackson/FormatSchema.java
@@ -698,9 +705,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
698
705
  required_rubygems_version: !ruby/object:Gem::Requirement
699
706
  none: false
700
707
  requirements:
701
- - - ! '>='
708
+ - - ! '>'
702
709
  - !ruby/object:Gem::Version
703
- version: '0'
710
+ version: 1.3.1
704
711
  requirements: []
705
712
  rubyforge_project:
706
713
  rubygems_version: 1.8.24