From 969f18286ea9e11686aa87a51e1bb3e06d5de287 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 16:33:02 +0800 Subject: [PATCH 01/35] [BREAKS BUILD] Copy feature specs from solidus_auth_devise solidus_auth_devise commit version was c03ca9a2a9eb1fa6e4421aff7b483c502f7151e0. --- spec/features/account_spec.rb | 59 ++++++++ spec/features/admin/password_reset_spec.rb | 80 +++++++++++ spec/features/admin/products_spec.rb | 10 ++ spec/features/admin/sign_in_spec.rb | 45 ++++++ spec/features/admin/sign_out_spec.rb | 23 +++ spec/features/admin_permissions_spec.rb | 47 ++++++ spec/features/change_email_spec.rb | 27 ++++ spec/features/checkout_spec.rb | 158 +++++++++++++++++++++ spec/features/confirmation_spec.rb | 28 ++++ spec/features/order_spec.rb | 63 ++++++++ spec/features/password_reset_spec.rb | 37 +++++ spec/features/sign_in_spec.rb | 53 +++++++ spec/features/sign_out_spec.rb | 26 ++++ spec/features/sign_up_spec.rb | 31 ++++ 14 files changed, 687 insertions(+) create mode 100644 spec/features/account_spec.rb create mode 100644 spec/features/admin/password_reset_spec.rb create mode 100644 spec/features/admin/products_spec.rb create mode 100644 spec/features/admin/sign_in_spec.rb create mode 100644 spec/features/admin/sign_out_spec.rb create mode 100644 spec/features/admin_permissions_spec.rb create mode 100644 spec/features/change_email_spec.rb create mode 100644 spec/features/checkout_spec.rb create mode 100644 spec/features/confirmation_spec.rb create mode 100644 spec/features/order_spec.rb create mode 100644 spec/features/password_reset_spec.rb create mode 100644 spec/features/sign_in_spec.rb create mode 100644 spec/features/sign_out_spec.rb create mode 100644 spec/features/sign_up_spec.rb diff --git a/spec/features/account_spec.rb b/spec/features/account_spec.rb new file mode 100644 index 00000000..a517d1cb --- /dev/null +++ b/spec/features/account_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +RSpec.feature 'Accounts', type: :feature do + context 'editing' do + scenario 'can edit an admin user' do + user = create(:admin_user, email: 'admin@person.com', password: 'password', password_confirmation: 'password') + visit spree.login_path + + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + click_button 'Login' + + click_link 'My Account' + expect(page).to have_text 'admin@person.com' + end + + scenario 'can edit a new user' do + stub_spree_preferences(Spree::Auth::Config, signout_after_password_change: false) + visit spree.signup_path + + fill_in 'Email', with: 'email@person.com' + fill_in 'Password', with: 'password' + fill_in 'Password Confirmation', with: 'password' + click_button 'Create' + + click_link 'My Account' + expect(page).to have_text 'email@person.com' + click_link 'Edit' + + fill_in 'Password', with: 'foobar' + fill_in 'Password Confirmation', with: 'foobar' + click_button 'Update' + + expect(page).to have_text 'email@person.com' + expect(page).to have_text 'Account updated' + end + + scenario 'can edit an existing user account' do + stub_spree_preferences(Spree::Auth::Config ,signout_after_password_change: false) + user = create(:user, email: 'email@person.com', password: 'secret', password_confirmation: 'secret') + visit spree.login_path + + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + click_button 'Login' + + click_link 'My Account' + expect(page).to have_text 'email@person.com' + click_link 'Edit' + + fill_in 'Password', with: 'foobar' + fill_in 'Password Confirmation', with: 'foobar' + click_button 'Update' + + expect(page).to have_text 'email@person.com' + expect(page).to have_text 'Account updated' + end + end +end diff --git a/spec/features/admin/password_reset_spec.rb b/spec/features/admin/password_reset_spec.rb new file mode 100644 index 00000000..4d44408f --- /dev/null +++ b/spec/features/admin/password_reset_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +RSpec.feature 'Admin - Reset Password', type: :feature do + let!(:store) { create(:store) } + + background do + ActionMailer::Base.default_url_options[:host] = 'http://example.com' + end + + context 'when an account with this email address exists' do + let!(:user) { create(:user, email: 'foobar@example.com', password: 'secret', password_confirmation: 'secret') } + + scenario 'allows a user to supply an email for the password reset' do + visit spree.admin_login_path + click_link 'Forgot Password?' + fill_in_email + click_button 'Reset my password' + expect(page).to have_text 'you will receive an email with instructions' + end + end + + # Revealing that an admin email address is not found allows an attacker to + # find admin account email addresses by trying email addresses until this + # error is not shown. + scenario 'does not reveal email addresses if they are not found' do + visit spree.admin_login_path + click_link 'Forgot Password?' + fill_in_email + click_button 'Reset my password' + expect(page).to_not have_text "Email not found" + expect(page).to have_text 'you will receive an email with instructions' + end + + def fill_in_email + fill_in 'Email', with: 'foobar@example.com' + end + + context 'password management' do + let!(:admin) do + create(:admin_user, + email: 'admin@example.com', + password: 'secret', + password_confirmation: 'secret' + ) + end + + let!(:user) do + create(:user, + email: 'user@example.com', + password: 'test123', + password_confirmation: 'test123' + ) + end + + before do + visit spree.admin_login_path + fill_in 'Email', with: admin.email + fill_in 'Password', with: admin.password + click_button 'Login' + visit spree.admin_users_path + end + + context 'if currently logged-in admin' do + context "clicks on an user's page" do + it 'can reset its password' do + within("#spree_user_#{user.id}") do + click_link user.email + end + + click_button 'Reset password' + expect(page).to have_content( + 'If an account with that email address exists, '\ + 'you will receive an email with instructions about '\ + 'how to reset your password in a few minutes.' + ) + end + end + end + end +end diff --git a/spec/features/admin/products_spec.rb b/spec/features/admin/products_spec.rb new file mode 100644 index 00000000..1daeb3e8 --- /dev/null +++ b/spec/features/admin/products_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +RSpec.feature 'Admin products', type: :feature do + context 'as anonymous user' do + # Regression test for #1250 + scenario 'redirects to login page when attempting to access product listing' do + expect { visit spree.admin_products_path }.not_to raise_error + end + end +end diff --git a/spec/features/admin/sign_in_spec.rb b/spec/features/admin/sign_in_spec.rb new file mode 100644 index 00000000..25840f1c --- /dev/null +++ b/spec/features/admin/sign_in_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +RSpec.feature 'Admin - Sign In', type: :feature do + background do + @user = create(:user, email: 'email@person.com') + visit spree.admin_login_path + end + + scenario 'asks user to sign in' do + visit spree.admin_path + expect(page).not_to have_text 'Authorization Failure' + end + + scenario 'lets a user sign in successfully' do + fill_in 'Email', with: @user.email + fill_in 'Password', with: 'secret' + click_button 'Login' + + expect(page).to have_text 'Logged in successfully' + expect(page).not_to have_text 'Login' + expect(page).to have_text 'Logout' + expect(current_path).to eq '/' + end + + scenario 'shows validation erros' do + fill_in 'Email', with: @user.email + fill_in 'Password', with: 'wrong_password' + click_button 'Login' + + expect(page).to have_text 'Invalid email or password' + expect(page).to have_text 'Login' + end + + scenario 'allows a user to access a restricted page after logging in' do + user = create(:admin_user, email: 'admin@person.com') + visit spree.admin_path + + fill_in 'Email', with: user.email + fill_in 'Password', with: 'secret' + click_button 'Login' + + expect(page).to have_text 'admin@person.com' + expect(current_path).to eq '/admin/orders' + end +end diff --git a/spec/features/admin/sign_out_spec.rb b/spec/features/admin/sign_out_spec.rb new file mode 100644 index 00000000..420ad145 --- /dev/null +++ b/spec/features/admin/sign_out_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +RSpec.feature 'Admin - Sign Out', type: :feature, js: true do + given!(:user) do + create :user, email: 'email@person.com' + end + + background do + visit spree.admin_login_path + fill_in 'Email', with: user.email + fill_in 'Password', with: 'secret' + # Regression test for #1257 + check 'Remember me' + click_button 'Login' + end + + scenario 'allows a signed in user to logout' do + click_link 'Logout' + visit spree.admin_login_path + expect(page).to have_text 'Login' + expect(page).not_to have_text 'Logout' + end +end diff --git a/spec/features/admin_permissions_spec.rb b/spec/features/admin_permissions_spec.rb new file mode 100644 index 00000000..2306d387 --- /dev/null +++ b/spec/features/admin_permissions_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +RSpec.feature 'Admin Permissions', type: :feature do + context 'orders' do + background do + user = create(:admin_user, email: 'admin@person.com', password: 'password', password_confirmation: 'password') + Spree::Ability.register_ability(AbilityDecorator) + visit spree.login_path + + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + click_button 'Login' + end + + context 'admin is restricted from accessing orders' do + scenario 'can not list orders' do + visit spree.admin_orders_path + expect(page).to have_text 'Authorization Failure' + end + + scenario 'can not edit orders' do + create(:order, number: 'R123') + visit spree.edit_admin_order_path('R123') + expect(page).to have_text 'Authorization Failure' + end + + scenario 'can not new orders' do + visit spree.new_admin_order_path + expect(page).to have_text 'Authorization Failure' + end + end + + context "admin is restricted from accessing an order's customer details" do + given(:order) { create(:order_with_totals) } + + scenario 'can not list customer details for an order' do + visit spree.admin_order_customer_path(order) + expect(page).to have_text 'Authorization Failure' + end + + scenario "can not edit an order's customer details" do + visit spree.edit_admin_order_customer_path(order) + expect(page).to have_text 'Authorization Failure' + end + end + end +end diff --git a/spec/features/change_email_spec.rb b/spec/features/change_email_spec.rb new file mode 100644 index 00000000..c04ee5db --- /dev/null +++ b/spec/features/change_email_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +RSpec.feature 'Change email', type: :feature do + background do + stub_spree_preferences(Spree::Auth::Config, signout_after_password_change: false) + + user = create(:user) + visit spree.root_path + click_link 'Login' + + fill_in 'spree_user[email]', with: user.email + fill_in 'spree_user[password]', with: 'secret' + click_button 'Login' + + visit spree.edit_account_path + end + + scenario 'work with correct password' do + fill_in 'user_email', with: 'tests@example.com' + fill_in 'user_password', with: 'password' + fill_in 'user_password_confirmation', with: 'password' + click_button 'Update' + + expect(page).to have_text 'Account updated' + expect(page).to have_text 'tests@example.com' + end +end diff --git a/spec/features/checkout_spec.rb b/spec/features/checkout_spec.rb new file mode 100644 index 00000000..3221aaae --- /dev/null +++ b/spec/features/checkout_spec.rb @@ -0,0 +1,158 @@ +# frozen_string_literal: true + +RSpec.feature 'Checkout', :js, type: :feature do + given!(:store) { create(:store) } + given!(:country) { create(:country, name: 'United States', states_required: true) } + given!(:state) { create(:state, name: 'Maryland', country: country) } + given!(:shipping_method) do + shipping_method = create(:shipping_method) + calculator = Spree::Calculator::Shipping::PerItem.create!(calculable: shipping_method, preferred_amount: 10) + shipping_method.calculator = calculator + shipping_method.tap(&:save) + end + + given!(:zone) { create(:zone) } + given!(:address) { create(:address, state: state, country: country) } + given!(:payment_method){ create :check_payment_method } + + background do + @product = create(:product, name: 'RoR Mug') + @product.master.stock_items.first.set_count_on_hand(1) + + # Bypass gateway error on checkout | ..or stub a gateway + stub_spree_preferences(allow_checkout_on_gateway_error: true) + + visit spree.root_path + end + + # Regression test for https://github.com/solidusio/solidus/issues/1588 + scenario 'leaving and returning to address step' do + stub_spree_preferences(Spree::Auth::Config, registration_step: true) + click_link 'RoR Mug' + click_button 'Add To Cart' + within('h1') { expect(page).to have_text 'Shopping Cart' } + click_button 'Checkout' + + within '#guest_checkout' do + fill_in 'Email', with: 'test@example.com' + end + click_on 'Continue' + + click_on 'Cart' + + click_on 'Checkout' + + expect(page).to have_content "Billing Address" + end + + context 'without payment being required' do + scenario 'allow a visitor to checkout as guest, without registration' do + click_link 'RoR Mug' + click_button 'Add To Cart' + within('h1') { expect(page).to have_text 'Shopping Cart' } + click_button 'Checkout' + + expect(page).to have_content(/Checkout as a Guest/i) + + within('#guest_checkout') { fill_in 'Email', with: 'spree@test.com' } + click_button 'Continue' + + expect(page).to have_text(/Billing Address/i) + expect(page).to have_text(/Shipping Address/i) + + fill_addresses_fields_with(address) + click_button 'Save and Continue' + + click_button 'Save and Continue' + click_button 'Save and Continue' + click_button 'Place Order' + + expect(page).to have_text 'Your order has been processed successfully' + end + + scenario 'associate an uncompleted guest order with user after logging in' do + user = create(:user, email: 'email@person.com', password: 'password', password_confirmation: 'password') + click_link 'RoR Mug' + click_button 'Add To Cart' + + visit spree.login_path + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + click_button 'Login' + click_link 'Cart' + + expect(page).to have_text 'RoR Mug' + within('h1') { expect(page).to have_text 'Shopping Cart' } + + click_button 'Checkout' + + fill_addresses_fields_with(address) + click_button 'Save and Continue' + + click_button 'Save and Continue' + click_button 'Save and Continue' + click_button 'Place Order' + + expect(page).to have_text 'Your order has been processed successfully' + expect(Spree::Order.first.user).to eq user + end + + # Regression test for #890 + scenario 'associate an incomplete guest order with user after successful password reset' do + create(:user, email: 'email@person.com', password: 'password', password_confirmation: 'password') + click_link 'RoR Mug' + click_button 'Add To Cart' + + visit spree.login_path + click_link 'Forgot Password?' + fill_in 'spree_user_email', with: 'email@person.com' + click_button 'Reset my password' + + # Need to do this now because the token stored in the DB is the encrypted version + # The 'plain-text' version is sent in the email and there's one way to get that! + reset_password_email = ActionMailer::Base.deliveries.first + token_url_regex = /\/user\/spree_user\/password\/edit\?reset_password_token=(.*)$/ + token = token_url_regex.match(reset_password_email.body.to_s)[1] + + visit spree.edit_spree_user_password_path(reset_password_token: token) + fill_in 'Password', with: 'password' + fill_in 'Password Confirmation', with: 'password' + click_button 'Update' + + click_link 'Cart' + click_button 'Checkout' + + fill_addresses_fields_with(address) + click_button 'Save and Continue' + + expect(page).not_to have_text 'Email is invalid' + end + + scenario 'allow a user to register during checkout' do + click_link 'RoR Mug' + click_button 'Add To Cart' + click_button 'Checkout' + + expect(page).to have_text 'Registration' + + click_link 'Create a new account' + + fill_in 'Email', with: 'email@person.com' + fill_in 'Password', with: 'spree123' + fill_in 'Password Confirmation', with: 'spree123' + click_button 'Create' + + expect(page).to have_text 'You have signed up successfully.' + + fill_addresses_fields_with(address) + click_button 'Save and Continue' + + click_button 'Save and Continue' + click_button 'Save and Continue' + click_button 'Place Order' + + expect(page).to have_text 'Your order has been processed successfully' + expect(Spree::Order.first.user).to eq Spree::User.find_by(email: 'email@person.com') + end + end +end diff --git a/spec/features/confirmation_spec.rb b/spec/features/confirmation_spec.rb new file mode 100644 index 00000000..f50df67c --- /dev/null +++ b/spec/features/confirmation_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.feature 'Confirmation' do + before do + allow(Spree::UserMailer).to receive(:confirmation_instructions) + .and_return(double(deliver: true)) + end + + let!(:store) { create(:store) } + + background do + ActionMailer::Base.default_url_options[:host] = 'http://example.com' + end + + scenario 'create a new user', js: true, confirmable: false do + visit spree.signup_path + + fill_in 'Email', with: 'email@person.com' + fill_in 'Password', with: 'password' + fill_in 'Password Confirmation', with: 'password' + click_button 'Create' + + expect(page).to have_text 'You have signed up successfully.' + expect(Spree::User.last.confirmed?).to be(false) + end +end diff --git a/spec/features/order_spec.rb b/spec/features/order_spec.rb new file mode 100644 index 00000000..5b45e758 --- /dev/null +++ b/spec/features/order_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +RSpec.feature 'Orders', :js, type: :feature do + scenario 'allow a user to view their cart at any time' do + visit spree.cart_path + expect(page).to have_text 'Your cart is empty' + end + + # regression test for spree/spree#1687 + scenario 'merge incomplete orders from different sessions' do + skip %{ + TODO: has been broken for ~2 months as of: + https://github.com/spree/spree_auth_devise/commit/3157b47b22c559817d34ec34024587d8aa6136dc + I dont think we can decode these sessions anymore since Rails 4 switched to encrypted cookies I believe devise stores session encrypted. + } + create(:product, name: 'RoR Mug') + create(:product, name: 'RoR Shirt') + + user = create(:user, email: 'email@person.com', password: 'password', password_confirmation: 'password') + + using_session('first') do + visit spree.root_path + + click_link 'RoR Mug' + click_button 'Add To Cart' + + visit spree.login_path + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + click_button 'Login' + + click_link 'Cart' + expect(page).to have_text 'RoR Mug' + end + + using_session('second') do + visit spree.root_path + + click_link 'RoR Shirt' + click_button 'Add To Cart' + + visit spree.login_path + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + click_button 'Login' + + # Order should have been merged with first session + click_link 'Cart' + expect(page).to have_text 'RoR Mug' + expect(page).to have_text 'RoR Shirt' + end + + using_session('first') do + visit spree.root_path + + click_link 'Cart' + + # Order should have been merged with second session + expect(page).to have_text 'RoR Mug' + expect(page).to have_text 'RoR Shirt' + end + end +end diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb new file mode 100644 index 00000000..70ee7a8d --- /dev/null +++ b/spec/features/password_reset_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +RSpec.feature 'Reset Password', type: :feature do + let!(:store) { create(:store) } + + background do + ActionMailer::Base.default_url_options[:host] = 'http://example.com' + end + + context 'when an account with this email address exists' do + let!(:user) { create(:user, email: 'foobar@example.com', password: 'secret', password_confirmation: 'secret') } + + scenario 'allows a user to supply an email for the password reset' do + visit spree.login_path + click_link 'Forgot Password?' + fill_in_email + click_button 'Reset my password' + expect(page).to have_text 'you will receive an email with instructions' + end + end + + # Test that we are extending the functionality from + # https://github.com/solidusio/solidus_auth_devise/pull/155 + # to the non-admin login + scenario 'does not reveal email addresses if they are not found' do + visit spree.login_path + click_link 'Forgot Password?' + fill_in_email + click_button 'Reset my password' + expect(page).to_not have_text "Email not found" + expect(page).to have_text 'you will receive an email with instructions' + end + + def fill_in_email + fill_in 'Email', with: 'foobar@example.com' + end +end diff --git a/spec/features/sign_in_spec.rb b/spec/features/sign_in_spec.rb new file mode 100644 index 00000000..006cf5ba --- /dev/null +++ b/spec/features/sign_in_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +RSpec.feature 'Sign In', type: :feature do + background do + @user = create(:user, email: 'email@person.com', password: 'secret', password_confirmation: 'secret') + visit spree.login_path + end + + scenario 'ask user to sign in' do + visit spree.admin_path + expect(page).not_to have_text 'Authorization Failure' + end + + scenario 'let a user sign in successfully' do + fill_in 'Email', with: @user.email + fill_in 'Password', with: @user.password + click_button 'Login' + + expect(page).to have_text 'Logged in successfully' + expect(page).not_to have_text 'Login' + expect(page).to have_text 'Logout' + expect(current_path).to eq '/' + end + + scenario 'show validation erros' do + fill_in 'Email', with: @user.email + fill_in 'Password', with: 'wrong_password' + click_button 'Login' + + expect(page).to have_text 'Invalid email or password' + expect(page).to have_text 'Login' + end + + scenario 'allow a user to access a restricted page after logging in' do + user = create(:admin_user, email: 'admin@person.com', password: 'password', password_confirmation: 'password') + visit spree.admin_path + + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + click_button 'Login' + + expect(page).to have_text 'admin@person.com' + expect(current_path).to eq '/admin/orders' + end + + it "should store the user previous location" do + visit spree.account_path + fill_in "Email", with: @user.email + fill_in "Password", with: @user.password + click_button "Login" + expect(current_path).to eq "/account" + end +end diff --git a/spec/features/sign_out_spec.rb b/spec/features/sign_out_spec.rb new file mode 100644 index 00000000..a61f5b20 --- /dev/null +++ b/spec/features/sign_out_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +RSpec.feature 'Sign Out', type: :feature, js: true do + given!(:user) do + create(:user, + email: 'email@person.com', + password: 'secret', + password_confirmation: 'secret') + end + + background do + visit spree.login_path + fill_in 'Email', with: user.email + fill_in 'Password', with: user.password + # Regression test for #1257 + check 'Remember me' + click_button 'Login' + end + + scenario 'allow a signed in user to logout' do + click_link 'Logout' + visit spree.root_path + expect(page).to have_text 'LOGIN' + expect(page).not_to have_text 'LOGOUT' + end +end diff --git a/spec/features/sign_up_spec.rb b/spec/features/sign_up_spec.rb new file mode 100644 index 00000000..98a40dc7 --- /dev/null +++ b/spec/features/sign_up_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +RSpec.feature 'Sign Up', type: :feature do + context 'with valid data' do + scenario 'create a new user' do + visit spree.signup_path + + fill_in 'Email', with: 'email@person.com' + fill_in 'Password', with: 'password' + fill_in 'Password Confirmation', with: 'password' + click_button 'Create' + + expect(page).to have_text 'You have signed up successfully.' + expect(Spree::User.count).to eq(1) + end + end + + context 'with invalid data' do + scenario 'does not create a new user' do + visit spree.signup_path + + fill_in 'Email', with: 'email@person.com' + fill_in 'Password', with: 'password' + fill_in 'Password Confirmation', with: '' + click_button 'Create' + + expect(page).to have_css '#errorExplanation' + expect(Spree::User.count).to eq(0) + end + end +end From f7276193ecacd98726846e1cb31a166001adb5e9 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 16:35:36 +0800 Subject: [PATCH 02/35] Remove backend solidus_auth_devise feature specs --- spec/features/admin/password_reset_spec.rb | 80 ---------------------- spec/features/admin/products_spec.rb | 10 --- spec/features/admin/sign_in_spec.rb | 45 ------------ spec/features/admin/sign_out_spec.rb | 23 ------- spec/features/admin_permissions_spec.rb | 47 ------------- spec/features/sign_in_spec.rb | 17 ----- 6 files changed, 222 deletions(-) delete mode 100644 spec/features/admin/password_reset_spec.rb delete mode 100644 spec/features/admin/products_spec.rb delete mode 100644 spec/features/admin/sign_in_spec.rb delete mode 100644 spec/features/admin/sign_out_spec.rb delete mode 100644 spec/features/admin_permissions_spec.rb diff --git a/spec/features/admin/password_reset_spec.rb b/spec/features/admin/password_reset_spec.rb deleted file mode 100644 index 4d44408f..00000000 --- a/spec/features/admin/password_reset_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -RSpec.feature 'Admin - Reset Password', type: :feature do - let!(:store) { create(:store) } - - background do - ActionMailer::Base.default_url_options[:host] = 'http://example.com' - end - - context 'when an account with this email address exists' do - let!(:user) { create(:user, email: 'foobar@example.com', password: 'secret', password_confirmation: 'secret') } - - scenario 'allows a user to supply an email for the password reset' do - visit spree.admin_login_path - click_link 'Forgot Password?' - fill_in_email - click_button 'Reset my password' - expect(page).to have_text 'you will receive an email with instructions' - end - end - - # Revealing that an admin email address is not found allows an attacker to - # find admin account email addresses by trying email addresses until this - # error is not shown. - scenario 'does not reveal email addresses if they are not found' do - visit spree.admin_login_path - click_link 'Forgot Password?' - fill_in_email - click_button 'Reset my password' - expect(page).to_not have_text "Email not found" - expect(page).to have_text 'you will receive an email with instructions' - end - - def fill_in_email - fill_in 'Email', with: 'foobar@example.com' - end - - context 'password management' do - let!(:admin) do - create(:admin_user, - email: 'admin@example.com', - password: 'secret', - password_confirmation: 'secret' - ) - end - - let!(:user) do - create(:user, - email: 'user@example.com', - password: 'test123', - password_confirmation: 'test123' - ) - end - - before do - visit spree.admin_login_path - fill_in 'Email', with: admin.email - fill_in 'Password', with: admin.password - click_button 'Login' - visit spree.admin_users_path - end - - context 'if currently logged-in admin' do - context "clicks on an user's page" do - it 'can reset its password' do - within("#spree_user_#{user.id}") do - click_link user.email - end - - click_button 'Reset password' - expect(page).to have_content( - 'If an account with that email address exists, '\ - 'you will receive an email with instructions about '\ - 'how to reset your password in a few minutes.' - ) - end - end - end - end -end diff --git a/spec/features/admin/products_spec.rb b/spec/features/admin/products_spec.rb deleted file mode 100644 index 1daeb3e8..00000000 --- a/spec/features/admin/products_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -RSpec.feature 'Admin products', type: :feature do - context 'as anonymous user' do - # Regression test for #1250 - scenario 'redirects to login page when attempting to access product listing' do - expect { visit spree.admin_products_path }.not_to raise_error - end - end -end diff --git a/spec/features/admin/sign_in_spec.rb b/spec/features/admin/sign_in_spec.rb deleted file mode 100644 index 25840f1c..00000000 --- a/spec/features/admin/sign_in_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -RSpec.feature 'Admin - Sign In', type: :feature do - background do - @user = create(:user, email: 'email@person.com') - visit spree.admin_login_path - end - - scenario 'asks user to sign in' do - visit spree.admin_path - expect(page).not_to have_text 'Authorization Failure' - end - - scenario 'lets a user sign in successfully' do - fill_in 'Email', with: @user.email - fill_in 'Password', with: 'secret' - click_button 'Login' - - expect(page).to have_text 'Logged in successfully' - expect(page).not_to have_text 'Login' - expect(page).to have_text 'Logout' - expect(current_path).to eq '/' - end - - scenario 'shows validation erros' do - fill_in 'Email', with: @user.email - fill_in 'Password', with: 'wrong_password' - click_button 'Login' - - expect(page).to have_text 'Invalid email or password' - expect(page).to have_text 'Login' - end - - scenario 'allows a user to access a restricted page after logging in' do - user = create(:admin_user, email: 'admin@person.com') - visit spree.admin_path - - fill_in 'Email', with: user.email - fill_in 'Password', with: 'secret' - click_button 'Login' - - expect(page).to have_text 'admin@person.com' - expect(current_path).to eq '/admin/orders' - end -end diff --git a/spec/features/admin/sign_out_spec.rb b/spec/features/admin/sign_out_spec.rb deleted file mode 100644 index 420ad145..00000000 --- a/spec/features/admin/sign_out_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -RSpec.feature 'Admin - Sign Out', type: :feature, js: true do - given!(:user) do - create :user, email: 'email@person.com' - end - - background do - visit spree.admin_login_path - fill_in 'Email', with: user.email - fill_in 'Password', with: 'secret' - # Regression test for #1257 - check 'Remember me' - click_button 'Login' - end - - scenario 'allows a signed in user to logout' do - click_link 'Logout' - visit spree.admin_login_path - expect(page).to have_text 'Login' - expect(page).not_to have_text 'Logout' - end -end diff --git a/spec/features/admin_permissions_spec.rb b/spec/features/admin_permissions_spec.rb deleted file mode 100644 index 2306d387..00000000 --- a/spec/features/admin_permissions_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -RSpec.feature 'Admin Permissions', type: :feature do - context 'orders' do - background do - user = create(:admin_user, email: 'admin@person.com', password: 'password', password_confirmation: 'password') - Spree::Ability.register_ability(AbilityDecorator) - visit spree.login_path - - fill_in 'Email', with: user.email - fill_in 'Password', with: user.password - click_button 'Login' - end - - context 'admin is restricted from accessing orders' do - scenario 'can not list orders' do - visit spree.admin_orders_path - expect(page).to have_text 'Authorization Failure' - end - - scenario 'can not edit orders' do - create(:order, number: 'R123') - visit spree.edit_admin_order_path('R123') - expect(page).to have_text 'Authorization Failure' - end - - scenario 'can not new orders' do - visit spree.new_admin_order_path - expect(page).to have_text 'Authorization Failure' - end - end - - context "admin is restricted from accessing an order's customer details" do - given(:order) { create(:order_with_totals) } - - scenario 'can not list customer details for an order' do - visit spree.admin_order_customer_path(order) - expect(page).to have_text 'Authorization Failure' - end - - scenario "can not edit an order's customer details" do - visit spree.edit_admin_order_customer_path(order) - expect(page).to have_text 'Authorization Failure' - end - end - end -end diff --git a/spec/features/sign_in_spec.rb b/spec/features/sign_in_spec.rb index 006cf5ba..15ddd3f4 100644 --- a/spec/features/sign_in_spec.rb +++ b/spec/features/sign_in_spec.rb @@ -6,11 +6,6 @@ visit spree.login_path end - scenario 'ask user to sign in' do - visit spree.admin_path - expect(page).not_to have_text 'Authorization Failure' - end - scenario 'let a user sign in successfully' do fill_in 'Email', with: @user.email fill_in 'Password', with: @user.password @@ -31,18 +26,6 @@ expect(page).to have_text 'Login' end - scenario 'allow a user to access a restricted page after logging in' do - user = create(:admin_user, email: 'admin@person.com', password: 'password', password_confirmation: 'password') - visit spree.admin_path - - fill_in 'Email', with: user.email - fill_in 'Password', with: user.password - click_button 'Login' - - expect(page).to have_text 'admin@person.com' - expect(current_path).to eq '/admin/orders' - end - it "should store the user previous location" do visit spree.account_path fill_in "Email", with: @user.email From ff667d5ee1a4a2b4836ae1b2979b6ee287d2e72f Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 16:36:08 +0800 Subject: [PATCH 03/35] Remove skipped spec --- spec/features/order_spec.rb | 63 ------------------------------------- 1 file changed, 63 deletions(-) delete mode 100644 spec/features/order_spec.rb diff --git a/spec/features/order_spec.rb b/spec/features/order_spec.rb deleted file mode 100644 index 5b45e758..00000000 --- a/spec/features/order_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -RSpec.feature 'Orders', :js, type: :feature do - scenario 'allow a user to view their cart at any time' do - visit spree.cart_path - expect(page).to have_text 'Your cart is empty' - end - - # regression test for spree/spree#1687 - scenario 'merge incomplete orders from different sessions' do - skip %{ - TODO: has been broken for ~2 months as of: - https://github.com/spree/spree_auth_devise/commit/3157b47b22c559817d34ec34024587d8aa6136dc - I dont think we can decode these sessions anymore since Rails 4 switched to encrypted cookies I believe devise stores session encrypted. - } - create(:product, name: 'RoR Mug') - create(:product, name: 'RoR Shirt') - - user = create(:user, email: 'email@person.com', password: 'password', password_confirmation: 'password') - - using_session('first') do - visit spree.root_path - - click_link 'RoR Mug' - click_button 'Add To Cart' - - visit spree.login_path - fill_in 'Email', with: user.email - fill_in 'Password', with: user.password - click_button 'Login' - - click_link 'Cart' - expect(page).to have_text 'RoR Mug' - end - - using_session('second') do - visit spree.root_path - - click_link 'RoR Shirt' - click_button 'Add To Cart' - - visit spree.login_path - fill_in 'Email', with: user.email - fill_in 'Password', with: user.password - click_button 'Login' - - # Order should have been merged with first session - click_link 'Cart' - expect(page).to have_text 'RoR Mug' - expect(page).to have_text 'RoR Shirt' - end - - using_session('first') do - visit spree.root_path - - click_link 'Cart' - - # Order should have been merged with second session - expect(page).to have_text 'RoR Mug' - expect(page).to have_text 'RoR Shirt' - end - end -end From 1b35df8754ed312576861d224f21fc94d47855e3 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 16:40:20 +0800 Subject: [PATCH 04/35] Copy solidus_auth_devise frontend routes Fixes ``` 1) Accounts editing can edit an admin user Failure/Error: visit spree.login_path NoMethodError: undefined method `login_path' for # # ./spec/features/account_spec.rb:7:in `block (3 levels) in ' ``` --- config/routes.rb | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/config/routes.rb b/config/routes.rb index ec44b41d..fd42f157 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,6 +3,40 @@ Spree::Core::Engine.routes.draw do root to: 'home#index' + devise_for(:spree_user, { + class_name: 'Spree::User', + controllers: { + sessions: 'spree/user_sessions', + registrations: 'spree/user_registrations', + passwords: 'spree/user_passwords', + confirmations: 'spree/user_confirmations' + }, + skip: [:unlocks, :omniauth_callbacks], + path_names: { sign_out: 'logout' }, + path_prefix: :user, + router_name: :spree + }) + + resources :users, only: [:edit, :update] + + devise_scope :spree_user do + get '/login', to: 'user_sessions#new', as: :login + post '/login', to: 'user_sessions#create', as: :create_new_session + match '/logout', to: 'user_sessions#destroy', as: :logout, via: Devise.sign_out_via + get '/signup', to: 'user_registrations#new', as: :signup + post '/signup', to: 'user_registrations#create', as: :registration + get '/password/recover', to: 'user_passwords#new', as: :recover_password + post '/password/recover', to: 'user_passwords#create', as: :reset_password + get '/password/change', to: 'user_passwords#edit', as: :edit_password + put '/password/change', to: 'user_passwords#update', as: :update_password + get '/confirm', to: 'user_confirmations#show', as: :confirmation if Spree::Auth::Config[:confirmable] + end + + get '/checkout/registration', to: 'checkout#registration', as: :checkout_registration + put '/checkout/registration', to: 'checkout#update_registration', as: :update_checkout_registration + + resource :account, controller: 'users' + resources :products, only: [:index, :show] get '/locale/set', to: 'locale#set' From e34e9e6efe44cc2ac0286739196748a39f858a5c Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 16:40:51 +0800 Subject: [PATCH 05/35] Move checkout solidus_auth_devise routes to checkout section --- config/routes.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index fd42f157..dc1ce449 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -32,9 +32,6 @@ get '/confirm', to: 'user_confirmations#show', as: :confirmation if Spree::Auth::Config[:confirmable] end - get '/checkout/registration', to: 'checkout#registration', as: :checkout_registration - put '/checkout/registration', to: 'checkout#update_registration', as: :update_checkout_registration - resource :account, controller: 'users' resources :products, only: [:index, :show] @@ -43,6 +40,8 @@ post '/locale/set', to: 'locale#set', as: :select_locale # non-restful checkout stuff + get '/checkout/registration', to: 'checkout#registration', as: :checkout_registration + put '/checkout/registration', to: 'checkout#update_registration', as: :update_checkout_registration patch '/checkout/update/:state', to: 'checkout#update', as: :update_checkout get '/checkout/:state', to: 'checkout#edit', as: :checkout_state get '/checkout', to: 'checkout#edit', as: :checkout From 6245ee45a229e37afe3d2d4a3310237876e04172 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 16:42:45 +0800 Subject: [PATCH 06/35] Add solidus_auth_devise Fixes ``` An error occurred while loading spec_helper. Failure/Error: Rails.application.initialize! NoMethodError: undefined method `devise_for' for # # ./config/routes.rb:6:in `block in ' # ./config/routes.rb:3:in `' # ./spec/dummy/config/environment.rb:5:in `' # ./spec/spec_helper.rb:15:in `require' # ./spec/spec_helper.rb:15:in `' ``` --- lib/solidus_starter_frontend.rb | 1 + solidus_starter_frontend.gemspec | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/solidus_starter_frontend.rb b/lib/solidus_starter_frontend.rb index 4d0efed4..67d57f96 100644 --- a/lib/solidus_starter_frontend.rb +++ b/lib/solidus_starter_frontend.rb @@ -4,6 +4,7 @@ require 'canonical-rails' require 'solidus_core' +require 'solidus_auth_devise' require 'solidus_support' require 'solidus_starter_frontend/solidus_support_extensions' diff --git a/solidus_starter_frontend.gemspec b/solidus_starter_frontend.gemspec index b0c1bb38..2d027c98 100644 --- a/solidus_starter_frontend.gemspec +++ b/solidus_starter_frontend.gemspec @@ -33,6 +33,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'solidus_api', ['>= 2.0', '< 4'] spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 4'] spec.add_dependency 'solidus_support', '~> 0.5' + spec.add_dependency 'solidus_auth_devise', '~> 2.5' spec.add_dependency 'truncate_html', '~> 0.9', '>= 0.9.2' spec.add_development_dependency 'apparition', '~> 0.6.0' From 544e8d0612d03613bb6d389343c062441883164a Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:02:57 +0800 Subject: [PATCH 07/35] Copy solidus_auth_devise controllers Fixes ``` An error occurred while loading spec_helper. Failure/Error: Spree::UserConfirmationsController, NameError: uninitialized constant Spree::UserConfirmationsController # ./lib/solidus_starter_frontend/engine.rb:20:in `block in ' # ./spec/dummy/config/environment.rb:5:in `' # ./spec/spec_helper.rb:15:in `require' # ./spec/spec_helper.rb:15:in `' ``` --- .../spree/user_confirmations_controller.rb | 16 +++++ .../spree/user_passwords_controller.rb | 53 +++++++++++++++ .../spree/user_registrations_controller.rb | 44 +++++++++++++ .../spree/user_sessions_controller.rb | 66 +++++++++++++++++++ app/controllers/spree/users_controller.rb | 65 ++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 app/controllers/spree/user_confirmations_controller.rb create mode 100644 app/controllers/spree/user_passwords_controller.rb create mode 100644 app/controllers/spree/user_registrations_controller.rb create mode 100644 app/controllers/spree/user_sessions_controller.rb create mode 100644 app/controllers/spree/users_controller.rb diff --git a/app/controllers/spree/user_confirmations_controller.rb b/app/controllers/spree/user_confirmations_controller.rb new file mode 100644 index 00000000..41bace4a --- /dev/null +++ b/app/controllers/spree/user_confirmations_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Spree::UserConfirmationsController < Devise::ConfirmationsController + helper 'spree/base', 'spree/store' + + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::Common + include Spree::Core::ControllerHelpers::Order + include Spree::Core::ControllerHelpers::Store + + protected + + def after_confirmation_path_for(resource_name, resource) + signed_in?(resource_name) ? spree.signed_in_root_path(resource) : spree.login_path + end +end diff --git a/app/controllers/spree/user_passwords_controller.rb b/app/controllers/spree/user_passwords_controller.rb new file mode 100644 index 00000000..80d24d53 --- /dev/null +++ b/app/controllers/spree/user_passwords_controller.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class Spree::UserPasswordsController < Devise::PasswordsController + helper 'spree/base', 'spree/store' + + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::Common + include Spree::Core::ControllerHelpers::Order + include Spree::Core::ControllerHelpers::Store + + # Overridden due to bug in Devise. + # respond_with resource, location: new_session_path(resource_name) + # is generating bad url /session/new.user + # + # overridden to: + # respond_with resource, location: spree.login_path + # + def create + self.resource = resource_class.send_reset_password_instructions(params[resource_name]) + + set_flash_message(:notice, :send_instructions) if is_navigational_format? + + if resource.errors.empty? + respond_with resource, location: spree.login_path + else + respond_with_navigational(resource) { render :new } + end + end + + # Devise::PasswordsController allows for blank passwords. + # Silly Devise::PasswordsController! + # Fixes spree/spree#2190. + def update + if params[:spree_user][:password].blank? + self.resource = resource_class.new + resource.reset_password_token = params[:spree_user][:reset_password_token] + set_flash_message(:error, :cannot_be_blank) + render :edit + else + super + end + end + + protected + + def translation_scope + 'devise.user_passwords' + end + + def new_session_path(resource_name) + spree.send("new_#{resource_name}_session_path") + end +end diff --git a/app/controllers/spree/user_registrations_controller.rb b/app/controllers/spree/user_registrations_controller.rb new file mode 100644 index 00000000..b1b42195 --- /dev/null +++ b/app/controllers/spree/user_registrations_controller.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +class Spree::UserRegistrationsController < Devise::RegistrationsController + helper 'spree/base', 'spree/store' + + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::Common + include Spree::Core::ControllerHelpers::Order + include Spree::Core::ControllerHelpers::Store + + before_action :check_permissions, only: [:edit, :update] + skip_before_action :require_no_authentication + + def create + build_resource(spree_user_params) + if resource.save + set_flash_message(:notice, :signed_up) + sign_in(:spree_user, resource) + session[:spree_user_signup] = true + respond_with resource, location: after_sign_up_path_for(resource) + else + clean_up_passwords(resource) + respond_with(resource) do |format| + format.html { render :new } + end + end + end + + protected + + def translation_scope + 'devise.user_registrations' + end + + def check_permissions + authorize!(:create, resource) + end + + private + + def spree_user_params + params.require(:spree_user).permit(Spree::PermittedAttributes.user_attributes | [:email]) + end +end diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb new file mode 100644 index 00000000..dfa67d99 --- /dev/null +++ b/app/controllers/spree/user_sessions_controller.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +class Spree::UserSessionsController < Devise::SessionsController + helper 'spree/base', 'spree/store' + + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::Common + include Spree::Core::ControllerHelpers::Order + include Spree::Core::ControllerHelpers::Store + + # This is included in ControllerHelpers::Order. We just want to call + # it after someone has successfully logged in. + after_action :set_current_order, only: :create + + def create + authenticate_spree_user! + + if spree_user_signed_in? + respond_to do |format| + format.html do + flash[:success] = I18n.t('spree.logged_in_succesfully') + redirect_back_or_default(after_sign_in_path_for(spree_current_user)) + end + format.js { render success_json } + end + else + respond_to do |format| + format.html do + flash.now[:error] = t('devise.failure.invalid') + render :new + end + format.js do + render json: { error: t('devise.failure.invalid') }, + status: :unprocessable_entity + end + end + end + end + + protected + + def translation_scope + 'devise.user_sessions' + end + + private + + def accurate_title + I18n.t('spree.login') + end + + def redirect_back_or_default(default) + redirect_to(session["spree_user_return_to"] || default) + session["spree_user_return_to"] = nil + end + + def success_json + { + json: { + user: spree_current_user, + ship_address: spree_current_user.ship_address, + bill_address: spree_current_user.bill_address + }.to_json + } + end +end diff --git a/app/controllers/spree/users_controller.rb b/app/controllers/spree/users_controller.rb new file mode 100644 index 00000000..81ecc60b --- /dev/null +++ b/app/controllers/spree/users_controller.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +class Spree::UsersController < Spree::StoreController + skip_before_action :set_current_order, only: :show, raise: false + prepend_before_action :load_object, only: [:show, :edit, :update] + prepend_before_action :authorize_actions, only: :new + + include Spree::Core::ControllerHelpers + + def show + @orders = @user.orders.complete.order('completed_at desc') + end + + def create + @user = Spree::User.new(user_params) + if @user.save + + if current_order + session[:guest_token] = nil + end + + redirect_back_or_default(root_url) + else + render :new + end + end + + def update + if @user.update(user_params) + spree_current_user.reload + redirect_url = spree.account_url + + if params[:user][:password].present? + # this logic needed b/c devise wants to log us out after password changes + if Spree::Auth::Config[:signout_after_password_change] + redirect_url = spree.login_url + else + bypass_sign_in(@user) + end + end + redirect_to redirect_url, notice: I18n.t('spree.account_updated') + else + render :edit + end + end + + private + + def user_params + params.require(:user).permit(Spree::PermittedAttributes.user_attributes | [:email]) + end + + def load_object + @user ||= Spree::User.find_by(id: spree_current_user&.id) + authorize! params[:action].to_sym, @user + end + + def authorize_actions + authorize! params[:action].to_sym, Spree::User.new + end + + def accurate_title + I18n.t('spree.my_account') + end +end From 7ba6cbfd5d16a048ef846a191a9a7d1017cc0e5c Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:09:11 +0800 Subject: [PATCH 08/35] Remove frontend_available? monkeypatch solidus_starter_frontend will be loading the authentication frontend so we no longer want solidus_auth_devise to load it again. Fixes ``` An error occurred while loading spec_helper. Failure/Error: Rails.application.initialize! ArgumentError: Invalid route name, already in use: 'new_spree_user_session' You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming. For the latter, you can restrict the routes created with `resources` as explained here: https://guides.rubyonrails.org/routing.html#restricting-the-routes-created # ./spec/dummy/config/environment.rb:5:in `' # ./spec/spec_helper.rb:15:in `require' # ./spec/spec_helper.rb:15:in `' ``` --- lib/solidus_starter_frontend.rb | 1 - .../solidus_support_extensions.rb | 9 --------- 2 files changed, 10 deletions(-) delete mode 100644 lib/solidus_starter_frontend/solidus_support_extensions.rb diff --git a/lib/solidus_starter_frontend.rb b/lib/solidus_starter_frontend.rb index 67d57f96..f2e55b4c 100644 --- a/lib/solidus_starter_frontend.rb +++ b/lib/solidus_starter_frontend.rb @@ -7,7 +7,6 @@ require 'solidus_auth_devise' require 'solidus_support' -require 'solidus_starter_frontend/solidus_support_extensions' require 'solidus_starter_frontend/version' require 'solidus_starter_frontend/config' require 'solidus_starter_frontend/engine' diff --git a/lib/solidus_starter_frontend/solidus_support_extensions.rb b/lib/solidus_starter_frontend/solidus_support_extensions.rb deleted file mode 100644 index d145f060..00000000 --- a/lib/solidus_starter_frontend/solidus_support_extensions.rb +++ /dev/null @@ -1,9 +0,0 @@ -# frozen_string_literal: true - -require 'solidus_support' - -module SolidusSupport - def self.frontend_available? - true - end -end From 479172fd300d0786c838436a1091192a8ca58141 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:17:52 +0800 Subject: [PATCH 09/35] Qualify Password field identifiers Fixes ``` 1) Accounts editing can edit a new user Failure/Error: fill_in 'Password', with: 'password' Capybara::Ambiguous: Ambiguous match, found 2 elements matching visible field "Password" that is not disabled # ./spec/features/account_spec.rb:22:in `block (3 levels) in ' ``` --- spec/features/account_spec.rb | 10 +++++----- spec/features/checkout_spec.rb | 6 +++--- spec/features/confirmation_spec.rb | 2 +- spec/features/sign_in_spec.rb | 4 ++-- spec/features/sign_out_spec.rb | 2 +- spec/features/sign_up_spec.rb | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/spec/features/account_spec.rb b/spec/features/account_spec.rb index a517d1cb..11261758 100644 --- a/spec/features/account_spec.rb +++ b/spec/features/account_spec.rb @@ -7,7 +7,7 @@ visit spree.login_path fill_in 'Email', with: user.email - fill_in 'Password', with: user.password + fill_in 'Password:', with: user.password click_button 'Login' click_link 'My Account' @@ -19,7 +19,7 @@ visit spree.signup_path fill_in 'Email', with: 'email@person.com' - fill_in 'Password', with: 'password' + fill_in 'Password:', with: 'password' fill_in 'Password Confirmation', with: 'password' click_button 'Create' @@ -27,7 +27,7 @@ expect(page).to have_text 'email@person.com' click_link 'Edit' - fill_in 'Password', with: 'foobar' + fill_in 'Password:', with: 'foobar' fill_in 'Password Confirmation', with: 'foobar' click_button 'Update' @@ -41,14 +41,14 @@ visit spree.login_path fill_in 'Email', with: user.email - fill_in 'Password', with: user.password + fill_in 'Password:', with: user.password click_button 'Login' click_link 'My Account' expect(page).to have_text 'email@person.com' click_link 'Edit' - fill_in 'Password', with: 'foobar' + fill_in 'Password:', with: 'foobar' fill_in 'Password Confirmation', with: 'foobar' click_button 'Update' diff --git a/spec/features/checkout_spec.rb b/spec/features/checkout_spec.rb index 3221aaae..fbd76a53 100644 --- a/spec/features/checkout_spec.rb +++ b/spec/features/checkout_spec.rb @@ -77,7 +77,7 @@ visit spree.login_path fill_in 'Email', with: user.email - fill_in 'Password', with: user.password + fill_in 'Password:', with: user.password click_button 'Login' click_link 'Cart' @@ -115,7 +115,7 @@ token = token_url_regex.match(reset_password_email.body.to_s)[1] visit spree.edit_spree_user_password_path(reset_password_token: token) - fill_in 'Password', with: 'password' + fill_in 'Password:', with: 'password' fill_in 'Password Confirmation', with: 'password' click_button 'Update' @@ -138,7 +138,7 @@ click_link 'Create a new account' fill_in 'Email', with: 'email@person.com' - fill_in 'Password', with: 'spree123' + fill_in 'Password:', with: 'spree123' fill_in 'Password Confirmation', with: 'spree123' click_button 'Create' diff --git a/spec/features/confirmation_spec.rb b/spec/features/confirmation_spec.rb index f50df67c..601dfd57 100644 --- a/spec/features/confirmation_spec.rb +++ b/spec/features/confirmation_spec.rb @@ -18,7 +18,7 @@ visit spree.signup_path fill_in 'Email', with: 'email@person.com' - fill_in 'Password', with: 'password' + fill_in 'Password:', with: 'password' fill_in 'Password Confirmation', with: 'password' click_button 'Create' diff --git a/spec/features/sign_in_spec.rb b/spec/features/sign_in_spec.rb index 15ddd3f4..bc59a656 100644 --- a/spec/features/sign_in_spec.rb +++ b/spec/features/sign_in_spec.rb @@ -8,7 +8,7 @@ scenario 'let a user sign in successfully' do fill_in 'Email', with: @user.email - fill_in 'Password', with: @user.password + fill_in 'Password:', with: @user.password click_button 'Login' expect(page).to have_text 'Logged in successfully' @@ -19,7 +19,7 @@ scenario 'show validation erros' do fill_in 'Email', with: @user.email - fill_in 'Password', with: 'wrong_password' + fill_in 'Password:', with: 'wrong_password' click_button 'Login' expect(page).to have_text 'Invalid email or password' diff --git a/spec/features/sign_out_spec.rb b/spec/features/sign_out_spec.rb index a61f5b20..92e8a640 100644 --- a/spec/features/sign_out_spec.rb +++ b/spec/features/sign_out_spec.rb @@ -11,7 +11,7 @@ background do visit spree.login_path fill_in 'Email', with: user.email - fill_in 'Password', with: user.password + fill_in 'Password:', with: user.password # Regression test for #1257 check 'Remember me' click_button 'Login' diff --git a/spec/features/sign_up_spec.rb b/spec/features/sign_up_spec.rb index 98a40dc7..2a19519b 100644 --- a/spec/features/sign_up_spec.rb +++ b/spec/features/sign_up_spec.rb @@ -6,7 +6,7 @@ visit spree.signup_path fill_in 'Email', with: 'email@person.com' - fill_in 'Password', with: 'password' + fill_in 'Password:', with: 'password' fill_in 'Password Confirmation', with: 'password' click_button 'Create' @@ -20,7 +20,7 @@ visit spree.signup_path fill_in 'Email', with: 'email@person.com' - fill_in 'Password', with: 'password' + fill_in 'Password:', with: 'password' fill_in 'Password Confirmation', with: '' click_button 'Create' From 5d2db5194544feaa6cefa2980de9e6f591811852 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:20:54 +0800 Subject: [PATCH 10/35] Move views from lib to app Remove AuthViews concern since it's no longer needed. Fixes ``` 1) Accounts editing can edit a new user Failure/Error: click_link 'Edit' AbstractController::ActionNotFound: The action 'edit' could not be found for Spree::UsersController # ./spec/features/account_spec.rb:28:in `block (3 levels) in ' ``` --- .../solidus_starter_frontend/auth_views.rb | 16 ---------------- .../views}/spree/checkout/registration.html.erb | 0 .../components/navigation/_auth_link.html.erb | 6 +++++- .../views}/spree/user_passwords/edit.html.erb | 0 .../views}/spree/user_passwords/new.html.erb | 0 .../views}/spree/user_registrations/new.html.erb | 0 .../views}/spree/user_sessions/guest.html.erb | 0 .../views}/spree/user_sessions/new.html.erb | 0 .../auth => app/views}/spree/users/edit.html.erb | 0 .../auth => app/views}/spree/users/show.html.erb | 0 lib/solidus_starter_frontend/engine.rb | 3 --- .../components/navigation/_auth_link.html.erb | 5 ----- 12 files changed, 5 insertions(+), 25 deletions(-) delete mode 100644 app/controllers/concerns/solidus_starter_frontend/auth_views.rb rename {lib/views/auth => app/views}/spree/checkout/registration.html.erb (100%) rename {lib/views/auth => app/views}/spree/user_passwords/edit.html.erb (100%) rename {lib/views/auth => app/views}/spree/user_passwords/new.html.erb (100%) rename {lib/views/auth => app/views}/spree/user_registrations/new.html.erb (100%) rename {lib/views/auth => app/views}/spree/user_sessions/guest.html.erb (100%) rename {lib/views/auth => app/views}/spree/user_sessions/new.html.erb (100%) rename {lib/views/auth => app/views}/spree/users/edit.html.erb (100%) rename {lib/views/auth => app/views}/spree/users/show.html.erb (100%) delete mode 100644 lib/views/auth/spree/components/navigation/_auth_link.html.erb diff --git a/app/controllers/concerns/solidus_starter_frontend/auth_views.rb b/app/controllers/concerns/solidus_starter_frontend/auth_views.rb deleted file mode 100644 index bf8f8cbd..00000000 --- a/app/controllers/concerns/solidus_starter_frontend/auth_views.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module SolidusStarterFrontend - module AuthViews - extend ActiveSupport::Concern - included do - before_action :configure_views - end - - protected - - def configure_views - prepend_view_path Engine.root.join('lib', 'views', 'auth') - end - end -end diff --git a/lib/views/auth/spree/checkout/registration.html.erb b/app/views/spree/checkout/registration.html.erb similarity index 100% rename from lib/views/auth/spree/checkout/registration.html.erb rename to app/views/spree/checkout/registration.html.erb diff --git a/app/views/spree/components/navigation/_auth_link.html.erb b/app/views/spree/components/navigation/_auth_link.html.erb index 7a695a11..5cbefaf3 100644 --- a/app/views/spree/components/navigation/_auth_link.html.erb +++ b/app/views/spree/components/navigation/_auth_link.html.erb @@ -1 +1,5 @@ -<%# This is loaded from lib/views/auth folder if an authentication method is defined %> +<% if spree_current_user %> + <%= link_to I18n.t('spree.my_account'), spree.account_path, class: 'auth-link' %> +<% else %> + <%= link_to I18n.t('spree.login'), spree.login_path, class: 'auth-link' %> +<% end %> diff --git a/lib/views/auth/spree/user_passwords/edit.html.erb b/app/views/spree/user_passwords/edit.html.erb similarity index 100% rename from lib/views/auth/spree/user_passwords/edit.html.erb rename to app/views/spree/user_passwords/edit.html.erb diff --git a/lib/views/auth/spree/user_passwords/new.html.erb b/app/views/spree/user_passwords/new.html.erb similarity index 100% rename from lib/views/auth/spree/user_passwords/new.html.erb rename to app/views/spree/user_passwords/new.html.erb diff --git a/lib/views/auth/spree/user_registrations/new.html.erb b/app/views/spree/user_registrations/new.html.erb similarity index 100% rename from lib/views/auth/spree/user_registrations/new.html.erb rename to app/views/spree/user_registrations/new.html.erb diff --git a/lib/views/auth/spree/user_sessions/guest.html.erb b/app/views/spree/user_sessions/guest.html.erb similarity index 100% rename from lib/views/auth/spree/user_sessions/guest.html.erb rename to app/views/spree/user_sessions/guest.html.erb diff --git a/lib/views/auth/spree/user_sessions/new.html.erb b/app/views/spree/user_sessions/new.html.erb similarity index 100% rename from lib/views/auth/spree/user_sessions/new.html.erb rename to app/views/spree/user_sessions/new.html.erb diff --git a/lib/views/auth/spree/users/edit.html.erb b/app/views/spree/users/edit.html.erb similarity index 100% rename from lib/views/auth/spree/users/edit.html.erb rename to app/views/spree/users/edit.html.erb diff --git a/lib/views/auth/spree/users/show.html.erb b/app/views/spree/users/show.html.erb similarity index 100% rename from lib/views/auth/spree/users/show.html.erb rename to app/views/spree/users/show.html.erb diff --git a/lib/solidus_starter_frontend/engine.rb b/lib/solidus_starter_frontend/engine.rb index deacfb8b..fe66fe4d 100644 --- a/lib/solidus_starter_frontend/engine.rb +++ b/lib/solidus_starter_frontend/engine.rb @@ -24,10 +24,7 @@ class Engine < Rails::Engine Spree::UsersController ].each do |auth_controller| auth_controller.include SolidusStarterFrontend::Taxonomies - auth_controller.include SolidusStarterFrontend::AuthViews end - - Spree::StoreController.include SolidusStarterFrontend::AuthViews end end end diff --git a/lib/views/auth/spree/components/navigation/_auth_link.html.erb b/lib/views/auth/spree/components/navigation/_auth_link.html.erb deleted file mode 100644 index 5cbefaf3..00000000 --- a/lib/views/auth/spree/components/navigation/_auth_link.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -<% if spree_current_user %> - <%= link_to I18n.t('spree.my_account'), spree.account_path, class: 'auth-link' %> -<% else %> - <%= link_to I18n.t('spree.login'), spree.login_path, class: 'auth-link' %> -<% end %> From 9b287a7668bde3f5bd67591ca3a7225d422ea384 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:22:51 +0800 Subject: [PATCH 11/35] Update Edit Account form field identifiers Fixes ``` 1) Change email work with correct password Failure/Error: fill_in 'user_email', with: 'tests@example.com' Capybara::ElementNotFound: Unable to find field "user_email" that is not disabled # ./spec/features/change_email_spec.rb:19:in `block (2 levels) in ' ``` --- spec/features/change_email_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/change_email_spec.rb b/spec/features/change_email_spec.rb index c04ee5db..fee3c64e 100644 --- a/spec/features/change_email_spec.rb +++ b/spec/features/change_email_spec.rb @@ -16,9 +16,9 @@ end scenario 'work with correct password' do - fill_in 'user_email', with: 'tests@example.com' - fill_in 'user_password', with: 'password' - fill_in 'user_password_confirmation', with: 'password' + fill_in 'user[email]', with: 'tests@example.com' + fill_in 'user[password]', with: 'password' + fill_in 'user[password_confirmation]', with: 'password' click_button 'Update' expect(page).to have_text 'Account updated' From f86dd85c713c616962a43267496178b2636e71ed Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:44:00 +0800 Subject: [PATCH 12/35] Inline solidus_auth_devise CheckoutControllerDecorator to CheckoutController Fixes ``` 1) Checkout leaving and returning to address step Failure/Error: within '#guest_checkout' do fill_in 'Email', with: 'test@example.com' end Capybara::ElementNotFound: Unable to find css "#guest_checkout" # ./spec/features/checkout_spec.rb:36:in `block (2 levels) in ' ``` --- app/controllers/spree/checkout_controller.rb | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/app/controllers/spree/checkout_controller.rb b/app/controllers/spree/checkout_controller.rb index 17a72a1d..b4509050 100644 --- a/app/controllers/spree/checkout_controller.rb +++ b/app/controllers/spree/checkout_controller.rb @@ -16,10 +16,15 @@ class CheckoutController < Spree::StoreController before_action :ensure_valid_state before_action :associate_user + before_action :check_registration, except: [:registration, :update_registration] before_action :check_authorization before_action :setup_for_current_state, only: [:edit, :update] + # This action builds some associations on the order, ex. addresses, which we + # don't to build or save here. + skip_before_action :setup_for_current_state, only: [:registration, :update_registration] + helper 'spree/orders' rescue_from Spree::Core::GatewayError, with: :rescue_from_spree_gateway_error @@ -47,6 +52,20 @@ def update end end + def registration + @user = Spree::User.new + end + + def update_registration + if params[:order][:email] =~ Devise.email_regexp && current_order.update(email: params[:order][:email]) + redirect_to spree.checkout_path + else + flash[:registration_error] = t(:email_is_invalid, scope: [:errors, :messages]) + @user = Spree::User.new + render 'registration' + end + end + private def update_order @@ -240,5 +259,49 @@ def insufficient_stock_error end end end + + def order_params + params. + fetch(:order, {}). + permit(:email) + end + + def skip_state_validation? + %w(registration update_registration).include?(params[:action]) + end + + def check_authorization + authorize!(:edit, current_order, cookies.signed[:guest_token]) + end + + # Introduces a registration step whenever the +registration_step+ preference is true. + def check_registration + return unless registration_required? + + store_location + redirect_to spree.checkout_registration_path + end + + def registration_required? + Spree::Auth::Config[:registration_step] && + !already_registered? + end + + def already_registered? + spree_current_user || guest_authenticated? + end + + def guest_authenticated? + current_order&.email.present? && + Spree::Config[:allow_guest_checkout] + end + + # Overrides the equivalent method defined in Spree::Core. This variation of the method will ensure that users + # are redirected to the tokenized order url unless authenticated as a registered user. + def completion_route + return spree.order_path(@order) if spree_current_user + + spree.token_order_path(@order, @order.guest_token) + end end end From 8af71c1bcb2c28faea11aee7a5da910e5f5eb6b9 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:46:52 +0800 Subject: [PATCH 13/35] Remove overridden checkout controller methods --- app/controllers/spree/checkout_controller.rb | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/controllers/spree/checkout_controller.rb b/app/controllers/spree/checkout_controller.rb index b4509050..78b6d8a4 100644 --- a/app/controllers/spree/checkout_controller.rb +++ b/app/controllers/spree/checkout_controller.rb @@ -192,11 +192,6 @@ def ensure_sufficient_stock_lines end end - # Provides a route to redirect after order completion - def completion_route - spree.order_path(@order) - end - def setup_for_current_state method_name = :"before_#{@order.state}" send(method_name) if respond_to?(method_name, true) @@ -239,10 +234,6 @@ def rescue_from_spree_gateway_error(exception) render :edit end - def check_authorization - authorize!(:edit, current_order, cookies.signed[:guest_token]) - end - def insufficient_stock_error packages = @order.shipments.map(&:to_package) if packages.empty? From 75f0cf44907210a11458747e4f4e6f2a3dd1fd2e Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:47:57 +0800 Subject: [PATCH 14/35] Copy FillAddressFields Fixes ``` 1) Checkout without payment being required allow a visitor to checkout as guest, without registration Failure/Error: fill_addresses_fields_with(address) NoMethodError: undefined method `fill_addresses_fields_with' for # # ./spec/features/checkout_spec.rb:63:in `block (3 levels) in ' ``` --- .../support/features/fill_addresses_fields.rb | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 spec/support/features/fill_addresses_fields.rb diff --git a/spec/support/features/fill_addresses_fields.rb b/spec/support/features/fill_addresses_fields.rb new file mode 100644 index 00000000..8beb82a7 --- /dev/null +++ b/spec/support/features/fill_addresses_fields.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module FillAddressFields + def fill_addresses_fields_with(address) + fields = %w[ + address1 + city + zipcode + phone + ] + fields += if SolidusSupport.combined_first_and_last_name_in_address? + %w[name] + else + %w[firstname lastname] + end + + fields.each do |field| + fill_in "order_bill_address_attributes_#{field}", with: address.send(field).to_s + end + select 'United States', from: "order_bill_address_attributes_country_id" + select address.state.name.to_s, from: "order_bill_address_attributes_state_id" + + check 'order_use_billing' + end +end + +RSpec.configure do |config| + config.include FillAddressFields, type: :feature +end From 30d1119724a26ca89ee0ca033f5fef8928e405d4 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:51:42 +0800 Subject: [PATCH 15/35] Copy solidus_auth_devise UserMailer with views Fixes ``` 1) Checkout without payment being required associate an incomplete guest order with user after successful password reset Got 0 failures and 2 other errors: 1.1) Failure/Error: token = token_url_regex.match(reset_password_email.body.to_s)[1] NoMethodError: undefined method `body' for nil:NilClass # ./spec/features/checkout_spec.rb:115:in `block (3 levels) in ' 1.2) Failure/Error: self.resource = resource_class.send_reset_password_instructions(params[resource_name]) ActionView::MissingTemplate: Missing template spree/user_mailer/reset_password_instructions with "mailer". Searched in: * "spree/user_mailer" # ./app/controllers/spree/user_passwords_controller.rb:19:in `create' # ------------------ # --- Caused by: --- # Capybara::CapybaraError: # Your application server raised an error - It has been raised in your test code because Capybara.raise_server_errors == true # /home/gsmendoza/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/capybara-3.35.3/lib/capybara/session.rb:160:in `raise_server_error!' ``` --- app/mailers/spree/user_mailer.rb | 17 +++++++++++++++++ .../confirmation_instructions.text.erb | 5 +++++ .../reset_password_instructions.text.erb | 10 ++++++++++ 3 files changed, 32 insertions(+) create mode 100644 app/mailers/spree/user_mailer.rb create mode 100644 app/views/spree/user_mailer/confirmation_instructions.text.erb create mode 100644 app/views/spree/user_mailer/reset_password_instructions.text.erb diff --git a/app/mailers/spree/user_mailer.rb b/app/mailers/spree/user_mailer.rb new file mode 100644 index 00000000..2ee9f3b3 --- /dev/null +++ b/app/mailers/spree/user_mailer.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module Spree + class UserMailer < BaseMailer + def reset_password_instructions(user, token, *_args) + @store = Spree::Store.default + @edit_password_reset_url = spree.edit_spree_user_password_url(reset_password_token: token, host: @store.url) + mail to: user.email, from: from_address(@store), subject: "#{@store.name} #{I18n.t(:subject, scope: [:devise, :mailer, :reset_password_instructions])}" + end + + def confirmation_instructions(user, token, _opts = {}) + @store = Spree::Store.default + @confirmation_url = spree.spree_user_confirmation_url(confirmation_token: token, host: @store.url) + mail to: user.email, from: from_address(@store), subject: "#{@store.name} #{I18n.t(:subject, scope: [:devise, :mailer, :confirmation_instructions])}" + end + end +end diff --git a/app/views/spree/user_mailer/confirmation_instructions.text.erb b/app/views/spree/user_mailer/confirmation_instructions.text.erb new file mode 100644 index 00000000..39832a34 --- /dev/null +++ b/app/views/spree/user_mailer/confirmation_instructions.text.erb @@ -0,0 +1,5 @@ +Welcome <%= @email %>! + +You can confirm your account email through the link below: + +<%= link_to 'Confirm my account', @confirmation_url %> \ No newline at end of file diff --git a/app/views/spree/user_mailer/reset_password_instructions.text.erb b/app/views/spree/user_mailer/reset_password_instructions.text.erb new file mode 100644 index 00000000..148526ce --- /dev/null +++ b/app/views/spree/user_mailer/reset_password_instructions.text.erb @@ -0,0 +1,10 @@ +A request to reset your password has been made. +If you did not make this request, simply ignore this email. + +If you did make this request just click the link below: + +<%= @edit_password_reset_url %> + +If the above URL does not work try copying and pasting it into your browser. +If you continue to have problems please feel free to contact us. + From 7a73d89746519079fe50229363d801ff1a94e84f Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:55:09 +0800 Subject: [PATCH 16/35] Fix spec "allow a user to register during checkout" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes ``` 1) Checkout without payment being required allow a user to register during checkout Failure/Error: expect(page).to have_text 'Registration' expected to find text "Registration" in "Search\nLOGIN\nCART: (1) $19.99\nLogin as Existing Customer\nEmail:\nPassword:\nRemember me\nLogin\nor Create a new account | Forgot Password?\nCheckout as a Guest\nEmail:\nContinue\nor Create a new account\nPowered by Solidus\nLanguage:\nCastellano (ES)\nCatalà\nDanish\nDeutsch (DE)\nDeutsch (Schweiz)\nEesti keel\nEnglish (Australia)\nEnglish (IN)\nEnglish (New Zealand)\nEnglish (UK)\nEnglish (US)\nEspañol\nEspañol (Chile)\nEspañol (México)\nFrançais (FR)\nIndonesian (ID)\nItaliano (IT)\nLatvijas (LV)\nNederlands (NL)\nNorsk\nPolski (PL)\nPortuguês (BR)\nPortuguês (PT)\nRomanian (RO)\nSlovenčina\nSlovenščina (SL)\nSuomi\nSvenska (SE)\nTürkçe (TR)\nUkrainian\ntiếng Việt (VN)\nČeština (CS)\nБългарски (БГ)\nРусский (RU)\nفارسی(fa)\nภาษาไทย (TH)\n中文 (繁體)\n中文(简体)\n日本語 (ja-JP)\n한국어 (KO)" # ./spec/features/checkout_spec.rb:136:in `block (3 levels) in ' ``` --- spec/features/checkout_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/checkout_spec.rb b/spec/features/checkout_spec.rb index fbd76a53..e7992049 100644 --- a/spec/features/checkout_spec.rb +++ b/spec/features/checkout_spec.rb @@ -133,9 +133,9 @@ click_button 'Add To Cart' click_button 'Checkout' - expect(page).to have_text 'Registration' - - click_link 'Create a new account' + within '#existing-customer' do + click_link 'Create a new account' + end fill_in 'Email', with: 'email@person.com' fill_in 'Password:', with: 'spree123' From bc668cee610997bc13e4e3cffa54765111af5f61 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 17:58:18 +0800 Subject: [PATCH 17/35] Fix "Sign In let a user sign in successfully" spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes ``` 1) Sign In let a user sign in successfully Failure/Error: expect(page).to have_text 'Logout' expected to find text "Logout" in "All departments Search\nMy Account\nCart\nLogged in successfully\nThe only eCommerce platform you’ll ever need.\nBuild, customize and scale your store with no limits or license fees. Solidus is the free, open-source eCommerce framework for digitally-native brands, fast-growing online businesses and pragmatic developers.\nNo products found\nPowered by Solidus\nLanguage: Castellano (ES) Català Danish Deutsch (DE) Deutsch (Schweiz) Eesti keel English (Australia) English (IN) English (New Zealand) English (UK) English (US) Español Español (Chile) Español (México) Français (FR) Indonesian (ID) Italiano (IT) Latvijas (LV) Nederlands (NL) Norsk Polski (PL) Português (BR) Português (PT) Romanian (RO) Slovenčina Slovenščina (SL) Suomi Svenska (SE) Türkçe (TR) Ukrainian tiếng Việt (VN) Čeština (CS) Български (БГ) Русский (RU) فارسی(fa) ภาษาไทย (TH) 中文 (繁體) 中文(简体) 日本語 (ja-JP) 한국어 (KO)" # ./spec/features/sign_in_spec.rb:16:in `block (2 levels) in ' ``` --- spec/features/sign_in_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/sign_in_spec.rb b/spec/features/sign_in_spec.rb index bc59a656..c62635b1 100644 --- a/spec/features/sign_in_spec.rb +++ b/spec/features/sign_in_spec.rb @@ -13,7 +13,7 @@ expect(page).to have_text 'Logged in successfully' expect(page).not_to have_text 'Login' - expect(page).to have_text 'Logout' + expect(page).to have_text 'My Account' expect(current_path).to eq '/' end From c873a105a258a3f78a1f662159c58be209face82 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 18:01:33 +0800 Subject: [PATCH 18/35] Copy unauthorized_redirect from solidus_auth_devise Fixes "Authorization Failure" error displayed on sign-in. Fixes ``` 1) Sign In should store the user previous location Failure/Error: fill_in "Email", with: @user.email Capybara::ElementNotFound: Unable to find field "Email" that is not disabled # ./spec/features/sign_in_spec.rb:31:in `block (2 levels) in ' ``` --- lib/solidus_starter_frontend/engine.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/solidus_starter_frontend/engine.rb b/lib/solidus_starter_frontend/engine.rb index fe66fe4d..61f34ca3 100644 --- a/lib/solidus_starter_frontend/engine.rb +++ b/lib/solidus_starter_frontend/engine.rb @@ -26,6 +26,26 @@ class Engine < Rails::Engine auth_controller.include SolidusStarterFrontend::Taxonomies end end + + Spree::BaseController.unauthorized_redirect = -> do + if try_spree_current_user + flash[:error] = I18n.t('spree.authorization_failure') + + if Spree::Auth::Engine.redirect_back_on_unauthorized? + redirect_back(fallback_location: spree.unauthorized_path) + else + redirect_to spree.unauthorized_path + end + else + store_location + + if Spree::Auth::Engine.redirect_back_on_unauthorized? + redirect_back(fallback_location: spree.login_path) + else + redirect_to spree.login_path + end + end + end end end end From f9e1b49d1f68febceb077bb2eceb9065022ecd8e Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Tue, 27 Jul 2021 18:03:43 +0800 Subject: [PATCH 19/35] Fix 'allow a signed in user to logout' spec Fixes ``` 1) Sign Out allow a signed in user to logout Failure/Error: click_link 'Logout' Capybara::ElementNotFound: Unable to find link "Logout" # ./spec/features/sign_out_spec.rb:21:in `block (2 levels) in ' ``` --- spec/features/sign_out_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/features/sign_out_spec.rb b/spec/features/sign_out_spec.rb index 92e8a640..a76784cf 100644 --- a/spec/features/sign_out_spec.rb +++ b/spec/features/sign_out_spec.rb @@ -18,7 +18,8 @@ end scenario 'allow a signed in user to logout' do - click_link 'Logout' + click_link 'My Account' + click_button 'Logout' visit spree.root_path expect(page).to have_text 'LOGIN' expect(page).not_to have_text 'LOGOUT' From 3828604f6f4e56b16333826b1b059a9b0854ac6f Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 28 Jul 2021 14:45:30 +0800 Subject: [PATCH 20/35] Fix system specs that require checking out as guest --- spec/support/system_helpers.rb | 11 +++++++++++ spec/system/address_spec.rb | 12 ++++++------ spec/system/checkout_spec.rb | 19 +++++++++++-------- spec/system/coupon_code_spec.rb | 4 +++- spec/system/first_order_promotion_spec.rb | 4 +++- spec/system/free_shipping_promotions_spec.rb | 4 +++- spec/system/products_spec.rb | 5 ++++- 7 files changed, 41 insertions(+), 18 deletions(-) create mode 100644 spec/support/system_helpers.rb diff --git a/spec/support/system_helpers.rb b/spec/support/system_helpers.rb new file mode 100644 index 00000000..3145ecbb --- /dev/null +++ b/spec/support/system_helpers.rb @@ -0,0 +1,11 @@ +module SystemHelpers + def checkout_as_guest + click_button "Checkout" + + within '#guest_checkout' do + fill_in 'Email', with: 'test@example.com' + end + + click_on 'Continue' + end +end diff --git a/spec/system/address_spec.rb b/spec/system/address_spec.rb index 8d35b144..01788f9c 100644 --- a/spec/system/address_spec.rb +++ b/spec/system/address_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe 'Address', type: :system, inaccessible: true do + include SystemHelpers + let!(:product) { create(:product, name: "RoR Mug") } let!(:order) { create(:order_with_totals, state: 'cart') } - stub_authorization! - before do visit spree.root_path @@ -27,7 +27,7 @@ context 'but has no state' do it 'shows the state input field' do - click_button 'Checkout' + checkout_as_guest within('#billing') do select canada.name, from: 'Country' @@ -41,7 +41,7 @@ before { create(:state, name: 'Ontario', country: canada) } it 'shows the state collection selection' do - click_button 'Checkout' + checkout_as_guest within('#billing') do select canada.name, from: 'Country' @@ -55,7 +55,7 @@ let!(:france) { create(:country, name: 'France', states_required: false, iso: 'FR') } it 'clears the state name' do - click_button 'Checkout' + checkout_as_guest within('#billing') do select canada.name, from: 'Country' @@ -74,7 +74,7 @@ let!(:france) { create(:country, name: 'France', states_required: false, iso: 'FR') } it 'shows a disabled state input field' do - click_button 'Checkout' + checkout_as_guest within('#billing') do select france.name, from: 'Country' diff --git a/spec/system/checkout_spec.rb b/spec/system/checkout_spec.rb index f0896013..13e34d9f 100644 --- a/spec/system/checkout_spec.rb +++ b/spec/system/checkout_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe 'Checkout', type: :system, inaccessible: true do + include SystemHelpers + include_context 'checkout setup' context "visitor makes checkout as guest without registration" do @@ -50,7 +52,7 @@ it "does not break the per-item shipping method calculator", js: true do add_mug_to_cart - click_button "Checkout" + checkout_as_guest fill_in "order_email", with: "test@example.com" fill_in_address @@ -66,7 +68,7 @@ context "free shipping" do before do add_mug_to_cart - click_button "Checkout" + checkout_as_guest end it "should not show 'Free Shipping' when there are no shipments", js: true do @@ -147,7 +149,7 @@ context "and proceeds with guest checkout" do it 'shows empty addresses', js: true do add_mug_to_cart - click_button "Checkout" + checkout_as_guest within("#billing") do expect(find_field('Name').value).to be_blank @@ -383,7 +385,7 @@ it "transit nicely through checkout steps again" do add_mug_to_cart - click_on "Checkout" + checkout_as_guest fill_in "order_email", with: "test@example.com" fill_in_address click_on "Save and Continue" @@ -409,7 +411,7 @@ context "from payment step customer goes back to cart", js: true do before do add_mug_to_cart - click_on "Checkout" + checkout_as_guest fill_in "order_email", with: "test@example.com" fill_in_address click_on "Save and Continue" @@ -474,7 +476,7 @@ promotion.actions << action add_mug_to_cart - click_on "Checkout" + checkout_as_guest fill_in "order_email", with: "test@example.com" fill_in_address @@ -611,6 +613,7 @@ it "displays the entered state name without evaluating" do add_mug_to_cart + checkout_as_guest visit spree.checkout_state_path(:address) fill_in_address fill_in 'Customer E-Mail', with: 'test@example.com' @@ -644,7 +647,7 @@ it "works with card number 1", js: true do add_mug_to_cart - click_on "Checkout" + checkout_as_guest fill_in "order_email", with: "test@example.com" fill_in_address click_on "Save and Continue" @@ -659,7 +662,7 @@ it "works with card number 4111111111111111", js: true do add_mug_to_cart - click_on "Checkout" + checkout_as_guest fill_in "order_email", with: "test@example.com" fill_in_address click_on "Save and Continue" diff --git a/spec/system/coupon_code_spec.rb b/spec/system/coupon_code_spec.rb index b91851c7..81933718 100644 --- a/spec/system/coupon_code_spec.rb +++ b/spec/system/coupon_code_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe 'Coupon code promotions', type: :system, js: true do + include SystemHelpers + let!(:store) { create(:store) } let!(:country) { create(:country, name: "United States of America", states_required: true) } let!(:state) { create(:state, name: "Alabama", country: country) } @@ -40,7 +42,7 @@ def create_basic_coupon_promotion(code) visit spree.root_path click_link "RoR Mug" click_button "add-to-cart-button" - click_button "Checkout" + checkout_as_guest fill_in "order_email", with: "spree@example.com" fill_in "Name", with: "John Smith" fill_in 'Street Address:', with: '1 John Street' diff --git a/spec/system/first_order_promotion_spec.rb b/spec/system/first_order_promotion_spec.rb index abfd9954..a3270970 100644 --- a/spec/system/first_order_promotion_spec.rb +++ b/spec/system/first_order_promotion_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe 'First Order promotion', type: :system do + include SystemHelpers + let!(:promotion) do FactoryBot.create( :promotion_with_first_order_rule, @@ -39,7 +41,7 @@ fill_in "Coupon code", with: "FIRSTONEFREE" click_button "Apply Code" expect(page).to have_content("The coupon code was successfully applied to your order") - click_on "Checkout" + checkout_as_guest fill_in "Customer E-Mail", with: "sam@tom.com" fill_in_address click_on "Save and Continue" diff --git a/spec/system/free_shipping_promotions_spec.rb b/spec/system/free_shipping_promotions_spec.rb index 92494b96..1a5077fc 100644 --- a/spec/system/free_shipping_promotions_spec.rb +++ b/spec/system/free_shipping_promotions_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe 'Free shipping promotions', type: :system, js: true do + include SystemHelpers + let!(:store) { create(:store) } let!(:country) { create(:country, name: "United States of America", states_required: true) } let!(:state) { create(:state, name: "Alabama", country: country) } @@ -32,7 +34,7 @@ visit spree.root_path click_link "RoR Mug" click_button "add-to-cart-button" - click_button "Checkout" + checkout_as_guest fill_in "order_email", with: "spree@example.com" fill_in "Name", with: "John Smith" fill_in 'Street Address:', with: '1 John Street' diff --git a/spec/system/products_spec.rb b/spec/system/products_spec.rb index 7a16bf34..e75df055 100644 --- a/spec/system/products_spec.rb +++ b/spec/system/products_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' describe 'Visiting Products', type: :system, inaccessible: true do + include SystemHelpers + include_context "custom products" let(:store_name) do @@ -136,7 +138,8 @@ it "when on the 'address' state of the cart", js: true do visit spree.product_path(product) click_button 'Add To Cart' - click_button 'Checkout' + checkout_as_guest + within('#item-total') do expect(page).to have_content('19.99 ₽') end From b5e0ebb9441c3d6c9b50cdafa3e0f827bbf5cf9c Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 28 Jul 2021 15:06:58 +0800 Subject: [PATCH 21/35] Fix expected completion routes in checkout specs --- spec/system/checkout_spec.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/system/checkout_spec.rb b/spec/system/checkout_spec.rb index 13e34d9f..bd683816 100644 --- a/spec/system/checkout_spec.rb +++ b/spec/system/checkout_spec.rb @@ -362,8 +362,9 @@ click_on "Save and Continue" click_on "Place Order" - expect(page).to have_current_path(spree.order_path(Spree::Order.last)) - expect(page).to have_current_path(spree.order_path(Spree::Order.last)) + + order = Spree::Order.last + expect(page).to have_current_path(spree.token_order_path(order, order.guest_token)) expect(page).to have_content("Ending in #{credit_card.last_digits}") end @@ -373,7 +374,9 @@ click_on "Save and Continue" click_on "Place Order" - expect(page).to have_current_path(spree.order_path(Spree::Order.last)) + + order = Spree::Order.last + expect(page).to have_current_path(spree.token_order_path(order, order.guest_token)) expect(page).to have_content('Ending in 1111') end end @@ -404,7 +407,8 @@ click_on "Save and Continue" click_on "Place Order" - expect(page).to have_current_path(spree.order_path(Spree::Order.last)) + order = Spree::Order.last + expect(page).to have_current_path(spree.token_order_path(order, order.guest_token)) end end From e00751a37301bbeeb18ba6125cd344006448a667 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 28 Jul 2021 15:16:50 +0800 Subject: [PATCH 22/35] Update specs for unauthorized order requests --- spec/requests/spree/orders_ability_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/requests/spree/orders_ability_spec.rb b/spec/requests/spree/orders_ability_spec.rb index 27b84235..b9d33b47 100644 --- a/spec/requests/spree/orders_ability_spec.rb +++ b/spec/requests/spree/orders_ability_spec.rb @@ -17,35 +17,35 @@ context '#populate' do it 'checks if user is authorized for :update' do post spree.populate_orders_path, params: { variant_id: variant.id } - expect(response).to redirect_to :unauthorized + expect(response).to redirect_to(spree.login_path) end end context '#edit' do it 'checks if user is authorized for :read' do get spree.cart_path - expect(response).to redirect_to :unauthorized + expect(response).to redirect_to(spree.login_path) end end context '#update' do it 'checks if user is authorized for :update' do put spree.order_path(order.number), params: { order: { email: "foo@bar.com" } } - expect(response).to redirect_to :unauthorized + expect(response).to redirect_to(spree.login_path) end end context '#empty' do it 'checks if user is authorized for :update' do put spree.empty_cart_path - expect(response).to redirect_to :unauthorized + expect(response).to redirect_to(spree.login_path) end end context "#show" do it "checks against the specified order" do get spree.order_path(id: order.number) - expect(response).to redirect_to :unauthorized + expect(response).to redirect_to(spree.login_path) end end end From 4ec315bf125c2fd3541d56cd7b14960aeac3a7c3 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 28 Jul 2021 16:22:27 +0800 Subject: [PATCH 23/35] Convert authentication feature specs to system specs --- spec/support/features/fill_addresses_fields.rb | 2 +- spec/{features => system/authentication}/account_spec.rb | 2 +- spec/{features => system/authentication}/change_email_spec.rb | 2 +- spec/{features => system/authentication}/checkout_spec.rb | 2 +- spec/{features => system/authentication}/confirmation_spec.rb | 0 spec/{features => system/authentication}/password_reset_spec.rb | 2 +- spec/{features => system/authentication}/sign_in_spec.rb | 2 +- spec/{features => system/authentication}/sign_out_spec.rb | 2 +- spec/{features => system/authentication}/sign_up_spec.rb | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename spec/{features => system/authentication}/account_spec.rb (97%) rename spec/{features => system/authentication}/change_email_spec.rb (93%) rename spec/{features => system/authentication}/checkout_spec.rb (99%) rename spec/{features => system/authentication}/confirmation_spec.rb (100%) rename spec/{features => system/authentication}/password_reset_spec.rb (95%) rename spec/{features => system/authentication}/sign_in_spec.rb (95%) rename spec/{features => system/authentication}/sign_out_spec.rb (91%) rename spec/{features => system/authentication}/sign_up_spec.rb (95%) diff --git a/spec/support/features/fill_addresses_fields.rb b/spec/support/features/fill_addresses_fields.rb index 8beb82a7..5ff6961a 100644 --- a/spec/support/features/fill_addresses_fields.rb +++ b/spec/support/features/fill_addresses_fields.rb @@ -25,5 +25,5 @@ def fill_addresses_fields_with(address) end RSpec.configure do |config| - config.include FillAddressFields, type: :feature + config.include FillAddressFields, type: :system end diff --git a/spec/features/account_spec.rb b/spec/system/authentication/account_spec.rb similarity index 97% rename from spec/features/account_spec.rb rename to spec/system/authentication/account_spec.rb index 11261758..bca76357 100644 --- a/spec/features/account_spec.rb +++ b/spec/system/authentication/account_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.feature 'Accounts', type: :feature do +RSpec.feature 'Accounts', type: :system do context 'editing' do scenario 'can edit an admin user' do user = create(:admin_user, email: 'admin@person.com', password: 'password', password_confirmation: 'password') diff --git a/spec/features/change_email_spec.rb b/spec/system/authentication/change_email_spec.rb similarity index 93% rename from spec/features/change_email_spec.rb rename to spec/system/authentication/change_email_spec.rb index fee3c64e..482977b1 100644 --- a/spec/features/change_email_spec.rb +++ b/spec/system/authentication/change_email_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.feature 'Change email', type: :feature do +RSpec.feature 'Change email', type: :system do background do stub_spree_preferences(Spree::Auth::Config, signout_after_password_change: false) diff --git a/spec/features/checkout_spec.rb b/spec/system/authentication/checkout_spec.rb similarity index 99% rename from spec/features/checkout_spec.rb rename to spec/system/authentication/checkout_spec.rb index e7992049..56bcbda8 100644 --- a/spec/features/checkout_spec.rb +++ b/spec/system/authentication/checkout_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.feature 'Checkout', :js, type: :feature do +RSpec.feature 'Checkout', :js, type: :system do given!(:store) { create(:store) } given!(:country) { create(:country, name: 'United States', states_required: true) } given!(:state) { create(:state, name: 'Maryland', country: country) } diff --git a/spec/features/confirmation_spec.rb b/spec/system/authentication/confirmation_spec.rb similarity index 100% rename from spec/features/confirmation_spec.rb rename to spec/system/authentication/confirmation_spec.rb diff --git a/spec/features/password_reset_spec.rb b/spec/system/authentication/password_reset_spec.rb similarity index 95% rename from spec/features/password_reset_spec.rb rename to spec/system/authentication/password_reset_spec.rb index 70ee7a8d..b7fd2b75 100644 --- a/spec/features/password_reset_spec.rb +++ b/spec/system/authentication/password_reset_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.feature 'Reset Password', type: :feature do +RSpec.feature 'Reset Password', type: :system do let!(:store) { create(:store) } background do diff --git a/spec/features/sign_in_spec.rb b/spec/system/authentication/sign_in_spec.rb similarity index 95% rename from spec/features/sign_in_spec.rb rename to spec/system/authentication/sign_in_spec.rb index c62635b1..7a3c0b15 100644 --- a/spec/features/sign_in_spec.rb +++ b/spec/system/authentication/sign_in_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.feature 'Sign In', type: :feature do +RSpec.feature 'Sign In', type: :system do background do @user = create(:user, email: 'email@person.com', password: 'secret', password_confirmation: 'secret') visit spree.login_path diff --git a/spec/features/sign_out_spec.rb b/spec/system/authentication/sign_out_spec.rb similarity index 91% rename from spec/features/sign_out_spec.rb rename to spec/system/authentication/sign_out_spec.rb index a76784cf..805430e0 100644 --- a/spec/features/sign_out_spec.rb +++ b/spec/system/authentication/sign_out_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.feature 'Sign Out', type: :feature, js: true do +RSpec.feature 'Sign Out', type: :system, js: true do given!(:user) do create(:user, email: 'email@person.com', diff --git a/spec/features/sign_up_spec.rb b/spec/system/authentication/sign_up_spec.rb similarity index 95% rename from spec/features/sign_up_spec.rb rename to spec/system/authentication/sign_up_spec.rb index 2a19519b..50857b90 100644 --- a/spec/features/sign_up_spec.rb +++ b/spec/system/authentication/sign_up_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.feature 'Sign Up', type: :feature do +RSpec.feature 'Sign Up', type: :system do context 'with valid data' do scenario 'create a new user' do visit spree.signup_path From 4165a327b833cc7ff1096dd63e793c9b05bb63af Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 28 Jul 2021 16:27:27 +0800 Subject: [PATCH 24/35] Include Devise::Test::ControllerHelpers in controller spec Fixes ``` 1) Spree::ProductsController sets the default locale based off SolidusStarterFrontend::Config[:locale] Failure/Error: @searcher = build_searcher(params.merge(include_images: true)) Devise::MissingWarden: Devise could not find the `Warden::Proxy` instance on your request environment. Make sure that your application is loading Devise and Warden as expected and that the `Warden::Manager` middleware is present in your middleware stack. If you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the `Devise::Test::ControllerHelpers` module to inject the `request.env['warden']` object for you. # ./app/controllers/spree/products_controller.rb:13:in `index' # ./spec/controllers/controller_helpers_spec.rb:26:in `block (2 levels) in ' ``` --- spec/controllers/controller_helpers_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/controllers/controller_helpers_spec.rb b/spec/controllers/controller_helpers_spec.rb index 00643224..1a1083dc 100644 --- a/spec/controllers/controller_helpers_spec.rb +++ b/spec/controllers/controller_helpers_spec.rb @@ -6,6 +6,8 @@ # So we need to use one of the controllers inside Spree. # ProductsController is good. describe Spree::ProductsController, type: :controller do + include Devise::Test::ControllerHelpers + before do I18n.enforce_available_locales = false stub_spree_preferences(SolidusStarterFrontend::Config, locale: :de) From 58dc7a8faa7c03225b3ececbf93f2c0ad4a14eb6 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 28 Jul 2021 18:30:15 +0800 Subject: [PATCH 25/35] [FIXES TEST SUITE] Sign in to request specs using Devise::Test::IntegrationHelpers Fixes intermittent system spec failures caused the mocks in the with_signed_in_user handler. --- spec/requests/spree/checkout_spec.rb | 1 + spec/requests/spree/home_spec.rb | 2 +- spec/requests/spree/products_spec.rb | 4 ++-- spec/requests/spree/taxons_spec.rb | 2 +- spec/spec_helper.rb | 10 +++------- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/spec/requests/spree/checkout_spec.rb b/spec/requests/spree/checkout_spec.rb index da4aba86..b2059ea4 100644 --- a/spec/requests/spree/checkout_spec.rb +++ b/spec/requests/spree/checkout_spec.rb @@ -309,6 +309,7 @@ def post_persist_address end context "when current_order id nil" do + let(:user) { create(:user) } let(:order) { create(:order_with_line_items, guest_token: nil, user_id: nil) } it "redirects to the cart_path" do diff --git a/spec/requests/spree/home_spec.rb b/spec/requests/spree/home_spec.rb index 60f038d7..d06aabe1 100644 --- a/spec/requests/spree/home_spec.rb +++ b/spec/requests/spree/home_spec.rb @@ -4,7 +4,7 @@ describe 'Home layout', type: :request, with_signed_in_user: true do let(:searcher_class) { instance_double(Spree::Config.searcher_class) } - let(:user) { mock_model(Spree.user_class) } + let(:user) { create(:user) } let(:product) { build_stubbed(:product) } before do diff --git a/spec/requests/spree/products_spec.rb b/spec/requests/spree/products_spec.rb index 84db7dd5..50879c4c 100644 --- a/spec/requests/spree/products_spec.rb +++ b/spec/requests/spree/products_spec.rb @@ -4,7 +4,7 @@ describe 'Product', type: :request, with_signed_in_user: true do let!(:product) { create(:product, available_on: 1.year.from_now) } - let(:user) { mock_model(Spree.user_class) } + let(:user) { create(:user) } context 'when not admin user' do it "cannot view non-active products" do @@ -22,7 +22,7 @@ end context 'when an admin' do - let(:user) { mock_model(Spree.user_class, has_spree_role?: 'admin', spree_api_key: 'fake') } + let(:user) { create(:admin_user) } # Regression test for https://github.com/spree/spree/issues/1390 it "allows admins to view non-active products" do diff --git a/spec/requests/spree/taxons_spec.rb b/spec/requests/spree/taxons_spec.rb index b00313ba..a86a4d2f 100644 --- a/spec/requests/spree/taxons_spec.rb +++ b/spec/requests/spree/taxons_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Taxon', type: :request, with_signed_in_user: true do - let(:user) { mock_model(Spree.user_class, has_spree_role?: 'admin', spree_api_key: 'fake') } + let(:user) { create(:admin_user) } it "provides the current user to the searcher class" do taxon = create(:taxon, permalink: "test") diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 06fb45ca..d554b326 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -48,14 +48,10 @@ config.include Spree::TestingSupport::Translations end - config.before(:each, with_signed_in_user: true) do - Spree::StoreController.define_method(:spree_current_user) do - Spree.user_class.find_by(spree_api_key: 'fake api key') - end + config.include Devise::Test::IntegrationHelpers, type: :request - allow(Spree.user_class).to receive(:find_by) - .with(hash_including(:spree_api_key)) - .and_return(user) + config.before(:each, with_signed_in_user: true) do + sign_in(user) end config.before(:each, with_guest_session: true) do From 0940006d81704168fb767183a3327d563d8cd6bc Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 28 Jul 2021 18:42:16 +0800 Subject: [PATCH 26/35] Inline inclusion of Taxonomies to auth_devise controllers --- .../spree/user_confirmations_controller.rb | 1 + app/controllers/spree/user_passwords_controller.rb | 1 + .../spree/user_registrations_controller.rb | 1 + app/controllers/spree/user_sessions_controller.rb | 1 + app/controllers/spree/users_controller.rb | 1 + lib/solidus_starter_frontend/engine.rb | 12 ------------ 6 files changed, 5 insertions(+), 12 deletions(-) diff --git a/app/controllers/spree/user_confirmations_controller.rb b/app/controllers/spree/user_confirmations_controller.rb index 41bace4a..86e2bb62 100644 --- a/app/controllers/spree/user_confirmations_controller.rb +++ b/app/controllers/spree/user_confirmations_controller.rb @@ -7,6 +7,7 @@ class Spree::UserConfirmationsController < Devise::ConfirmationsController include Spree::Core::ControllerHelpers::Common include Spree::Core::ControllerHelpers::Order include Spree::Core::ControllerHelpers::Store + include SolidusStarterFrontend::Taxonomies protected diff --git a/app/controllers/spree/user_passwords_controller.rb b/app/controllers/spree/user_passwords_controller.rb index 80d24d53..3c2563f8 100644 --- a/app/controllers/spree/user_passwords_controller.rb +++ b/app/controllers/spree/user_passwords_controller.rb @@ -7,6 +7,7 @@ class Spree::UserPasswordsController < Devise::PasswordsController include Spree::Core::ControllerHelpers::Common include Spree::Core::ControllerHelpers::Order include Spree::Core::ControllerHelpers::Store + include SolidusStarterFrontend::Taxonomies # Overridden due to bug in Devise. # respond_with resource, location: new_session_path(resource_name) diff --git a/app/controllers/spree/user_registrations_controller.rb b/app/controllers/spree/user_registrations_controller.rb index b1b42195..0ef1478f 100644 --- a/app/controllers/spree/user_registrations_controller.rb +++ b/app/controllers/spree/user_registrations_controller.rb @@ -7,6 +7,7 @@ class Spree::UserRegistrationsController < Devise::RegistrationsController include Spree::Core::ControllerHelpers::Common include Spree::Core::ControllerHelpers::Order include Spree::Core::ControllerHelpers::Store + include SolidusStarterFrontend::Taxonomies before_action :check_permissions, only: [:edit, :update] skip_before_action :require_no_authentication diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb index dfa67d99..28d8fee1 100644 --- a/app/controllers/spree/user_sessions_controller.rb +++ b/app/controllers/spree/user_sessions_controller.rb @@ -7,6 +7,7 @@ class Spree::UserSessionsController < Devise::SessionsController include Spree::Core::ControllerHelpers::Common include Spree::Core::ControllerHelpers::Order include Spree::Core::ControllerHelpers::Store + include SolidusStarterFrontend::Taxonomies # This is included in ControllerHelpers::Order. We just want to call # it after someone has successfully logged in. diff --git a/app/controllers/spree/users_controller.rb b/app/controllers/spree/users_controller.rb index 81ecc60b..89ced38b 100644 --- a/app/controllers/spree/users_controller.rb +++ b/app/controllers/spree/users_controller.rb @@ -6,6 +6,7 @@ class Spree::UsersController < Spree::StoreController prepend_before_action :authorize_actions, only: :new include Spree::Core::ControllerHelpers + include SolidusStarterFrontend::Taxonomies def show @orders = @user.orders.complete.order('completed_at desc') diff --git a/lib/solidus_starter_frontend/engine.rb b/lib/solidus_starter_frontend/engine.rb index 61f34ca3..6a6fba78 100644 --- a/lib/solidus_starter_frontend/engine.rb +++ b/lib/solidus_starter_frontend/engine.rb @@ -15,18 +15,6 @@ class Engine < Rails::Engine end config.to_prepare do - if defined?(Spree::Auth::Engine) - [ - Spree::UserConfirmationsController, - Spree::UserPasswordsController, - Spree::UserRegistrationsController, - Spree::UserSessionsController, - Spree::UsersController - ].each do |auth_controller| - auth_controller.include SolidusStarterFrontend::Taxonomies - end - end - Spree::BaseController.unauthorized_redirect = -> do if try_spree_current_user flash[:error] = I18n.t('spree.authorization_failure') From 40cb47435a2094b540a546bb538996faa04e396c Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Thu, 29 Jul 2021 08:27:56 +0800 Subject: [PATCH 27/35] Ignore solidus_auth_devise controllers on solidus_compare --- config/solidus_compare.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/solidus_compare.yml b/config/solidus_compare.yml index f03eb4d5..bae2902f 100644 --- a/config/solidus_compare.yml +++ b/config/solidus_compare.yml @@ -9,6 +9,18 @@ source_base_path: frontend/ ignore: - path: app/controllers diffs: + - file: frontend/app/controllers/spree/checkout_controller.rb + skip: true + - file: app/controllers/spree/user_confirmations_controller.rb + skip: true + - file: app/controllers/spree/user_passwords_controller.rb + skip: true + - file: app/controllers/spree/user_registrations_controller.rb + skip: true + - file: app/controllers/spree/users_controller.rb + skip: true + - file: app/controllers/spree/user_sessions_controller.rb + skip: true - file: app/controllers/concerns/solidus_starter_frontend/auth_views.rb skip: true - file: app/controllers/concerns/solidus_starter_frontend/taxonomies.rb From 70c3713cb2059fd4f99fc2dc5dc9d481dcaf787f Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Thu, 29 Jul 2021 08:29:26 +0800 Subject: [PATCH 28/35] Remove auth_views from solidus_compare --- config/solidus_compare.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/solidus_compare.yml b/config/solidus_compare.yml index bae2902f..0d1320e0 100644 --- a/config/solidus_compare.yml +++ b/config/solidus_compare.yml @@ -21,8 +21,6 @@ ignore: skip: true - file: app/controllers/spree/user_sessions_controller.rb skip: true - - file: app/controllers/concerns/solidus_starter_frontend/auth_views.rb - skip: true - file: app/controllers/concerns/solidus_starter_frontend/taxonomies.rb skip: true - hash: 1422395649 From 774c6b75037a8132795fe46e65c4e289033353fe Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Thu, 29 Jul 2021 08:48:35 +0800 Subject: [PATCH 29/35] Move unauthorized_redirect handler to initializer --- ...lidus_auth_devise_unauthorized_redirect.rb | 21 ++++++++++++++++++ lib/solidus_starter_frontend/engine.rb | 22 ------------------- 2 files changed, 21 insertions(+), 22 deletions(-) create mode 100644 config/initializers/solidus_auth_devise_unauthorized_redirect.rb diff --git a/config/initializers/solidus_auth_devise_unauthorized_redirect.rb b/config/initializers/solidus_auth_devise_unauthorized_redirect.rb new file mode 100644 index 00000000..14b6e402 --- /dev/null +++ b/config/initializers/solidus_auth_devise_unauthorized_redirect.rb @@ -0,0 +1,21 @@ +Rails.application.config.to_prepare do + Spree::BaseController.unauthorized_redirect = -> do + if try_spree_current_user + flash[:error] = I18n.t('spree.authorization_failure') + + if Spree::Auth::Engine.redirect_back_on_unauthorized? + redirect_back(fallback_location: spree.unauthorized_path) + else + redirect_to spree.unauthorized_path + end + else + store_location + + if Spree::Auth::Engine.redirect_back_on_unauthorized? + redirect_back(fallback_location: spree.login_path) + else + redirect_to spree.login_path + end + end + end +end diff --git a/lib/solidus_starter_frontend/engine.rb b/lib/solidus_starter_frontend/engine.rb index 6a6fba78..e2728eb8 100644 --- a/lib/solidus_starter_frontend/engine.rb +++ b/lib/solidus_starter_frontend/engine.rb @@ -13,27 +13,5 @@ class Engine < Rails::Engine config.generators do |g| g.test_framework :rspec end - - config.to_prepare do - Spree::BaseController.unauthorized_redirect = -> do - if try_spree_current_user - flash[:error] = I18n.t('spree.authorization_failure') - - if Spree::Auth::Engine.redirect_back_on_unauthorized? - redirect_back(fallback_location: spree.unauthorized_path) - else - redirect_to spree.unauthorized_path - end - else - store_location - - if Spree::Auth::Engine.redirect_back_on_unauthorized? - redirect_back(fallback_location: spree.login_path) - else - redirect_to spree.login_path - end - end - end - end end end From 22f0bf5901cb1158f63d0f9433c5532489174c99 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Thu, 29 Jul 2021 09:05:17 +0800 Subject: [PATCH 30/35] Fix generator to copy solidus_auth_devise frontend files to app --- .../solidus_starter_frontend_generator.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/generators/solidus_starter_frontend/solidus_starter_frontend_generator.rb b/lib/generators/solidus_starter_frontend/solidus_starter_frontend_generator.rb index d9c63a46..1823b678 100644 --- a/lib/generators/solidus_starter_frontend/solidus_starter_frontend_generator.rb +++ b/lib/generators/solidus_starter_frontend/solidus_starter_frontend_generator.rb @@ -6,17 +6,11 @@ class SolidusStarterFrontendGenerator < Rails::Generators::Base def install # Copy directories directory 'app', 'app' - directory 'lib/views', 'lib/views' # Copy files copy_file 'lib/solidus_starter_frontend_configuration.rb', 'lib/solidus_starter_frontend_configuration.rb' copy_file 'lib/solidus_starter_frontend/config.rb', 'lib/solidus_starter_frontend/config.rb' - copy_file 'lib/solidus_starter_frontend/solidus_support_extensions.rb', 'lib/solidus_starter_frontend/solidus_support_extensions.rb' - - # Initializer - initializer 'solidus_starter_frontend.rb' do - "require 'solidus_starter_frontend/solidus_support_extensions'" - end + copy_file 'config/initializers/solidus_auth_devise_unauthorized_redirect.rb', 'config/initializers/solidus_auth_devise_unauthorized_redirect.rb' # Routes copy_file 'config/routes.rb', 'tmp/routes.rb' @@ -24,6 +18,7 @@ def install # Gems gem 'canonical-rails' + gem 'solidus_auth_devise' gem 'solidus_support' gem 'truncate_html' From 4b1f2ba09144b88322b0d95c1ab6ebd341ba2a4b Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Thu, 29 Jul 2021 17:44:46 +0800 Subject: [PATCH 31/35] Indicate that solidus_auth_devise is currently installed by the generator --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5c9853c..214dc863 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,6 @@ bundle add solidus_core solidus_backend solidus_api solidus_sample bin/rails generate solidus:install ``` -And type `y` when prompted if you want to install Solidus Auth Devise - ### For existing stores In your `Gemfile` replace: @@ -78,6 +76,10 @@ Please note however that you won't be able to auto-update the storefront code with the next versions released since this project's gem will not be present in your Gemfile. +In addition, please note that the command will add Solidus Auth Devise and its +frontend components to your app. At the moment, you will need to manually +remove the gem and its frontend components if ever you don't need them. + ## Development For information about contributing to this project please refer to this From 7387c68b62bb0d8e1d43085ce9aa5f7f0a72296f Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Mon, 2 Aug 2021 15:41:56 +0800 Subject: [PATCH 32/35] Copy controller and mailer specs from solidus_auth_devise Include Devise::Test::ControllerHelpers --- .../controllers/spree/base_controller_spec.rb | 53 +++++ .../spree/checkout_controller_spec.rb | 192 ++++++++++++++++++ .../spree/products_controller_spec.rb | 24 +++ .../spree/user_passwords_controller_spec.rb | 45 ++++ .../user_registrations_controller_spec.rb | 97 +++++++++ .../spree/user_sessions_controller_spec.rb | 127 ++++++++++++ .../spree/users_controller_spec.rb | 79 +++++++ spec/mailers/user_mailer_spec.rb | 47 +++++ spec/spec_helper.rb | 1 + 9 files changed, 665 insertions(+) create mode 100644 spec/controllers/spree/base_controller_spec.rb create mode 100644 spec/controllers/spree/checkout_controller_spec.rb create mode 100644 spec/controllers/spree/products_controller_spec.rb create mode 100644 spec/controllers/spree/user_passwords_controller_spec.rb create mode 100644 spec/controllers/spree/user_registrations_controller_spec.rb create mode 100644 spec/controllers/spree/user_sessions_controller_spec.rb create mode 100644 spec/controllers/spree/users_controller_spec.rb create mode 100644 spec/mailers/user_mailer_spec.rb diff --git a/spec/controllers/spree/base_controller_spec.rb b/spec/controllers/spree/base_controller_spec.rb new file mode 100644 index 00000000..9dc565cd --- /dev/null +++ b/spec/controllers/spree/base_controller_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Spree::BaseController, type: :controller do + describe '#unauthorized_redirect' do + controller(described_class) do + def index; authorize!(:read, :something); end + end + + before do + stub_spree_preferences(Spree::Config, redirect_back_on_unauthorized: true) + end + + context "when user is logged in" do + before { sign_in(create(:user)) } + + context "when http_referrer is not present" do + it "redirects to unauthorized path" do + get :index + expect(response).to redirect_to(spree.unauthorized_path) + end + end + + context "when http_referrer is present" do + before { request.env['HTTP_REFERER'] = '/redirect' } + + it "redirects back" do + get :index + expect(response).to redirect_to('/redirect') + end + end + end + + context "when user is not logged in" do + context "when http_referrer is not present" do + it "redirects to login path" do + get :index + expect(response).to redirect_to(spree.login_path) + end + end + + context "when http_referrer is present" do + before { request.env['HTTP_REFERER'] = '/redirect' } + + it "redirects back" do + get :index + expect(response).to redirect_to('/redirect') + end + end + end + end +end diff --git a/spec/controllers/spree/checkout_controller_spec.rb b/spec/controllers/spree/checkout_controller_spec.rb new file mode 100644 index 00000000..f831a07d --- /dev/null +++ b/spec/controllers/spree/checkout_controller_spec.rb @@ -0,0 +1,192 @@ +# frozen_string_literal: true + +RSpec.describe Spree::CheckoutController, type: :controller do + let(:order) { create(:order_with_line_items, email: nil, user: nil, guest_token: token) } + let(:user) { build(:user, spree_api_key: 'fake') } + let(:token) { 'some_token' } + let(:cookie_token) { token } + + before do + request.cookie_jar.signed[:guest_token] = cookie_token + allow(controller).to receive(:current_order) { order } + allow(order).to receive(:confirmation_required?) { true } + end + + context '#edit' do + context 'when registration step enabled' do + context 'when authenticated as registered user' do + before { allow(controller).to receive(:spree_current_user) { user } } + + it 'proceeds to the first checkout step' do + get :edit, params: { state: 'address' } + expect(response).to render_template :edit + end + end + + context 'when not authenticated as guest' do + it 'redirects to registration step' do + get :edit, params: { state: 'address' } + expect(response).to redirect_to spree.checkout_registration_path + end + end + + context 'when authenticated as guest' do + before { order.email = 'guest@solidus.io' } + + it 'proceeds to the first checkout step' do + get :edit, params: { state: 'address' } + expect(response).to render_template :edit + end + + context 'when guest checkout not allowed' do + before do + stub_spree_preferences(allow_guest_checkout: false) + end + + it 'redirects to registration step' do + get :edit, params: { state: 'address' } + expect(response).to redirect_to spree.checkout_registration_path + end + end + end + end + + context 'when registration step disabled' do + before do + stub_spree_preferences(Spree::Auth::Config, registration_step: false) + end + + context 'when authenticated as registered' do + before { allow(controller).to receive(:spree_current_user) { user } } + + it 'proceeds to the first checkout step' do + get :edit, params: { state: 'address' } + expect(response).to render_template :edit + end + end + + context 'when authenticated as guest' do + it 'proceeds to the first checkout step' do + get :edit, params: { state: 'address' } + expect(response).to render_template :edit + end + end + end + end + + context '#update' do + context 'when in the confirm state' do + before do + order.update(email: 'spree@example.com', state: 'confirm') + + # So that the order can transition to complete successfully + allow(order).to receive(:payment_required?) { false } + end + + context 'with a token' do + before { allow(order).to receive(:guest_token) { 'ABC' } } + + it 'redirects to the tokenized order view' do + request.cookie_jar.signed[:guest_token] = 'ABC' + post :update, params: { state: 'confirm' } + expect(response).to redirect_to spree.token_order_path(order, 'ABC') + expect(flash.notice).to eq I18n.t('spree.order_processed_successfully') + end + end + + context 'with a registered user' do + before do + allow(controller).to receive(:spree_current_user) { user } + allow(order).to receive(:user) { user } + allow(order).to receive(:guest_token) { nil } + end + + it 'redirects to the standard order view' do + post :update, params: { state: 'confirm' } + expect(response).to redirect_to spree.order_path(order) + end + end + end + end + + context '#registration' do + it 'does not check registration' do + expect(controller).not_to receive(:check_registration) + get :registration + end + + it 'checks if the user is authorized for :edit' do + expect(controller).to receive(:authorize!).with(:edit, order, token) + request.cookie_jar.signed[:guest_token] = token + get :registration, params: {} + end + end + + context '#update_registration' do + subject { put :update_registration, params: { order: { email: email } } } + let(:email) { 'foo@example.com' } + + it 'does not check registration' do + expect(controller).not_to receive(:check_registration) + subject + end + + it 'redirects to the checkout_path after saving' do + subject + expect(response).to redirect_to spree.checkout_path + end + + # Regression test for https://github.com/solidusio/solidus/issues/1588 + context 'order in address state' do + let(:order) do + create( + :order_with_line_items, + email: nil, + user: nil, + guest_token: token, + bill_address: nil, + ship_address: nil, + state: 'address' + ) + end + + # This may seem out of left field, but previously there was an issue + # where address would be built in a before filter and then would be saved + # when trying to update the email. + it "doesn't create addresses" do + expect { + subject + }.not_to change { Spree::Address.count } + expect(response).to redirect_to spree.checkout_path + end + end + + context 'invalid email' do + let(:email) { 'invalid' } + + it 'renders the registration view' do + subject + expect(flash[:registration_error]).to eq I18n.t(:email_is_invalid, scope: [:errors, :messages]) + expect(response).to render_template :registration + end + end + + context 'with wrong order token' do + let(:cookie_token) { 'lol_no_access' } + + it 'redirects to login' do + put :update_registration, params: { order: { email: 'foo@example.com' } } + expect(response).to redirect_to(login_path) + end + end + + context 'without order token' do + let(:cookie_token) { nil } + + it 'redirects to login' do + put :update_registration, params: { order: { email: 'foo@example.com' } } + expect(response).to redirect_to(login_path) + end + end + end +end diff --git a/spec/controllers/spree/products_controller_spec.rb b/spec/controllers/spree/products_controller_spec.rb new file mode 100644 index 00000000..8596f3b0 --- /dev/null +++ b/spec/controllers/spree/products_controller_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +RSpec.describe Spree::ProductsController, type: :controller do + let!(:product) { create(:product, available_on: 1.year.from_now) } + let!(:user) { build(:user, spree_api_key: 'fake') } + + it 'allows admins to view non-active products' do + allow(controller).to receive(:before_save_new_order) + allow(controller).to receive(:spree_current_user) { user } + allow(user).to receive(:has_spree_role?) { true } + get :show, params: { id: product.to_param } + expect(response.status).to eq(200) + end + + it 'cannot view non-active products' do + allow(controller).to receive(:before_save_new_order) + allow(controller).to receive(:spree_current_user) { user } + allow(user).to receive(:has_spree_role?) { false } + + expect { + get :show, params: { id: product.to_param } + }.to raise_error(ActiveRecord::RecordNotFound) + end +end diff --git a/spec/controllers/spree/user_passwords_controller_spec.rb b/spec/controllers/spree/user_passwords_controller_spec.rb new file mode 100644 index 00000000..2165a22c --- /dev/null +++ b/spec/controllers/spree/user_passwords_controller_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +RSpec.describe Spree::UserPasswordsController, type: :controller do + let(:token) { 'some_token' } + + before { @request.env['devise.mapping'] = Devise.mappings[:spree_user] } + + describe 'GET edit' do + context 'when the user token has not been specified' do + it 'redirects to the new session path' do + get :edit + expect(response).to redirect_to( + 'http://test.host/user/spree_user/sign_in' + ) + end + + it 'flashes an error' do + get :edit + expect(flash[:alert]).to include( + "You can't access this page without coming from a password reset " \ + 'email' + ) + end + end + + context 'when the user token has been specified' do + it 'does something' do + get :edit, params: { reset_password_token: token } + expect(response.code).to eq('200') + end + end + end + + context '#update' do + context 'when updating password with blank password' do + it 'shows error flash message, sets spree_user with token and re-displays password edit form' do + put :update, params: { spree_user: { password: '', password_confirmation: '', reset_password_token: token } } + expect(assigns(:spree_user).is_a?(Spree::User)).to eq true + expect(assigns(:spree_user).reset_password_token).to eq token + expect(flash[:error]).to eq I18n.t(:cannot_be_blank, scope: [:devise, :user_passwords, :spree_user]) + expect(response).to render_template :edit + end + end + end +end diff --git a/spec/controllers/spree/user_registrations_controller_spec.rb b/spec/controllers/spree/user_registrations_controller_spec.rb new file mode 100644 index 00000000..b258b22a --- /dev/null +++ b/spec/controllers/spree/user_registrations_controller_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +RSpec.describe Spree::UserRegistrationsController, type: :controller do + before { @request.env['devise.mapping'] = Devise.mappings[:spree_user] } + + context '#create' do + before do + allow(controller).to receive(:after_sign_up_path_for) do + spree.root_path(thing: 7) + end + end + + let(:password_confirmation) { 'foobar123' } + + subject do + post(:create, { + params: { + spree_user: { + email: 'foobar@example.com', + password: 'foobar123', + password_confirmation: password_confirmation + } + } + }) + end + + context 'when user created successfuly' do + it 'saves the user' do + expect { subject }.to change { Spree::User.count }.from(0).to(1) + end + + it 'sets flash message' do + subject + expect(flash[:notice]).to eq('Welcome! You have signed up successfully.') + end + + it 'signs in user' do + expect(controller.warden).to receive(:set_user) + subject + end + + it 'sets spree_user_signup session' do + subject + expect(session[:spree_user_signup]).to be true + end + + it 'redirects to after_sign_up path' do + subject + expect(response).to redirect_to spree.root_path(thing: 7) + end + + context 'with a guest token present' do + before do + request.cookie_jar.signed[:guest_token] = 'ABC' + end + + it 'assigns orders with the correct token and no user present' do + order = create(:order, guest_token: 'ABC', user_id: nil, created_by_id: nil) + subject + user = Spree::User.find_by(email: 'foobar@example.com') + + order.reload + expect(order.user_id).to eq user.id + expect(order.created_by_id).to eq user.id + end + + it 'does not assign orders with an existing user' do + order = create(:order, guest_token: 'ABC', user_id: 200) + subject + + expect(order.reload.user_id).to eq 200 + end + + it 'does not assign orders with a different token' do + order = create(:order, guest_token: 'DEF', user_id: nil, created_by_id: nil) + subject + + expect(order.reload.user_id).to be_nil + end + end + end + + context 'when user not valid' do + let(:password_confirmation) { 'foobard123' } + + it 'resets password fields' do + expect(controller).to receive(:clean_up_passwords) + subject + end + + it 'renders new view' do + subject + expect(:response).to render_template(:new) + end + end + end +end diff --git a/spec/controllers/spree/user_sessions_controller_spec.rb b/spec/controllers/spree/user_sessions_controller_spec.rb new file mode 100644 index 00000000..77810fdb --- /dev/null +++ b/spec/controllers/spree/user_sessions_controller_spec.rb @@ -0,0 +1,127 @@ +# frozen_string_literal: true + +RSpec.describe Spree::UserSessionsController, type: :controller do + let(:user) { create(:user) } + + before { @request.env['devise.mapping'] = Devise.mappings[:spree_user] } + + context "#create" do + let(:format) { :html } + let(:password) { 'secret' } + + subject do + post(:create, { + params: { + spree_user: { + email: user.email, + password: password + }, + format: format + } + }) + end + + context "when using correct login information" do + context 'with a guest token present' do + before do + request.cookie_jar.signed[:guest_token] = 'ABC' + end + + it 'assigns orders with the correct token and no user present' do + order = create(:order, email: user.email, guest_token: 'ABC', user_id: nil, created_by_id: nil) + subject + + order.reload + expect(order.user_id).to eq user.id + expect(order.created_by_id).to eq user.id + end + + it 'assigns orders with the correct token and no user or email present' do + order = create(:order, guest_token: 'ABC', user_id: nil, created_by_id: nil) + subject + + order.reload + expect(order.user_id).to eq user.id + expect(order.created_by_id).to eq user.id + end + + it 'does not assign completed orders' do + order = create(:order, email: user.email, guest_token: 'ABC', + user_id: nil, created_by_id: nil, + completed_at: 1.minute.ago) + subject + + order.reload + expect(order.user_id).to be_nil + expect(order.created_by_id).to be_nil + end + + it 'does not assign orders with an existing user' do + order = create(:order, guest_token: 'ABC', user_id: 200) + subject + + expect(order.reload.user_id).to eq 200 + end + + it 'does not assign orders with a different token' do + order = create(:order, guest_token: 'DEF', user_id: nil, created_by_id: nil) + subject + + expect(order.reload.user_id).to be_nil + end + end + + context "when html format is requested" do + it "redirects to default after signing in" do + subject + expect(response).to redirect_to spree.root_path + end + end + + context "when js format is requested" do + let(:format) { :js } + + it "returns a json with ship and bill address" do + subject + parsed = ActiveSupport::JSON.decode(response.body) + expect(parsed).to have_key("user") + expect(parsed).to have_key("ship_address") + expect(parsed).to have_key("bill_address") + end + end + end + + context "when using incorrect login information" do + let(:password) { 'wrong' } + + context "when html format is requested" do + it "renders new template again with errors" do + subject + expect(response).to render_template(:new) + expect(flash[:error]).to eq I18n.t(:'devise.failure.invalid') + end + end + + context "when js format is requested" do + let(:format) { :js } + it "returns json with the error" do + subject + parsed = ActiveSupport::JSON.decode(response.body) + expect(parsed).to have_key("error") + end + end + end + end + + context "#destroy" do + subject do + delete(:destroy) + end + + it "redirects to default after signing out" do + subject + expect(controller.spree_current_user).to be_nil + expect(response).to redirect_to spree.root_path + end + end +end diff --git a/spec/controllers/spree/users_controller_spec.rb b/spec/controllers/spree/users_controller_spec.rb new file mode 100644 index 00000000..c4ca9586 --- /dev/null +++ b/spec/controllers/spree/users_controller_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true + +RSpec.describe Spree::UsersController, type: :controller do + let(:admin_user) { create(:user) } + let(:user) { create(:user) } + let(:role) { create(:role) } + + context '#load_object' do + it 'redirects to signup path if user is not found' do + put :update, params: { user: { email: 'foobar@example.com' } } + expect(response).to redirect_to spree.login_path + end + end + + context '#create' do + it 'creates a new user' do + post :create, params: { user: { email: 'foobar@example.com', password: 'foobar123', password_confirmation: 'foobar123' } } + expect(assigns[:user].new_record?).to be false + end + end + + context '#update' do + before { sign_in(user) } + + context 'when updating own account' do + context 'when user updated successfuly' do + before { put :update, params: { user: { email: 'mynew@email-address.com' } } } + + it 'saves user' do + expect(assigns[:user].email).to eq 'mynew@email-address.com' + end + + it 'updates spree_current_user' do + expect(subject.spree_current_user.email).to eq 'mynew@email-address.com' + end + + it 'redirects to account url' do + expect(response).to redirect_to spree.account_url(only_path: true) + end + end + + context 'when user not valid' do + before { put :update, params: { user: { email: '' } } } + + it 'does not affect spree_current_user' do + expect(subject.spree_current_user.email).to eq user.email + end + end + + context 'when updating password' do + before do + stub_spree_preferences(Spree::Auth::Config, signout_after_password_change: signout_after_change) + put :update, params: { user: { password: 'foobar123', password_confirmation: 'foobar123' } } + end + + context 'when signout after password change is enabled' do + let(:signout_after_change) { true } + + it 'redirects to login url' do + expect(response).to redirect_to spree.login_url(only_path: true) + end + end + + context 'when signout after password change is disabled' do + let(:signout_after_change) { false } + + it 'redirects to account url' do + expect(response).to redirect_to spree.account_url(only_path: true) + end + end + end + end + + it 'does not update roles' do + put :update, params: { user: { spree_role_ids: [role.id] } } + expect(assigns[:user].spree_roles).to_not include role + end + end +end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb new file mode 100644 index 00000000..a5ae4904 --- /dev/null +++ b/spec/mailers/user_mailer_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +RSpec.describe Spree::UserMailer, type: :mailer do + let!(:store) { create(:store) } + let(:user) { create(:user) } + + before do + user = create(:user) + Spree::UserMailer.reset_password_instructions(user, 'token goes here').deliver_now + @message = ActionMailer::Base.deliveries.last + end + + describe '#reset_password_instructions' do + describe 'message contents' do + before do + described_class.reset_password_instructions(user, 'token goes here').deliver_now + @message = ActionMailer::Base.deliveries.last + end + + context 'subject includes' do + it 'translated devise instructions' do + expect(@message.subject).to include( + I18n.t(:subject, scope: [:devise, :mailer, :reset_password_instructions]) + ) + end + + it 'Spree site name' do + expect(@message.subject).to include store.name + end + end + + context 'body includes' do + it 'password reset url' do + expect(@message.body.raw_source).to include "http://#{store.url}/user/spree_user/password/edit" + end + end + end + + describe 'legacy support for User object' do + it 'sends an email' do + expect { + described_class.reset_password_instructions(user, 'token goes here').deliver_now + }.to change(ActionMailer::Base.deliveries, :size).by(1) + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d554b326..077d5c26 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -48,6 +48,7 @@ config.include Spree::TestingSupport::Translations end + config.include Devise::Test::ControllerHelpers, type: :controller config.include Devise::Test::IntegrationHelpers, type: :request config.before(:each, with_signed_in_user: true) do From a88dee4891d3f31afbb466f02b0886c06161f2b4 Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Thu, 5 Aug 2021 09:45:51 +0800 Subject: [PATCH 33/35] Fix intermittent checkout example The example fails frequently. See for example, https://app.circleci.com/pipelines/github/nebulab/solidus_starter_frontend/879/workflows/778f9ce5-62d3-43b4-af6b-6e282b275815/jobs/2243/tests. In the test run I did in the video below, I got it to fail 40 out of 100 times. I discovered that the example fails frequently under the following conditions: 1. When signing in as a guest during checkout. 2. When using the apparition JS driver. However, under ANY of these conditions, the example succeeds most of the time: 1. On the current master branch, where we don't have authentication yet. 2. When signing in as a user during checkout. 3. When using a different JS driver, like selenium_chrome_headless. Please see the video below for more details. https://www.loom.com/share/2a6db47101f24fcd8206361f8300d7f9 --- spec/system/checkout_spec.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/spec/system/checkout_spec.rb b/spec/system/checkout_spec.rb index bd683816..f28541bb 100644 --- a/spec/system/checkout_spec.rb +++ b/spec/system/checkout_spec.rb @@ -607,6 +607,8 @@ context "with attempted XSS", js: true do shared_examples "safe from XSS" do + let(:user) { create(:user) } + # We need a country with states required but no states so that we have # access to the state_name input let!(:canada) { create(:country, name: 'Canada', iso: "CA", states_required: true) } @@ -617,8 +619,19 @@ it "displays the entered state name without evaluating" do add_mug_to_cart - checkout_as_guest visit spree.checkout_state_path(:address) + + # Unlike with the other examples in this spec, calling + # `checkout_as_guest` in this example causes this example to fail + # intermittently. Please see + # https://github.com/nebulab/solidus_starter_frontend/pull/172/files#r683067589 + # for more details. + within '#existing-customer' do + fill_in 'Email:', with: user.email + fill_in 'Password:', with: user.password + click_button 'Login' + end + fill_in_address fill_in 'Customer E-Mail', with: 'test@example.com' From bccabeffeed33d208a14a4335ebe21856d1c317c Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Fri, 6 Aug 2021 11:09:17 +0800 Subject: [PATCH 34/35] Update instructions to install Solidus with Auth Devise --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 214dc863..efd89877 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,14 @@ Just run: rails new store --skip-javascript cd store bundle add solidus_core solidus_backend solidus_api solidus_sample -bin/rails generate solidus:install +bin/rails generate solidus:install --auto-accept ``` +Please note that `--auto-accept` will add [Solidus Auth Devise] +(https://github.com/solidusio/solidus_auth_devise) to your application. At the +moment, SolidusStarterFrontend requires the application to include the gem. In +the future, we'll make Solidus Auth Devise optional. + ### For existing stores In your `Gemfile` replace: @@ -59,6 +64,10 @@ gem 'solidus_sample' And replace all the references of the string `Spree::Frontend::Config` in your project with `SolidusStarterFrontend::Config`. +You'll also need to make sure that [Solidus Auth Devise] +(https://github.com/solidusio/solidus_auth_devise) is installed in your +application. + ### Frontend installation You can copy the starter frontend files to your project: @@ -72,14 +81,14 @@ These commands will install the gem globally and copy this project's views, assets, routes and controllers to your project. You can change easily anything that we created; this gives you a lot of freedom of customization. -Please note however that you won't be able to auto-update the storefront code +In addition, please note that the command will add Solidus Auth Devise +frontend components to your app. At the moment, you will need to manually +remove the gem and its frontend components if you don't need them. + +Finally, please note that you won't be able to auto-update the storefront code with the next versions released since this project's gem will not be present in your Gemfile. -In addition, please note that the command will add Solidus Auth Devise and its -frontend components to your app. At the moment, you will need to manually -remove the gem and its frontend components if ever you don't need them. - ## Development For information about contributing to this project please refer to this From 97463269d1fc72fd497302e4d2ac56b2d4fda6cc Mon Sep 17 00:00:00 2001 From: George Mendoza Date: Wed, 11 Aug 2021 09:26:20 +0800 Subject: [PATCH 35/35] Update comment in checkout controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marc Busqué --- app/controllers/spree/checkout_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/spree/checkout_controller.rb b/app/controllers/spree/checkout_controller.rb index 78b6d8a4..2a50a772 100644 --- a/app/controllers/spree/checkout_controller.rb +++ b/app/controllers/spree/checkout_controller.rb @@ -22,7 +22,7 @@ class CheckoutController < Spree::StoreController before_action :setup_for_current_state, only: [:edit, :update] # This action builds some associations on the order, ex. addresses, which we - # don't to build or save here. + # don't need to build or save here. skip_before_action :setup_for_current_state, only: [:registration, :update_registration] helper 'spree/orders'