watir-classic 3.4.0 → 3.5.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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjFhN2FkNjA3OWY3Y2NjM2ZiM2UwNGU3OWRhNWJmY2ViYThjMDc1Ng==
5
+ data.tar.gz: !binary |-
6
+ OTU2NmYzOWZkZmY2NGM5ZDgxOWVjZDUxZWZjYzhhYWU5MTZlN2VjNA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ ZTg1ODg2NjFjZTUyYzM2MGQxODhmYjY1NzkwOTVkNTRkNzY2MDNjYzUwYTRj
10
+ ZjI4ZGJmNDA0MWFhMjk1YTI2ZDljNDkzMjVhNjUwMGQyOGJiODkwZWZiOWJl
11
+ N2EyOWY4NTIzN2Q0OWJiYWEyY2MzNjcyNDU5Yjc4YjUzOTI2ZWQ=
12
+ data.tar.gz: !binary |-
13
+ OTYyNWQ2YjVkYjA4NWQyMjFlZWQwYWNiNDNjYjA2MWFhYWQ0M2VmNDE4YTI0
14
+ ZTdhNzBlNGQ2MjY1MGE5ZTNhYmFmNjJmMTlkMDJjMjE4MjI1NzgwNjhjNTFi
15
+ MjJmY2NlNzk0OTVlY2Y4YWQ5OTcyMDZjZTdlZWYzZmFjYmVjMDg=
data/CHANGES CHANGED
@@ -1,3 +1,11 @@
1
+ == 3.5.0 - 2013/03/10
2
+
3
+ * Browser#name returns :internet_explorer instead of :ie.
4
+ * Element#visible? returns true for child element with visibility set to visible even if parent has visibility set to hidden. Fixes #52.
5
+ * Loosen up RAutomation dependency version.
6
+ * Make FileField window titles, button values etc configurable for multi language environments. Closes #50.
7
+ * When searching elements with :css locator then elements should be of class Watir::Element. Closes https://github.com/watir/watir/issues/7
8
+
1
9
  == 3.4.0 - 2013/01/06
2
10
 
3
11
  * All deprecated methods will print out warnings.
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
data/Gemfile.lock CHANGED
@@ -1,71 +1,74 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- watir-classic (3.3.0)
4
+ watir-classic (3.4.0)
5
5
  ffi (~> 1.0)
6
6
  multi_json
7
7
  nokogiri
8
- rautomation (~> 0.7.2)
8
+ rautomation (~> 0.7)
9
9
  user-choices
10
10
  win32-process (>= 0.5.5)
11
11
  win32screenshot
12
12
  windows-pr (>= 0.6.6)
13
13
 
14
14
  GEM
15
- remote: http://rubygems.org/
15
+ remote: https://rubygems.org/
16
16
  specs:
17
- builder (3.1.4)
18
- childprocess (0.3.4)
19
- ffi (~> 1.0, >= 1.0.6)
20
- diff-lcs (1.1.3)
21
- ffi (1.1.3-x86-mingw32)
22
- hoe (3.3.0)
23
- rake (~> 0.8)
24
- mini_magick (3.2.1)
25
- subexec (~> 0.0.4)
26
- multi_json (1.3.7)
27
- nokogiri (1.5.5-x86-mingw32)
28
- rack (1.4.1)
29
- rack-protection (1.2.0)
17
+ builder (3.2.0)
18
+ childprocess (0.3.9)
19
+ ffi (~> 1.0, >= 1.0.11)
20
+ diff-lcs (1.2.1)
21
+ ffi (1.4.0)
22
+ ffi (1.4.0-x86-mingw32)
23
+ hoe (3.5.1)
24
+ rake (>= 0.8, < 11.0)
25
+ mini_magick (3.5.0)
26
+ subexec (~> 0.2.1)
27
+ multi_json (1.6.1)
28
+ nokogiri (1.5.6)
29
+ nokogiri (1.5.6-x86-mingw32)
30
+ rack (1.5.2)
31
+ rack-protection (1.4.0)
30
32
  rack
31
- rake (0.9.4)
32
- rautomation (0.7.3)
33
+ rake (10.0.3)
34
+ rautomation (0.8.0)
33
35
  ffi
34
- rspec (2.11.0)
35
- rspec-core (~> 2.11.0)
36
- rspec-expectations (~> 2.11.0)
37
- rspec-mocks (~> 2.11.0)
38
- rspec-core (2.11.1)
39
- rspec-expectations (2.11.2)
40
- diff-lcs (~> 1.1.3)
41
- rspec-mocks (2.11.1)
36
+ rspec (2.13.0)
37
+ rspec-core (~> 2.13.0)
38
+ rspec-expectations (~> 2.13.0)
39
+ rspec-mocks (~> 2.13.0)
40
+ rspec-core (2.13.0)
41
+ rspec-expectations (2.13.0)
42
+ diff-lcs (>= 1.1.3, < 2.0)
43
+ rspec-mocks (2.13.0)
42
44
  s4t-utils (1.0.4)
43
45
  hoe (>= 1.3.0)
44
- sinatra (1.3.2)
45
- rack (~> 1.3, >= 1.3.6)
46
- rack-protection (~> 1.2)
46
+ sinatra (1.3.5)
47
+ rack (~> 1.4)
48
+ rack-protection (~> 1.3)
47
49
  tilt (~> 1.3, >= 1.3.3)
48
- subexec (0.0.4)
50
+ subexec (0.2.2)
49
51
  syntax (1.0.0)
50
- tilt (1.3.3)
52
+ tilt (1.3.4)
51
53
  user-choices (1.1.6.1)
52
54
  builder (>= 2.1.2)
53
55
  s4t-utils (>= 1.0.3)
54
56
  xml-simple (>= 1.0.11)
57
+ win32-api (1.4.8)
55
58
  win32-api (1.4.8-x86-mingw32)
56
- win32-process (0.7.0)
59
+ win32-process (0.7.1)
57
60
  ffi (>= 1.0.0)
58
- win32screenshot (1.0.7)
61
+ win32screenshot (1.0.8)
59
62
  ffi (~> 1.0)
60
- mini_magick (~> 3.2.1)
61
- rautomation (~> 0.7.0)
63
+ mini_magick (~> 3.2)
64
+ rautomation (~> 0.7)
62
65
  windows-api (0.4.2)
63
66
  win32-api (>= 1.4.5)
64
67
  windows-pr (1.2.2)
65
68
  win32-api (>= 1.4.5)
66
69
  windows-api (>= 0.3.0)
67
70
  xml-simple (1.1.2)
68
- yard (0.8.3)
71
+ yard (0.8.5.2)
69
72
 
70
73
  PLATFORMS
71
74
  x86-mingw32
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.4.0
1
+ 3.5.0
@@ -8,7 +8,7 @@ module Watir
8
8
  #
9
9
  # @example When the title of your IE dialog is missing, add a new one:
10
10
  # Watir::Alert::WINDOW_TITLES << "My missing title"
11
- WINDOW_TITLES = ['Message from webpage', 'Windows Internet Explorer', 'Microsoft Internet Explorer', /Mensaje de p.*/, "Explorer User Prompt"]
11
+ WINDOW_TITLES = ['Message from webpage', 'Windows Internet Explorer', 'Microsoft Internet Explorer', /Mensaje de p.*/, 'Explorer User Prompt']
12
12
 
13
13
  def initialize(container)
14
14
  @container = container
@@ -47,7 +47,7 @@ module Watir
47
47
  private
48
48
 
49
49
  def dialog
50
- @window ||= RAutomation::Window.new(:hwnd => @container.hwnd).child(:title => /^(#{WINDOW_TITLES.join('|')})$/)
50
+ @window ||= RAutomation::Window.new(:hwnd => @container.hwnd).child(:title => Regexp.new("^#{Regexp.union WINDOW_TITLES}$", Regexp::IGNORECASE))
51
51
  end
52
52
 
53
53
  def wait_until_not_exists
@@ -1,6 +1,24 @@
1
1
  module Watir
2
2
  # Returned by {Container#file_field}.
3
3
  class FileField < InputElement
4
+ # File upload dialog titles to search for.
5
+ #
6
+ # @example When the title of your IE dialog is missing, add a new one:
7
+ # Watir::FileField::WINDOW_TITLES << "My missing title"
8
+ WINDOW_TITLES = [/choose file( to upload)?/i, "Elegir archivos para cargar", "Datei zum Hochladen"]
9
+
10
+ # File upload dialog "OK" button values to search for.
11
+ #
12
+ # @example When the "OK" button of your IE is missing, add a new one:
13
+ # Watir::FileField::OK_BUTTON_VALUES << "My missing button value"
14
+ OK_BUTTON_VALUES = ['&Open', '&Abrir', '&ffnen']
15
+
16
+ # File upload dialog "Cancel" button values to search for.
17
+ #
18
+ # @example When the "Cancel" button of your IE is missing, add a new one:
19
+ # Watir::FileField::CANCEL_BUTTON_VALUES << "My missing button value"
20
+ CANCEL_BUTTON_VALUES = ['Cancel', 'Abbrechen']
21
+
4
22
  # Set the path of the file field.
5
23
  #
6
24
  # @example
@@ -31,15 +49,21 @@ module Watir
31
49
  end
32
50
 
33
51
  def open_button
34
- file_upload_window.button(:value => /&Open|&Abrir/)
52
+ file_upload_window.button(:value => formatted_regexp(OK_BUTTON_VALUES))
35
53
  end
36
54
 
37
55
  def cancel_button
38
- file_upload_window.button(:value => /Cancel/)
56
+ file_upload_window.button(:value => formatted_regexp(CANCEL_BUTTON_VALUES))
39
57
  end
40
58
 
41
59
  def file_upload_window
42
- @window ||= RAutomation::Window.new(:title => /^choose file( to upload)?|Elegir archivos para cargar$/i)
60
+ @window ||= RAutomation::Window.new(:title => formatted_regexp(WINDOW_TITLES))
61
+ end
62
+
63
+ private
64
+
65
+ def formatted_regexp(values)
66
+ Regexp.new("^#{Regexp.union values}$", Regexp::IGNORECASE)
43
67
  end
44
68
 
45
69
  end
@@ -251,12 +251,17 @@ module Watir
251
251
  # Now iterate up the DOM element tree and return false if any
252
252
  # parent element isn't visible
253
253
  assert_exists
254
+ visible_child = false
254
255
  object = @o
255
256
  while object
256
257
  begin
257
- if object.currentstyle.invoke('visibility') =~ /^hidden$/i
258
+ visibility = object.currentstyle.invoke('visibility')
259
+ if visibility =~ /^visible$/i
260
+ visible_child = true
261
+ elsif !visible_child && visibility =~ /^hidden$/i
258
262
  return false
259
263
  end
264
+
260
265
  if object.currentstyle.invoke('display') =~ /^none$/i
261
266
  return false
262
267
  end
@@ -306,9 +306,9 @@ module Watir
306
306
  @hwnd ||= @ie.hwnd
307
307
  end
308
308
 
309
- # @return [Symbol] the name of the browser. Is always :ie.
309
+ # @return [Symbol] the name of the browser. Is always :internet_explorer.
310
310
  def name
311
- :ie
311
+ :internet_explorer
312
312
  end
313
313
 
314
314
  # @return [Boolean] true when IE is window exists, false otherwise.
@@ -523,7 +523,7 @@ module Watir
523
523
  # Gives focus to the window frame.
524
524
  def focus
525
525
  active_element = document.activeElement
526
- active_element.blur unless active_element.tagName == "BODY"
526
+ active_element.blur if active_element && active_element.tagName != "BODY"
527
527
  document.focus
528
528
  end
529
529
 
@@ -15,7 +15,7 @@ module Watir
15
15
  def each
16
16
  if has_excluding_specifiers?
17
17
  locate_elements_by_xpath_css_ole.each do |element|
18
- yield element
18
+ yield create_element element
19
19
  end
20
20
  else
21
21
  @tags.each do |tag|
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+ require File.expand_path("watirspec/spec_helper", File.dirname(__FILE__))
3
+
4
+ describe "Elements" do
5
+
6
+ before :each do
7
+ browser.goto(WatirSpec.url_for("non_control_elements.html"))
8
+ end
9
+
10
+ it "returns a collection of Watir::Element when searching with :css" do
11
+ elements = browser.elements(:css => "div")
12
+ elements.size.should > 0
13
+ elements.each do |element|
14
+ element.class.should == Watir::Element
15
+ end
16
+ end
17
+
18
+ end
@@ -6,11 +6,11 @@ WatirSpec.implementation do |imp|
6
6
 
7
7
  WatirSpec.persistent_browser = false
8
8
  imp.browser_class = Watir::IE
9
- browser = :ie
10
- browser_version = "ie#{imp.browser_class.version.to_i}".to_sym
9
+ browser = :internet_explorer
10
+ browser_version = "#{browser}#{imp.browser_class.version.to_i}".to_sym
11
11
 
12
12
  imp.guard_proc = lambda { |args|
13
- args.any? {|arg| arg == :watir_classic || arg == [:watir_classic, browser] || arg == :ie || arg == browser_version || arg == [:watir_classic, browser_version] }
13
+ args.any? {|arg| arg == :watir_classic || arg == [:watir_classic, browser] || arg == browser.to_sym || arg == browser_version || arg == [:watir_classic, browser_version] }
14
14
  }
15
15
  end
16
16
 
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
27
27
  s.add_dependency 'windows-pr', '>= 0.6.6'
28
28
  s.add_dependency 'nokogiri'
29
29
  s.add_dependency 'ffi', '~>1.0'
30
- s.add_dependency 'rautomation', '~>0.7.2'
30
+ s.add_dependency 'rautomation', '~>0.7'
31
31
  s.add_dependency 'user-choices'
32
32
  s.add_dependency 'multi_json'
33
33
  s.add_dependency 'win32screenshot'
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: watir-classic
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.0
5
- prerelease:
4
+ version: 3.5.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Bret Pettichord
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-06 00:00:00.000000000 Z
11
+ date: 2013-03-10 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: win32-process
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ! '>='
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ! '>='
28
25
  - !ruby/object:Gem::Version
@@ -30,7 +27,6 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: windows-pr
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ! '>='
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ! '>='
44
39
  - !ruby/object:Gem::Version
@@ -46,7 +41,6 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: nokogiri
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ! '>='
52
46
  - !ruby/object:Gem::Version
@@ -54,7 +48,6 @@ dependencies:
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ! '>='
60
53
  - !ruby/object:Gem::Version
@@ -62,7 +55,6 @@ dependencies:
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: ffi
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :runtime
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
@@ -78,23 +69,20 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rautomation
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - ~>
84
74
  - !ruby/object:Gem::Version
85
- version: 0.7.2
75
+ version: '0.7'
86
76
  type: :runtime
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - ~>
92
81
  - !ruby/object:Gem::Version
93
- version: 0.7.2
82
+ version: '0.7'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: user-choices
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
87
  - - ! '>='
100
88
  - !ruby/object:Gem::Version
@@ -102,7 +90,6 @@ dependencies:
102
90
  type: :runtime
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
94
  - - ! '>='
108
95
  - !ruby/object:Gem::Version
@@ -110,7 +97,6 @@ dependencies:
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: multi_json
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
101
  - - ! '>='
116
102
  - !ruby/object:Gem::Version
@@ -118,7 +104,6 @@ dependencies:
118
104
  type: :runtime
119
105
  prerelease: false
120
106
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
107
  requirements:
123
108
  - - ! '>='
124
109
  - !ruby/object:Gem::Version
@@ -126,7 +111,6 @@ dependencies:
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: win32screenshot
128
113
  requirement: !ruby/object:Gem::Requirement
129
- none: false
130
114
  requirements:
131
115
  - - ! '>='
132
116
  - !ruby/object:Gem::Version
@@ -134,7 +118,6 @@ dependencies:
134
118
  type: :runtime
135
119
  prerelease: false
136
120
  version_requirements: !ruby/object:Gem::Requirement
137
- none: false
138
121
  requirements:
139
122
  - - ! '>='
140
123
  - !ruby/object:Gem::Version
@@ -142,7 +125,6 @@ dependencies:
142
125
  - !ruby/object:Gem::Dependency
143
126
  name: rspec
144
127
  requirement: !ruby/object:Gem::Requirement
145
- none: false
146
128
  requirements:
147
129
  - - ~>
148
130
  - !ruby/object:Gem::Version
@@ -150,7 +132,6 @@ dependencies:
150
132
  type: :development
151
133
  prerelease: false
152
134
  version_requirements: !ruby/object:Gem::Requirement
153
- none: false
154
135
  requirements:
155
136
  - - ~>
156
137
  - !ruby/object:Gem::Version
@@ -158,7 +139,6 @@ dependencies:
158
139
  - !ruby/object:Gem::Dependency
159
140
  name: syntax
160
141
  requirement: !ruby/object:Gem::Requirement
161
- none: false
162
142
  requirements:
163
143
  - - ! '>='
164
144
  - !ruby/object:Gem::Version
@@ -166,7 +146,6 @@ dependencies:
166
146
  type: :development
167
147
  prerelease: false
168
148
  version_requirements: !ruby/object:Gem::Requirement
169
- none: false
170
149
  requirements:
171
150
  - - ! '>='
172
151
  - !ruby/object:Gem::Version
@@ -174,7 +153,6 @@ dependencies:
174
153
  - !ruby/object:Gem::Dependency
175
154
  name: yard
176
155
  requirement: !ruby/object:Gem::Requirement
177
- none: false
178
156
  requirements:
179
157
  - - ! '>='
180
158
  - !ruby/object:Gem::Version
@@ -182,7 +160,6 @@ dependencies:
182
160
  type: :development
183
161
  prerelease: false
184
162
  version_requirements: !ruby/object:Gem::Requirement
185
- none: false
186
163
  requirements:
187
164
  - - ! '>='
188
165
  - !ruby/object:Gem::Version
@@ -190,7 +167,6 @@ dependencies:
190
167
  - !ruby/object:Gem::Dependency
191
168
  name: sinatra
192
169
  requirement: !ruby/object:Gem::Requirement
193
- none: false
194
170
  requirements:
195
171
  - - ! '>='
196
172
  - !ruby/object:Gem::Version
@@ -198,7 +174,6 @@ dependencies:
198
174
  type: :development
199
175
  prerelease: false
200
176
  version_requirements: !ruby/object:Gem::Requirement
201
- none: false
202
177
  requirements:
203
178
  - - ! '>='
204
179
  - !ruby/object:Gem::Version
@@ -206,7 +181,6 @@ dependencies:
206
181
  - !ruby/object:Gem::Dependency
207
182
  name: childprocess
208
183
  requirement: !ruby/object:Gem::Requirement
209
- none: false
210
184
  requirements:
211
185
  - - ! '>='
212
186
  - !ruby/object:Gem::Version
@@ -214,7 +188,6 @@ dependencies:
214
188
  type: :development
215
189
  prerelease: false
216
190
  version_requirements: !ruby/object:Gem::Requirement
217
- none: false
218
191
  requirements:
219
192
  - - ! '>='
220
193
  - !ruby/object:Gem::Version
@@ -301,6 +274,7 @@ files:
301
274
  - lib/watir-classic/yard/global_macros.rb
302
275
  - spec/browser_spec.rb
303
276
  - spec/element_spec.rb
277
+ - spec/elements_spec.rb
304
278
  - spec/frame_spec.rb
305
279
  - spec/implementation.rb
306
280
  - spec/link_spec.rb
@@ -308,18 +282,17 @@ files:
308
282
  - watir-classic.gemspec
309
283
  homepage: http://watir.com/
310
284
  licenses: []
285
+ metadata: {}
311
286
  post_install_message:
312
287
  rdoc_options: []
313
288
  require_paths:
314
289
  - lib
315
290
  required_ruby_version: !ruby/object:Gem::Requirement
316
- none: false
317
291
  requirements:
318
292
  - - ! '>='
319
293
  - !ruby/object:Gem::Version
320
294
  version: '0'
321
295
  required_rubygems_version: !ruby/object:Gem::Requirement
322
- none: false
323
296
  requirements:
324
297
  - - ! '>='
325
298
  - !ruby/object:Gem::Version
@@ -327,13 +300,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
327
300
  requirements:
328
301
  - Microsoft Windows running Internet Explorer 5.5 or later.
329
302
  rubyforge_project:
330
- rubygems_version: 1.8.24
303
+ rubygems_version: 2.0.0
331
304
  signing_key:
332
- specification_version: 3
305
+ specification_version: 4
333
306
  summary: Automated testing tool for web applications.
334
307
  test_files:
335
308
  - spec/browser_spec.rb
336
309
  - spec/element_spec.rb
310
+ - spec/elements_spec.rb
337
311
  - spec/frame_spec.rb
338
312
  - spec/implementation.rb
339
313
  - spec/link_spec.rb