furter 0.0.3 → 0.0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +3 -0
- data/Changelog +4 -0
- data/README.md +60 -4
- data/app/FurterApp/FurterApp/DetailViewController.h +1 -0
- data/app/FurterApp/FurterApp/DetailViewController.m +2 -0
- data/app/FurterApp/FurterApp/en.lproj/MainStoryboard_iPad.storyboard +9 -0
- data/features/slider.feature +9 -0
- data/features/step_definitions/navigation_steps.rb +1 -1
- data/features/step_definitions/slider_steps.rb +11 -0
- data/features/support/screens/detail.rb +4 -0
- data/lib/furter.rb +4 -4
- data/lib/furter/accessors.rb +18 -0
- data/lib/furter/accessors/slider.rb +20 -0
- data/lib/furter/accessors/view.rb +6 -0
- data/lib/furter/navigation.rb +1 -1
- data/lib/furter/version.rb +1 -1
- data/spec/lib/furter/accessors/slider_spec.rb +24 -0
- data/spec/lib/furter/accessors/view_spec.rb +6 -1
- data/spec/lib/furter/accessors_spec.rb +24 -0
- data/spec/lib/furter/navigation_spec.rb +31 -0
- metadata +13 -4
data/.travis.yml
CHANGED
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
|
-
|
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
|
-
|
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
|
-
|
19
|
+
```ruby
|
20
|
+
require 'furter'
|
21
|
+
require 'rspec-expectations'
|
16
22
|
|
17
|
-
|
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"
|
@@ -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
|
data/lib/furter.rb
CHANGED
@@ -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
|
+
|
data/lib/furter/accessors.rb
CHANGED
@@ -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}"
|
data/lib/furter/navigation.rb
CHANGED
data/lib/furter/version.rb
CHANGED
@@ -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
|
-
|
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-
|
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: -
|
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: -
|
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
|