Quiero comprobar si hay muchos cambios en un modelo al enviar un formulario en una especificación de función. Por ejemplo, quiero asegurarme de que el nombre de usuario haya cambiado de X a Y, y que la contraseña cifrada haya cambiado por cualquier valor.
Sé que ya hay algunas preguntas sobre eso, pero no encontré una respuesta adecuada para mí. La respuesta más precisa parece la ChangeMultiple
de Michael Johnston aquí: ¿Es posible que RSpec espere cambios en dos tablas? . Su desventaja es que solo se verifican cambios explícitos de valores conocidos a valores conocidos.
Creé un pseudo código sobre cómo creo que podría verse un mejor comparador:
expect {
click_button 'Save'
}.to change_multiple { @user.reload }.with_expectations(
name: {from: 'donald', to: 'gustav'},
updated_at: {by: 4},
great_field: {by_at_leaset: 23},
encrypted_password: true, # Must change
created_at: false, # Must not change
some_other_field: nil # Doesn't matter, but want to denote here that this field exists
)
También he creado el esqueleto básico del ChangeMultiple
matcher como este:
module RSpec
module Matchers
def change_multiple(receiver=nil, message=nil, &block)
BuiltIn::ChangeMultiple.new(receiver, message, &block)
end
module BuiltIn
class ChangeMultiple < Change
def with_expectations(expectations)
# What to do here? How do I add the expectations passed as argument?
end
end
end
end
end
Pero ahora ya recibo este error:
Failure/Error: expect {
You must pass an argument rather than a block to use the provided matcher (nil), or the matcher must implement `supports_block_expectations?`.
# ./spec/features/user/registration/edit_spec.rb:20:in `block (2 levels) in <top (required)>'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
# /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
Cualquier ayuda para crear este comparador personalizado es muy apreciada.
fuente
.and change { @something }.by(0)
.should_not
para cualquiera que la necesiteSi desea probar que no se cambiaron varios registros, puede invertir un comparador usando
RSpec::Matchers.define_negated_matcher
. Entonces, agregaRSpec::Matchers.define_negated_matcher :not_change, :change
en la parte superior de su archivo (o en su
rails_helper.rb
) y luego puede encadenar usandoand
:expect{described_class.reorder}.to not_change{ruleset.reload.position}. and not_change{simple_ruleset.reload.position}
fuente
La respuesta aceptada no es 100% correcta, ya que se agregó el soporte completo del comparador compuesto
change {}
en RSpec versión 3.1.0 . Si intenta ejecutar el código dado en la respuesta aceptada con la versión 3.0 de RSpec, obtendrá un error.Para utilizar comparadores compuestos con
change {}
, hay dos formas;def supports_block_expectations?; true; end
a laRSpec::Matchers::BuiltIn::Compound
clase, ya sea parcheándola o editando directamente la copia local de la gema. Una nota importante: esta forma no es completamente equivalente a la primera, ¡elexpect {}
bloque se ejecuta varias veces de esta forma!La solicitud de extracción que agregó el soporte completo de la funcionalidad de comparadores compuestos se puede encontrar aquí .
fuente
La respuesta de BroiSatse es la mejor, pero si está utilizando RSpec 2 (o tiene comparadores más complejos como
.should_not
), este método también funciona:lambda { lambda { lambda { lambda { click_button 'Save' @user.reload }.should change {@user.name}.from('donald').to('gustav') }.should change {@user.updated_at}.by(4) }.should change {@user.great_field}.by_at_least(23) }.should change {@user.encrypted_password}
fuente