Using env with rack_test - ruby

In a Rails app, I have the following configuration to run System Rspec specs.
RSpec.configure do |config|
config.before(:each, type: :system) do
driven_by :rack_test
end
config.before(:each, type: :system, js: true) do
driven_by :selenium, using: :headless_chrome, screen_size: [1300, 1240]
end
end
Now, I have added a middleware that depends upon env['REQUEST_PATH'] and, when I run the specs using rack_test I get
Failure/Error: _, id, request_path = env['REQUEST_PATH'].split('/', 3)
NoMethodError: undefined method `split' for nil:NilClass
However, if I always use selenium, all the specs pass like before.
Is there a way to use/set env['REQUEST_PATH'] with rack_test?

Related

undefined method `entry_mapping' for nil:NilClass

I am trying to play around with the RODA Ruby web framework based on Rack. However, I am having issues with using Minitest with the framework. RSpec was hectic with it too unlike Rails. I tried to reproduce the error with pry, but I couldn't make sense of it. How should I fix this? I am getting
undefined method `entry_mapping' for nil:NilClass.
Below is the associated code:
Gemfile
gem 'contentful_model', '~> 1.3' # ActiveModel-like wrapper for the Contentful SDKs
group :test do
gem 'capybara'
gem 'minitest', '>= 5.7.0'
gem 'minitest-hooks', '>= 1.1.0'
gem "minitest-global_expectations"
gem "warning"
gem 'pry'
end
models/recipe.rb
require 'contentful_model'
class Recipe < ContentfulModel::Base
self.content_type_id = 'recipe'
def self.all_recipes
all.load!
end
end
app.rb | Tree Routing
require './.env' if File.exist?(".env.rb")
require './config/initializers/contentful_model'
require 'roda'
require './models/recipe'
require 'tilt/sass'
class App < Roda
hash_routes do
view '', 'index'
end
route do |r|
#recipes = Recipe.all_recipes
r.public
r.assets
check_csrf!
r.hash_routes('')
r.get String do |id|
#recipe_details = Recipe.find(id)
next unless #recipe_details
view 'show'
end
end
end
spec/models/spec_helper.rb
ENV["RACK_ENV"] = "test"
require_relative '../../models/recipe'
require_relative '../minitest_helper'
spec/models/recipe_spec.rb
require_relative 'spec_helper'
describe Recipe do
let(:recipes) { Recipe.all_recipes }
describe '.all_recipes' do
it 'return all records with content type recipe' do
recipes = Recipe.all_recipes # undefined method `entry_mapping' for nil:NilClass
expect(recipes).to all must_be Recipe
end
end
end
pry debug
From: /Users/tiwa/RubymineProjects/marley-spoon-roda/spec/models/recipe_spec.rb:27 .all_recipes#test_0001_return all records with content type recipe:
24: it 'return all records with content type recipe' do
25: recipes = Recipe.all_recipes # undefined method `entry_mapping' for nil:NilClass
26: binding.pry
=> 27: expect(recipes).to all must_be Recipe
28: end
[1] pry(#<.all_recipes>)> Recipe.all_recipes
NoMethodError: undefined method `entry_mapping' for nil:NilClass
from /Users/tiwa/.gem/ruby/2.7.1/gems/contentful_model-1.3.0/lib/contentful_model/base.rb:124:in `mapping?'
I see the code in contentful_model-1.3.0/lib/contentful_model/base.rb:124 is:
ContentfulModel.configuration.entry_mapping.key?(#content_type_id)
If error msg is undefined method `entry_mapping' for nil:NilClass then
ContentfulModel.configuration
Is nil
To fix this you need configure ContentfulModel. Something like that:
ContentfulModel.configure do |config|
config.access_token = "your access token in here" # Required
config.preview_access_token = "your preview token in here" # Optional - required if you want to use the preview API
config.management_token = "your management token in here" # Optional - required if you want to update or create content
config.space = "your space id in here" # Required
config.environment = "master" # Optional - defaults to 'master'
config.default_locale = "en-US" # Optional - defaults to 'en-US'
config.options = { # Optional
# Extra options to send to the Contentful::Client and Contentful::Management::Client
# See https://github.com/contentful/contentful.rb#configuration
# Optional:
# Use `delivery_api` and `management_api` keys to limit to what API the settings
# will apply. Useful because Delivery API is usually visitor facing, while Management
# is used in background tasks that can run much longer. For example:
delivery_api: {
timeout_read: 6
},
management_api: {
timeout_read: 100
}
}
end
With this config this call is not more nil
ContentfulModel.configuration
See https://github.com/contentful/contentful_model

Rake in Ruby: undefined method `namespace' for main:Object (NoMethodError)

I'm currently trying to run a Rake task in a Ruby project (No Rails). What I am trying to accomplish is to run a method from a file within my Ruby project. However I get the following error:
undefined method `namespace' for main:Object (NoMethodError)
I created a folder task that holds a test.rb file. Before I had it as test.rake but I think this was incorrect. I also created a Rakefile pointing to task/test.rb
For redeability, I'm using namespace: although I'll be honest I'm not sure if I even need it.
#Rakefile
task :default => [:test]
task :test do
ruby 'task/test.rb'
end
Here is the task.test.rb
require './src/lambda_function.rb'
class KMS
def initialize
end
def decrypt(key)
return "some password"
end
end
class SNS
def initialize
end
end
TEST_FORM_ID=123
namespace :test do
namespace :lambda do
desc 'Run the Lambda process function'
task :process do
LambdaFunctions::LambdaHandler.process(box_api: BoxApi.new,
form: TEST_FORM_ID,
sns: SNS.new,
kms: KMS.new)
end
end
end
What I'm I doing wrong?

Why can't RSpec find the Airbrake env keys in a test involving Sidekiq when I specify environment?

Here is my setup:
airbrake.rb
require 'airbrake'
Airbrake.configure do |c|
c.ignore_environments = [:test, :development]
c.project_id = ENV['PROJECT_ID']
c.project_key = ENV['PROJECT_KEY']
end
use Airbrake::Rack::Middleware
spec_helper.rb
RSpec.configure do |config|
config.before(:suite) do
FactoryGirl.reload
FactoryGirl.define do
to_create { |instance| instance.save }
end
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
Airbrake.configure(:test) do |c|
c.project_id = ENV['PROJECT_ID']
c.project_key = ENV['PROJECT_KEY']
end
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
config.include FactoryGirl::Syntax::Methods
end
worker_test_spec.rb
require 'spec_helper'
RSpec.describe NotificationWorker do
it "perform should call Airbrake#notify" do
anotification_worker = LNotificationWorker.new
airbrake_notification_worker.perform("some error message"))
expect(Airbrake).to receive(:notify).with("some error message")
end
end
I call Airbrake#notify in other (non-Sidekiq) tests, and they find the appropriate ENV variables just fine.
Yet if I run the above Sidekiq test with the above setup, I get the following error:
Airbrake::Error:
the 'default' notifier isn't configured
But if I change the Airbrake config in spec_helper.rb to:
Airbrake.configure do |c|
c.project_id = ENV['PROJECT_ID']
c.project_key = ENV['PROJECT_KEY']
end
the ENV keys are able to be found in the tests. Why is this?
When you say Airbrake.configure(:test), it does not mean "configure Airbrake for the test RAILS_ENV". Rather :test creates a non-default named notifier. Then you can send specific notifications to that notifier by saying Airbrake.notify("oops", {time: Time.now}, :test). But that is not about development/test/production, it is about categorizing your notifications.
So the problem is that you have configured a notifier named test, but you have not yet configured one named default, and default is what Airbrake wants to use when you don't tell it otherwise. That's why your spec passes when you say simply Airbrake.configure { ... }.

Watir / MiniTest - Undefined local variable or method 'browser'

I have 66 watir scripts that I have been creating over the past week to automate testing on the clients website.
However I have recently found out about a test framework called MiniTest which I am trying to implement now.
The reason I have set the URL as a variable is because there are 5 different sites that these tests need to run on so when they want me to run my pack on a different website I just need to update that 1 variable and not in each individual test.
require 'minitest/autorun'
require "watir-webdriver"
class MPTEST < MiniTest::Unit::TestCase
def setup()
url = "http://thewebsite.com/"
$browser = Watir::Browser.new :chrome
$browser.goto url
end
def test_myTestCase
$browser.link(:text, "Submit your CV").click
sleep(2)
$browser.button(:value,"Submit").click
assert($browser.label.text.includes?("This field is required"))
def teardown
$browser.close
end
end
When running that I receive the following output:
NameError: undefined local variable or method 'browser' for #<MPTEST:0x4cc72f8>c:/directory stuff...
Any ideas?
EDIT I have browser working however now there is an issue with my assert:
New code:
require 'minitest/autorun'
require "watir-webdriver"
class MPTEST < MiniTest::Unit::TestCase
def setup()
url ="http://thewebsite.com"
$browser = Watir::Browser.new :chrome
$browser.goto url
end
def test_myTestCase
$browser.link(:text, "Submit your CV").click
sleep(2)
$browser.button(:value,"Submit").click
assert($browser.label.text.includes?("This field is required"))
end
def teardown
$browser.close
end
end
And the error is:
NoMEthodError: undefined method 'includes?' for "":String
it seems to me you can you use #browser instead of $browser (but the problem might be not in this code)
The exception
NoMEthodError: undefined method 'includes?' for "":String
Is due to strings, in this case the value returned by $browser.label.text do not have an includes? method.
The method you actually want is include? (no plural):
assert($browser.label.text.include?("This field is required"))

What is the best way to mock a 3rd party object in ruby?

I'm writing a test app using the twitter gem and I'd like to write an integration test but I can't figure out how to mock the objects in the Twitter namespace. Here's the function that I want to test:
def build_twitter(omniauth)
Twitter.configure do |config|
config.consumer_key = TWITTER_KEY
config.consumer_secret = TWITTER_SECRET
config.oauth_token = omniauth['credentials']['token']
config.oauth_token_secret = omniauth['credentials']['secret']
end
client = Twitter::Client.new
user = client.current_user
self.name = user.name
end
and here's the rspec test that I'm trying to write:
feature 'testing oauth' do
before(:each) do
#twitter = double("Twitter")
#twitter.stub!(:configure).and_return true
#client = double("Twitter::Client")
#client.stub!(:current_user).and_return(#user)
#user = double("Twitter::User")
#user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
But, I'm getting this error:
1) testing oauth twitter
Failure/Error: login_with_oauth
Twitter::Error::Unauthorized:
GET https://api.twitter.com/1/account/verify_credentials.json: 401: Invalid / expired Token
# ./app/models/user.rb:40:in `build_twitter'
# ./app/models/user.rb:16:in `build_authentication'
# ./app/controllers/authentications_controller.rb:47:in `create'
# ./spec/support/integration_spec_helper.rb:3:in `login_with_oauth'
# ./spec/integration/twit_test.rb:16:in `block (2 levels) in <top (required)>'
The mocks above are using rspec but I'm open to trying mocha too. Any help would be greatly appreciated.
OK, I managed to figure this out thanks to everyone's help. Here's the final test:
feature 'testing oauth' do
before(:each) do
#client = double("Twitter::Client")
#user = double("Twitter::User")
Twitter.stub!(:configure).and_return true
Twitter::Client.stub!(:new).and_return(#client)
#client.stub!(:current_user).and_return(#user)
#user.stub!(:name).and_return("Tester")
end
scenario 'twitter' do
visit root_path
login_with_oauth
page.should have_content("Pages#home")
end
end
The trick was figuring out that I needed to stub :configure and :new on the real objects and stub :current_user and :name on a dobuled object instance.
I think the problem is just the way you are using the mock, you created the mock #twitter, but you never actually use it. I think you may be under the impression that any calls to Twitter will use the stubbed methods you specified, but that's not how it works, only calls made to #twitter are stubbed.
I use double ruby, not rspec mocks, but i believe you want to do something like this instead:
Twitter.stub!(:configure).and_return true
...
Twitter::Client.stub!(:current_user).and_return #user
This ensures that anytime the methods you stubbed on Twitter, Twitter::Client are called, they respond how you want.
Also, it seems strange that this is tested as part of a view, should really be part of a controller test instead unless i'm missing something.
You can try using something like http://jondot.github.com/moxy/ . Mock Web Requests

Resources