mundo-pepino 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,54 @@
1
+ # gem stuff
2
+ require 'rubygems'
3
+ gem 'hoe', '>= 2.1.0'
4
+ require 'hoe'
5
+ require 'fileutils'
6
+ require 'newgem/tasks'
7
+ require 'lib/mundo_pepino/version'
8
+
9
+ Hoe.plugin :newgem
10
+
11
+ $hoe = Hoe.spec 'mundo-pepino' do
12
+ self.summary = 'MundoPepino is a set of reusable step definitions to test Rails apps with Cucumber'
13
+ self.version = MundoPepino::VERSION::STRING
14
+ self.developer 'Fernando García Samblas', 'fernando.garcia@the-cocktail.com'
15
+ self.rubyforge_name = self.name # TODO this is default value
16
+ self.extra_deps = [['string-mapper','>= 0.1.0'],
17
+ ['cucumber', '>=0.3.102']]
18
+ end
19
+
20
+
21
+
22
+ # build stuff
23
+ require(File.join(File.dirname(__FILE__), 'features', 'support', 'app', 'config', 'boot'))
24
+
25
+ require 'rake'
26
+ require 'rake/testtask'
27
+ require 'rake/rdoctask'
28
+
29
+ require 'tasks/rails'
30
+
31
+
32
+ unless ARGV.any? {|a| a =~ /^gems/}
33
+
34
+ begin
35
+ require 'cucumber/rake/task'
36
+ namespace :mundo_pepino do
37
+ Cucumber::Rake::Task.new({:es_ES => 'db:test:prepare'}) do |t|
38
+ t.cucumber_opts = "--require features/support/env.rb --require features/step_definitions/mundo_pepino_es_ES.rb --format progress --language es features/es_ES"
39
+ end
40
+
41
+ desc 'Run all MundoPepino features on every supported language'
42
+ task :all => [:es_ES]
43
+ end
44
+
45
+ task :default => 'mundo_pepino:es_ES'
46
+
47
+ rescue LoadError
48
+ desc 'cucumber rake task not available (cucumber not installed)'
49
+ task :cucumber do
50
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1 @@
1
+ default: --require features/support/env.rb --require features/step_definitions/mundo_pepino_es_ES.rb --language es features/es_ES/
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
@@ -0,0 +1,241 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'cucumber/rails/world'
5
+ require 'mundo_pepino/resources_history'
6
+ require 'mundo_pepino/visits_history'
7
+ require 'mundo_pepino/version'
8
+
9
+ require 'string-mapper'
10
+
11
+ module MundoPepino
12
+
13
+ include ResourcesHistory
14
+ include VisitsHistory
15
+
16
+ def real_value_for(v)
17
+ (v.is_a?(String) ? v.to_real_value : v )
18
+ end
19
+
20
+ def parsed_attributes(raw_attributes)
21
+ attributes = {}
22
+ raw_attributes.each do |k, v|
23
+ if k =~ /^(.+)_id$/
24
+ if polymorph = raw_attributes.delete($1 + '_type')
25
+ attributes[$1.to_sym] = polymorph.constantize.find(v.to_i)
26
+ else
27
+ attributes[$1.to_sym] = ($1.to_relation_model || $1.camelize.constantize).find(v.to_i)
28
+ end
29
+ else
30
+ attributes[k] = real_value_for(v)
31
+ end
32
+ end
33
+ attributes
34
+ end
35
+
36
+ def create(model, raw_attributes = {})
37
+ through = raw_attributes.delete(:through)
38
+ attributes = parsed_attributes(raw_attributes)
39
+ obj = if defined?(FixtureReplacement)
40
+ self.send "create_#{model.name.underscore}", attributes
41
+ elsif defined?(Machinist)
42
+ model.make attributes
43
+ elsif defined?(Factory)
44
+ Factory(model.name.underscore.to_sym, attributes)
45
+ else
46
+ model.create! attributes
47
+ end
48
+ if(through)
49
+ create through['model'], through['attributes'].merge(model.name.underscore.to_sym => obj)
50
+ end
51
+ obj
52
+ end
53
+
54
+ def find_or_create(model_or_modelo, attributes = {}, options = {})
55
+ model = if model_or_modelo.is_a?(String)
56
+ model_or_modelo.to_model
57
+ else
58
+ model_or_modelo
59
+ end
60
+ if attributes.any?
61
+ attribs = Hash.new
62
+ attributes.each do |key, value|
63
+ if child_model = (key.to_s.to_model || key.to_s.to_relation_model)
64
+ child = add_resource(child_model, field_for(child_model, 'nombre') => value)
65
+ field_name = key.to_s.to_relation_model ? key : child_model.name.underscore
66
+ attribs["#{field_name}_id"] = child.id
67
+ else
68
+ attribs[key] = value
69
+ end
70
+ end
71
+ if ((options[:force_creation].nil? || !options[:force_creation]) &&
72
+ obj = model.find(:first, :conditions => conditions_from_attributes(attribs)))
73
+ if(through = attribs[:through])
74
+ create through['model'], through['attributes'].merge(model.name.underscore.to_sym => obj)
75
+ end
76
+ obj
77
+ else
78
+ create model, attribs
79
+ end
80
+ else
81
+ create model
82
+ end
83
+ end
84
+
85
+ def conditions_from_attributes(attributes)
86
+ attribs = attributes.reject {|k,v| k == :through}
87
+ [attribs.keys.map{|s| "#{s}=?"}.join(' AND ')] + attribs.values
88
+ end
89
+
90
+ def names_for_simple_creation(model, number, name_or_names, options = {})
91
+ base_hash = base_hash_for(options)
92
+ if name_or_names
93
+ field = field_for(model, 'nombre')
94
+ names = name_or_names.split(/ ?, | y /)
95
+ if names.size == number
96
+ names.map { |name| base_hash.dup.merge(field => name) }
97
+ else
98
+ [base_hash.dup.merge(field => name_or_names)] * number
99
+ end
100
+ else
101
+ [base_hash] * number
102
+ end
103
+ end
104
+
105
+ def field_for(model, campo = 'nombre')
106
+ "#{model && model.name}::#{campo}".to_field || campo.to_field
107
+ end
108
+ def shouldify(should_or_not)
109
+ affirmative = 'debo|debo ver|veo|deber[ií]a|deber[íi]a ver|leo|debo leer|deber[ií]a leer'
110
+ should_or_not =~ /^(#{affirmative})$/i ? :should : :should_not
111
+ end
112
+
113
+ def not_shouldify(should_or_not)
114
+ shouldify(should_or_not) == :should ? :should_not : :should
115
+ end
116
+
117
+ def relative_page(pagina)
118
+ if pagina =~ /la siguiente p[aá]gina|la p[aá]gina anterior/i
119
+ head, current, tail = if last_visited =~ /(.+page=)(\d+)(.*)/
120
+ [$1, $2.to_i, $3]
121
+ else
122
+ [last_visited + '?page=', 1, '']
123
+ end
124
+ (pagina =~ /siguiente/ ? current += 1 : current -= 1)
125
+ head + current.to_s + tail
126
+ else
127
+ nil
128
+ end
129
+ end
130
+
131
+ # Cucumber::Model::Table's hashes traduciendo nombres de campo
132
+ def translated_hashes(step_table, options = {})
133
+ base_hash = base_hash_for(options)
134
+ header = step_table[0].map do |campo|
135
+ field_for(options[:model], campo) || campo
136
+ end
137
+ step_table[1..-1].map do |row|
138
+ h = base_hash.dup
139
+ row.each_with_index do |v,n|
140
+ key = header[n]
141
+ h[key] = v
142
+ end
143
+ h
144
+ end
145
+ end
146
+
147
+ def base_hash_for(options)
148
+ if options[:parent]
149
+ # polymorphic associations
150
+ if options[:polymorphic_as]
151
+ { "#{options[:polymorphic_as]}_id" => options[:parent].id,
152
+ "#{options[:polymorphic_as]}_type" => options[:parent].class.name }
153
+ else
154
+ field_prefix = options[:parent].class.name.underscore
155
+ if options[:through]
156
+ {:through => {"model" => eval(options[:through].to_s.classify),
157
+ "attributes" => {"#{field_prefix}_id" => options[:parent].id}}}
158
+ else
159
+ { "#{field_prefix}_id" => options[:parent].id }
160
+ end
161
+ end
162
+ else
163
+ {}
164
+ end
165
+ end
166
+
167
+ def campo_to_field(campo, model = nil)
168
+ unless campo.nil?
169
+ if field = field_for(model, campo.to_unquoted)
170
+ field
171
+ else
172
+ raise MundoPepino::FieldNotMapped.new(campo)
173
+ end
174
+ end
175
+ end
176
+
177
+ def last_mentioned_should_have_value(campo, valor)
178
+ res = last_mentioned
179
+ if child_model = campo.to_model
180
+ child = child_model.find_by_name(valor)
181
+ child_field = campo.to_field || child_model.name.underscore
182
+ (res.send child_field).should == child
183
+ elsif field = field_for(res.class, campo)
184
+ (res.send field).to_s.should == valor.to_s
185
+ else
186
+ raise FieldNotMapped.new(campo)
187
+ end
188
+ end
189
+
190
+ def last_mentioned_should_have_child(child, name)
191
+ if child_model = child.to_model
192
+ child = child_model.find_by_name(name)
193
+ (last_mentioned.send child_model.table_name).detect do |c|
194
+ c.id == child.id
195
+ end.should_not be_nil
196
+ else
197
+ raise ModelNotMapped.new(child)
198
+ end
199
+ end
200
+
201
+ def find_field_and_do_with_webrat(action, campo, options = nil)
202
+ do_with_webrat action, campo.to_unquoted.to_translated, options # a pelo (localización vía labels)
203
+ rescue Webrat::NotFoundError
204
+ field = campo_to_field(campo, last_mentioned_model)
205
+ begin
206
+ do_with_webrat action, field, options # campo traducido tal cual...
207
+ rescue Webrat::NotFoundError
208
+ if singular = last_mentioned_singular # traducido y con el modelo por delante
209
+ do_with_webrat action, singular + '_' + field.to_s, options # p.e.: user_name
210
+ else
211
+ raise
212
+ end
213
+ end
214
+ end
215
+
216
+ def do_with_webrat(action, field, options)
217
+ if options
218
+ if options[:path] and options[:content_type]
219
+ self.send action, field, options[:path], options[:content_type]
220
+ else
221
+ self.send action, field, options
222
+ end
223
+ else
224
+ self.send action, field
225
+ end
226
+ end
227
+
228
+ def parent_options(parent, child)
229
+ options = {:parent => parent}
230
+ # polymorphic associations
231
+ if reflections = parent.class.reflect_on_association(child.table_name.to_sym)
232
+ if reflections.options[:as]
233
+ options.merge!({:polymorphic_as => reflections.options[:as]})
234
+ elsif reflections.options[:through]
235
+ options.merge!({:through => reflections.options[:through]})
236
+ end
237
+ end
238
+ options
239
+ end
240
+
241
+ end
@@ -0,0 +1,420 @@
1
+ begin
2
+ module Cucumber::StepMethods
3
+ alias_method :Dado, :Given
4
+ alias_method :Cuando, :When
5
+ alias_method :Entonces, :Then
6
+ end
7
+ rescue
8
+ # NO NEED TO CREATE ALIASES IN post-0.2 Cucumbers
9
+ end
10
+
11
+ String.add_mapper(:real_value, {
12
+ /^verdader[oa]$/i => true,
13
+ /^fals[ao]$/i => false
14
+ }) { |value| value }
15
+ String.add_mapper :model
16
+ String.add_mapper :relation_model
17
+ String.add_mapper(:field) { |str| :name if str =~ /nombres?/ }
18
+ String.add_mapper(:url, /^la (portada|home)/i => '/') do |string|
19
+ string if string =~ /^\/.*$|^https?:\/\//i
20
+ end
21
+
22
+ String.add_mapper(:number, {
23
+ /^un[oa]?$/i => 1,
24
+ /^primer[oa]?$/i => 1,
25
+ :dos => 2,
26
+ /^segund[oa]?$/i => 2,
27
+ :tres => 3,
28
+ /^tercer[ao]/i => 3,
29
+ :cuatro => 4,
30
+ /^cuart[ao]/i => 4,
31
+ :cinco => 5,
32
+ /^quint[ao]/i => 5}) { |string| string.to_i }
33
+ String.add_mapper(:crud_action,
34
+ /^alta$/i => 'new',
35
+ /^creaci[óo]n$/i => 'new',
36
+ /^nuev(?:o|a|o\/a|a\/o)$/i => 'new',
37
+ /^cambio$/i => 'edit',
38
+ /^modificaci[oó]n(?:es)?$/i => 'edit',
39
+ /^edici[oó]n$/i => 'edit')
40
+ String.add_mapper(:month,
41
+ :enero => 'January',
42
+ :febrero => 'February',
43
+ :marzo => 'March',
44
+ :abril => 'April',
45
+ :mayo => 'May',
46
+ :junio => 'June',
47
+ :julio => 'July',
48
+ :agosto => 'August',
49
+ /^sep?tiembre$/i => 'September',
50
+ :octubre => 'October',
51
+ :noviembre => 'November',
52
+ :diciembre => 'December')
53
+ String.add_mapper(:content_type,
54
+ /\.png$/ => 'image/png',
55
+ /\.jpe?g$/ => 'image/jpg',
56
+ /\.gif$/ => 'image/gif') { |str| 'text/plain' }
57
+ String.add_mapper(:underscored) { |string| string.gsub(/ +/, '_') }
58
+ String.add_mapper(:unquoted) { |str| str =~ /^['"](.*)['"]$/ ? $1 : str}
59
+ String.add_mapper(:translated) { |str|
60
+ if str =~ /^[a-z_]+\.[a-z_]+[a-z_\.]+$/
61
+ I18n.translate(str, :default => str)
62
+ elsif str =~ /^([a-z_]+\.[a-z_]+[a-z_\.]+),(\{.+\})$/
63
+ I18n.translate($1, {:default => str}.merge(eval($2)))
64
+ else
65
+ str
66
+ end
67
+ }
68
+
69
+
70
+
71
+ numero = 'un|una|dos|tres|cuatro|cinco|\d+'
72
+ cuyo = '(?:cuy[oa]s?|que tienen? como)'
73
+ # Creación simple con nombre opcional
74
+ Dado /^(?:que tenemos )?(#{numero}) (?!.+ #{cuyo})(.+?)(?: (?:llamad[oa]s? )?['"](.+)["'])?$/i do |numero, modelo, nombre|
75
+ if model = modelo.to_unquoted.to_model
76
+ number = numero.to_number
77
+ attribs = names_for_simple_creation(model, number, nombre)
78
+ add_resource(model, attribs, :force_creation => true)
79
+ else
80
+ raise MundoPepino::ModelNotMapped.new(modelo)
81
+ end
82
+ end
83
+ # Creación con asignación de valor en campo
84
+ Dado /^(?:que tenemos )?(#{numero}) (.+) #{cuyo} (.+?) (?:(?:es|son) (?:de )?)?['"](.+)["'](?: .+)?$/i do |numero, modelo, campo, valor|
85
+ Dado "que tenemos #{numero} #{modelo}"
86
+ Dado "que dichos #{modelo} tienen como #{campo} '#{valor}'"
87
+ end
88
+
89
+ Dado /^(?:que tenemos )?(?:el|la|los|las|el\/la|los\/las) (?:siguientes? )?(.+):$/ do |modelo, tabla|
90
+ model = modelo.to_unquoted.to_model
91
+ add_resource model, translated_hashes(tabla.raw, :model => model), :force_creation => true
92
+ end
93
+
94
+ Dado /^que (?:el|la) (.+) ['"](.+)["'] tiene como (.+) ['"](.+)["'](?: \w+)?$/ do |modelo, nombre, campo, valor|
95
+ if resource = last_mentioned_of(modelo, nombre)
96
+ if field = field_for(resource.class, campo)
97
+ resource.update_attribute field, real_value_for(valor)
98
+ pile_up resource
99
+ else
100
+ raise MundoPepino::FieldNotMapped.new(campo)
101
+ end
102
+ end
103
+ end
104
+
105
+ Dado /^que dich[oa]s? (.+) tienen? como (.+) ['"](.+)["'](?:.+)?$/i do |modelo, campo, valor|
106
+ if res = last_mentioned_of(modelo)
107
+ resources, field, values = resources_array_field_and_values(res, campo, valor)
108
+ if field
109
+ resources.each_with_index do |r, i|
110
+ r.update_attribute field, real_value_for(values[i])
111
+ end
112
+ pile_up res
113
+ else
114
+ raise MundoPepino::FieldNotMapped.new(campo)
115
+ end
116
+ end
117
+ end
118
+
119
+ Dado /^que dich[oa]s? (.+) tienen? (un|una|dos|tres|cuatro|cinco|\d+) (.+?)(?: (?:llamad[oa]s? )?['"](.+)["'])?$/i do |modelo_padre, numero, modelo_hijos, nombres|
120
+ if mentioned = last_mentioned_of(modelo_padre.to_unquoted)
121
+ children_model = modelo_hijos.to_unquoted.to_model
122
+ resources = (mentioned.is_a?(Array) ? mentioned : [mentioned])
123
+ resources.each do |resource|
124
+ attribs = names_for_simple_creation(children_model,
125
+ numero.to_number, nombres, parent_options(resource, children_model))
126
+ add_resource children_model, attribs, :force_creation => nombres.nil?
127
+ end
128
+ pile_up mentioned
129
+ end
130
+ end
131
+
132
+ Dado /^que dich[ao]s? (.+) tienen? (?:el|la|los|las) siguientes? (.+):$/i do |modelo_padre, modelo_hijos, tabla|
133
+ if mentioned = last_mentioned_of(modelo_padre.to_unquoted)
134
+ children_model = modelo_hijos.to_unquoted.to_model
135
+ resources = (mentioned.is_a?(Array) ? mentioned : [mentioned])
136
+ resources.each do |resource|
137
+ add_resource children_model,
138
+ translated_hashes(tabla.raw, parent_options(resource, children_model))
139
+ end
140
+ end
141
+ end
142
+
143
+
144
+ ###############################################################################
145
+
146
+ pagina_re = '(?:p[áa]gina|portada|[íi]ndice|listado|colecci[óo]n)'
147
+ Cuando /^(?:que )?visito (?:el|la) #{pagina_re} de ([\w]+|['"][\w ]+["'])$/i do |modelo_en_crudo|
148
+ modelo = modelo_en_crudo.to_unquoted
149
+ if model = modelo.to_model
150
+ pile_up model.new
151
+ do_visit eval("#{model.table_name}_path")
152
+ elsif url = "la página de #{modelo_en_crudo}".to_url
153
+ do_visit url
154
+ else
155
+ raise MundoPepino::ModelNotMapped.new(modelo)
156
+ end
157
+ end
158
+
159
+ Cuando /^(?:que )?visito (?:el|la) #{pagina_re} (?:del|de la) (.+) ['"](.+)["']$/i do |modelo, nombre|
160
+ if resource = last_mentioned_of(modelo, nombre)
161
+ do_visit eval("#{resource.class.name.underscore}_path(resource)")
162
+ else
163
+ raise MundoPepino::ResourceNotFound.new("model #{modelo}, name #{nombre}")
164
+ end
165
+ end
166
+
167
+ Cuando /^(?:que )?visito la p[áa]gina de (?!la)([\w\/]+) (?:de |de la |del )?(.+?)(?: (['"].+["']))?$/i do |accion, modelo, nombre|
168
+ action = accion.to_crud_action or raise(MundoPepino::CrudActionNotMapped.new(accion))
169
+ if action != 'new'
170
+ nombre, modelo = modelo, nil unless nombre
171
+ resource = if modelo && modelo.to_unquoted.to_model
172
+ last_mentioned_of(modelo, nombre.to_unquoted)
173
+ else
174
+ last_mentioned_called(nombre.to_unquoted)
175
+ end
176
+ if resource
177
+ do_visit eval("#{action}_#{resource.mr_singular}_path(resource)")
178
+ else
179
+ MundoPepino::ResourceNotFound.new("model #{modelo}, name #{nombre}")
180
+ end
181
+ else
182
+ model = modelo.to_unquoted.to_model or raise(MundoPepino::ModelNotMapped.new(modelo))
183
+ pile_up model.new
184
+ do_visit eval("#{action}_#{model.name.underscore}_path")
185
+ end
186
+ end
187
+
188
+ Cuando /^(?:que )?visito su (?:p[áa]gina|portada)$/i do
189
+ do_visit last_mentioned_url
190
+ end
191
+
192
+ negative_lookahead = '(?:la|el) \w+ del? |su p[aá]gina|su portada'
193
+ Cuando /^(?:que )?visito (?!#{negative_lookahead})(.+)$/i do |pagina|
194
+ do_visit pagina.to_unquoted.to_url
195
+ end
196
+
197
+ Cuando /^(?:que )?(?:pulso|pincho) (?:en )?el bot[oó]n (.+)$/i do |boton|
198
+ click_button(boton.to_unquoted.to_translated)
199
+ end
200
+
201
+ Cuando /^(?:que )?(?:pulso|pincho) (?:en )?el (enlace|enlace ajax|enlace con efectos) (.+)$/i do |tipo, enlace|
202
+ options = {}
203
+ options[:wait] = case tipo.downcase
204
+ when 'enlace con efectos' then :effects
205
+ when 'enlace ajax' then :ajax
206
+ else :page
207
+ end
208
+ click_link(enlace.to_unquoted.to_translated, options)
209
+ end
210
+
211
+ Cuando /^(?:que )?(?:completo|relleno) (.+) con (?:el valor )?['"](.+)["']$/i do |campo, valor|
212
+ find_field_and_do_with_webrat :fill_in, campo, :with => valor
213
+ end
214
+
215
+ Cuando /^(?:que )?(?:completo|relleno):$/i do |tabla|
216
+ tabla.raw[1..-1].each do |row|
217
+ Cuando "relleno \"#{row[0].gsub('"', '\"')}\" con \"#{row[1].gsub('"', '\"')}\""
218
+ end
219
+ end
220
+
221
+ Cuando /^(?:que )?elijo (?:la|el)? ?(.+) ['"](.+)["']$/i do |campo, valor|
222
+ choose(campo_to_field(campo).to_s + '_' + valor.downcase.to_underscored)
223
+ end
224
+
225
+ Cuando /^(?:que )?marco (?:la|el)? ?(.+)$/i do |campo|
226
+ find_field_and_do_with_webrat :check, campo
227
+ end
228
+
229
+ Cuando /^(?:que )?desmarco (?:la|el)? ?(.+)$/i do |campo|
230
+ find_field_and_do_with_webrat :uncheck, campo
231
+ end
232
+
233
+ Cuando /^(?:que )?adjunto el fichero ['"](.*)["'] (?:a|en) (.*)$/ do |ruta, campo|
234
+ find_field_and_do_with_webrat :attach_file, campo,
235
+ {:path => ruta, :content_type => ruta.to_content_type}
236
+ end
237
+
238
+ Cuando /^(?:que )?selecciono ["']([^"']+?)["'](?: en (?:el listado de )?(.+))?$/i do |valor, campo|
239
+ begin
240
+ if campo
241
+ select valor, :from => campo.to_unquoted.to_translated # Vía label
242
+ else
243
+ select valor
244
+ end
245
+ rescue Webrat::NotFoundError
246
+ select(valor, :from => campo_to_field(campo)) # Sin label
247
+ end
248
+ end
249
+
250
+ Cuando /^(?:que )?selecciono ['"]?(\d\d?) de (\w+) de (\d{4}), (\d\d?:\d\d)["']? como fecha y hora(?: (?:de )?['"]?(.+?)["']?)?$/ do |dia, mes, anio, hora, etiqueta|
251
+ # Cuando selecciono "25 de diciembre de 2008, 10:00" como fecha y hora
252
+ # Cuando selecciono 23 de noviembre de 2004, 11:20 como fecha y hora "Preferida"
253
+ # Cuando selecciono 23 de noviembre de 2004, 11:20 como fecha y hora de "Publicación"
254
+ time = Time.parse("#{mes.to_month} #{dia}, #{anio} #{hora}")
255
+ options = etiqueta ? { :from => etiqueta } : {}
256
+ select_datetime(time, options)
257
+ end
258
+
259
+ Cuando /^(?:que )?selecciono ['"]?(.*)["']? como (?:la )?hora(?: (?:(?:del?|para) (?:la |el )?)?['"]?(.+?)["']?)?$/ do |hora, etiqueta|
260
+ options = etiqueta ? { :from => etiqueta } : {}
261
+ select_time(hora, options)
262
+ end
263
+
264
+ Cuando /^(?:que )?selecciono ['"]?(\d\d?) de (\w+) de (\d{4})["']? como (?:la )?fecha(?: (?:(?:del?|para) (?:la |el )?)?['"]?(.+?)["']?)?$/ do |dia, mes, anio, etiqueta|
265
+ time = Time.parse("#{mes.to_month} #{dia}, #{anio} 12:00")
266
+ options = etiqueta ? { :from => etiqueta } : {}
267
+ select_date(time, options)
268
+ end
269
+
270
+ Cuando /^borro (?:el|la|el\/la) (.+) en (?:la )?(\w+|\d+)(?:ª|º)? posición$/ do |modelo, posicion|
271
+ pile_up modelo.to_unquoted.to_model.new
272
+ do_visit last_mentioned_url
273
+ within("table > tr:nth-child(#{posicion.to_number+1})") do
274
+ click_link "Borrar"
275
+ end
276
+ end
277
+
278
+ #############################################################################
279
+ veo_o_no = '(?:no )?(?:veo|debo ver|deber[ií]a ver)'
280
+
281
+ Entonces /^(#{veo_o_no}) el texto (.+)?$/i do |should, text|
282
+ eval('response.body.send(shouldify(should))') =~ /#{Regexp.escape(text.to_unquoted.to_translated)}/m
283
+ end
284
+
285
+ leo_o_no = '(?:no )?(?:leo|debo leer|deber[íi]a leer)'
286
+ Entonces /^(#{leo_o_no}) el texto (.+)?$/i do |should, text|
287
+ begin
288
+ HTML::FullSanitizer.new.sanitize(response.body).send(shouldify(should)) =~ /#{Regexp.escape(text.to_unquoted.to_translated)}/m
289
+ rescue Spec::Expectations::ExpectationNotMetError
290
+ webrat.save_and_open_page
291
+ raise
292
+ end
293
+ end
294
+
295
+ Entonces /^(#{veo_o_no}) los siguientes textos:$/i do |should, texts|
296
+ texts.raw.each do |row|
297
+ Entonces "#{should} el texto #{row[0]}"
298
+ end
299
+ end
300
+
301
+ Entonces /^(#{leo_o_no}) los siguientes textos:$/i do |should, texts|
302
+ texts.raw.each do |row|
303
+ Entonces "#{should} el texto #{row[0]}"
304
+ end
305
+ end
306
+
307
+ Entonces /^(#{veo_o_no}) (?:en )?(?:el selector|la etiqueta|el tag) (["'].+?['"]|[^ ]+)(?:(?: con)? el (?:valor|texto) )?["']?([^"']+)?["']?$/ do |should, tag, value |
308
+ lambda {
309
+ if value
310
+ response.should have_tag(tag.to_unquoted, /.*#{value.to_translated}.*/i)
311
+ else
312
+ response.should have_tag(tag.to_unquoted)
313
+ end
314
+ }.send(not_shouldify(should), raise_error)
315
+ end
316
+
317
+ Entonces /^(#{veo_o_no}) (?:las|los) siguientes (?:etiquetas|selectores):$/i do |should, texts|
318
+ check_contents, from_index = texts.raw[0].size == 2 ? [true, 1] : [false, 0]
319
+ texts.raw[from_index..-1].each do |row|
320
+ if check_contents
321
+ Entonces "#{should} el selector \"#{row[0]}\" con el valor \"#{row[1]}\""
322
+ else
323
+ Entonces "#{should} el selector \"#{row[0]}\""
324
+ end
325
+ end
326
+ end
327
+
328
+
329
+
330
+ Entonces /^(#{veo_o_no}) un enlace (?:a|para) (.+)?$/i do |should, pagina|
331
+ lambda {
332
+ href = relative_page(pagina) || pagina.to_unquoted.to_url
333
+ response.should have_tag('a[href=?]', href)
334
+ }.send(not_shouldify(should), raise_error)
335
+ end
336
+
337
+
338
+ Entonces /^(#{veo_o_no}) marcad[ao] (?:la casilla|el checkbox)? ?(.+)$/ do |should, campo|
339
+ field_labeled(campo.to_unquoted).send shouldify(should), be_checked
340
+ end
341
+
342
+ Entonces /^(#{veo_o_no}) (?:una|la) tabla (?:(["'].+?['"]|[^ ]+) )?con (?:el|los) (?:siguientes? )?(?:valore?s?|contenidos?):$/ do |should, table_id, valores|
343
+ table_id = "##{table_id.to_unquoted}" if table_id
344
+ shouldified = shouldify(should)
345
+ response.send shouldified, have_selector("table#{table_id}")
346
+
347
+ if have_selector("table#{table_id} tbody").matches?(response)
348
+ start_row = 1
349
+ tbody = "tbody"
350
+ else
351
+ start_row = 2
352
+ tbody = ""
353
+ end
354
+
355
+ valores.raw[1..-1].each_with_index do |row, i|
356
+ row.each_with_index do |cell, j|
357
+ response.send shouldified,
358
+ have_selector("table#{table_id} #{tbody} tr:nth-child(#{i+start_row})>td:nth-child(#{j+1})") { |td|
359
+ td.inner_text.should =~ /#{cell == '.*' ? cell : Regexp.escape((cell||"").to_translated)}/
360
+ }
361
+ end
362
+ end
363
+ end
364
+
365
+ Entonces /^(#{veo_o_no}) un formulario con (?:el|los) (?:siguientes? )?(?:campos?|elementos?):$/ do |should, elementos|
366
+ shouldified = shouldify(should)
367
+ response.send(shouldified, have_tag('form')) do
368
+ elementos.raw[1..-1].each do |row|
369
+ label, type = row[0].to_translated, row[1]
370
+ case type
371
+ when "submit":
372
+ with_tag "input[type='submit'][value='#{label}']"
373
+ when "radio":
374
+ with_tag('div') do
375
+ with_tag "label", label
376
+ with_tag "input[type='radio']"
377
+ end
378
+ when "select", "textarea":
379
+ field_labeled(label).element.name.should == type
380
+ else
381
+ field_labeled(label).element.attributes['type'].to_s.should == type
382
+ end
383
+ end
384
+ end
385
+ end
386
+
387
+ #BBDD
388
+ en_bbdd_tenemos = '(?:en (?:la )?(?:bb?dd?|base de datos) tenemos|tenemos en (?:la )?(?:bb?dd?|base de datos))'
389
+ tiene_en_bbdd = '(?:tiene en (?:la )?bbdd|en (?:la )?bbdd tiene|tiene en (?:la )?base de datos|en (?:la )?base de datos tiene)'
390
+ Entonces /^#{en_bbdd_tenemos} (un|una|dos|tres|cuatro|cinco|\d+) ([^ ]+)(?: (?:llamad[oa]s? )?['"](.+)["'])?$/ do |numero, modelo, nombre|
391
+ model = modelo.to_unquoted.to_model
392
+ conditions = if nombre
393
+ {:conditions => [ "#{field_for(model, 'nombre')}=?", nombre ]}
394
+ else
395
+ {}
396
+ end
397
+ resources = model.find(:all, conditions)
398
+ resources.size.should == numero.to_number
399
+ if resources.size > 0
400
+ pile_up (resources.size == 1 ? resources.first : resources)
401
+ end
402
+ end
403
+
404
+ Entonces /^(?:el|la) (.+) "(.+)" #{tiene_en_bbdd} como (.+) "(.+)"(?: \w+)?$/ do |modelo, nombre, campo, valor|
405
+ add_resource_from_database(modelo, nombre)
406
+ last_mentioned_should_have_value(campo, valor.to_real_value)
407
+ end
408
+
409
+ Entonces /^#{tiene_en_bbdd} como (.+) "(.+)"(?: \w+)?$/ do |campo, valor|
410
+ last_mentioned_should_have_value(campo, valor.to_real_value)
411
+ end
412
+
413
+ Entonces /^(?:el|la) (.+) "(.+)" #{tiene_en_bbdd} una? (.+) "(.+)"$/ do |padre, nombre_del_padre, hijo, nombre_del_hijo|
414
+ add_resource_from_database(padre, nombre_del_padre)
415
+ last_mentioned_should_have_child(hijo, nombre_del_hijo)
416
+ end
417
+
418
+ Entonces /^#{tiene_en_bbdd} una? (.+) "(.+)"$/ do |hijo, nombre_del_hijo|
419
+ last_mentioned_should_have_child(hijo, nombre_del_hijo)
420
+ end