furter 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/.gitignore +21 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +2 -0
  4. data/Changelog +3 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +25 -0
  8. data/Rakefile +30 -0
  9. data/app/FurterApp/Frank/features/my_first.feature +12 -0
  10. data/app/FurterApp/Frank/features/step_definitions/launch_steps.rb +20 -0
  11. data/app/FurterApp/Frank/features/support/env.rb +8 -0
  12. data/app/FurterApp/Frank/frankify.xcconfig +6 -0
  13. data/app/FurterApp/Frank/libCocoaAsyncSocket.a +0 -0
  14. data/app/FurterApp/Frank/libCocoaAsyncSocketMac.a +0 -0
  15. data/app/FurterApp/Frank/libCocoaHTTPServer.a +0 -0
  16. data/app/FurterApp/Frank/libCocoaHTTPServerMac.a +0 -0
  17. data/app/FurterApp/Frank/libCocoaLumberjack.a +0 -0
  18. data/app/FurterApp/Frank/libCocoaLumberjackMac.a +0 -0
  19. data/app/FurterApp/Frank/libFrank.a +0 -0
  20. data/app/FurterApp/Frank/libFrankMac.a +0 -0
  21. data/app/FurterApp/Frank/libShelley.a +0 -0
  22. data/app/FurterApp/Frank/libShelleyMac.a +0 -0
  23. data/app/FurterApp/FurterApp.xcodeproj/project.pbxproj +807 -0
  24. data/app/FurterApp/FurterApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  25. data/app/FurterApp/FurterApp.xcodeproj/project.xcworkspace/xcuserdata/lwilson.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  26. data/app/FurterApp/FurterApp.xcodeproj/xcuserdata/lwilson.xcuserdatad/xcschemes/FurterApp.xcscheme +86 -0
  27. data/app/FurterApp/FurterApp.xcodeproj/xcuserdata/lwilson.xcuserdatad/xcschemes/xcschememanagement.plist +22 -0
  28. data/app/FurterApp/FurterApp/AppDelegate.h +22 -0
  29. data/app/FurterApp/FurterApp/AppDelegate.m +161 -0
  30. data/app/FurterApp/FurterApp/Default-568h@2x.png +0 -0
  31. data/app/FurterApp/FurterApp/Default.png +0 -0
  32. data/app/FurterApp/FurterApp/Default@2x.png +0 -0
  33. data/app/FurterApp/FurterApp/DetailViewController.h +23 -0
  34. data/app/FurterApp/FurterApp/DetailViewController.m +80 -0
  35. data/app/FurterApp/FurterApp/FurterApp-Info.plist +59 -0
  36. data/app/FurterApp/FurterApp/FurterApp-Prefix.pch +15 -0
  37. data/app/FurterApp/FurterApp/FurterApp.xcdatamodeld/.xccurrentversion +8 -0
  38. data/app/FurterApp/FurterApp/FurterApp.xcdatamodeld/FurterApp.xcdatamodel/contents +9 -0
  39. data/app/FurterApp/FurterApp/MasterViewController.h +22 -0
  40. data/app/FurterApp/FurterApp/MasterViewController.m +235 -0
  41. data/app/FurterApp/FurterApp/en.lproj/InfoPlist.strings +2 -0
  42. data/app/FurterApp/FurterApp/en.lproj/MainStoryboard_iPad.storyboard +260 -0
  43. data/app/FurterApp/FurterApp/en.lproj/MainStoryboard_iPhone.storyboard +129 -0
  44. data/app/FurterApp/FurterApp/main.m +18 -0
  45. data/cucumber.yml +2 -0
  46. data/features/button.feature +12 -0
  47. data/features/label.feature +10 -0
  48. data/features/navigation.feature +5 -0
  49. data/features/step_definitions/button_steps.rb +7 -0
  50. data/features/step_definitions/label_steps.rb +8 -0
  51. data/features/step_definitions/navigation_steps.rb +7 -0
  52. data/features/step_definitions/switches_steps.rb +12 -0
  53. data/features/step_definitions/text_steps.rb +25 -0
  54. data/features/support/core_ext/string.rb +9 -0
  55. data/features/support/env.rb +25 -0
  56. data/features/support/hooks.rb +3 -0
  57. data/features/support/screens/detail.rb +15 -0
  58. data/features/support/screens/elsewhere_page.rb +7 -0
  59. data/features/switches.feature +7 -0
  60. data/features/text.feature +15 -0
  61. data/furter.gemspec +26 -0
  62. data/lib/furter.rb +53 -0
  63. data/lib/furter/accessors.rb +87 -0
  64. data/lib/furter/accessors/alert_button.rb +18 -0
  65. data/lib/furter/accessors/button.rb +17 -0
  66. data/lib/furter/accessors/label.rb +13 -0
  67. data/lib/furter/accessors/map_pin.rb +18 -0
  68. data/lib/furter/accessors/switch.rb +20 -0
  69. data/lib/furter/accessors/table.rb +15 -0
  70. data/lib/furter/accessors/table_item.rb +10 -0
  71. data/lib/furter/accessors/text.rb +27 -0
  72. data/lib/furter/accessors/view.rb +46 -0
  73. data/lib/furter/navigation.rb +25 -0
  74. data/lib/furter/version.rb +3 -0
  75. data/spec/lib/furter/accessors/button_spec.rb +23 -0
  76. data/spec/lib/furter/accessors/label_spec.rb +24 -0
  77. data/spec/lib/furter/accessors/switch_spec.rb +28 -0
  78. data/spec/lib/furter/accessors/text_spec.rb +39 -0
  79. data/spec/lib/furter/accessors/view_spec.rb +43 -0
  80. data/spec/lib/furter/accessors_spec.rb +116 -0
  81. data/spec/spec_helper.rb +18 -0
  82. metadata +234 -0
@@ -0,0 +1,18 @@
1
+ module Furter
2
+ module Accessors
3
+ class AlertButton < View
4
+ include Frank::Cucumber::FrankHelper
5
+
6
+ def click
7
+ wait_for_nothing_to_be_animating
8
+ super
9
+ end
10
+
11
+ private
12
+ def selector
13
+ "view:'UIAlertView' view:'UIAlertButton' marked:'#{@locator[:text]}'"
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,17 @@
1
+ module Furter
2
+ module Accessors
3
+ class Button < View
4
+ private
5
+ def view_class
6
+ case
7
+ when @locator[:type]
8
+ "view:'#{@locator[:type]}'"
9
+ when @locator[:text]
10
+ "button label"
11
+ else
12
+ "button"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Furter
2
+ module Accessors
3
+ class Label < View
4
+ def view_class
5
+ 'label'
6
+ end
7
+
8
+ def text
9
+ frankly_map(selector, 'text')[0]
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module Furter
2
+ module Accessors
3
+ class MapPin < View
4
+ include Frank::Cucumber::FrankHelper
5
+
6
+ def click
7
+ wait_for_nothing_to_be_animating
8
+ super
9
+ end
10
+
11
+ private
12
+ def selector
13
+ "view:'MKPinAnnotationView' marked:'#{@locator[:text]}'"
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,20 @@
1
+ module Furter
2
+ module Accessors
3
+ class Switch < View
4
+ include Furter
5
+
6
+ def on?
7
+ frankly_map(selector, 'isOn')[0]
8
+ end
9
+
10
+ def set(on_or_off)
11
+ click if on_or_off != on?
12
+ end
13
+
14
+ private
15
+ def view_class
16
+ "view:'UISwitch'"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module Furter
2
+ module Accessors
3
+ class Table < View
4
+ def options
5
+ frankly_map("#{selector} label", "text").compact.map(&:strip).reject(&:empty?)
6
+ end
7
+
8
+ private
9
+ def selector
10
+ "view:'UITableView' marked:'#{@locator[:label]}'"
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,10 @@
1
+ module Furter
2
+ module Accessors
3
+ class TableItem < Button
4
+ private
5
+ def selector
6
+ "label marked:'#{@locator[:text]}' parent tableViewCell"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ module Furter
2
+ module Accessors
3
+ class Text < View
4
+ alias_method :editable?, :enabled?
5
+
6
+ def get_text
7
+ frankly_map(selector, "text")[0]
8
+ end
9
+
10
+ def set_text(text)
11
+ frankly_map(selector, "becomeFirstResponder")
12
+ frankly_map(selector, "setText:", text)
13
+ frankly_map(selector, "endEditing:", true)
14
+ end
15
+
16
+ def has_text?(text)
17
+ element_exists "view marked:'#{text}'"
18
+ end
19
+
20
+ private
21
+ def selector
22
+ return "textField placeholder:'#{@locator[:placeholder]}'" if @locator[:placeholder]
23
+ return "textField marked:'#{@locator[:label]}'" if @locator[:label]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,46 @@
1
+ module Furter
2
+ module Accessors
3
+ class View
4
+ include Furter, Frank::Cucumber::FrankHelper, Frank::Cucumber::WaitHelper
5
+
6
+ def initialize(locator={})
7
+ @locator = locator
8
+ end
9
+
10
+ def click
11
+ wait_for_and_touch selector
12
+ end
13
+
14
+ def visible?
15
+ element_is_not_hidden selector
16
+ end
17
+
18
+ def enabled?
19
+ frankly_map(selector, 'isEnabled')[0]
20
+ end
21
+
22
+ private
23
+ def selector
24
+ "#{view_class} #{selector_how}#{selector_extra}"
25
+ end
26
+
27
+ def selector_how
28
+ case
29
+ when @locator[:label]
30
+ "marked:'#{@locator[:label]}'"
31
+ when @locator[:text]
32
+ "text:'#{@locator[:text]}'"
33
+ end
34
+ end
35
+
36
+ def selector_extra
37
+ " #{@locator[:extra]}" if @locator[:extra]
38
+ end
39
+
40
+ def view_class
41
+ return "view:'#{@locator[:type]}'" if @locator[:type]
42
+ "view"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ require 'page_navigation'
2
+
3
+ module Furter
4
+ module Navigation
5
+ include PageNavigation, Frank::Cucumber::FrankHelper
6
+
7
+ def wait_a_bit_for_animations
8
+ begin
9
+ wait_for_nothing_to_be_animating 3
10
+ rescue
11
+ end
12
+ end
13
+
14
+ def on(cls, &block)
15
+ screen = cls.new
16
+ wait_a_bit_for_animations
17
+ wait_until(:message => "Expected #{cls} to be active", :timeout => 30) do
18
+ screen.active?
19
+ end
20
+ wait_a_bit_for_animations
21
+ block.call screen if block
22
+ screen
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Furter
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Furter::Accessors::Button do
4
+ let(:button) { Furter::Accessors::Button.new(:text => 'Some Text') }
5
+ let(:selector) { button.send(:selector) }
6
+
7
+ context 'locating buttons' do
8
+ it 'can be found by text' do
9
+ text_button = Furter::Accessors::Button.new(:text => 'Some Text')
10
+ text_button.send(:selector).should eq("button label text:'Some Text'")
11
+ end
12
+
13
+ it ':text is the same as :label' do
14
+ label_button = Furter::Accessors::Button.new(:label => 'Some Text')
15
+ label_button.send(:selector).should eq("button marked:'Some Text'")
16
+ end
17
+
18
+ it 'can be a custom button type as well' do
19
+ custom_button = Furter::Accessors::Button.new(:label => 'Some Label', :type => 'MyButtonType')
20
+ custom_button.send(:selector).should eq("view:'MyButtonType' marked:'Some Label'")
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Furter::Accessors::Label do
4
+ let(:label) { Furter::Accessors::Label.new(:label => 'someLabel')}
5
+ let(:selector) { label.send(:selector) }
6
+
7
+ context 'locating labels' do
8
+ it 'can be found by accessibility label' do
9
+ label_control = Furter::Accessors::Label.new(:label => 'someAccessibilityLabel')
10
+ label_control.send(:selector).should eq("label marked:'someAccessibilityLabel'")
11
+ end
12
+
13
+ it 'can be found by text' do
14
+ label_control = Furter::Accessors::Label.new(:text => 'Text Value')
15
+ label_control.send(:selector).should eq("label text:'Text Value'")
16
+ end
17
+ end
18
+
19
+ it 'knows the text value' do
20
+ label.should_receive(:frankly_map).with(selector, 'text').and_return(['expected text'])
21
+ label.text.should eq('expected text')
22
+ end
23
+ end
24
+
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Furter::Accessors::Switch do
4
+ let(:switch) { Furter::Accessors::Switch.new(:label => 'accessibilityLabel') }
5
+
6
+ context 'locating switches' do
7
+ it 'can be found by label' do
8
+ switch.send(:selector).should eq("view:'UISwitch' marked:'accessibilityLabel'")
9
+ end
10
+ end
11
+
12
+ it 'knows if it is on' do
13
+ switch.should_receive(:frankly_map).with(anything, 'isOn').and_return([false])
14
+ switch.should_not be_on
15
+ end
16
+
17
+ it 'can turn it off or on' do
18
+ switch.should_receive(:on?).and_return(true, false)
19
+ switch.should_receive(:click).twice
20
+ [false, true].each { |on_or_off| switch.set on_or_off }
21
+ end
22
+
23
+ it 'will only toggle if in the expected state' do
24
+ switch.should_receive(:frankly_map).with(anything, 'isOn').and_return([false])
25
+ switch.should_not_receive(:click)
26
+ switch.set false
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Furter::Accessors::Text do
4
+ let(:placeholder) { Furter::Accessors::Text.new(:placeholder => 'Placeholder Text') }
5
+ let(:label) { Furter::Accessors::Text.new(:label => 'accessibilityLabel') }
6
+
7
+ context 'locating text fields' do
8
+ it 'should work by placeholder' do
9
+ placeholder.send(:selector).should eq("textField placeholder:'Placeholder Text'")
10
+ end
11
+
12
+ it 'should work by accessibility label' do
13
+ label.send(:selector).should eq("textField marked:'accessibilityLabel'")
14
+ end
15
+ end
16
+
17
+ it 'can get text' do
18
+ placeholder.should_receive(:frankly_map).with(anything, 'text').and_return(['expected text'])
19
+ placeholder.get_text.should eq('expected text')
20
+ end
21
+
22
+ it 'can set text' do
23
+ placeholder.should_receive(:frankly_map).with(anything, 'becomeFirstResponder').ordered
24
+ placeholder.should_receive(:frankly_map).with(anything, 'setText:', 'the new text').ordered
25
+ placeholder.should_receive(:frankly_map).with(anything, 'endEditing:', true).ordered
26
+
27
+ placeholder.set_text 'the new text'
28
+ end
29
+
30
+ it 'knows if text exists anywhere' do
31
+ placeholder.should_receive(:element_exists).with("view marked:'to find anywhere'")
32
+ placeholder.has_text? 'to find anywhere'
33
+ end
34
+
35
+ it 'knows whether we are editable or not' do
36
+ placeholder.should_receive(:frankly_map).with(anything, 'isEnabled').and_return([true])
37
+ placeholder.should be_enabled
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Furter::Accessors::View do
4
+ let(:view) { Furter::Accessors::View.new(:label => 'id') }
5
+ let(:selector) { view.send(:selector) }
6
+
7
+ context 'locating views' do
8
+ it 'can be found by accessibility label' do
9
+ by_label = Furter::Accessors::View.new(:label => 'id')
10
+ by_label.send(:selector).should eq("view marked:'id'")
11
+ end
12
+
13
+ it 'can use a custom type' do
14
+ by_type = Furter::Accessors::View.new(:type => 'UICustomType', :label => 'id')
15
+ by_type.send(:selector).should eq("view:'UICustomType' marked:'id'")
16
+ end
17
+
18
+ it 'can pass extra information as well' do
19
+ with_extras = Furter::Accessors::View.new(:label => 'id', :extra => 'label')
20
+ with_extras.send(:selector).should eq("view marked:'id' label")
21
+ end
22
+
23
+ it 'can be found by text' do
24
+ by_text = Furter::Accessors::View.new(:text => "Some Text")
25
+ by_text.send(:selector).should eq("view text:'Some Text'")
26
+ end
27
+ end
28
+
29
+ it 'can be clicked' do
30
+ view.should_receive(:wait_for_and_touch).with(selector)
31
+ view.click
32
+ end
33
+
34
+ it 'knows if it is visible' do
35
+ view.should_receive(:element_is_not_hidden).with(selector).and_return(true)
36
+ view.should be_visible
37
+ end
38
+
39
+ it 'knows if it is enabled' do
40
+ view.should_receive(:frankly_map).with(selector, 'isEnabled').and_return([true])
41
+ view.should be_enabled
42
+ end
43
+ end
@@ -0,0 +1,116 @@
1
+ require 'spec_helper'
2
+
3
+ class SomePage
4
+ include Furter
5
+
6
+ text(:text_field, :placeholder => 'text')
7
+ label(:label_field, :label => 'id')
8
+ view(:generic_view, :label => 'id')
9
+ button(:button_field, :label => 'id')
10
+ switch(:switch_field, :label => 'id')
11
+ end
12
+
13
+ describe Furter::Accessors do
14
+ let(:screen) { SomePage.new }
15
+
16
+ context 'text' do
17
+ let(:text) { double('Text accessor') }
18
+
19
+ before(:each) do
20
+ Furter::Accessors::Text.should_receive(:new).with(:placeholder => 'text').and_return(text)
21
+ end
22
+
23
+ it 'can be returned' do
24
+ text.should_receive(:get_text)
25
+ screen.text_field
26
+ end
27
+
28
+ it 'can be set' do
29
+ text.should_receive(:set_text).with('new text')
30
+ screen.text_field = 'new text'
31
+ end
32
+
33
+ it 'has editability' do
34
+ text.should_receive(:editable?).and_return(false)
35
+ screen.should_not be_text_field_editable
36
+ end
37
+
38
+ it 'can dish out a view' do
39
+ screen.text_field_view.should be(text)
40
+ end
41
+ end
42
+
43
+ context 'label' do
44
+ let(:label) { double('Label control') }
45
+
46
+ before(:each) do
47
+ Furter::Accessors::Label.should_receive(:new).with(:label => 'id').and_return(label)
48
+ end
49
+
50
+ it 'knows its value' do
51
+ label.should_receive(:text).and_return('expected text')
52
+ screen.label_field.should eq('expected text')
53
+ end
54
+
55
+ it 'can dish out a view' do
56
+ screen.label_field_view.should be(label)
57
+ end
58
+
59
+ end
60
+
61
+ context 'view' do
62
+ let(:view) { double('View accessor') }
63
+
64
+ before(:each) do
65
+ Furter::Accessors::View.should_receive(:new).with(:label => 'id').and_return(view)
66
+ end
67
+
68
+ it 'can be clicked' do
69
+ view.should_receive(:click)
70
+ screen.generic_view
71
+ end
72
+
73
+ it 'can return the raw view' do
74
+ screen.generic_view_view.should be(view)
75
+ end
76
+ end
77
+
78
+ context 'button' do
79
+ let(:button) { double('Button accessor') }
80
+
81
+ before(:each) do
82
+ Furter::Accessors::Button.should_receive(:new).with(:label => 'id').and_return(button)
83
+ end
84
+
85
+ it 'can be clicked' do
86
+ button.should_receive(:click)
87
+ screen.button_field
88
+ end
89
+
90
+ it 'can return the raw view' do
91
+ screen.button_field_view.should be(button)
92
+ end
93
+ end
94
+
95
+ context 'switch' do
96
+ let(:switch) { double('Switch accessor') }
97
+
98
+ before(:each) do
99
+ Furter::Accessors::Switch.should_receive(:new).with(:label => 'id').and_return(switch)
100
+ end
101
+
102
+ it 'is aware of its state' do
103
+ switch.should_receive(:on?).and_return(true)
104
+ screen.switch_field.should be_true
105
+ end
106
+
107
+ it 'can be turned on or off' do
108
+ switch.should_receive(:set).with(false)
109
+ screen.switch_field = false
110
+ end
111
+
112
+ it 'can return the raw view' do
113
+ screen.switch_field_view.should be(switch)
114
+ end
115
+ end
116
+ end