touch_action 0.0.2alpha → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9d3e2af6c99f3deef3611b2c7110b26f780d8dea
4
+ data.tar.gz: 165fa9f2bf25346239a51b0f6fd663f1b0c61213
5
+ SHA512:
6
+ metadata.gz: 0e3e0e96f9665c9b4ff044b4e0852a3328abc5c538f14872c32dbeeced283b904aecffba0f1251e221e59b296714a705b6f74c44180ded05221f7d3e25be7657
7
+ data.tar.gz: c52e192b96ac4af15786162ac6f7729cf10bc0bb2cd5b528ded46789c27cfa023aba196158bfe43dddbac5c788ae0b17ef2ae6d687c2cc382b3c60d19c7bd8e0
data/.gitignore CHANGED
@@ -12,5 +12,5 @@
12
12
  *.o
13
13
  *.a
14
14
  mkmf.log
15
- console
16
- .DS_Store
15
+ .DS_Store
16
+ console
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TouchAction
2
2
 
3
- Adds touch gestures to Watir and Selenium using YUI JS. Very useful when using Appium to test mobile websites.
3
+ Touch Action is a Ruby Gem used to add touch gestures simulation to the Watir-webdriver (and Selenium in the near future) in order to perform automated tests on mobile websites that requires those type of actions. It encapsulates the touch action library of [YUI JS](http://yuilibrary.com/yui/docs/event/simulate.html#simulating-touch-gestures). Very useful for example when testing mobile websites using [Appium](http://appium.io).
4
4
 
5
5
  ## Installation
6
6
 
@@ -15,30 +15,30 @@ And then execute:
15
15
  $ bundle
16
16
 
17
17
  And then add `require 'touch_action'` to your spec_helper.rb or wherever you want to use it.
18
- ## WARNING
19
- It's currently being developed and there are no tests on it. For now, it's only supporting Watir-webdriver.
20
18
 
21
19
  ## Usage
22
20
 
23
21
  ```ruby
24
- #on the element you want to perform the action, call touch_action(:name_of_method)
22
+ #on the element you want to perform the action, call touch_action(:name_of_action)
25
23
  element = @driver.div(:id, 'hit')
26
24
  element.touch_action(:swipe)
27
25
  ```
28
26
  ###Available Gestures
29
- It's currently supporting the gestures bellow. The hash as second argument is optional (here it's showing the default for each action).
27
+
28
+ It's currently supporting the gestures bellow. The only required argument is the action symbol, the rest are optional (here it's showing the default options for each action).
29
+
30
30
  ```ruby
31
- element.touch_action(:flick, {axis: 'x', distance: -100, duration: 50}) #flick and swipe are the same
31
+ element.touch_action(:flick, axis: 'x', distance: 100, duration: 50) #flick and swipe are the same
32
32
 
33
- element.touch_action(:pinch, {r1: 50, r2: 100})
33
+ element.touch_action(:pinch, r1: 50, r2: 100)
34
34
 
35
35
  element.touch_action(:tap)
36
36
 
37
37
  element.touch_action(:doubletap)
38
38
 
39
- element.touch_action(:press, {hold: 2000})
39
+ element.touch_action(:press, hold: 2000)
40
40
 
41
- element.touch_action(:move, {xdist: 70, ydist: -50, duration: 2000})
41
+ element.touch_action(:move, xdist: 70, ydist: -50, duration: 500)
42
42
 
43
43
  element.touch_action(:rotate, {rotation: -75})
44
44
 
data/lib/touch_action.rb CHANGED
@@ -5,57 +5,26 @@ require 'watir-webdriver'
5
5
 
6
6
  module TouchAction
7
7
 
8
- def touch_action action, options = {}
9
- browser.execute_script( send(action.to_s + '_script', options), self )
10
- end
11
-
12
- def flick_script options = {}
13
- default_options = {axis: 'x', distance: -100, duration: 50}
14
- default_options.merge! options
15
- flick = File.read(File.expand_path("../touch_action/javascripts/flick.js.erb", __FILE__))
16
- render_erb(flick, default_options)
17
- end
18
-
19
- def pinch_script options = {}
20
- default_options = {r1: 50, r2: 100}
21
- default_options.merge! options
22
- pinch = File.read(File.expand_path("../touch_action/javascripts/pinch.js.erb", __FILE__))
23
- render_erb(pinch_file.read, default_options)
24
- end
25
-
26
- def tap_script options = {}
27
- tap = File.read(File.expand_path("../touch_action/javascripts/tap.js.erb", __FILE__))
28
- render_erb tap
29
- end
8
+ ACTIONS_WITH_DEFAULT_OPTIONS = {
9
+ tap: {},
10
+ doubletap: {},
11
+ flick: {axis: 'x', distance: 100, duration: 50},
12
+ pinch: {r1: 50, r2: 100},
13
+ press: {hold: 2000},
14
+ move: {xdist: 70, ydist: -50, duration: 500},
15
+ rotate: {rotation: -75}
16
+ }
30
17
 
31
- def doubletap_script options = {}
32
- doubletap = File.read(File.expand_path("../touch_action/javascripts/doubletap.js.erb", __FILE__))
33
- render_erb doubletap
34
- end
35
-
36
- def press_script options = {}
37
- default_options = {hold: 2000}
38
- default_options.merge! options
39
- press = File.read(File.expand_path("../touch_action/javascripts/press.js.erb", __FILE__))
40
- render_erb(press, default_options)
41
- end
42
-
43
- def move_script options = {}
44
- default_options = {xdist: 70, ydist: -50, duration: 2000}
45
- default_options.merge! options
46
- move = File.read(File.expand_path("../touch_action/javascripts/move.js.erb", __FILE__))
47
- render_erb(move, default_options)
48
- end
49
-
50
- def rotate_script options = {}
51
- default_options = {rotation: -75}
52
- default_options.merge! options
53
- rotate = File.read(File.expand_path("../touch_action/javascripts/rotate.js.erb", __FILE__))
54
- render_erb(rotate, default_options)
18
+ def touch_action action, options = {}
19
+ action = :flick if action == :swipe
20
+ raise ArgumentError, "The touch action #{action} doesn't exist" unless ACTIONS_WITH_DEFAULT_OPTIONS[action]
21
+ default_options = ACTIONS_WITH_DEFAULT_OPTIONS[action]
22
+ options = default_options.merge options
23
+ script = File.read(File.expand_path("../touch_action/javascripts/#{action.to_s}.js.erb", __FILE__))
24
+ final_script = render_erb(script, options)
25
+ browser.execute_script( final_script, self )
55
26
  end
56
27
 
57
- alias_method :swipe_script, :flick_script
58
-
59
28
  private
60
29
 
61
30
  def render_erb template, vars = {}
@@ -6,7 +6,7 @@ function loadYui(callback) {
6
6
  var head = document.getElementsByTagName('head')[0];
7
7
  var script = document.createElement('script');
8
8
  script.type = 'text/javascript';
9
- script.src = "http://yui.yahooapis.com/3.17.2/build/yui/yui-min.js";
9
+ script.src = "//yui.yahooapis.com/3.18.0/build/yui/yui-min.js";
10
10
 
11
11
  // Then bind the event to the callback function.
12
12
  // There are several events for cross browser compatibility.
@@ -1,3 +1,3 @@
1
1
  module TouchAction
2
- VERSION = "0.0.2alpha"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe TouchAction do
4
+ describe "Doubletap" do
5
+ it 'should doubletap the div bound by HammerJS' do
6
+ @browser.goto('http://localhost:9292/tap')
7
+ element = @browser.div(id: 'myElement')
8
+ element.touch_action :doubletap
9
+ sleep(5)
10
+ expect(@browser.text).to include('doubletap')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe TouchAction do
4
+ describe "Flick" do
5
+ it 'should flick the div bound by hammerJs' do
6
+ @browser.goto('http://localhost:9292')
7
+ div = @browser.div(id: 'hit')
8
+ div.touch_action :flick
9
+ sleep(5)
10
+ expect(@browser.p(id: 'distance_x').text).to include('100')
11
+ end
12
+
13
+ it 'should flick the div bound by hammerJs when passing swipe instead of flick' do
14
+ @browser.goto('http://localhost:9292')
15
+ div = @browser.div(id: 'hit')
16
+ div.touch_action :swipe
17
+ sleep(5)
18
+ expect(@browser.p(id: 'distance_x').text).to include('100')
19
+ end
20
+
21
+ context "Options" do
22
+
23
+ it 'should flick the div bound by hammerJs to the left when passing the a negative distance' do
24
+ @browser.goto('http://localhost:9292')
25
+ div = @browser.div(id: 'hit')
26
+ div.touch_action :flick, distance: -80
27
+ sleep(5)
28
+ expect(@browser.p(id: 'distance_x').text).to include('-80')
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe TouchAction do
4
+ describe "Move" do
5
+ it 'should move the div bound by hammerJs' do
6
+ @browser.goto('http://localhost:9292')
7
+ div = @browser.div(id: 'hit')
8
+ div.touch_action :move
9
+ sleep(5)
10
+ expect(@browser.p(id: 'distance_x').text).to include('70')
11
+ expect(@browser.p(id: 'distance_y').text).to include('-50')
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe TouchAction do
4
+ describe "Pinch" do
5
+ it 'should pinch the photo bound by pinchzoom js' do
6
+ @browser.goto('http://localhost:9292/pinch')
7
+ pinch_zoom_div = @browser.div(class: 'pinch-zoom')
8
+ last_transform_value = pinch_zoom_div.style('-webkit-transform')
9
+ element = @browser.image
10
+ element.touch_action :pinch
11
+ sleep(5)
12
+ expect(last_transform_value).not_to be_equal(pinch_zoom_div.style('-webkit-transform'))
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe TouchAction do
4
+ describe "Press" do
5
+ it 'should press the div bound by HammerJS' do
6
+ @browser.goto('http://localhost:9292/tap')
7
+ element = @browser.div(id: 'myElement')
8
+ element.touch_action :press
9
+ sleep(5)
10
+ expect(element.text).to include('press')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe TouchAction do
4
+ describe "Rotate" do
5
+ it 'should Rotate the photo bound by pinchzoom js' do
6
+ @browser.goto('http://localhost:9292')
7
+ div = @browser.div(id: 'hit')
8
+ div.touch_action :move # don't ask me why, on this example rotate only works after a move
9
+ sleep(5)
10
+ last_transform_value = div.style('-webkit-transform')
11
+ div.touch_action :rotate
12
+ sleep(3)
13
+ expect(last_transform_value).not_to be_equal(div.style('-webkit-transform'))
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe TouchAction do
4
+ describe "Tap" do
5
+ it 'should tap the div bound by HammerJS' do
6
+ @browser.goto('http://localhost:9292/tap')
7
+ element = @browser.div(id: 'myElement')
8
+ element.touch_action :tap
9
+ sleep(5)
10
+ expect(element.text).to include('tap')
11
+ end
12
+
13
+ it 'should tap link bound by FastClick' do
14
+ @browser.goto('http://localhost:9292/tap')
15
+ @browser.a(id: 'fastclick').touch_action :tap
16
+ sleep(5)
17
+ expect(@browser.p(id: 'fast-click-test').text).to include('1 times')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,56 @@
1
+ require "rspec"
2
+ require "pry"
3
+ require 'rack'
4
+ require 'thin'
5
+ require 'touch_action'
6
+ require 'watir-webdriver'
7
+
8
+ Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
9
+
10
+ @server_thread = Thread.new do
11
+ Rack::Handler::Thin.run @app, :Port => 9292
12
+ end
13
+
14
+
15
+ case ENV['platform']
16
+ when 'ios'
17
+ capabilities = {
18
+ :deviceName => 'iPhone 5s',
19
+ :browserName => 'Safari',
20
+ :platformVersion => '7.1',
21
+ :platformName => 'iOS',
22
+ :app => 'safari',
23
+ :newCommandTimeout => 9999
24
+ }
25
+
26
+ when 'android'
27
+ capabilities = {
28
+
29
+ :deviceName => 'android_simulator',
30
+ :version => '4.4.2',
31
+ :platformName => 'Android',
32
+ :newCommandTimeout => 9999,
33
+ :browserName => 'Browser',
34
+ :avd => 'android_simulator',
35
+ autoAcceptAlerts: true
36
+ }
37
+
38
+ end
39
+
40
+
41
+ ENV['appium_url'] ||= "http://127.0.0.1:4723/wd/hub"
42
+ ENV['browser'] ||= 'firefox'
43
+
44
+ RSpec.configure do |config|
45
+
46
+ config.before(:each) do
47
+ if ENV['platform']
48
+ @browser = Watir::Browser.new(Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => ENV['appium_url']))
49
+ else
50
+ @browser = Watir::Browser.new ENV['browser']
51
+ end
52
+ end
53
+ config.after(:each) do
54
+ @browser.close if @browser
55
+ end
56
+ end
@@ -0,0 +1,77 @@
1
+ @import url(http://fonts.googleapis.com/css?family=Open+Sans);
2
+
3
+ *, *:after, *:before {
4
+ box-sizing: border-box;
5
+ -moz-box-sizing: border-box;
6
+ }
7
+
8
+ html, body {
9
+ margin: 0;
10
+ padding: 0;
11
+ height: 100%;
12
+ min-height: 100%;
13
+ background: #eee;
14
+ font: 13px/1.5em 'Open Sans', Helvetica, Arial, sans-serif;
15
+ }
16
+
17
+ a {
18
+ color: #4986e7;
19
+ }
20
+
21
+ .bg1, .green { background: #42d692; }
22
+ .bg2, .blue { background: #4986e7; }
23
+ .bg3, .red { background: #d06b64; }
24
+ .bg4, .purple { background: #cd74e6; }
25
+ .bg5, .azure { background: #9fe1e7; }
26
+
27
+ body {
28
+ margin: 20px;
29
+ }
30
+
31
+ pre {
32
+ background: #fff;
33
+ padding: 20px;
34
+ margin-bottom: 20px;
35
+ }
36
+
37
+ .container {
38
+ max-width: 900px;
39
+ margin: 0 auto;
40
+ }
41
+
42
+ .clear { clear: both; }
43
+
44
+
45
+ html, body {
46
+ overflow: hidden;
47
+ margin: 0;
48
+ }
49
+
50
+ body {
51
+ -webkit-perspective: 500;
52
+ -moz-perspective: 500;
53
+ perspective: 500;
54
+ }
55
+
56
+ .animate {
57
+ -webkit-transition: all .3s;
58
+ -moz-transition: all .3s;
59
+ transition: all .3s;
60
+ }
61
+
62
+ #hit {
63
+ padding: 10px;
64
+ }
65
+
66
+ #log {
67
+ position: absolute;
68
+ padding: 10px;
69
+ }
70
+
71
+ #myElement {
72
+ background: silver;
73
+ height: 300px;
74
+ text-align: center;
75
+ font: 30px/300px Helvetica, Arial, sans-serif;
76
+ }
77
+
@@ -0,0 +1,198 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Touch Page Test</title>
6
+ <script type="text/javascript" src="../js/jquery-1.7.2.min.js"></script>
7
+
8
+ <script type='application/javascript' src='js/hammer.js'></script>
9
+ <link rel="stylesheet" type="text/css" href="css/style.css" />
10
+ <style type="text/css">
11
+ #blue{
12
+ position:absolute;
13
+ top:100px;
14
+ left:500px;
15
+ width:100px;
16
+ height:100px;
17
+ background-color:blue;
18
+ cursor:pointer;
19
+ right:
20
+ }
21
+ </style>
22
+ </head>
23
+ <body>
24
+
25
+ <p>Move the square to get it moving (it's using Hammer JS to recognize the touch).</p>
26
+
27
+ <p id="distance_x">Distance moved horizontaly:</p>
28
+ <br>
29
+ <p id="distance_y">Distance moved verticaly:</p>
30
+
31
+
32
+ <div id="hit" style="background: #42d692; width: 150px; height: 150px;"></div>
33
+
34
+
35
+ <script>
36
+
37
+ var reqAnimationFrame = (function () {
38
+ return window[Hammer.prefixed(window, 'requestAnimationFrame')] || function (callback) {
39
+ window.setTimeout(callback, 1000 / 60);
40
+ };
41
+ })();
42
+
43
+ var el = document.querySelector("#hit");
44
+
45
+ var START_X = Math.round((window.innerWidth - el.offsetWidth) / 2);
46
+ var START_Y = Math.round((window.innerHeight - el.offsetHeight) / 2);
47
+
48
+ var ticking = false;
49
+ var transform;
50
+ var timer;
51
+
52
+ var mc = new Hammer.Manager(el);
53
+
54
+ mc.add(new Hammer.Pan({ threshold: 0, pointers: 0 }));
55
+
56
+ mc.add(new Hammer.Swipe()).recognizeWith(mc.get('pan'));
57
+ mc.add(new Hammer.Rotate({ threshold: 0 })).recognizeWith(mc.get('pan'));
58
+ mc.add(new Hammer.Pinch({ threshold: 0 })).recognizeWith([mc.get('pan'), mc.get('rotate')]);
59
+
60
+ mc.add(new Hammer.Tap({ event: 'doubletap', taps: 2 }));
61
+ mc.add(new Hammer.Tap());
62
+
63
+ mc.on("panstart panmove", onPan);
64
+ mc.on("rotatestart rotatemove", onRotate);
65
+ mc.on("pinchstart pinchmove", onPinch);
66
+ mc.on("swipe", onSwipe);
67
+ mc.on("tap", onTap);
68
+ mc.on("doubletap", onDoubleTap);
69
+
70
+ mc.on("hammer.input", function(ev) {
71
+ if(ev.isFinal) {
72
+ START_X = START_X + ev.deltaX;
73
+ START_Y = START_Y + ev.deltaY;
74
+ $('#distance_x').text("Distance moved horizontaly: " + ev.deltaX);
75
+ $('#distance_y').text("Distance moved verticaly: " + ev.deltaY);
76
+
77
+ }
78
+ });
79
+
80
+
81
+ function resetElement() {
82
+ el.className = 'animate';
83
+ transform = {
84
+ translate: { x: START_X, y: START_Y },
85
+ scale: 1,
86
+ angle: 0,
87
+ rx: 0,
88
+ ry: 0,
89
+ rz: 0
90
+ };
91
+
92
+ requestElementUpdate();
93
+
94
+
95
+ }
96
+
97
+ function updateElementTransform() {
98
+ var value = [
99
+ 'translate3d(' + transform.translate.x + 'px, ' + transform.translate.y + 'px, 0)',
100
+ 'scale(' + transform.scale + ', ' + transform.scale + ')',
101
+ 'rotate3d('+ transform.rx +','+ transform.ry +','+ transform.rz +','+ transform.angle + 'deg)'
102
+ ];
103
+
104
+ value = value.join(" ");
105
+ el.textContent = value;
106
+ el.style.webkitTransform = value;
107
+ el.style.mozTransform = value;
108
+ el.style.transform = value;
109
+ ticking = false;
110
+ }
111
+
112
+ function requestElementUpdate() {
113
+ if(!ticking) {
114
+ reqAnimationFrame(updateElementTransform);
115
+ ticking = true;
116
+ }
117
+ }
118
+
119
+ function onPan(ev) {
120
+ el.className = '';
121
+ transform.translate = {
122
+ x: START_X + ev.deltaX,
123
+ y: START_Y + ev.deltaY
124
+ };
125
+
126
+ requestElementUpdate();
127
+
128
+ }
129
+
130
+ var initScale = 1;
131
+ function onPinch(ev) {
132
+ if(ev.type == 'pinchstart') {
133
+ initScale = transform.scale || 1;
134
+ }
135
+
136
+ el.className = '';
137
+ transform.scale = initScale * ev.scale;
138
+
139
+ requestElementUpdate();
140
+
141
+ }
142
+
143
+ var initAngle = 0;
144
+ function onRotate(ev) {
145
+ if(ev.type == 'rotatestart') {
146
+ initAngle = transform.angle || 0;
147
+ }
148
+
149
+ el.className = '';
150
+ transform.rz = 1;
151
+ transform.angle = initAngle + ev.rotation;
152
+ requestElementUpdate();
153
+
154
+ }
155
+
156
+ function onSwipe(ev) {
157
+ var angle = 50;
158
+ transform.ry = (ev.direction & Hammer.DIRECTION_HORIZONTAL) ? 1 : 0;
159
+ transform.rx = (ev.direction & Hammer.DIRECTION_VERTICAL) ? 1 : 0;
160
+ transform.angle = (ev.direction & (Hammer.DIRECTION_RIGHT | Hammer.DIRECTION_UP)) ? angle : -angle;
161
+
162
+ clearTimeout(timer);
163
+ timer = setTimeout(function () {
164
+ resetElement();
165
+ }, 300);
166
+ requestElementUpdate();
167
+
168
+ }
169
+
170
+ function onTap(ev) {
171
+ transform.rx = 1;
172
+ transform.angle = 25;
173
+
174
+ clearTimeout(timer);
175
+ timer = setTimeout(function () {
176
+ resetElement();
177
+ }, 200);
178
+ requestElementUpdate();
179
+
180
+ }
181
+
182
+ function onDoubleTap(ev) {
183
+ transform.rx = 1;
184
+ transform.angle = 80;
185
+
186
+ clearTimeout(timer);
187
+ timer = setTimeout(function () {
188
+ resetElement();
189
+ }, 500);
190
+ requestElementUpdate();
191
+
192
+ }
193
+
194
+ resetElement();
195
+
196
+ </script>
197
+ </body>
198
+ </html>