Rails 第二个请求出现 WebMock 错误 try ::NetConnectNotAllowedError

Rails WebMock error on the second request try ::NetConnectNotAllowedError

我想模拟自定义设计策略以在我的功能规范中对用户进行身份验证。为了存根对第 3 方应用程序的请求,我使用 WebMock 实现如下:

spec/utility/stub_methods.rb

  def stub_aware_auth(creds, returns_token, _valid)
    stub_request(:post, "http://example.com/oauth/token").
        with(body: {"grant_type" => "password", "password" => creds.password, "username" => creds.email},
             headers: {'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/x-www-form-urlencoded'}).
        to_return(status: 200, body: {'access_token' => returns_token, 'token_type' => 'bearer', 'expires_in' => 1200}.to_json, headers: {})
  end

在规范中被称为:

context 'AWARxE authenticated user' do
  before do
    stub_aware_auth(creds, return_token, valid)  
  end

  let(:creds) do
    OpenStruct.new(email: 'physiciansreallyshouldonlyautoauth@example.com', password: "Ican'tb3li3v3itsn0tbutt3r")
  end
  let(:return_token) { SecureRandom.hex(32) }
  let(:valid) { true }
  # other logic (...)
end

spec_helper.rb

WebMock.disable_net_connect!(allow_localhost: true)

它的工作方式非常令人惊讶,因为如果在一个测试示例中它必须使用 stub_aware_auth 两次,第一次请求 returns 定义的结果,但第二次会抛出错误:

WebMock::NetConnectNotAllowedError: Real HTTP connections are disabled. Unregistered request: POST http://example.com/oauth/token with body 'grant_type=password&password=Ican%27tb3li3v3itsn0tbutt3r&username=PHYSICIANSREALLYSHOULDONLYAUTOAUTH%40EXAMPLE.COM' with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Faraday v0.12.1'}

You can stub this request with the following snippet:

stub_request(:post, "http://example.com/oauth/token").
  with(body: {"grant_type"=>"password", "password"=>"Ican'tb3li3v3itsn0tbutt3r", "username"=>"PHYSICIANSREALLYSHOULDONLYAUTOAUTH@EXAMPLE.COM"},
       headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Faraday v0.12.1'}).
  to_return(status: 200, body: "", headers: {})

registered request stubs:

stub_request(:get, "http://example.com/api/v1/user").
  with(headers: {'Authorization'=>'Bearer dc2dcf4c5b47ffcfea28c26490ed2a0e2580f152dfb18dbfc97670028d24ecaa'})
stub_request(:post, "http://example.com/oauth/token").
  with(body: {"grant_type"=>"password", "password"=>"Ican'tb3li3v3itsn0tbutt3r", "username"=>"physiciansreallyshouldonlyautoauth@example.com"},
       headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/x-www-form-urlencoded'})

这令人惊讶,因为 WebMock.disable_net_connect!(allow_localhost: true) 是在 spec_helper 中定义的。

[编辑]

如果有帮助,完整的失败示例:

spec/features/login_strategies_spec.rb

  context 'AWARxE authenticated user' do
    before do
      stub_aware_auth(creds, return_token, valid)
    end

    let(:return_token) { SecureRandom.hex(32) }
    let(:valid) { true }
    context 'physician' do
      let(:creds) do
        OpenStruct.new(email: 'physiciansreallyshouldonlyautoauth@example.com', password: "Ican'tb3li3v3itsn0tbutt3r")
      end
      let(:user) { build(:physician) }

      before do
        stub_aware_user_info(user, 'Physician (MD, DO)', return_token, valid, 1)
      end
      
      # some other it block (...)

      context 'case insensitive' do
        let(:valid) { true }
        let(:uppercase_email_creds) {
          OpenStruct.new(email: creds.email.upcase, password: creds.password)
        }

        scenario 'logging in with upper case email' do
          expect { subject }.to change(Login, :count)
          logout
          expect {
            login(uppercase_email_creds)
          }.to_not change(Login, :count)
          expect(page).to have_current_path(name_search_registrants_url, url: true)
        end
      end
    end

您正在创建的存根仍在带有小写电子邮件的原始 creds 上。除非您实际调用

之类的东西,否则 webmock 不可能模拟调用
      stub_aware_auth(uppercase_email_creds, return_token, valid)

如果您实际上希望应用程序在正文中使用小写电子邮件进行调出,那么测试将失败,因为它应该会失败,它会使用大写电子邮件进行调出:

You can stub this request with the following snippet:

stub_request(:post, "http://example.com/oauth/token").
  with(body: {..., "username"=>"PHYSICIANSREALLYSHOULDONLYAUTOAUTH@EXAMPLE.COM"},
       ...).
  to_return(status: 200, body: "", headers: {})