¿Cómo escribo una afirmación de Capybara que comprueba la presencia de un botón y su estado habilitado o deshabilitado?

Tengo una aplicación que habilita / deshabilita botones en respuesta a cosas que suceden en la interfaz de usuario.

Puedo usar capibara fácilmente para detectar si existe un botón

should have_button 'save'

pero no tengo idea de cómo verificar el estado del botón de guardar. Es decir:

¿Cómo escribo una afirmación de Capybara que comprueba la presencia de un botón?y su estado habilitado o deshabilitado?

He hackeado juntos un cheque para un botón deshabilitado; para habilitado, supongo que podría verificar que hay un botón coincidente y que no hay un botón deshabilitado coincidente. Pero esto, por decir lo menos, es torpe.

Esto parece una comprobación de UI tan fundamental, que estoy seguro de que me he perdido algo, pero parece que no puedo averiguar qué.

Seguimiento basado en la respuesta de gregates:

Como mencioné en el comentario, el comportamiento de Capybara depende del controlador subyacente. Estamos utilizando webkit y devuelve resultados de cadena "true" / "false". Al parecer, otros controladores devuelven verdadero / falso. La gente de Capybara es consciente del problema (github.com/jnicklas/capybara/issues/705), pero sienten (probablemente correctamente) que no es realmente su problema resolverlo.

En lugar de que mis pruebas dependan del controlador que estoy usando, terminé creando un emparejador personalizado:

RSpec::Matchers.define :be_enabled do
  match do |actual|
    driver_result = actual[:disabled]
    # nil, false, or "false" will all satisfy this matcher
    (driver_result.nil? || driver_result == false || driver_result == "false").should be_true
  end
end

RSpec::Matchers.define :be_disabled do
  match do |actual|
    driver_result = actual[:disabled]
    (driver_result == "disabled" || driver_result == true || driver_result == "true").should be_true
  end
end

A continuación, puede escribir:

user_license_area.find_button('Save').should be_disabled

Respuestas a la pregunta(5)

Su respuesta a la pregunta