ruby-on-rails 使用Rails 7 API在RSpec中设置会话

flvtvl50  于 2023-05-30  发布在  Ruby
关注(0)|答案(1)|浏览(196)

我试图创建一个逻辑,用户从一个组中获得邀请。如果他们通过该邀请注册,则组ID将存储在会话中,当他们注册时,他们将自动添加到组中作为成员。
我正在使用Devise进行身份验证。所以我把它定制成这样:

class Users::RegistrationsController < Devise::RegistrationsController
  def create
    super
    if @user
      # We create a membership to the group if the user had it in the session (it means that it was invited)
      Membership.create(user: @user, group: session[:group]) if session[:group]
      # We remove the existing session
      reset_session
    end
  end
end

现在,我想测试一下这种行为。我想测试两个场景:
1.用户没有会话,就这样注册
1.用户拥有会话并注册->生成组成员资格
第一个很好,但第二个是我正在努力的:

context "when user signs up via invitation" do
 let(:group) {create :group}

 before do
  # We need to create an icon so that we can attach it to the use when created
  create :icon
  
  post user_registration_path,
  params: { "user": { "username": "test", "email": "myemail@email.com", "password": "mypassword" }},
  session: { "group": group.id }
 end

 it "has a session saved with group id" do
  expect(session[:group]).to eq group.id
 end
end

我找到了这样的here,但它抛出了以下错误:

ArgumentError:
       unknown keyword: :session

如果我试着这样打电话:

params: { user: { "username": "test", "email": "myemail@email.com", "password": "mypassword" }, session: { "group": group.id}}

它仍然抛出一个错误:

NoMethodError:
       undefined method `enabled?' for {}:Hash
     
               return unless session.enabled?

我也试着这样设置:

request.session[:group] = group.id

在我进行post调用之后(只有参数)。它确实通过了期望值,但我无法从控制器中获取它。
另外,就像这样设置它:

session[:group] = group.id

抛出以下错误:

NoMethodError:
       undefined method `session' for nil:NilClass
     
             @request.session

最后,如果我尝试在before {}块中模拟它:

allow_any_instance_of(ActionDispatch::Request).to receive(:session).and_return( group: group.id )

它给了我以下错误:

NoMethodError:
       undefined method `enabled?' for {:group=>1}:Hash
     
               return unless session.enabled?

我该如何处理这个问题?
使用Rails 7 API和ruby 3.1.2
在我的application.rb中,我添加了以下内容,以便能够在应用程序中使用会话(当我手动测试时,它确实有效)

# Configure session storage
config.session_store :cookie_store, key: '_interslice_session'
config.middleware.use ActionDispatch::Cookies
config.middleware.use config.session_store, config.session_options

谢谢!

yfjy0ee7

yfjy0ee71#

我也一直在努力解决这个问题,直到我遵循了这种方法,并包括了一个“会话双”支持,就像这个例子:

支持:

https://github.com/DFE-Digital/schools-experience/blob/master/spec/support/session_double.rb

用法:

https://github.com/DFE-Digital/schools-experience/blob/master/spec/controllers/schools/sessions_controller_spec.rb

您的示例

# your test...

RSpec.describe '...', type: :request do
  describe '...' do
    include_context 'session double'

    let(:group) {create :group}
    let(:session_hash) { {} }

    before do
      session_hash[:group] = group.id
    end

    it 'has a session saved with group id' do
      post user_registration_path, params: { "user": { "username": "test", "email": "myemail@email.com", "password": "mypassword" }}

      expect(session[:group]).to eq group.id
    end
  end
end

增加会话支持:

# spec/support/session_double.rb

shared_context 'session double' do
  let(:session_hash) { {} }

  before do
    session_double = instance_double(ActionDispatch::Request::Session, enabled?: true, loaded?: false)

    allow(session_double).to receive(:[]) do |key|
      session_hash[key]
    end

    allow(session_double).to receive(:[]=) do |key, value|
      session_hash[key] = value
    end

    allow(session_double).to receive(:delete) do |key|
      session_hash.delete(key)
    end

    allow(session_double).to receive(:clear) do |_key|
      session_hash.clear
    end

    allow(session_double).to receive(:fetch) do |key|
      session_hash.fetch(key)
    end

    allow(session_double).to receive(:key?) do |key|
      session_hash.key?(key)
    end

    allow_any_instance_of(ActionDispatch::Request)
      .to receive(:session).and_return(session_double)
  end
end

相关问题