flights_gui_tests 0.0.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.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/features/data/host.yml +78 -0
  4. data/features/data/miles.yml +216 -0
  5. data/features/data/sites.yml +44 -0
  6. data/features/data/tag_microsoft.yml +68 -0
  7. data/features/step_definitions/checkout/checkout_steps.rb +24 -0
  8. data/features/step_definitions/checkout/form_steps.rb +20 -0
  9. data/features/step_definitions/checkout/load_steps.rb +36 -0
  10. data/features/step_definitions/conditional_steps.rb +12 -0
  11. data/features/step_definitions/cookies_steps.rb +8 -0
  12. data/features/step_definitions/flights_tracker/flights_tracker_steps.rb +30 -0
  13. data/features/step_definitions/landing/itineraries_steps.rb +75 -0
  14. data/features/step_definitions/landing/landing_steps.rb +59 -0
  15. data/features/step_definitions/landing/load_steps.rb +30 -0
  16. data/features/step_definitions/page_steps.rb +18 -0
  17. data/features/step_definitions/results/basefare_steps.rb +65 -0
  18. data/features/step_definitions/results/desambiguation_steps.rb +144 -0
  19. data/features/step_definitions/results/errors_steps.rb +23 -0
  20. data/features/step_definitions/results/filters_steps.rb +301 -0
  21. data/features/step_definitions/results/load_steps.rb +52 -0
  22. data/features/step_definitions/results/matrix_steps.rb +213 -0
  23. data/features/step_definitions/results/order_steps.rb +49 -0
  24. data/features/step_definitions/results/pagination_steps.rb +29 -0
  25. data/features/step_definitions/results/recommendation_steps.rb +75 -0
  26. data/features/step_definitions/results/results_steps.rb +40 -0
  27. data/features/step_definitions/results/reviews_steps.rb +16 -0
  28. data/features/step_definitions/results/tags_steps.rb +102 -0
  29. data/features/step_definitions/results/wish_list_steps.rb +114 -0
  30. data/features/step_definitions/thanks/load_steps.rb +10 -0
  31. data/features/step_definitions/thanks/thanks_steps.rb +12 -0
  32. data/features/support/classes/clusters/checkout_cluster.rb +117 -0
  33. data/features/support/classes/clusters/data/data.rb +33 -0
  34. data/features/support/classes/clusters/results/details_cluster.rb +36 -0
  35. data/features/support/classes/clusters/results/landing_cluster.rb +29 -0
  36. data/features/support/classes/clusters/results/render_cluster.rb +83 -0
  37. data/features/support/classes/clusters/results_cluster.rb +171 -0
  38. data/features/support/classes/date.rb +26 -0
  39. data/features/support/classes/element.rb +23 -0
  40. data/features/support/classes/price.rb +66 -0
  41. data/features/support/classes/process_manager.rb +104 -0
  42. data/features/support/classes/string.rb +16 -0
  43. data/features/support/env.rb +94 -0
  44. data/features/support/hooks.rb +20 -0
  45. data/features/support/matchers.rb +108 -0
  46. data/features/support/modules/accessor.rb +26 -0
  47. data/features/support/modules/browser.rb +80 -0
  48. data/features/support/modules/checkout/datos_de_facturacion.rb +64 -0
  49. data/features/support/modules/checkout/informacion_de_contacto.rb +30 -0
  50. data/features/support/modules/checkout/pasajeros.rb +71 -0
  51. data/features/support/modules/checkout/tarjeta.rb +71 -0
  52. data/features/support/modules/element.rb +12 -0
  53. data/features/support/modules/helpers.rb +64 -0
  54. data/features/support/modules/pages/cookies.rb +33 -0
  55. data/features/support/modules/pages/tags.rb +27 -0
  56. data/features/support/modules/results/filters.rb +37 -0
  57. data/features/support/modules/results/itineraries/bussines.rb +17 -0
  58. data/features/support/modules/results/itineraries/data.rb +25 -0
  59. data/features/support/modules/results/itineraries/details.rb +80 -0
  60. data/features/support/modules/results/itineraries/miles.rb +64 -0
  61. data/features/support/modules/results/itineraries/payments.rb +27 -0
  62. data/features/support/modules/results/matrix/matrix_airline.rb +52 -0
  63. data/features/support/modules/results/matrix/matrix_fare_chart.rb +21 -0
  64. data/features/support/modules/results/matrix/matrix_price.rb +18 -0
  65. data/features/support/modules/results/recommendation.rb +29 -0
  66. data/features/support/modules/results/search_params.rb +21 -0
  67. data/features/support/modules/results/wish_list.rb +33 -0
  68. data/features/support/pages/all_pages.rb +95 -0
  69. data/features/support/pages/checkout/checkout_page.rb +45 -0
  70. data/features/support/pages/checkout/popup_results_page.rb +39 -0
  71. data/features/support/pages/flights_tracker/search_page.rb +54 -0
  72. data/features/support/pages/landing/search_page.rb +94 -0
  73. data/features/support/pages/results/desambiguation_airports_page.rb +16 -0
  74. data/features/support/pages/results/desambiguation_city_page.rb +20 -0
  75. data/features/support/pages/results/search_page.rb +101 -0
  76. data/features/support/pages/thanks/thanks_page.rb +7 -0
  77. data/features/tests/checkout/book_ok.feature +209 -0
  78. data/features/tests/flights_tracker/search.feature +65 -0
  79. data/features/tests/landing/search.feature +152 -0
  80. data/features/tests/results/basefare.feature +90 -0
  81. data/features/tests/results/desambiguation/airports.feature +89 -0
  82. data/features/tests/results/desambiguation/city.feature +87 -0
  83. data/features/tests/results/errors.feature +198 -0
  84. data/features/tests/results/filters.feature +113 -0
  85. data/features/tests/results/itineraries.feature +93 -0
  86. data/features/tests/results/matrix/matrix_airlines.feature +46 -0
  87. data/features/tests/results/matrix/matrix_fare_chart.feature +41 -0
  88. data/features/tests/results/matrix/matrix_price.feature +41 -0
  89. data/features/tests/results/orders.feature +89 -0
  90. data/features/tests/results/pagination.feature +74 -0
  91. data/features/tests/results/recommendation.feature +111 -0
  92. data/features/tests/results/reviews_airlines.feature +84 -0
  93. data/features/tests/results/search.feature +209 -0
  94. data/features/tests/results/wish_list.feature +55 -0
  95. data/flights_gui_tests.gemspec +34 -0
  96. data/henry-context.yml +4938 -0
  97. metadata +306 -0
@@ -0,0 +1,26 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class Date
3
+ def self.parse_new_result(string)
4
+ aux = string.gsub(/\.|\,/,'').match(/(\D.+) (\d{1,2}) (\D.+)(,|) (\d{4})/)
5
+ fecha = "#{aux[5]}/#{MONTHNAMES.index(aux[3].capitalize) ? MONTHNAMES.index(aux[3].capitalize) : ABBR_MONTHNAMES.index(aux[3].downcase)}/#{aux[2]}"
6
+ self.parse(fecha)
7
+ end
8
+ def self.parse_details(string)
9
+ aux = string.match(/(\d{1,2}) (\D.+) (\d{4}) (\d{2}):(\d{2})/)
10
+ fecha = "#{aux[3]}/#{ABBR_MONTHNAMES.index(aux[2].downcase)}/#{aux[1]}"
11
+ self.parse(fecha)
12
+ end
13
+ def self.parse_new_details(string)
14
+ aux = string.match(/(\D.+) (\d{1,2}) (\D.+)/)
15
+ fecha = "#{aux[2]}/#{ABBR_MONTHNAMES.index(aux[3].downcase)}/#{Date.today.year}"
16
+ date = self.parse(fecha)
17
+ date = date.next_year if date < Date.today
18
+ return date
19
+ end
20
+ def mes
21
+ return MONTHNAMES[self.month]
22
+ end
23
+ def mes_abrr
24
+ return ABBR_MONTHNAMES[self.month]
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ module PageObject
3
+ module Elements
4
+ class Element
5
+ # @private
6
+ # delegate calls to driver element
7
+ def method_missing(*args, &block)
8
+ m = args.shift
9
+ #$stderr.puts "*** DEPRECATION WARNING"
10
+ #$stderr.puts "*** You are calling a method named #{m} at #{caller[0]}."
11
+ #$stderr.puts "*** This method does not exist in page-object so it is being passed to the driver."
12
+ #$stderr.puts "*** This feature will be removed in the near future."
13
+ #$stderr.puts "*** Please change your code to call the correct page-object method."
14
+ #$stderr.puts "*** If you are using functionality that does not exist in page-object please request it be added."
15
+ begin
16
+ element.send m, *args, &block
17
+ rescue Exception => e
18
+ raise
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,66 @@
1
+ # -*- encoding : utf-8 -*-
2
+ #clase que representa un precio, con su moneda y valor correspondiente
3
+ #se le pasa una string que contiene al precio(moneda y valor juntos)
4
+ class Price
5
+
6
+ include Comparable
7
+
8
+ attr_accessor :value, :currency
9
+
10
+ def initialize(precio, costos=nil, item=nil)
11
+ @currency = (precio.empty?) ? '$' : (precio.gsub(/\-|\.|\d/,'').upstrip == 'BSF' ? "Bs.F." : precio.gsub(/\-|\.|\d| /,'').upstrip )
12
+ @value = (precio.empty?) ? 0 : precio.match(/([^\s]+)\s+([^\s]+)/i)[2].strip.gsub(/\./,'').to_i
13
+ end
14
+
15
+ def moneda
16
+ self.currency
17
+ end
18
+
19
+ def valor
20
+ self.value
21
+ end
22
+
23
+ def set_valor(value)
24
+ @value = value
25
+ end
26
+
27
+ #metodo que pregunta si el precio es en dolares
28
+ def dolar?
29
+ self.currency =~ /(U\$S)|(U\$D)|(USD)|(US\$)|(\$US)/
30
+ end
31
+
32
+ #metodos de comparacion
33
+ def <=>(other)
34
+ ( (self.dolar? and other.dolar?) or self.same_moneda?(other) ) ? ( self.value <=> other.value ) : ( self.to_dolar.value <=> other.to_dolar.value)
35
+ end
36
+
37
+ #informa si la diferencia es mayor a un rango determinado
38
+ def diff(other,range)
39
+ ( (self.dolar? and other.dolar?) or self.same_moneda?(other) ) ? ( self.value <=> other.value ) : ( self.to_dolar.value <=> other.to_dolar.value )
40
+ end
41
+
42
+ #devuelve un string del precio
43
+ def to_s
44
+ "#{self.currency}#{self.value}"
45
+ end
46
+
47
+ def +(other)
48
+ ( self.same_moneda?(other) )? ( Precio.new("#{self.currency} #{self.value + other.value}",true) ) : ( Precio.new("U$S #{self.to_dolar.value + other.to_dolar.value}",true) )
49
+ end
50
+ def -(other)
51
+ ( self.same_moneda?(other) )? ( Precio.new("#{self.currency} #{self.value - other.value}","change") ) : ( Precio.new("U$S #{self.to_dolar.value - other.to_dolar.value}","change") )
52
+ end
53
+
54
+ def same_moneda?(other)
55
+ self.currency == other.currency or ver_moneda_en_base(other.currency) or (MainData.site =~ /ECUADOR/)
56
+ end
57
+
58
+ def zero?
59
+ self.value == 0
60
+ end
61
+
62
+ def empty?
63
+ self.zero?
64
+ end
65
+
66
+ end
@@ -0,0 +1,104 @@
1
+ #encoding: utf-8
2
+
3
+ class ProcessManager
4
+
5
+ #Crea un árbol de procesos, donde el PID recibido es el nodo raíz
6
+ def self.process_tree(pid)
7
+ tree = process_info(pid)
8
+ tree[:childs] = []
9
+ process_childs(pid).each do |child_pid|
10
+ tree[:childs].push(self.process_tree(child_pid))
11
+ end
12
+ tree
13
+ end
14
+
15
+ #Recibe un PID y devuelve un array con los PID de sus hijos
16
+ def self.process_childs(pid)
17
+ `ps -fea | grep #{pid} | grep -v grep | awk '$2!=#{pid} && $8!~/awk/ && $3==#{pid}{print $2}'`.split("\n")
18
+ end
19
+
20
+ #Devuelve un array con la información de los hijos
21
+ def self.process_childs_info(pid)
22
+ process_childs(pid).collect do |child_pid|
23
+ process_info(child_pid)
24
+ end
25
+ end
26
+
27
+ #Devuelve un hash con la información del proceso
28
+ def self.process_info(pid)
29
+ {
30
+ :user => process_user(pid),
31
+ :pid => pid,
32
+ :parent => process_parent(pid),
33
+ :status => process_status(pid),
34
+ :cmd => process_cmd(pid)
35
+ }
36
+ end
37
+
38
+ #Devuelve el usuario del proceso
39
+ def self.process_user(pid)
40
+ `ps -fea | grep #{pid} | awk '$2==#{pid}{print $1}'`.split("\n")[0]
41
+ end
42
+
43
+ #Devuelve el padre del proceso
44
+ def self.process_parent(pid)
45
+ `ps -fea | grep #{pid} | awk '$2==#{pid}{print $3}'`.split("\n")[0]
46
+ end
47
+
48
+ #Devuelve el estado del proceso
49
+ def self.process_status(pid)
50
+ `ps aux | grep #{pid} | awk '$2==#{pid}{print $8}'`.split("\n")[0]
51
+ end
52
+
53
+ #Devuelve el comando del proceso
54
+ def self.process_cmd(pid)
55
+ `ps -fea | grep #{pid} | awk '$2==#{pid}{print $8}'`.split("\n")[0]
56
+ end
57
+
58
+ #Mata al proceso que recibe, si existe
59
+ def self.kill_process(pid)
60
+ begin
61
+ Process.kill('INT', pid)
62
+ #Proceso matado
63
+ true
64
+ rescue Errno::EPERM
65
+ #Permiso insuficiente para matar al proceso
66
+ begin
67
+ `kill -9 #{pid.to_i}`
68
+ true
69
+ rescue
70
+ false
71
+ end
72
+ rescue Errno::ESRCH
73
+ #El proceso no existía
74
+ true
75
+ end
76
+ end
77
+
78
+ #Recibe un árbol de procesos y los mata a todos, incluyendo al nodo principal
79
+ def self.kill_tree(tree)
80
+ tree[:childs].each do |child|
81
+ kill_tree(child)
82
+ end
83
+ kill_process(tree[:pid].to_i)
84
+ end
85
+
86
+ #Recibe un PID y mata todo el árbol de procesos a partir de él, sin matar al nodo principal
87
+ def self.kill_all_childs(pid)
88
+ tree = process_tree(pid)
89
+ tree[:childs].each do |child|
90
+ kill_tree(child)
91
+ end
92
+ end
93
+
94
+ #Se asegura que no queden procesos chrome zombies
95
+ def self.chrome_zombies_collector
96
+ zombies_parent = `ps -fea | grep defunct | grep chrome | grep -v grep | grep -v chromedriver | awk '{print $3}'`.split("\n")
97
+ zombies_parent.each do |parent|
98
+ parent_info = process_info(parent)
99
+ ##Parent == 1, si se volvió huerfano
100
+ kill_process(parent.to_i) if parent_info[:parent] == '1' and parent_info[:cmd] and parent_info[:cmd].match(/chrome/)
101
+ end
102
+ end
103
+
104
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class String
3
+
4
+ def no_accents
5
+ return self.force_encoding("UTF-8").unaccent
6
+ end
7
+
8
+ def downstrip
9
+ return self.downcase.strip.gsub(/\n\r/,'')
10
+ end
11
+
12
+ def upstrip
13
+ return self.upcase.strip
14
+ end
15
+
16
+ end
@@ -0,0 +1,94 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'rubygems'
3
+ require 'watir-webdriver'
4
+ require 'hpricot'
5
+ require 'page-object'
6
+ require 'rspec'
7
+ require 'sixarm_ruby_unaccent'
8
+ require 'httparty'
9
+ require 'henry/environment'
10
+ require 'sanitize'
11
+ require 'uri'
12
+ require 'henry/config'
13
+ require 'mock_search'
14
+ require 'byebug'
15
+
16
+ $VERBOSE = nil
17
+
18
+ #carga de clases y redefiniciones
19
+ require_relative 'classes/date'
20
+ require_relative 'classes/string'
21
+ require_relative 'classes/price'
22
+ require_relative 'classes/element'
23
+ require_relative 'classes/process_manager'
24
+
25
+ #carga de modulos
26
+ require_relative 'modules/helpers'
27
+ require_relative 'modules/browser'
28
+ require_relative 'modules/element'
29
+ require_relative 'modules/accessor'
30
+
31
+ require_relative 'modules/pages/tags'
32
+ require_relative 'modules/pages/cookies'
33
+
34
+ require_relative 'pages/all_pages'
35
+
36
+ require_relative 'modules/results/search_params'
37
+ require_relative 'modules/results/filters'
38
+ require_relative 'modules/results/wish_list'
39
+ require_relative 'modules/results/recommendation'
40
+ require_relative 'modules/results/matrix/matrix_airline'
41
+ require_relative 'modules/results/matrix/matrix_price'
42
+ require_relative 'modules/results/matrix/matrix_fare_chart'
43
+ require_relative 'modules/results/itineraries/miles'
44
+ require_relative 'modules/results/itineraries/bussines'
45
+ require_relative 'modules/results/itineraries/payments'
46
+ require_relative 'modules/results/itineraries/details'
47
+ require_relative 'modules/results/itineraries/data'
48
+
49
+ require_relative 'modules/checkout/pasajeros'
50
+ require_relative 'modules/checkout/tarjeta'
51
+ require_relative 'modules/checkout/datos_de_facturacion'
52
+ require_relative 'modules/checkout/informacion_de_contacto'
53
+
54
+ #carga de paginas y modulos de cargas
55
+ require_relative 'pages/flights_tracker/search_page'
56
+ require_relative 'pages/results/desambiguation_airports_page'
57
+ require_relative 'pages/results/desambiguation_city_page'
58
+ require_relative 'pages/results/search_page'
59
+ require_relative 'pages/checkout/checkout_page'
60
+ require_relative 'pages/checkout/popup_results_page'
61
+ require_relative 'pages/thanks/thanks_page'
62
+ require_relative 'pages/landing/search_page'
63
+
64
+ #carga de asserts personalizados
65
+ require_relative 'matchers'
66
+ require_relative 'hooks'
67
+
68
+ #carga de clases de cluster
69
+ require_relative 'classes/clusters/results_cluster'
70
+ require_relative 'classes/clusters/results/landing_cluster'
71
+ require_relative 'classes/clusters/results/render_cluster'
72
+ require_relative 'classes/clusters/results/details_cluster'
73
+ require_relative 'classes/clusters/checkout_cluster'
74
+
75
+ #carga de parametros globales
76
+ $HENRY_PARAMS = Henry::Environment.params
77
+ $ENV = $HENRY_PARAMS['env']
78
+
79
+ @@error_navegador = nil
80
+ reintentos = 2
81
+ begin
82
+ $browser = Browser.iniciar($HENRY_PARAMS['browser'])
83
+ rescue Net::ReadTimeout, Selenium::WebDriver::Error::WebDriverError, ChildProcess::TimeoutError
84
+ $browser = nil
85
+ ProcessManager.kill_all_childs(Process.pid)
86
+ reintentos -= 1
87
+ sleep 5
88
+ if reintentos > 0
89
+ puts "Error Net::ReadTimeout - Reintentando abrir el browser..."
90
+ retry
91
+ else
92
+ @@error_navegador = true
93
+ end
94
+ end
@@ -0,0 +1,20 @@
1
+ # -*- encoding : utf-8 -*-
2
+ Before do |scenario|
3
+ #creo una ventana de navegador
4
+ end
5
+
6
+ After do |scenario|
7
+ if $HENRY_PARAMS['browser']
8
+ if scenario.failed?
9
+ FileUtils.mkdir_p(Henry::Environment.output_path+"/reports/html/screenshots/")
10
+ name = "FAILED_#{scenario.name.gsub(' ','').gsub(/[^0-9A-Za-z]/, '')}.png"
11
+ screenshot = "#{Henry::Environment.output_path}/reports/html/screenshots/#{name}"
12
+ $browser.driver.save_screenshot(screenshot)
13
+ embed "./screenshots/#{name}", 'image/png'
14
+ end
15
+ end
16
+ end
17
+
18
+ at_exit do
19
+ $browser.close
20
+ end
@@ -0,0 +1,108 @@
1
+ # -*- encoding : utf-8 -*-
2
+ RSpec::Matchers.define :visible do
3
+ match do |actual|
4
+ actual.present?
5
+ end
6
+ failure_message_for_should do |actual|
7
+ "se esperaba que el elemento #{actual} sea visible"
8
+ end
9
+ failure_message_for_should_not do |actual|
10
+ "se esperaba que el elemento #{actual} no sea visible"
11
+ end
12
+ end
13
+
14
+ RSpec::Matchers.define :enabled do
15
+ match do |actual|
16
+ actual.enabled?
17
+ end
18
+ failure_message_for_should do |actual|
19
+ "se esperaba que el elemento #{actual} estuviera habilitado"
20
+ end
21
+ failure_message_for_should_not do |actual|
22
+ "se esperaba que el elemento #{actual} estuviera deshabilitado"
23
+ end
24
+ end
25
+
26
+ RSpec::Matchers.define :visible do |text|
27
+ match do |actual|
28
+ actual.present?
29
+ end
30
+ failure_message_for_should do |actual|
31
+ "se esperaba que el elemento #{text} sea visible"
32
+ end
33
+ failure_message_for_should_not do |actual|
34
+ "se esperaba que el elemento #{text} no sea visible"
35
+ end
36
+ end
37
+
38
+ RSpec::Matchers.define :match do |text_for_match|
39
+ match do |actual|
40
+ actual.match(/#{text_for_match}/)
41
+ end
42
+ failure_message_for_should do |actual|
43
+ "se esperaba que el texto #{actual} contenga a #{text_for_match}"
44
+ end
45
+ failure_message_for_should_not do |actual|
46
+ "se esperaba que el texto #{actual} no contenga a #{text_for_match}"
47
+ end
48
+ end
49
+
50
+ RSpec::Matchers.define :match_sensitive do |text_for_match|
51
+ match do |actual|
52
+ actual.match(/#{text_for_match}/i)
53
+ end
54
+ failure_message_for_should do |actual|
55
+ "se esperaba que el texto #{actual} contenga a #{text_for_match}"
56
+ end
57
+ failure_message_for_should_not do |actual|
58
+ "se esperaba que el texto #{actual} no contenga a #{text_for_match}"
59
+ end
60
+ end
61
+
62
+ RSpec::Matchers.define :equal do |text|
63
+ match do |actual|
64
+ actual == text
65
+ end
66
+ failure_message_for_should do |actual|
67
+ "se esperaba que el texto #{actual} sea igual a #{text}"
68
+ end
69
+ failure_message_for_should_not do |actual|
70
+ "se esperaba que el texto #{actual} no sea igual a #{text}"
71
+ end
72
+ end
73
+
74
+ RSpec::Matchers.define :include? do |text|
75
+ match do |actual|
76
+ actual.include?(text)
77
+ end
78
+ failure_message_for_should do |actual|
79
+ "se esperaba que la coleccion [#{actual.join('-')}] contenga a #{text}"
80
+ end
81
+ failure_message_for_should_not do |actual|
82
+ "se esperaba que la coleccion [#{actual.join('-')}] no contenga a #{text}"
83
+ end
84
+ end
85
+
86
+ RSpec::Matchers.define :is_empty? do
87
+ match do |actual|
88
+ actual.empty?
89
+ end
90
+ failure_message_for_should do |actual|
91
+ "Se esperaba que la coleccion #{actual.join('-')} sea vacia"
92
+ end
93
+ failure_message_for_should_not do |actual|
94
+ "Se esperaba que la coleccion #{actual.join('-')} no sea vacia"
95
+ end
96
+ end
97
+
98
+ RSpec::Matchers.define :es_mayor_que do |min|
99
+ match do |actual|
100
+ actual.to_i > min
101
+ end
102
+ failure_message_for_should do |actual|
103
+ "se esperaba que el valor #{actual} sea mayor a #{min}"
104
+ end
105
+ failure_message_for_should_not do |actual|
106
+ "se esperaba que el valor #{actual} no sea mayor a #{min}"
107
+ end
108
+ end