在Rails 7 API中设置RSpec的会话

huangapple go评论132阅读模式
英文:

Set Session in RSpec with Rails 7 API

问题

以下是您要翻译的代码部分:

class Users::RegistrationsController < Devise::RegistrationsController
  def create
    super
    if @user
      # 如果用户在会话中有群组,我们为该用户创建一个群组成员
      Membership.create(user: @user, group: session[:group]) if session[:group]
      # 移除会话中的群组信息
      reset_session
    end
  end
end
context "当用户通过邀请注册时" do
  let(:group) {create :group}

  before do
    # 我们需要创建一个图标,以便在创建用户时将其附加到用户
    create :icon
    
    post user_registration_path,
    params: { "user": { "username": "test", "email": "myemail@email.com", "password": "mypassword" }},
    session: { "group": group.id }
  end

  it "保存了一个带有群组ID的会话" do
    expect(session[:group]).to eq group.id
  end
end

我希望这些代码部分对您有所帮助。如果您需要更多帮助,请随时告诉我。

英文:

I am trying to create a logic where a user gets an invitation from a group. If they signup via that invitation, the group id will be stored in the session and when they signup, they will be automatically added to the group as a member.

I am using Devise for authentication. So I customized it like this:

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

Now, I want to test this behaviour.
I would like to test 2 scenarios:

  1. User doesn't have the session and signs up just like that
  2. User has the session and signs up -> a group membership is generated

The first one is fine but the second one is the one I am struggling at:

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

I found this way here, but it throws the following error:

ArgumentError:
       unknown keyword: :session

If I try making the call like this instead:

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

It still throws an error:

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

I also tried setting it like this:

request.session[:group] = group.id

After I make the post call (with only the params). It does pass the expectation but I cannot fetch it from the controller.

Also, just setting it like this:

session[:group] = group.id

Throws the following error:

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

Finally, if I try to mock it inside the before {} block:

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

It gives me the following error:

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

Any ideas on how can I tackle this?

PD. Using Rails 7 API and ruby 3.1.2

and also in my application.rb I added the following to be able to work with sessions in the app (and when I test manually it does work)

# 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

Thanks!

答案1

得分: 1

I also struggled with this until I followed this approach and included a "session double" support, like this example:

Support:

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

Usage:

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

Your Example

# 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

Add Session Support:

# 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
英文:

I also struggled with this until I followed this approach and included a "session double" support, like this example:

Support:

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

Usage:

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

Your Example

# 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

Add Session Support:

# 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

huangapple
  • 本文由 发表于 2023年3月7日 05:24:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75655990.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定