web-dev-qa-db-fra.com

Comment utiliser les symboles de code d'état HTTP dans RSpec?

J'utilise symboles de code d'état HTTP dans le code d'un contrôleur tel que:

render json: {
    auth_token: user.authentication_token, 
    user: user
  }, 
  status: :created

ou

render json: {
    errors: ["Missing parameter."]
  }, 
  success: false, 
  status: :unprocessable_entity

Dans le code de ma spécification de demande, je voudrais également utiliser les symboles:

post user_session_path, email: @user.email, password: @user.password
expect(last_response.status).to eq(201)

...

expect(last_response.status).to eq(422)

Cependant, chaque test où j'utilise les symboles au lieu d'entiers échoue:

Failure/Error: expect(last_response.status).to eq(:created)

  expected: :created
       got: 201

  (compared using ==)

Voici la dernière liste de symboles de code d'état HTTP dans Rack .

29
JJD

D'une part, la réponse est construite avec des méthodes comme:

  • succès?

  • réorienter?

  • impraticable?

  • liste complète: response.methods.grep(/\?/)

D'un autre côté, les prédicats Rspec transforment chaque foo? méthode à un be_foo matcher.

Je ne suis pas sûr que vous puissiez avoir le 201 de cette façon, malheureusement, mais la création d'un matcher personnalisé est assez facile.

Remarque Rails test uniquement comptez sur quelques statuts .

11
apneadiving

L'objet response répond à plusieurs types de symboles sous forme de messages. Vous pouvez donc simplement faire:

expect(response).to be_success
expect(response).to be_error
expect(response).to be_missing
expect(response).to be_redirect

Pour les autres types, tels que :created, vous pouvez créer un matcher personnalisé simple pour cela qui enveloppe assert_response :

RSpec::Matchers.define :have_status do |type, message = nil|
  match do |_response|
    assert_response type, message
  end
end

expect(response).to have_status(:created)
expect(response).to have_status(404)

Cela devrait fonctionner correctement pour les spécifications du contrôleur qui ont la configuration d'état appropriée. Cela ne fonctionnera pas pour les spécifications des fonctionnalités. Je n'ai pas essayé avec les spécifications de la demande, donc votre kilométrage peut y varier.

La raison pour laquelle cela fonctionne est qu'il exploite le fait que les spécifications du contrôleur RSpec ont une configuration d'état similaire dans les coulisses. Donc quand assert_response accède @response c'est disponible.

Ce matcher peut probablement être amélioré en copiant simplement le code utilisé par assert_response dans le match:

RSpec::Matchers.define :have_status do |type, message = nil|
  match do |response|
    if Symbol === type
      if [:success, :missing, :redirect, :error].include?(type)
        response.send("#{type}?")
      else
        code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
        response.response_code == code
      end
    else
      response.response_code == type
    end
  end

  failure_message do |response|
    message or
      "Expected response to be a <#{type}>, but was <#{response.response_code}>"
  end
end

MISE À JOUR: 2014-07-02

Ceci est maintenant disponible dès la sortie de l'emballage avec RSpec Rails 3: https://www.relishapp.com/rspec/rspec-Rails/v/3-0/docs/ matchers/have-http-status-matcher

21
Aaron K

cela fonctionne pour moi:

expect(response.response_code).to eq(Rack::Utils::SYMBOL_TO_STATUS_CODE[:not_found])
21
cyrilchampier

Avec rspec-Rails (à partir de rspec 3) il est possible d'utiliser

expect(response).to have_http_status(:created)

Mise à jour 2018-06-11:

À partir de Rails 6, certains des matchers seront remplacés (par ex. success par successful).

9
schmijos