touch_action 0.0.2alpha → 0.1.0

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 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>