Im following a tutorial on Rails 4 and Multitenancy, but am getting an error when trying to test if a user can sign in as an owner and redirect to a created subdomain.
This is the test error:
Failures:
1) User sign in signs in as an account owner successfully
Failure/Error: visit root_url
URI::InvalidURIError:
bad URI(is not URI?): http://#{account.subdomain}.example.com
# /Users/developer/.rvm/gems/ruby-2.3.1/gems/capybara-2.10.1/lib/capybara/rack_test/browser.rb:71:in `reset_host!'
# /Users/developer/.rvm/gems/ruby-2.3.1/gems/capybara-2.10.1/lib/capybara/rack_test/browser.rb:21:in `visit'
# /Users/developer/.rvm/gems/ruby-2.3.1/gems/capybara-2.10.1/lib/capybara/rack_test/driver.rb:43:in `visit'
# /Users/developer/.rvm/gems/ruby-2.3.1/gems/capybara-2.10.1/lib/capybara/session.rb:240:in `visit'
# /Users/developer/.rvm/gems/ruby-2.3.1/gems/capybara-2.10.1/lib/capybara/dsl.rb:52:in `block (2 levels) in <module:DSL>'
# ./spec/features/users/sign_in_spec.rb:9:in `block (3 levels) in <top (required)>'
Finished in 0.56981 seconds (files took 1.26 seconds to load)
11 examples, 1 failure, 6 pending
This is the test:
require "rails_helper"
feature "User sign in" do
extend SubdomainHelpers
let!(:account) { FactoryGirl.create(:account) }
let(:sign_in_url) {"http://#{account.subdomain}.example.com/sign_in"}
let(:root_url) {"http://#{account.subdomain}.example.com/"}
within_account_subdomain do
scenario "signs in as an account owner successfully" do
visit root_url
expect(page.current_url).to eq(sign_in_url)
fill_in "Email", :with => account.owner.email
fill_in "Password", :with => "password"
click_button "Sign in"
expect(page).to have_content("You are now signed in.")
expect(page.current_url).to eq(root_url)
end
end
end
Here are the factories:
Account:
FactoryGirl.define do
factory :account, :class => Subscribe::Account do
sequence(:name) { |n| "Test Account ##{n}" }
sequence(:subdomain) { |n| "test#{n}" }
association :owner, :factory => :user
end
end
User:
FactoryGirl.define do
factory :user, :class => Subscribe::User do
sequence(:email) { |n| "test#{n}#example.com" }
password "password"
password_confirmation "password"
end
end
I am really not familiar with BDD, please let me know if you need me to post anything further.
So I solved this:
The problem was in my SubdomainHelpers file
module SubdomainHelpers
def within_account_subdomain
### This Line Is the original line
let(:subdomain_url) { 'http://#{account.subdomain}.example.com' }
### Changed it to this
let(:subdomain_url) { "http://#{account.subdomain}.example.com" }
before { Capybara.default_host = subdomain_url }
after { Capybara.default_host = 'http://www.example.com' }
yield
end
end
For some reason using single quotes was keeping account.subdomain as a string; as soon as I changed to double quotes the test passed!
Thanks.
Related
I'm using latest version of Solidus e-commerce (fork of Spree) and I'm having this issue. To describe it quickly:
In Admin I create Spree::Membership record
after_save callback in Spree::Membership creates Product and 2 variants
This code works when I run the server, but when I'm trying to use Rspec it gives me this error:
Failure/Error: reload.product.setup_membership_variants
NoMethodError:
undefined method `setup_membership_variants' for nil:NilClass
# ./app/models/spree/membership.rb:26:in `block in setup_product'
# ./app/models/spree/membership.rb:18:in `setup_product'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/configuration.rb:18:in `block in initialize'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/evaluation.rb:15:in `create'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:12:in `block in result'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:9:in `tap'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy/create.rb:9:in `result'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/factory.rb:42:in `run'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/factory_runner.rb:29:in `block in run'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/factory_runner.rb:28:in `run'
# /box/gems/factory_girl-4.8.0/lib/factory_girl/strategy_syntax_method_registrar.rb:20:in `block in define_singular_strategy_method'
# ./spec/controllers/spree/premium_controller_spec.rb:4:in `block (2 levels) in <top (required)>'
# ./spec/controllers/spree/premium_controller_spec.rb:33:in `block (6 levels) in <top (required)>'
# ./spec/controllers/spree/premium_controller_spec.rb:53:in `block (8 levels) in <top (required)>'
# ./spec/controllers/spree/premium_controller_spec.rb:53:in `block (7 levels) in <top (required)>'
Here is code I'm using:
membership.rb
class Spree::Membership < Spree::Base
has_many :active_memberships, class_name: 'Spree::ActiveMembership', dependent: :destroy
has_one :membership_product, class_name: "Spree::MembershipProduct", dependent: :destroy
has_one :product, through: :membership_product, source: :product
validates :name, presence: true
validates :monthly_quota, presence: true
validates :price, presence: true
after_save :setup_product
private
def setup_product
if product.nil?
ActiveRecord::Base.transaction do
create_membership_product(
product: Spree::Product.create(
name: name,
price: price,
shipping_category: Spree::ShippingCategory.find_by(name: "Default")
)
)
reload.product.setup_membership_variants
end
else
product.update(name: name, price: price)
end
end
end
product_decorator.rb
Spree::Product.class_eval do
def setup_membership_variants
ot = Spree::OptionType.find_or_create_by(name: "Membership")
option_types << ot
if ot.option_values.empty?
["Monthly", "Yearly"].each do |freq|
ot.option_values.create(name: freq, presentation: freq)
end
end
month = variants.create(is_master: false, price: price, track_inventory: false)
month.option_values << Spree::OptionValue.find_by(name: "Monthly")
year = variants.create(is_master: false, price: price * 12, track_inventory: false)
year.option_values << Spree::OptionValue.find_by(name: "Yearly")
end
end
membership.rb factory
FactoryGirl.define do
factory :membership, class: Spree::Membership do
name {FFaker::Lorem.word}
monthly_quota { rand(10..200) }
price { rand(10..200) }
trait :unnamed do
name nil
end
trait :without_quota do
monthly_quota nil
end
trait :priceless do
price nil
end
end
end
example of controller test
require 'rails_helper'
RSpec.describe Spree::PremiumController, type: :controller do
let(:valid_membership) { create(:membership) }
let(:variant) { create(:master_variant) }
context "#show" do
it "returns http success" do
get :show
expect(response).to have_http_status(:success)
end
it "returns all memberships" do
get :show
expect(assigns[:memberships]).to include(valid_membership)
end
end
context "#create" do
let!(:store) { create(:store) }
context "user not logged" do
context "valid attributes" do
context "user doesn't exist in database" do
subject do
post(:create, params: {
premium: {
first_name: "Ondrej",
last_name: "Kubala",
email: "ondrej#bala.com",
password: "test123",
password_confirmation: "test123",
membership_id: valid_membership.id,
payment_frequency: "1", #monthly yearly is 2
cc_number: "4111111111111111",
cc_exp_date: "10/22",
cvv: "123"
}
})
end
it "creates user with valid attributes" do
expect { subject }.to change { Spree::User.count }.from(0).to(1)
end
it "logs in user" do
expect(controller.warden).to receive(:set_user)
subject
end
context "create order with variant" do
it "should handle population" do
expect { subject }.to change { Spree::Order.count }.by(1)
user = Spree::User.find_by email: "ondrej#bala.com"
order = user.orders.last
expect(response).to redirect_to go_premium_path
expect(order.line_items.size).to eq(1)
# line_item = order.line_items.first
# expect(line_item.variant_id).to eq(valid_membership.reload.product.variants.)
end
it "charges credit card"
it "should redirect to account page"
end
end
context "user already exists"
end
context "wrong user attributes" do
end
context "wrong payment attributes" do
end
end
context "user is logged in" do
let(:user) { create(:user) }
before do
allow(controller).to receive_messages try_spree_current_user: user
allow(controller).to receive_messages spree_current_user: user
end
it "doesn't create user"
end
end
end
I don't have too much experience in Rspec, but it's weird that it works when server is running in development but in test it gives me that error.
Any idea what is wrong?
My guess would be that product creation call fails for some reason.
Try bang version(product: Spree::Product.create!) to have the error thrown when it occurs.
If product indeed gets created, use pry or byebug to figure out why after reload membership, product is not associated with membership.
I'm having problems with FactoryGirl, I'm using sequence to avoid duplicating fields, but validations are failing anyway.
Output:
1) CustomersController anonymous user GET #edit is redirected to signin when accessing edit form
Failure/Error: get :edit, id: create(:customer)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken, Email has already been taken
# ./spec/controllers/customers_controller_spec.rb:25:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
3) Customer public class methods executes its methods correctly #find_by_id_or_name finds customer by name
Failure/Error: let(:john) {create(:customer, name: 'John Doe X')}
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken, Email has already been taken
# ./spec/models/customer_spec.rb:25:in `block (3 levels) in <top (required)>'
# ./spec/models/customer_spec.rb:38:in `block (5 levels) in <top (required)>'
# -e:1:in `<main>'
Factories:
FactoryGirl.define do
factory :customer do
user
name {Faker::Name.name}
sequence(:mail) { |n| "person#{n}#example.com" }
address {Faker::Address.street_address}
phone {Faker::PhoneNumber.phone_number}
end
end
FactoryGirl.define do
factory :user do
sequence(:email) {|i| "example#{i}#example.com"}
password {Faker::Internet.password(10)}
end
end
These are the tests that are failing:
RSpec.describe Customer, type: :model do
describe "public class methods" do
let(:john) {create(:customer, name: 'John Doe X')}
let(:frank) {create(:customer)}
context "responds to its methods" do
it "responds to #find_by_id_or_name" do
expect(Customer).to respond_to(:find_by_id_or_name)
end
end
context "executes its methods correctly" do
context "#find_by_id_or_name" do
it "finds customer by name" do
customer = Customer.find_by_id_or_name('John Doe X')
expect(customer).to eq john
end
it "finds customer by id" do
customer = Customer.find_by_id_or_name(frank.id)
expect(customer).to eq frank
end
end
end
end
end
RSpec.describe CustomersController, type: :controller do
context "signed in user" do
before :each do
#user = create(:user)
end
describe "GET #edit" do
it "renders :edit view" do
get :edit, id: create(:customer).id
expect(response).to render_template(:edit)
end
end
describe "DELETE #destroy" do
before :each do
#customer = create(:customer, user: #user)
end
it "deletes record" do
expect {delete :destroy, id: #customer.id}.to change(Customer, :count).by(-1)
end
end
end
end
This is happening to me all over my app. I just copied some tests that apply to Customer.
Thanks
My problem was related to not appropiately configuring database_cleaner. The configuration in this post solves the problem: How can I clean my database between erroneous rspec specs?
I have two Factory Girl objects on a single file.
spec/factories/users.rb
FactoryGirl.define do
factory :user do
first_name "Charlie"
last_name "Brown"
email "email#example.com"
password "charbar1234"
password_confirmation "charbar1234"
end
factory :admin do
first_name "Bob"
last_name "Marley"
email "bob#marley.com"
password "bobmarley1234"
password_confirmation "bobmarley1234"
admin true
end
end
When I call create(:user), my test runs fine. When I call create(:admin), I get the following error...
Failures:
1) admin accesses the database
Failure/Error: create(:admin)
NameError:
uninitialized constant Admin
# ./spec/features/admins/admin_spec.rb:5:in `block (2 levels) in <top (required)>'
Here is the test..
spec/features/admins/admin_spec.rb
require "rails_helper"
describe "admin" do
it 'accesses the database' do
create(:admin)
visit root_path
click_link "Log In"
fill_in "Email", with: "bob#marley.com"
fill_in "Password", with: "bobmarley1234"
click_button "Log In"
expect(current_path).to eq(admin_dashboard_path)
with 'h1' do
expect(page).to have_content 'Administration'
end
expect(page).to have_content 'Manage Users'
expect(page).to have_content 'Manage Articles'
end
end
You need to put the factory :admin inside of the factory :user.
It should look something like this:
FactoryGirl.define do
factory :user do
...
factory :admin do
admin true
end
end
end
See Factorygirl Admin Creation
I'm using rails 3.2 with devise and rspec with factory girl. I'm trying to log a user in but it seems there is a problem creating the user in the first place.
user factory:
factory :user do
first_name "Test"
last_name "User"
sequence(:email) { |n| "foo#{n}#test.com" }
password "secretpassword"
confirmed_at Time.now
end
my spec
feature "BackOffice" do
subject { page }
context "as user" do
let(:user) { create(:user) }
describe "should not have access to backoffice" do
before do
visit "http://domain_name/fr/users/sign_in"
within ".login-wrapper" do
fill_in "user_email", with: user.email
fill_in "user_password", with: user.password
click_button "S'identifier"
end
end
it { should have_content "Bienvenue"}
end
end
Error
Failure/Error: let(:user) { create(:user) }
ActionView::Template::Error:
No route matches {:action=>"edit", :controller=>"users/registrations"}
# ./app/views/user_mailer/welcome.html.erb:3:in `_app_views_user_mailer_welcome_html_erb__212088972377821759_70301344598820'
# ./app/mailers/user_mailer.rb:31:in `welcome'
# ./app/models/user.rb:125:in `send_welcome_email'
# ./spec/requests/backoffice_spec.rb:15:in `block (3 levels) in <top (required)>'
# ./spec/requests/backoffice_spec.rb:20:in `block (5 levels) in <top (required)>'
# ./spec/requests/backoffice_spec.rb:19:in `block (4 levels) in <top (required)>'
# ./spec/support/database_cleaner.rb:17:in `block (2 levels) in <top (required)>'
why would it be trying to go to the edit action when it should be creating the resource?
There was a problem with a link in a welcome email I added the following to fix it:
config.action_mailer.default_url_options = { protocol: "http", host: "localhost", port: 3000, locale: I18n.locale }
I'm following Michael Hartl's great book on Ruby on Rails(rails 3.2 version). I'm having some problems in section 9.3.3. Pagination.
After I modified my factory at spec/factories.rb using sequence like this(note that I have the previous version commented out):
FactoryGirl.define do
#factory :user do
# name "Michael Hartl"
# email "michael#example.com"
# password "foobar"
# password_confirmation "foobar"
#end
factory :user do
sequence(:user){ |n| "Person #{n}" }
sequence(:email){ |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
end
end
I cannot use this anymore in my tests:
let(:user){ FactoryGirl.create(:user) }
For instance the test with code:
require 'spec_helper'
describe "User pages" do
subject { page }
describe "index" do
let(:user){ FactoryGirl.create(:user) }
before(:all){ 30.times {FactoryGirl.create(:user) }}
after(:all) {User.delete_all}
before(:each) do
valid_signin user
visit users_path
end
it { should have_selector('title', text: 'All users') }
it { should have_selector('h1', text: 'All users') }
.
.
.
end
Returns errors such as:
Failure/Error: before(:all){ 30.times {FactoryGirl.create(:user) }}
NoMethodError:
undefined method `user=' for #<User:0x00000002760140>
# ./spec/requests/user_pages_spec.rb:16:in `block (4 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:16:in `times'
# ./spec/requests/user_pages_spec.rb:16:in `block (3 levels) in <top (required)>'
It somehow makes sense that I can't use this syntax (let(:user){...}) anymore, since I'm now creating sequences of elements, but I can't seem to find a fix for this.
Any ideas? thanks!
I think you mean sequence(:name) instead of sequence(:user) in your factory. It's looking for a method user= in your User model instead of the name= method.