I have a feature which works fine in production and in development, but the test I wrote for it doesn't pass. It seems like the data is not persisting, although when I use byebug it shows that it's fine.
Here's my spec:
it "cancels a user plan" do
plan = FactoryBot.create(:plan, name: 'MOMLab', paypal_id: 'MOMLab15')
user = FactoryBot.create(:user, email: 'payer#email.com',
payer_id: '6M5AMEDMVMSNL')
user_plan = FactoryBot.create(:user_plan, user: user, plan: plan, end_date: nil)
ipn = FactoryBot.create(:ipn, :cancelation)
sign_in FactoryBot.create(:user, :admin)
visit ipn_path(ipn)
expect(user_plan.status).to eq('Active')
click_on 'Process'
sleep 10
expect(ipn.reload.complete?).to be_truthy
expect(user_plan.reload.end_date.to_date).to eq(Time.zone.now.to_date)
expect(user_plan.status).to eq('Canceled')
end
Here's the code:
def cancel_subscription
#user = find_user
#user_plan = #plan.user_plans.where(user: #user).active.first
if #user_plan
#user_plan.end_date = Time.zone.now
#user_plan.status = 'Canceled'
#user_plan.save!
if #user_plan.persisted?
#ipn.update(complete: true)
else
handle_errors("User plan didn't save")
end
else
handle_errors("Couldn't find subscription")
end
end
I put the object with inspect during the execution and in the test - in the execution it appears like everything is okay and changes have persisted (it goes into the persisted? tree, but outside in the test it shows as if the object has never been saved.
Any ideas?
Edit:
Here's my rails_helper.rb:
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
require "capybara/rspec"
require 'devise'
Capybara.register_driver :chrome do |app|
Capybara::Selenium::Driver.new(app, browser: :chrome)
end
Capybara.register_driver :headless_chrome do |app|
caps = Selenium::WebDriver::Remote::Capabilities.chrome(loggingPrefs: { browser: 'ALL' })
opts = Selenium::WebDriver::Chrome::Options.new
chrome_args = %w[--headless --no-sandbox --disable-gpu --window-size=1920,1080 --remote-debugging-port=9222]
chrome_args.each { |arg| opts.add_argument(arg) }
Capybara::Selenium::Driver.new(app, browser: :chrome, options: opts, desired_capabilities: caps)
end
Capybara.javascript_driver = :headless_chrome
Capybara.current_driver = :headless_chrome
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.include Devise::Test::IntegrationHelpers, type: :feature
config.include Devise::Test::IntegrationHelpers, type: :request
config.infer_spec_type_from_file_location!
config.include Warden::Test::Helpers
Warden.test_mode!
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
config.filter_rails_from_backtrace!
end
and my spec_helper.rb:
require 'webmock/rspec'
require 'capybara/rspec'
include WebMock::API
require 'etsy'
RSpec.configure do |config|
Capybara.default_max_wait_time = 10
Capybara.register_driver :insecure_selenium do |app|
Capybara::Selenium::Driver.new(
app,
browser: :firefox,
desired_capabilities: { accept_insecure_certs: true }
)
end
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.shared_context_metadata_behavior = :apply_to_host_groups
begin
config.filter_run_when_matching :focus
config.example_status_persistence_file_path = "spec/examples.txt"
config.disable_monkey_patching!
if config.files_to_run.one?
config.default_formatter = "doc"
end=
config.profile_examples = 3
Kernel.srand config.seed
end
end
Related
I can understand this question is quite general, but I'm having an issue that my tests on Heroku are incredibly slow (20+ minutes) vs when I run them locally that takes around 9 or 10 minutes. And I was wondering if I could get pointed in a good direction on what the issue might be. This is my rails_helper.rb:
require 'simplecov'
SimpleCov.start
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'spec_helper'
require 'rspec/rails'
require 'shoulda/matchers'
require 'sidekiq/testing'
Sidekiq::Testing.fake!
require 'public_activity/testing'
PublicActivity.enabled = false
# Checks for pending migrations before tests are run.
ActiveRecord::Migration.maintain_test_schema!
require 'capybara/rspec'
Capybara.asset_host = ENV['CAPYBARA_ASSET_HOST'] || "http://localhost:#{ENV.fetch('PORT', 3000)}"
Capybara.register_driver :headless_chrome do |app|
chrome_bin = ENV.fetch('GOOGLE_CHROME_SHIM', nil)
chrome_opts = chrome_bin ? { 'binary': chrome_bin } : {}
capabilities = Selenium::WebDriver::Remote::Capabilities.chrome chromeOptions: { args: %w[headless disable-gpu disable-dev-shm-usage no-sandbox] }.merge(chrome_opts)
Capybara::Selenium::Driver.new app, browser: :chrome, desired_capabilities: capabilities
end
Capybara.javascript_driver = :headless_chrome
Capybara.server = :puma, { Silent: true }
# NOTE: Running with sauce REQUIRES SAUCE CONNECT tunnel driver
# so that saucelabs instance can communicate with your test server.
# run with...
# bin/sc -u obiefernandez -k 24e2ec72-ff16-4526-9a35-d7e8bd180d5a
#
# require "selenium/webdriver"
# Capybara.register_driver :sauce do |app|
# caps = Selenium::WebDriver::Remote::Capabilities.chrome()
# caps['platform'] = 'macOS 10.12'
# caps['version'] = '52.0'
# sauce_endpoint = "http://obiefernandez:24e2ec72-ff16-4526-9a35-d7e8bd180d5a#ondemand.saucelabs.com:80/wd/hub"
# Capybara::Selenium::Driver.new app, :browser => :remote, :url => sauce_endpoint, :desired_capabilities => caps
# end
# Capybara.javascript_driver = :sauce
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
config.before(:suite) do
# compile front-end and load manifest
`bin/webpack`
Webpacker::Manifest.load
DatabaseCleaner.allow_remote_database_url = true
DatabaseCleaner.strategy = :truncation, { pre_count: true, except: %w(ar_internal_metadata) }
DatabaseCleaner.clean
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
config.backtrace_exclusion_patterns << %r{/rails_helper\.rb:}
module SignInHelpers
extend ActiveSupport::Concern
class_methods do
def managing_project(&block)
if block_given?
let!(:project, &block)
let(:organization) { project.organization }
let(:project_manager) { create(:user, organization: organization, organization_admin: true) }
else
let!(:organization) { create(:organization_with_project_manager) }
let!(:project) { create(:project, organization: organization) }
let(:project_manager) { organization.admins.first }
end
before do
set_current_user(project_manager)
sign_in(project_manager) if respond_to?(:sign_in)
end
end
end
end
config.fixture_path = 'spec/fixtures'
config.include Devise::Test::ControllerHelpers, type: :controller
Devise::Test::ControllerHelpers.module_eval do
alias_method :original_sign_in, :sign_in
def sign_in(resource, deprecated = nil, scope: nil)
original_sign_in(resource, scope: scope)
# needed because devise integration helper bypasses normal ApplicationController logic
set_current_user(resource)
end
end
config.include Devise::Test::IntegrationHelpers, type: :feature
Devise::Test::IntegrationHelpers.module_eval do
alias_method :original_sign_in, :sign_in
def sign_in(resource, scope: nil)
original_sign_in(resource, scope: scope)
# needed because devise integration helper bypasses normal ApplicationController logic
set_current_user(resource)
end
end
config.include SignInHelpers # needed everywhere
# https://github.com/state-machines/state_machines-rspec
config.include StateMachinesRspec::Matchers
module IntegrationHelpers
extend ActiveSupport::Concern
included do
subject { page }
end
def visit(url, *args)
super(polymorphic_path(url), *args)
rescue
super
end
end
config.before(:each) do
Sidekiq::Worker.clear_all
end
config.include IntegrationHelpers, type: :feature
end
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
I'm working on updating a rails 3.2 app to rails 4.2.10, I've got almost everything worked out, unit tests and integration tests passing.
I'm having some issues with feature tests, I'm using capybara 3.3.0 and poltergeist 1.18.1 and it throws me error on visit '/'
I've looked at lots of issues on Stack regarding Attemped to assign to readonly property but none of them apply to my case here,
This is my stripped down spec file
require 'vcr'
Capybara.default_max_wait_time = 10
feature "Create something" do
include SpecHelpers
include Acceptance
before do
setup_database
end
after do
teardown_database
end
scenario "Creating a Consignment", :js => true do
puts "Running with #{Capybara.current_driver}"
VCR.use_cassette('cassette_name.yml') do
page.driver.resize(1000,2200) unless Capybara.current_driver == :selenium
visit '/'
expect(page).to have_content 'EMAIL'
expect(page).to have_content 'PASSWORD'
end
end
end
This is my stripped down spec helper file
ENV["RAILS_ENV"] ||= 'test'
require_relative '../config/environment.rb'
require 'rspec/rails'
require 'capybara/rails'
require 'capybara/poltergeist'
require 'shoulda/matchers'
require 'redis'
require 'redis-namespace'
require 'resque'
require 'mock_redis'
require 'bcrypt'
Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end
# rspec
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods
end
RSpec.configure do |config|
config.deprecation_stream = 'log/deprecations.log'
end
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, :type => :controller
end
RSpec::Expectations.configuration.on_potential_false_positives = :nothing
BCrypt::Engine.cost = 1
if (ENV['DEBUG_CAP'])
Capybara.register_driver :selenium do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
else
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, {js_errors: true})
end
Capybara.javascript_driver = :poltergeist
end
Capybara.server_port = 31337
Capybara.server = :webrick
module SpecHelpers
def setup_database
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start
end
def teardown_database
DatabaseCleaner.clean
end
end
module Acceptance
VCR.configure do |c|
require 'webmock'
c.hook_into :webmock
c.cassette_library_dir = 'fixtures/vcr_cassettes'
c.allow_http_connections_when_no_cassette = true
c.default_cassette_options = {:record => :new_episodes}
c.ignore_request do |request|
URI(request.uri).port == Capybara.server_port || request.uri=~/shutdown/ || request.uri=~/session/
end
end
def wait_until(timeout = Capybara.default_max_wait_time)
require "timeout"
begin
Timeout.timeout(timeout) do
sleep(0.3) until value = yield
value
end
rescue => e
save_screenshot "capybara_#{Time.now.to_i}.png"
puts e.message
puts e.backtrace
raise e
end
end
end
require "rspec/mocks/standalone"
....
This is the error stack trace
Running with poltergeist
Error: Attempted to assign to readonly property.
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:22:3139
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:3551
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:19730
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12707
s#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:20964
g#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12573
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:16265
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:22205
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4884
$digest#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:7801
$apply#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:9410
http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26430
a#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26340
Z#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26051
http://127.0.0.1:31337/lib/bfd57c67.components.js:7:28112
d#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:18351
fireWith#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:19152
ready#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:13970
wt#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:11347
Error: Attempted to assign to readonly property.
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:22:3139
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:3551
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:19730
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12707
s#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:20964
g#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12573
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:16265
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:22205
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4884
$digest#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:7801
$apply#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:9410
http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26430
a#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26340
Z#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26051
http://127.0.0.1:31337/lib/bfd57c67.components.js:7:28112
d#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:18351
fireWith#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:19152
ready#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:13970
wt#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:11347
Error: Attempted to assign to readonly property.
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:22:3139
r#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:3551
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:19730
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12707
s#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:20964
g#http://127.0.0.1:31337/lib/bfd57c67.components.js:5:12573
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:16265
http://127.0.0.1:31337/lib/bfd57c67.components.js:5:22205
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
c#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4206
http://127.0.0.1:31337/lib/bfd57c67.components.js:6:4884
$digest#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:7801
$apply#http://127.0.0.1:31337/lib/bfd57c67.components.js:6:9410
http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26430
a#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26340
Z#http://127.0.0.1:31337/lib/bfd57c67.components.js:4:26051
http://127.0.0.1:31337/lib/bfd57c67.components.js:7:28112
d#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:18351
fireWith#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:19152
ready#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:13970
wt#http://127.0.0.1:31337/lib/bfd57c67.components.js:1:11347
Update 1
Upon some debugging, it turns out that error gets thrown from angularjs-bootstrap-datetimepicker package when it tries to set $render to a function,
var ngModelController = $element.controller('ngModel')
var configuration = createConfiguration()
$scope.screenReader = configuration.screenReader
// Behavior
$scope.changeView = changeView
ngModelController.$render = $render --> in this line
I have a very basic RSpec/Capybara Rails test written down but i keep on getting that expect method is undefined
my spec/features/signin_spec.rb:
require "rails_helper"
RSpec.feature "the signin process", :type => :feature do
before :each do
User.create(:email => "user#example.com", :password => "password")
end
scenario "signs me in" do
visit "/users/sign_in"
within("#new_user") do
fill_in "Email", :with => "user#example.com"
fill_in "Password", :with => "password"
end
click_button "Log in"
expect(page).to have_content "successfully"
end
end
rails_helper:
This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.infer_spec_type_from_file_location!
end
spec_helper:
require 'capybara/rspec'
RSpec.configure do |config|
config.include Capybara::DSL
config.expect_with(:rspec) { |c| c.syntax = :should }
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
=begin
config.filter_run :focus
config.run_all_when_everything_filtered = true
config.disable_monkey_patching!
if config.files_to_run.one?
config.default_formatter = 'doc'
end
config.profile_examples = 10
config.order = :random
Kernel.srand config.seed
=end
end
Adding :expect to this in spec_helper removed the error
config.expect_with :rspec do |c|
c.syntax = [:should, :expect]
end
https://www.relishapp.com/rspec/rspec-expectations/docs/syntax-configuration#disable-expect-syntax
Thank you for your help #apneadiving and Frederick
Just replace
expectations.syntax = :should
with
expectations.syntax = [:should , :expect]
in your spec_helper.rb
just replace
expectations.syntax = :should
with
expectations.syntax = [:should , :expect]
In your spec_helper.rb
I have the tests that looks like the following:
require "rails_helper"
feature "Ordering units management" do
scenario "Creating new ordering unit" do
visit new_ordering_units_path
fill_in I18n.t('activerecord.attributes.ordering_unit.name'), with: "Ordering unit name"
click_button I18n.t('submit')
expect(page).to have_text(I18n.t('ordering_units.created'))
expect(page).to have_content("Ordering unit name")
end
end
When I run it I have the following error message:
undefined local variable or method `new_ordering_units_path' for #<RSpec::ExampleGroups::OrderingUnitsManagement:0x00000004962810>
My spec_helper:
RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
config.filter_run :focus
config.run_all_when_everything_filtered = true
if config.files_to_run.one?
config.default_formatter = 'doc'
end
config.profile_examples = 10
config.order = :random
Kernel.srand config.seed do
end
end
My rails helper:
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'capybara'
require 'rspec/rails'
require 'capybara/rspec'
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include Capybara::DSL
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.infer_spec_type_from_file_location!
end
I can't find solution for this. Could anyone tell me why this ain't working?
It should be called new_ordering_unit_path (singular). Type rake routes in your console to see all routes in effect.
Objects are persisting after tests run. I confirmed by doing a PowerUp.all.count test and the count increases by 2 on each run, which a number equal to the objects created for the test on each run. I don't know if I'm misusing FactoryGirl, or if I have a misconfigured spec_helper.
spec/support/factory_girl.rb:
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
spec/rails_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
ActiveRecord::Migration.maintain_test_schema!
RSpec.configure do |config|
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = false
config.infer_base_class_for_anonymous_controllers = false
config.infer_spec_type_from_file_location!
end
spec/spec_helper.rb:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'factory_girl'
RSpec.configure do |config|
config.order = :random
config.before(:all) do
FactoryGirl.reload
end
Kernel.srand config.seed
config.expect_with :rspec do |expectations|
expectations.syntax = :expect
end
config.mock_with :rspec do |mocks|
mocks.syntax = :expect
mocks.verify_partial_doubles = true
end
end
spec/api/power_up_spec.rb:
describe Api::PowerUpsController, :type => :controller do
describe "GET power_ups" do
it "returns all power-ups" do
FactoryGirl.create :power_up, name: "Increase rate of take", description: "You gain points more quickly"
FactoryGirl.create :power_up, name: "Decrease rate of give", description: "You lose points more slowly"
get :index, :format => :json
expect(response.status).to eq 200
body = JSON.parse(response.body)
power_up_names = body.map { |m| m["name"] }
expect(power_up_names).to match_array(["Increase rate of take",
"Decrease rate of give"])
end
end
end
config.use_transactional_fixtures = false
This turns off the default behavior, which is to rollback transactions after each example. When set to false RSpec does not attempt to manage the test database.
You can use database_cleaner to remove the rows created by tests when RSpec is not using transactions. This is often used when writing feature specs.