furter 0.0.3 → 0.0.3.1

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.
@@ -1,2 +1,5 @@
1
1
  language: ruby
2
2
  rvm: 1.9.3
3
+ before_install:
4
+ - sudo apt-get update -qq
5
+ - sudo apt-get install -qq libavahi-compat-libdnssd-dev
data/Changelog CHANGED
@@ -1,3 +1,7 @@
1
+ === Version 0.3.1 / 2013-04-23
2
+ * added a new slider accessor
3
+ * added a views accessor to define which view controllers should be on a screen
4
+
1
5
  === Version 0.3 / 2013-04-03
2
6
  Initial release with support for text, label, button, view, alert_button,
3
7
  table, table_item, map_pin and switch controls
data/README.md CHANGED
@@ -1,20 +1,76 @@
1
1
  # Furter
2
2
 
3
- TODO: Write a gem description
3
+ A gem to assist in building page-object like structures for testing iOS applications. `furter` uses [`frank-cucumber`](http://testingwithfrank.com/) to automate iOS applications using page-objects.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'furter', :git => 'https://github.com/leviwilson/furter.git'
9
+ source 'https://rubygems.org'
10
+ gem 'furter'
10
11
 
11
12
  And then execute:
12
13
 
13
14
  $ bundle
15
+
16
+ ### Setting Up Cucumber
17
+ After your `Gemfile` has been updated, add these lines to your `features/support/env.rb` file in `cucumber`:
14
18
 
15
- ## Usage
19
+ ```ruby
20
+ require 'furter'
21
+ require 'rspec-expectations'
16
22
 
17
- TODO: Write usage instructions here
23
+ World(Furter::Navigation)
24
+
25
+ APP_BUNDLE_PATH = File.expand_path( '../../../Frank/frankified_build/YourApp.app', __FILE__ )
26
+
27
+ Frank::Cucumber::FrankHelper.use_shelley_from_now_on
28
+
29
+ Before do
30
+ version = '6.1'
31
+ idiom = 'iPhone'
32
+
33
+ launch_app APP_BUNDLE_PATH, version, idiom
34
+ end
35
+ ```
36
+
37
+ ## Defining Screens
38
+ Simply create a new class that describes the screen that you are working with and include `Furter`.
39
+
40
+ ```ruby
41
+ class LoginScreen
42
+ include Furter
43
+
44
+ text(:username, :label => 'usernameField')
45
+ text(:password, :label => 'passwordField')
46
+ button(:login, :text => 'Login')
47
+ end
48
+ ```
49
+
50
+ In your step definition, use the `Furter::Navigation#on` method when using your page-object. This method will create your screen and then wait until all animations have stopped before letting you interact with your page-object.
51
+
52
+ ```ruby
53
+ When ^I login to my application$ do
54
+ on(LoginScreen) do |screen|
55
+ screen.username = 'user@example.com'
56
+ screen.password = '$3cr3t`
57
+ screen.login
58
+ end
59
+ end
60
+ ```
61
+
62
+ ### Waiting for Screens
63
+ If you would like for `furter` to wait until your screen becomes "active" (perhaps after some asynchronous call has come back), simply define an `active?` method and `furter` will wait until this returns `true` before interacting with it.
64
+
65
+ ```ruby
66
+ class LandingScreen
67
+ include Furter
68
+
69
+ def active?
70
+ has_text? 'You have successfully logged in!'
71
+ end
72
+ end
73
+ ```
18
74
 
19
75
  ## Contributing
20
76
 
@@ -15,6 +15,7 @@
15
15
  @property (weak, nonatomic) IBOutlet UIButton *textButton;
16
16
  @property (weak, nonatomic) IBOutlet UIButton *labeledButton;
17
17
  @property (weak, nonatomic) IBOutlet UILabel *labeledLabel;
18
+ @property (weak, nonatomic) IBOutlet UISlider *slider;
18
19
 
19
20
  @property (strong, nonatomic) id detailItem;
20
21
 
@@ -14,6 +14,7 @@
14
14
  @end
15
15
 
16
16
  @implementation DetailViewController
17
+ @synthesize slider;
17
18
 
18
19
  #pragma mark - Managing the detail item
19
20
 
@@ -47,6 +48,7 @@
47
48
  [self configureView];
48
49
  [self.labeledButton setAccessibilityLabel:@"labeledButtonId"];
49
50
  [self.labeledLabel setAccessibilityLabel:@"labelByAccessibilityLabel"];
51
+ [slider setAccessibilityLabel:@"sliderByLabel"];
50
52
  }
51
53
 
52
54
  - (void)didReceiveMemoryWarning
@@ -107,6 +107,12 @@
107
107
  <segue destination="2m6-NE-oGx" kind="push" id="g3T-p0-Sec"/>
108
108
  </connections>
109
109
  </button>
110
+ <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="wB4-9F-vl7">
111
+ <accessibility key="accessibilityConfiguration" label="sliderByLabel"/>
112
+ <constraints>
113
+ <constraint firstAttribute="width" constant="288" id="dCS-tQ-uoe"/>
114
+ </constraints>
115
+ </slider>
110
116
  </subviews>
111
117
  <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
112
118
  <constraints>
@@ -125,6 +131,7 @@
125
131
  <constraint firstItem="MgB-Y1-P3J" firstAttribute="leading" secondItem="HNa-e4-2od" secondAttribute="leading" type="default" id="TI6-aB-T6l"/>
126
132
  <constraint firstItem="6Hu-uu-EUY" firstAttribute="trailing" secondItem="MgB-Y1-P3J" secondAttribute="trailing" type="default" id="Tkv-gE-Bb0"/>
127
133
  <constraint firstItem="79f-eU-bDt" firstAttribute="top" secondItem="26" secondAttribute="top" constant="23" id="WAb-82-oiE"/>
134
+ <constraint firstAttribute="bottom" secondItem="wB4-9F-vl7" secondAttribute="bottom" constant="250" id="bJ6-kP-IlL"/>
128
135
  <constraint firstItem="HNa-e4-2od" firstAttribute="trailing" secondItem="mEd-bW-xG3" secondAttribute="trailing" type="default" id="e4T-wS-zIa"/>
129
136
  <constraint firstItem="27" firstAttribute="centerY" secondItem="26" secondAttribute="centerY" type="default" id="fbb-bQ-YI1"/>
130
137
  <constraint firstItem="MgB-Y1-P3J" firstAttribute="top" secondItem="26" secondAttribute="top" constant="120" id="fxO-Da-wfr"/>
@@ -133,6 +140,7 @@
133
140
  <constraint firstItem="n4M-Kb-ePv" firstAttribute="trailing" secondItem="6Hu-uu-EUY" secondAttribute="trailing" type="default" id="kXJ-R6-5W3"/>
134
141
  <constraint firstItem="79f-eU-bDt" firstAttribute="baseline" secondItem="mEd-bW-xG3" secondAttribute="baseline" type="default" id="piK-8v-q9x"/>
135
142
  <constraint firstItem="Nyi-ck-8hR" firstAttribute="top" secondItem="nbu-fr-Znd" secondAttribute="top" type="default" id="wtS-Ul-nbp"/>
143
+ <constraint firstItem="wB4-9F-vl7" firstAttribute="leading" secondItem="26" secondAttribute="leading" constant="206" id="zbX-ES-KTX"/>
136
144
  </constraints>
137
145
  <simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
138
146
  </view>
@@ -144,6 +152,7 @@
144
152
  <outlet property="labeledButton" destination="6Hu-uu-EUY" id="lP4-Wp-TLL"/>
145
153
  <outlet property="labeledLabel" destination="27" id="GUQ-6K-Ygb"/>
146
154
  <outlet property="placeholderTextField" destination="mEd-bW-xG3" id="WJN-WF-CeJ"/>
155
+ <outlet property="slider" destination="wB4-9F-vl7" id="tyV-Zf-nQd"/>
147
156
  <outlet property="textButton" destination="MgB-Y1-P3J" id="dgB-Uo-P2L"/>
148
157
  </connections>
149
158
  </viewController>
@@ -0,0 +1,9 @@
1
+ Feature: Working with sliders
2
+
3
+ Scenario: Interacting with the slider
4
+ Then we can interact with the raw view of the slider identified by "label"
5
+
6
+ Scenario: Getting and Setting value of the slider
7
+ Given we can interact with the raw view of the slider identified by "label"
8
+ When I set the progress of the slider identified by "label" to "0.2"
9
+ Then I can see the progress of the slider identified by "label" is "0.2"
@@ -4,4 +4,4 @@ end
4
4
 
5
5
  Then /^I should end up on the "([^"]*)"$/ do |where|
6
6
  on(where.to_class).should be_active
7
- end
7
+ end
@@ -0,0 +1,11 @@
1
+ Then /^we can interact with the raw view of the slider identified by "([^"]*)"$/ do |how|
2
+ on(DetailPage).send("slider_#{how}_view").should be_kind_of(Furter::Accessors::View)
3
+ end
4
+
5
+ When /^I set the progress of the slider identified by "([^"]*)" to "([^"]*)"$/ do |how, value|
6
+ on(DetailPage).send("slider_#{how}_move", value.to_f)
7
+ end
8
+
9
+ Then /^I can see the progress of the slider identified by "([^"]*)" is "([^"]*)"$/ do |how, value|
10
+ on(DetailPage).send("slider_#{how}_progress").should eq(value.to_f)
11
+ end
@@ -12,4 +12,8 @@ class DetailPage
12
12
  button(:go_elsewhere, :text => 'Go Elsewhere')
13
13
 
14
14
  switch(:switch_toggle, :label => 'switchToggle')
15
+
16
+ slider(:slider_label, :label=> 'sliderByLabel')
17
+
18
+ views('DetailViewController')
15
19
  end
@@ -10,6 +10,7 @@ require 'furter/accessors/table'
10
10
  require 'furter/accessors/table_item'
11
11
  require 'furter/accessors/text'
12
12
  require 'furter/accessors/label'
13
+ require 'furter/accessors/slider'
13
14
 
14
15
  module Furter
15
16
  include Frank::Cucumber::FrankHelper
@@ -46,8 +47,7 @@ module Furter
46
47
  touch locator
47
48
  end
48
49
  end
49
-
50
- def active?
51
- true
52
- end
53
50
  end
51
+
52
+
53
+
@@ -83,5 +83,23 @@ module Furter
83
83
  Furter::Accessors::Switch.new(locator)
84
84
  end
85
85
  end
86
+
87
+ def slider(name, locator)
88
+ define_method("#{name}_view") do
89
+ Furter::Accessors::Slider.new(locator)
90
+ end
91
+ define_method("#{name}_move") do |value|
92
+ Furter::Accessors::Slider.new(locator).move value
93
+ end
94
+ define_method("#{name}_progress") do
95
+ Furter::Accessors::Slider.new(locator).progress
96
+ end
97
+ end
98
+
99
+ def views(*view_classes)
100
+ define_method(:active?) do
101
+ (view_classes & Furter::Accessors::View.new.next_responders) == view_classes
102
+ end
103
+ end
86
104
  end
87
105
  end
@@ -0,0 +1,20 @@
1
+ module Furter
2
+ module Accessors
3
+ class Slider < View
4
+
5
+ def move(value)
6
+ frankly_map(selector, 'setValue:animated:', value, 'YES')
7
+ end
8
+
9
+ def progress
10
+ frankly_map(selector, 'value')[0]
11
+ end
12
+
13
+ def view_class
14
+ return "view:'#{@locator[:type]}'" if @locator[:type]
15
+ "view:'UISlider'"
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -19,6 +19,12 @@ module Furter
19
19
  frankly_map(selector, 'isEnabled')[0]
20
20
  end
21
21
 
22
+ def next_responders
23
+ frankly_map("view:'UIView'", 'nextResponder').map do |r|
24
+ r.gsub(/[<>]/,'')
25
+ end
26
+ end
27
+
22
28
  private
23
29
  def selector
24
30
  "#{view_class} #{selector_how}#{selector_extra}"
@@ -16,7 +16,7 @@ module Furter
16
16
  wait_a_bit_for_animations
17
17
  wait_until(:message => "Expected #{cls} to be active", :timeout => 30) do
18
18
  screen.active?
19
- end
19
+ end if screen.respond_to?(:active?)
20
20
  wait_a_bit_for_animations
21
21
  block.call screen if block
22
22
  screen
@@ -1,3 +1,3 @@
1
1
  module Furter
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.3.1"
3
3
  end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Furter::Accessors::Slider do
4
+ let(:slider) { Furter::Accessors::Slider.new(:label => 'id') }
5
+ let(:selector) { slider.send(:selector) }
6
+
7
+ context 'locating slider' do
8
+ it 'can be found by id' do
9
+ id_slider = Furter::Accessors::Slider.new(:label => 'someSliderLabel')
10
+ id_slider.send(:selector).should eq("view:'UISlider' marked:'someSliderLabel'")
11
+ end
12
+ end
13
+
14
+ context 'moving slider' do
15
+ it "can move the slider value" do
16
+ slider.should_receive(:frankly_map).with(selector,"setValue:animated:", 0.20, "YES")
17
+ slider.move 0.20
18
+ end
19
+ it "can get progress value of slider" do
20
+ slider.should_receive(:frankly_map).with(selector, 'value').and_return([0.20])
21
+ slider.progress.should eq(0.20)
22
+ end
23
+ end
24
+ end
@@ -40,4 +40,9 @@ describe Furter::Accessors::View do
40
40
  view.should_receive(:frankly_map).with(selector, 'isEnabled').and_return([true])
41
41
  view.should be_enabled
42
42
  end
43
- end
43
+
44
+ it 'should know about next responders' do
45
+ view.should_receive(:frankly_map).with("view:'UIView'", 'nextResponder').and_return(['<First>', '<Second>', '<Third>'])
46
+ view.next_responders.should eq ['First', 'Second', 'Third']
47
+ end
48
+ end
@@ -8,6 +8,7 @@ class SomePage
8
8
  view(:generic_view, :label => 'id')
9
9
  button(:button_field, :label => 'id')
10
10
  switch(:switch_field, :label => 'id')
11
+ views('First', 'Fifth', 'Seventh')
11
12
  end
12
13
 
13
14
  describe Furter::Accessors do
@@ -113,4 +114,27 @@ describe Furter::Accessors do
113
114
  screen.switch_field_view.should be(switch)
114
115
  end
115
116
  end
117
+
118
+ context 'views' do
119
+ let(:view) { double('View') }
120
+
121
+ before(:each) do
122
+ Furter::Accessors::View.should_receive(:new).and_return(view)
123
+ end
124
+
125
+ it 'is active if it has all of the views' do
126
+ view.should_receive(:next_responders).and_return(['First', 'Fifth', 'Seventh'])
127
+ screen.should be_active
128
+ end
129
+
130
+ it 'does not care about the order' do
131
+ view.should_receive(:next_responders).and_return(['Seventh', 'First', 'Fifth'])
132
+ screen.should be_active
133
+ end
134
+
135
+ it 'is inactive if not all views are represented' do
136
+ view.should_receive(:next_responders).and_return(['First', 'Fifth', 'Not The Seventh'])
137
+ screen.should_not be_active
138
+ end
139
+ end
116
140
  end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ class NavigationScreen; end
4
+
5
+ RSpec.configure do |c|
6
+ c.include Furter::Navigation, :navigation => true
7
+ end
8
+
9
+ describe Furter::Navigation, :navigation => true do
10
+ let(:screen) { double('navigation screen') }
11
+
12
+ before(:each) do
13
+ NavigationScreen.should_receive(:new).and_return(screen)
14
+ end
15
+
16
+ it 'returns the screen that was asked for' do
17
+ on(NavigationScreen).should be(screen)
18
+ end
19
+
20
+ it 'cares about active? if you do' do
21
+ screen.should_receive(:active?).and_return(true)
22
+ on(NavigationScreen)
23
+ end
24
+
25
+ it 'gives you your object when it is ready' do
26
+ screen.should_receive(:call_me)
27
+ on(NavigationScreen) do |s|
28
+ s.call_me
29
+ end
30
+ end
31
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: furter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-03 00:00:00.000000000 Z
12
+ date: 2013-04-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: frank-cucumber
@@ -146,9 +146,11 @@ files:
146
146
  - features/button.feature
147
147
  - features/label.feature
148
148
  - features/navigation.feature
149
+ - features/slider.feature
149
150
  - features/step_definitions/button_steps.rb
150
151
  - features/step_definitions/label_steps.rb
151
152
  - features/step_definitions/navigation_steps.rb
153
+ - features/step_definitions/slider_steps.rb
152
154
  - features/step_definitions/switches_steps.rb
153
155
  - features/step_definitions/text_steps.rb
154
156
  - features/support/core_ext/string.rb
@@ -165,6 +167,7 @@ files:
165
167
  - lib/furter/accessors/button.rb
166
168
  - lib/furter/accessors/label.rb
167
169
  - lib/furter/accessors/map_pin.rb
170
+ - lib/furter/accessors/slider.rb
168
171
  - lib/furter/accessors/switch.rb
169
172
  - lib/furter/accessors/table.rb
170
173
  - lib/furter/accessors/table_item.rb
@@ -174,10 +177,12 @@ files:
174
177
  - lib/furter/version.rb
175
178
  - spec/lib/furter/accessors/button_spec.rb
176
179
  - spec/lib/furter/accessors/label_spec.rb
180
+ - spec/lib/furter/accessors/slider_spec.rb
177
181
  - spec/lib/furter/accessors/switch_spec.rb
178
182
  - spec/lib/furter/accessors/text_spec.rb
179
183
  - spec/lib/furter/accessors/view_spec.rb
180
184
  - spec/lib/furter/accessors_spec.rb
185
+ - spec/lib/furter/navigation_spec.rb
181
186
  - spec/spec_helper.rb
182
187
  homepage: ''
183
188
  licenses: []
@@ -193,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
193
198
  version: '0'
194
199
  segments:
195
200
  - 0
196
- hash: -3139935095822533556
201
+ hash: -3754935544043957014
197
202
  required_rubygems_version: !ruby/object:Gem::Requirement
198
203
  none: false
199
204
  requirements:
@@ -202,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
207
  version: '0'
203
208
  segments:
204
209
  - 0
205
- hash: -3139935095822533556
210
+ hash: -3754935544043957014
206
211
  requirements: []
207
212
  rubyforge_project:
208
213
  rubygems_version: 1.8.25
@@ -213,9 +218,11 @@ test_files:
213
218
  - features/button.feature
214
219
  - features/label.feature
215
220
  - features/navigation.feature
221
+ - features/slider.feature
216
222
  - features/step_definitions/button_steps.rb
217
223
  - features/step_definitions/label_steps.rb
218
224
  - features/step_definitions/navigation_steps.rb
225
+ - features/step_definitions/slider_steps.rb
219
226
  - features/step_definitions/switches_steps.rb
220
227
  - features/step_definitions/text_steps.rb
221
228
  - features/support/core_ext/string.rb
@@ -227,8 +234,10 @@ test_files:
227
234
  - features/text.feature
228
235
  - spec/lib/furter/accessors/button_spec.rb
229
236
  - spec/lib/furter/accessors/label_spec.rb
237
+ - spec/lib/furter/accessors/slider_spec.rb
230
238
  - spec/lib/furter/accessors/switch_spec.rb
231
239
  - spec/lib/furter/accessors/text_spec.rb
232
240
  - spec/lib/furter/accessors/view_spec.rb
233
241
  - spec/lib/furter/accessors_spec.rb
242
+ - spec/lib/furter/navigation_spec.rb
234
243
  - spec/spec_helper.rb