mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-21 00:47:26 +00:00
A customer should be able to complete the checkout even if the voucher has been deactivated after being added to the order.
1210 lines
43 KiB
Ruby
1210 lines
43 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "system_helper"
|
|
|
|
describe "As a consumer, I want to checkout my order" do
|
|
include ShopWorkflow
|
|
include SplitCheckoutHelper
|
|
include FileHelper
|
|
include StripeHelper
|
|
include StripeStubs
|
|
include PaypalHelper
|
|
include AuthenticationHelper
|
|
|
|
let!(:zone) { create(:zone_with_member) }
|
|
let(:supplier) { create(:supplier_enterprise) }
|
|
let(:distributor) { create(:distributor_enterprise, charges_sales_tax: true) }
|
|
let(:product) {
|
|
create(:taxed_product, supplier: supplier, price: 10, zone: zone, tax_rate_amount: 0.1)
|
|
}
|
|
let(:variant) { product.variants.first }
|
|
let!(:order_cycle) {
|
|
create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor],
|
|
coordinator: create(:distributor_enterprise), variants: [variant])
|
|
}
|
|
let(:order) {
|
|
create(:order, order_cycle: order_cycle, distributor: distributor, bill_address_id: nil,
|
|
ship_address_id: nil, state: "cart",
|
|
line_items: [create(:line_item, variant: variant)])
|
|
}
|
|
|
|
let(:fee_tax_rate) { create(:tax_rate, amount: 0.10, zone: zone, included_in_price: true) }
|
|
let(:fee_tax_category) { create(:tax_category, tax_rates: [fee_tax_rate]) }
|
|
let(:enterprise_fee) { create(:enterprise_fee, amount: 1.23, tax_category: fee_tax_category) }
|
|
|
|
let(:free_shipping_with_required_address) {
|
|
create(:shipping_method, require_ship_address: true,
|
|
name: "A Free Shipping with required address")
|
|
}
|
|
let(:free_shipping) {
|
|
create(:shipping_method, require_ship_address: false, name: "free Shipping",
|
|
description: "yellow",
|
|
calculator: Calculator::FlatRate.new(preferred_amount: 0.00))
|
|
}
|
|
let(:shipping_tax_rate) { create(:tax_rate, amount: 0.25, zone: zone, included_in_price: true) }
|
|
let(:shipping_tax_category) { create(:tax_category, tax_rates: [shipping_tax_rate]) }
|
|
let(:shipping_with_fee) {
|
|
create(:shipping_method, require_ship_address: true, tax_category: shipping_tax_category,
|
|
name: "Shipping with Fee", description: "blue",
|
|
calculator: Calculator::FlatRate.new(preferred_amount: 4.56))
|
|
}
|
|
let(:free_shipping_without_required_address) {
|
|
create(:shipping_method, require_ship_address: false,
|
|
name: "Z Free Shipping without required address")
|
|
}
|
|
let(:tagged_shipping) {
|
|
create(:shipping_method, require_ship_address: false, name: "Local", tag_list: "local")
|
|
}
|
|
let!(:payment_with_fee) {
|
|
create(:payment_method, distributors: [distributor],
|
|
name: "Payment with Fee", description: "Payment with fee",
|
|
calculator: Calculator::FlatRate.new(preferred_amount: 1.23))
|
|
}
|
|
let(:shipping_backoffice_only) {
|
|
create(:shipping_method, require_ship_address: true, name: "Shipping Backoffice Only",
|
|
display_on: "back_end")
|
|
}
|
|
let(:shipping_methods) {
|
|
[free_shipping_with_required_address, free_shipping, shipping_with_fee,
|
|
free_shipping_without_required_address, tagged_shipping]
|
|
}
|
|
|
|
before do
|
|
add_enterprise_fee enterprise_fee
|
|
set_order order
|
|
|
|
distributor.shipping_methods.push(shipping_methods)
|
|
end
|
|
|
|
context "guest checkout when distributor doesn't allow guest orders" do
|
|
before do
|
|
distributor.update_columns allow_guest_orders: false
|
|
visit checkout_step_path(:details)
|
|
end
|
|
|
|
it "should display the split checkout login page" do
|
|
expect(page).to have_content("Ok, ready to checkout?")
|
|
expect(page).to have_content("Login")
|
|
expect(page).to have_no_content("Checkout as guest")
|
|
end
|
|
|
|
it "should show the login modal when clicking the login button" do
|
|
click_on "Login"
|
|
expect(page).to have_selector ".login-modal"
|
|
end
|
|
end
|
|
|
|
shared_examples "when I have an out of stock product in my cart" do
|
|
before do
|
|
variant.update!(on_demand: false, on_hand: 0)
|
|
end
|
|
|
|
it "returns me to the cart with an error message" do
|
|
visit checkout_path
|
|
|
|
expect(page).not_to have_selector 'closing', text: "Checkout now"
|
|
expect(page).to have_selector 'closing', text: "Your shopping cart"
|
|
expect(page).to have_content "An item in your cart has become unavailable"
|
|
expect(page).to have_content "Update"
|
|
end
|
|
end
|
|
|
|
context "as a guest user" do
|
|
before do
|
|
visit checkout_path
|
|
end
|
|
|
|
context "actually user has an account and wants to login" do
|
|
let(:user) { create(:user) }
|
|
|
|
it "should redirect to '/checkout/details' when user submit the login form" do
|
|
expect(page).to have_content("Ok, ready to checkout?")
|
|
|
|
click_on "Login"
|
|
within ".login-modal" do
|
|
fill_in_and_submit_login_form(user)
|
|
end
|
|
|
|
expect_logged_in
|
|
expect(page).not_to have_selector ".login-modal"
|
|
expect_to_be_on_first_step
|
|
end
|
|
end
|
|
|
|
it "should display the split checkout login/guest form" do
|
|
expect(page).to have_content distributor.name
|
|
expect(page).to have_content("Ok, ready to checkout?")
|
|
expect(page).to have_content("Login")
|
|
expect(page).to have_content("Checkout as guest")
|
|
end
|
|
|
|
it "should display the split checkout details page" do
|
|
click_on "Checkout as guest"
|
|
expect(page).to have_content distributor.name
|
|
expect_to_be_on_first_step
|
|
end
|
|
|
|
context "when no shipping methods are available" do
|
|
before do
|
|
shipping_methods.each { |sm| sm.update(tag_list: "hidden") }
|
|
end
|
|
|
|
it "should display an error message" do
|
|
create(:filter_shipping_methods_tag_rule,
|
|
enterprise: distributor,
|
|
is_default: true,
|
|
preferred_shipping_method_tags: "hidden",
|
|
preferred_matched_shipping_methods_visibility: 'hidden')
|
|
|
|
visit checkout_path
|
|
expect(page).to have_content(
|
|
"Checkout is not possible due to absence of shipping options. " \
|
|
"Please contact the shop owner."
|
|
)
|
|
end
|
|
end
|
|
|
|
it "should display error when fields are empty" do
|
|
click_on "Checkout as guest"
|
|
click_button "Next - Payment method"
|
|
expect(page).to have_content("Saving failed, please update the highlighted fields")
|
|
expect(page).to have_css 'span.field_with_errors label', count: 6
|
|
expect(page).to have_css 'span.field_with_errors input', count: 6
|
|
expect(page).to have_css 'span.formError', count: 7
|
|
end
|
|
|
|
it "should validate once each needed field is filled" do
|
|
click_on "Checkout as guest"
|
|
fill_in "First Name", with: "Jane"
|
|
fill_in "Last Name", with: "Doe"
|
|
fill_in "Phone number", with: "07987654321"
|
|
fill_in "Address (Street + House Number)", with: "Flat 1 Elm apartments"
|
|
fill_in "City", with: "London"
|
|
fill_in "Postcode", with: "SW1A 1AA"
|
|
choose free_shipping.name
|
|
|
|
click_button "Next - Payment method"
|
|
expect(page).to have_button("Next - Order summary")
|
|
end
|
|
|
|
context "on the 'details' step" do
|
|
before do
|
|
visit checkout_step_path(:details)
|
|
click_on "Checkout as guest"
|
|
end
|
|
|
|
context "should show a flash message and inline error messages" do
|
|
before do
|
|
click_button "Next - Payment method"
|
|
end
|
|
|
|
it "should not display bill address phone number error message" do
|
|
expect(page).to have_content "Saving failed, please update the highlighted fields."
|
|
|
|
expect(page).to have_selector ".field_with_errors"
|
|
expect(page).to have_content "can't be blank"
|
|
end
|
|
end
|
|
|
|
it "should allow visit '/checkout/details'" do
|
|
expect(page).to have_current_path("/checkout/details")
|
|
end
|
|
|
|
it 'does not show the save as default bill address checkbox' do
|
|
expect(page).not_to have_content "Save as default billing address"
|
|
end
|
|
|
|
it 'does not show the save as default ship address checkbox' do
|
|
choose free_shipping_with_required_address.name
|
|
uncheck "ship_address_same_as_billing"
|
|
expect(page).not_to have_content "Save as default shipping address"
|
|
end
|
|
|
|
it 'display shipping methods alphabetically' do
|
|
shipping_methods = page.all(:field, "shipping_method_id")
|
|
.map { |field| field.sibling("label") }.map(&:text)
|
|
expect(shipping_methods).to eq [
|
|
"A Free Shipping with required address", "free Shipping",
|
|
"Local", "Shipping with Fee", "Z Free Shipping without required address"
|
|
]
|
|
end
|
|
|
|
it_behaves_like "when I have an out of stock product in my cart"
|
|
end
|
|
|
|
context "on the 'payment' step" do
|
|
before do
|
|
order.update(state: "payment")
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
it "should allow visit '/checkout/payment'" do
|
|
expect(page).to have_current_path("/checkout/payment")
|
|
end
|
|
|
|
it_behaves_like "when I have an out of stock product in my cart"
|
|
end
|
|
|
|
describe "hidding a shipping method" do
|
|
let(:user) { create(:user) }
|
|
let(:customer) { create(:customer, user: user, enterprise: distributor) }
|
|
|
|
it "shows shipping methods allowed by the rule" do
|
|
visit checkout_path
|
|
click_on "Checkout as guest"
|
|
|
|
# No rules in effect
|
|
expect(page).to have_content free_shipping.name
|
|
expect(page).to have_content shipping_with_fee.name
|
|
expect(page).to have_content free_shipping_without_required_address.name
|
|
expect(page).to have_content tagged_shipping.name
|
|
|
|
create(:filter_shipping_methods_tag_rule,
|
|
enterprise: distributor,
|
|
preferred_customer_tags: "local",
|
|
preferred_shipping_method_tags: "local",
|
|
preferred_matched_shipping_methods_visibility: 'visible')
|
|
create(:filter_shipping_methods_tag_rule,
|
|
enterprise: distributor,
|
|
is_default: true,
|
|
preferred_shipping_method_tags: "local",
|
|
preferred_matched_shipping_methods_visibility: 'hidden')
|
|
|
|
visit checkout_path
|
|
|
|
# Default rule in effect, disallows access to 'Local'
|
|
expect(page).to have_content free_shipping.name
|
|
expect(page).to have_content shipping_with_fee.name
|
|
expect(page).to have_content free_shipping_without_required_address.name
|
|
expect(page).not_to have_content tagged_shipping.name
|
|
|
|
login_as(user)
|
|
visit checkout_path
|
|
|
|
# Default rule in still effect, disallows access to 'Local'
|
|
expect(page).to have_content free_shipping.name
|
|
expect(page).to have_content shipping_with_fee.name
|
|
expect(page).to have_content free_shipping_without_required_address.name
|
|
expect(page).not_to have_content tagged_shipping.name
|
|
|
|
customer.update_attribute(:tag_list, "local")
|
|
visit checkout_path
|
|
|
|
# #local Customer can access 'Local' shipping method
|
|
expect(page).to have_content free_shipping.name
|
|
expect(page).to have_content shipping_with_fee.name
|
|
expect(page).to have_content free_shipping_without_required_address.name
|
|
expect(page).to have_content tagged_shipping.name
|
|
end
|
|
end
|
|
end
|
|
|
|
context "as a logged in user" do
|
|
let(:user) { create(:user) }
|
|
|
|
before do
|
|
login_as(user)
|
|
visit checkout_path
|
|
end
|
|
|
|
context "when no selecting a shipping method" do
|
|
before do
|
|
fill_out_details
|
|
fill_out_billing_address
|
|
end
|
|
|
|
it "errors is shown to the user when submitting the form" do
|
|
click_button "Next - Payment method"
|
|
expect(page).to have_content "Select a shipping method"
|
|
end
|
|
end
|
|
|
|
context "details step" do
|
|
context "when form is submitted but invalid" do
|
|
it "display the checkbox about shipping address same as billing address " \
|
|
"when selecting a shipping method that requires ship address" do
|
|
choose free_shipping_with_required_address.name
|
|
check "Shipping address same as billing address?"
|
|
expect(page).to have_content "Save as default shipping address"
|
|
|
|
click_button "Next - Payment method"
|
|
|
|
expect(page).to have_content "Saving failed, please update the highlighted fields."
|
|
expect(page).to have_content "Save as default shipping address"
|
|
expect(page).to have_checked_field "Shipping address same as billing address?"
|
|
end
|
|
end
|
|
|
|
describe "filling out order details" do
|
|
before do
|
|
fill_out_details
|
|
fill_out_billing_address
|
|
order.update(user_id: user.id)
|
|
end
|
|
|
|
context "billing address" do
|
|
describe "checking the default address box" do
|
|
before do
|
|
check "order_save_bill_address"
|
|
choose free_shipping.name
|
|
end
|
|
|
|
it "creates a new default bill address" do
|
|
expect {
|
|
proceed_to_payment
|
|
order.reload
|
|
user.reload
|
|
}.to change {
|
|
order.bill_address&.address1
|
|
}.from(nil).to("Rue de la Vie, 77")
|
|
.and change {
|
|
order.customer&.bill_address&.address1
|
|
}.from(nil).to("Rue de la Vie, 77")
|
|
.and change {
|
|
order.bill_address&.address1
|
|
}
|
|
.from(nil).to("Rue de la Vie, 77")
|
|
end
|
|
end
|
|
|
|
describe "unchecking the default address box" do
|
|
before do
|
|
uncheck "order_save_bill_address"
|
|
choose free_shipping.name
|
|
end
|
|
|
|
context "proceeding to payment" do
|
|
before do
|
|
expect {
|
|
proceed_to_payment
|
|
}.to_not change {
|
|
user.reload.bill_address
|
|
}
|
|
end
|
|
|
|
it "updates the bill address of the order and customer" do
|
|
expect(order.reload.bill_address.address1).to eq "Rue de la Vie, 77"
|
|
expect(order.customer.bill_address.address1).to eq "Rue de la Vie, 77"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "shipping address" do
|
|
describe "checking the default address box" do
|
|
before do
|
|
choose free_shipping_with_required_address.name
|
|
uncheck "ship_address_same_as_billing"
|
|
fill_out_shipping_address
|
|
check "order_save_ship_address"
|
|
end
|
|
|
|
context "proceeding to payment" do
|
|
it "creates a new default ship address" do
|
|
expect {
|
|
proceed_to_payment
|
|
order.reload
|
|
user.reload
|
|
}.to change {
|
|
order.ship_address&.address1
|
|
}.from(nil).to("Rue de la Vie, 66")
|
|
.and change {
|
|
order.customer&.ship_address&.address1
|
|
}.from(nil).to("Rue de la Vie, 66")
|
|
.and change {
|
|
order.ship_address&.address1
|
|
}
|
|
.from(nil).to("Rue de la Vie, 66")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "unchecking the default address box" do
|
|
before do
|
|
choose free_shipping_with_required_address.name
|
|
uncheck "ship_address_same_as_billing"
|
|
fill_out_shipping_address
|
|
uncheck "order_save_ship_address"
|
|
end
|
|
|
|
context "proceeding to payment" do
|
|
before do
|
|
expect {
|
|
proceed_to_payment
|
|
}.to_not change {
|
|
user.reload.ship_address
|
|
}
|
|
end
|
|
|
|
it "updates the ship address of the order and customer" do
|
|
expect(order.reload.ship_address.address1).to eq "Rue de la Vie, 66"
|
|
expect(order.customer.ship_address.address1).to eq "Rue de la Vie, 66"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "selecting a pick-up shipping method and submiting the form" do
|
|
before do
|
|
choose free_shipping.name
|
|
end
|
|
|
|
it "redirects the user to the Payment Method step" do
|
|
fill_notes("SpEcIaL NoTeS")
|
|
proceed_to_payment
|
|
end
|
|
|
|
context 'when the user has no shipping address' do
|
|
before do
|
|
# Hack so we can have "Shipping address same as billing address?" unticked
|
|
choose free_shipping_with_required_address.name
|
|
uncheck "Shipping address same as billing address?"
|
|
choose free_shipping_without_required_address.name
|
|
end
|
|
|
|
it "redirects the user to the Payment Method step" do
|
|
proceed_to_payment
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "selecting a delivery method with a shipping fee" do
|
|
before do
|
|
choose shipping_with_fee.name
|
|
end
|
|
|
|
context "with same shipping and billing address" do
|
|
before do
|
|
check "ship_address_same_as_billing"
|
|
end
|
|
|
|
it "displays the shipping fee" do
|
|
expect(page).to have_content("#{shipping_with_fee.name} " + with_currency(4.56).to_s)
|
|
end
|
|
|
|
it "does not display the shipping address form" do
|
|
expect(page).not_to have_field "order_ship_address_attributes_address1"
|
|
end
|
|
|
|
it "redirects the user to the Payment Method step, when submiting the form" do
|
|
proceed_to_payment
|
|
# asserts whether shipping and billing addresses are the same
|
|
ship_add_id = order.reload.ship_address_id
|
|
bill_add_id = order.reload.bill_address_id
|
|
expect(Spree::Address.where(id: bill_add_id).pluck(:address1) ==
|
|
Spree::Address.where(id: ship_add_id).pluck(:address1)).to be true
|
|
end
|
|
|
|
context "with a shipping fee" do
|
|
before do
|
|
proceed_to_payment
|
|
click_button "Next - Order summary"
|
|
end
|
|
|
|
shared_examples "displays the shipping fee" do |checkout_page|
|
|
it "on the #{checkout_page} page" do
|
|
expect(page).to have_content("Shipping #{with_currency(4.56)}")
|
|
|
|
if checkout_page.eql?("order confirmation")
|
|
expect(page).to have_content "Your order has been processed successfully"
|
|
end
|
|
end
|
|
end
|
|
|
|
it_behaves_like "displays the shipping fee", "order summary"
|
|
|
|
context "after completing the order" do
|
|
before do
|
|
click_on "Complete order"
|
|
end
|
|
it_behaves_like "displays the shipping fee", "order confirmation"
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with different shipping and billing address" do
|
|
before do
|
|
uncheck "ship_address_same_as_billing"
|
|
end
|
|
it "displays the shipping address form and the option to save it as default" do
|
|
expect(page).to have_field "order_ship_address_attributes_address1"
|
|
end
|
|
|
|
it "displays error messages when submitting incomplete billing address" do
|
|
click_button "Next - Payment method"
|
|
within "checkout" do
|
|
expect(page).to have_field("Address", with: "")
|
|
expect(page).to have_field("City", with: "")
|
|
expect(page).to have_field("Postcode", with: "")
|
|
expect(page).to have_content("can't be blank", count: 3)
|
|
end
|
|
within ".flash[type='error']" do
|
|
expect(page).to have_content "Saving failed, please update the highlighted fields."
|
|
end
|
|
end
|
|
|
|
it "fills in shipping details and redirects the user to the Payment Method step,
|
|
when submiting the form" do
|
|
fill_out_shipping_address
|
|
fill_notes("SpEcIaL NoTeS")
|
|
proceed_to_payment
|
|
# asserts whether shipping and billing addresses are the same
|
|
ship_add_id = Spree::Order.first.ship_address_id
|
|
bill_add_id = Spree::Order.first.bill_address_id
|
|
expect(Spree::Address.where(id: bill_add_id).pluck(:address1) ==
|
|
Spree::Address.where(id: ship_add_id).pluck(:address1)).to be false
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "pre-selecting a shipping method" do
|
|
it "preselect a shipping method if only one is available" do
|
|
order.distributor.update! shipping_methods: [free_shipping, shipping_backoffice_only]
|
|
|
|
visit checkout_step_path(:details)
|
|
|
|
expect(page).to have_checked_field "shipping_method_#{free_shipping.id}"
|
|
end
|
|
|
|
it "don't preselect a shipping method if more than one is available" do
|
|
order.distributor.update! shipping_methods: [free_shipping, shipping_with_fee]
|
|
|
|
visit checkout_step_path(:details)
|
|
|
|
expect(page).to have_field "shipping_method_#{free_shipping.id}", checked: false
|
|
expect(page).to have_field "shipping_method_#{shipping_with_fee.id}", checked: false
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "not filling out delivery details" do
|
|
before do
|
|
fill_in "Email", with: ""
|
|
end
|
|
it "should display error when fields are empty" do
|
|
click_button "Next - Payment method"
|
|
within "checkout" do
|
|
expect(page).to have_field("First Name", with: "")
|
|
expect(page).to have_field("Last Name", with: "")
|
|
expect(page).to have_field("Email", with: "")
|
|
expect(page).to have_content("is invalid")
|
|
expect(page).to have_field("Phone number", with: "")
|
|
expect(page).to have_field("Address", with: "")
|
|
expect(page).to have_field("City", with: "")
|
|
expect(page).to have_field("Postcode", with: "")
|
|
expect(page).to have_content("can't be blank", count: 7)
|
|
expect(page).to have_content("Select a shipping method")
|
|
end
|
|
within ".flash[type='error']" do
|
|
expect(page).to have_content("Saving failed, please update the highlighted fields")
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with a saved address" do
|
|
let!(:address_state) do
|
|
create(:state, name: "Testville", abbr: "TST", country: DefaultCountry.country )
|
|
end
|
|
let(:saved_address) do
|
|
create(:bill_address, state: address_state, zipcode: "TST01" )
|
|
end
|
|
|
|
before do
|
|
user.update_columns bill_address_id: saved_address.id
|
|
end
|
|
|
|
it "pre-fills address details" do
|
|
visit checkout_path
|
|
expect(page).to have_select(
|
|
"order_bill_address_attributes_state_id", selected: "Testville"
|
|
)
|
|
expect(page).to have_field "order_bill_address_attributes_zipcode", with: "TST01"
|
|
end
|
|
end
|
|
end
|
|
|
|
context "payment step" do
|
|
let(:order) { create(:order_ready_for_payment, distributor: distributor) }
|
|
|
|
context "with one payment method, with a fee" do
|
|
before do
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
it "preselect the payment method if only one is available" do
|
|
expect(page).to have_checked_field "payment_method_#{payment_with_fee.id}"
|
|
end
|
|
it "displays the transaction fee" do
|
|
expect(page).to have_content("#{payment_with_fee.name} " + with_currency(1.23).to_s)
|
|
end
|
|
end
|
|
|
|
context "with a transaction fee" do
|
|
before do
|
|
click_button "Next - Order summary"
|
|
end
|
|
|
|
shared_examples "displays the transaction fee" do |checkout_page|
|
|
it "on the #{checkout_page} page" do
|
|
expect(page).to have_content("Transaction fee #{with_currency(1.23)}")
|
|
|
|
if checkout_page.eql?("order confirmation")
|
|
expect(page).to have_content "Your order has been processed successfully"
|
|
end
|
|
end
|
|
end
|
|
|
|
it_behaves_like "displays the transaction fee", "order summary"
|
|
|
|
context "after completing the order" do
|
|
before do
|
|
click_on "Complete order"
|
|
end
|
|
it_behaves_like "displays the transaction fee", "order confirmation"
|
|
end
|
|
end
|
|
|
|
context "with more than one payment method" do
|
|
let!(:payment_method) { create(:payment_method, distributors: [distributor]) }
|
|
|
|
before do
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
it "don't preselect the payment method if more than one is available" do
|
|
expect(page).to have_field "payment_method_#{payment_with_fee.id}", checked: false
|
|
expect(page).to have_field "payment_method_#{payment_method.id}", checked: false
|
|
end
|
|
|
|
it "requires choosing a payment method" do
|
|
click_on "Next - Order summary"
|
|
expect(page).to have_content "Select a payment method"
|
|
end
|
|
end
|
|
|
|
describe "vouchers" do
|
|
before { Flipper.enable :vouchers }
|
|
|
|
context "with no voucher available" do
|
|
before do
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
it "doesn't show voucher input" do
|
|
expect(page).not_to have_content "Apply voucher"
|
|
end
|
|
end
|
|
|
|
context "with voucher available" do
|
|
let!(:voucher) do
|
|
create(:voucher_flat_rate, code: 'some_code', enterprise: distributor, amount: 15)
|
|
end
|
|
|
|
describe "adding voucher to the order" do
|
|
before do
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
it "adds a voucher to the order" do
|
|
apply_voucher "some_code"
|
|
|
|
expect(page).to have_content "$15.00 Voucher"
|
|
expect(order.reload.voucher_adjustments.length).to eq(1)
|
|
end
|
|
|
|
context "when voucher covers more then the order total" do
|
|
before do
|
|
order.total = 6
|
|
order.save!
|
|
end
|
|
|
|
it "shows a warning message and doesn't require payment" do
|
|
apply_voucher "some_code"
|
|
|
|
expect(page).to have_content "$15.00 Voucher"
|
|
expect(page).to have_content(
|
|
"Note: if your order total is less than your voucher " \
|
|
"you may not be able to spend the remaining value."
|
|
)
|
|
|
|
expect(page).to have_content "No payment required"
|
|
click_button "Next - Order summary"
|
|
# Expect to be on the Order Summary page
|
|
expect(page).to have_content "Delivery details"
|
|
end
|
|
end
|
|
|
|
context "voucher doesn't exist" do
|
|
it "show an error" do
|
|
fill_in "Enter voucher code", with: "non_code"
|
|
click_button("Apply")
|
|
|
|
expect(page).to have_content("Voucher code Not found")
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "removing voucher from order" do
|
|
before do
|
|
add_voucher_to_order(voucher, order)
|
|
|
|
visit checkout_step_path(:payment)
|
|
|
|
accept_confirm "Are you sure you want to remove the voucher?" do
|
|
click_on "Remove code"
|
|
end
|
|
end
|
|
|
|
it "removes voucher" do
|
|
within '#voucher-section' do
|
|
expect(page).to have_button("Apply", disabled: true)
|
|
expect(page).to have_field "Enter voucher code" # Currently no confirmation msg
|
|
end
|
|
|
|
expect(page).not_to have_content "No payment required"
|
|
expect(order.voucher_adjustments.length).to eq(0)
|
|
end
|
|
|
|
it "can re-enter a voucher" do
|
|
apply_voucher "some_code"
|
|
|
|
expect(page).to have_content("$15.00 Voucher")
|
|
expect(order.reload.voucher_adjustments.length).to eq(1)
|
|
|
|
expect(page).to have_content "No payment required"
|
|
|
|
click_button "Next - Order summary"
|
|
# Expect to be on the Order Summary page
|
|
expect(page).to have_content "Delivery details"
|
|
end
|
|
|
|
it "can proceed with payment" do
|
|
click_button "Next - Order summary"
|
|
# Expect to be on the Order Summary page
|
|
expect(page).to have_content "Delivery details"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "choosing" do
|
|
shared_examples "different payment methods" do |pay_method|
|
|
context "checking out with #{pay_method}", if: pay_method.eql?("Stripe SCA") == false do
|
|
before do
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
it "proceeds to the summary step and completes the order" do
|
|
choose pay_method.to_s
|
|
proceed_to_summary
|
|
|
|
place_order
|
|
expect(page).to have_content "Paying via: #{pay_method}"
|
|
expect(order.reload.state).to eq "complete"
|
|
end
|
|
end
|
|
|
|
context "for Stripe SCA", if: pay_method.eql?("Stripe SCA") do
|
|
around do |example|
|
|
with_stripe_setup { example.run }
|
|
end
|
|
|
|
before do
|
|
stripe_enable
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
it "selects Stripe SCA and proceeds to the summary step" do
|
|
choose pay_method.to_s
|
|
fill_out_card_details
|
|
click_on "Next - Order summary"
|
|
proceed_to_summary
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "shared examples" do
|
|
let!(:cash) { create(:payment_method, distributors: [distributor], name: "Cash") }
|
|
|
|
context "Cash" do
|
|
it_behaves_like "different payment methods", "Cash"
|
|
end
|
|
|
|
context "Paypal" do
|
|
let!(:paypal) do
|
|
Spree::Gateway::PayPalExpress.create!(
|
|
name: "Paypal",
|
|
environment: "test",
|
|
distributor_ids: [distributor.id]
|
|
)
|
|
end
|
|
|
|
before do
|
|
stub_paypal_response(
|
|
success: true,
|
|
redirect: payment_gateways_confirm_paypal_path(
|
|
payment_method_id: paypal.id, token: "t123", PayerID: 'p123'
|
|
)
|
|
)
|
|
stub_paypal_confirm
|
|
end
|
|
|
|
it_behaves_like "different payment methods", "Paypal"
|
|
end
|
|
|
|
context "Stripe SCA" do
|
|
let!(:stripe_account) { create(:stripe_account, enterprise: distributor) }
|
|
let!(:stripe_sca_payment_method) {
|
|
create(:stripe_sca_payment_method, distributors: [distributor], name: "Stripe SCA")
|
|
}
|
|
|
|
it_behaves_like "different payment methods", "Stripe SCA"
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "hiding a payment method with a default rule" do
|
|
let!(:tagged_customer) { create(:customer, user: user, enterprise: distributor) }
|
|
let!(:hidden_method) {
|
|
create(:payment_method, distributors: [distributor], name: "Hidden", tag_list: "hide_pm")
|
|
}
|
|
before do
|
|
create(:filter_payment_methods_tag_rule,
|
|
enterprise: distributor,
|
|
is_default: true,
|
|
preferred_payment_method_tags: "hide_pm",
|
|
preferred_matched_payment_methods_visibility: 'hidden')
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
context "with no exceptions set to a customer" do
|
|
it "hides the payment method" do
|
|
expect(page).not_to have_content hidden_method.name
|
|
end
|
|
end
|
|
|
|
context "with an exception set to a customer" do
|
|
before do
|
|
create(:filter_payment_methods_tag_rule,
|
|
enterprise: distributor,
|
|
preferred_customer_tags: "show_pm",
|
|
preferred_payment_method_tags: "hide_pm",
|
|
preferred_matched_payment_methods_visibility: 'visible')
|
|
tagged_customer.update_attribute(:tag_list, "show_pm")
|
|
visit checkout_step_path(:payment)
|
|
end
|
|
|
|
it "displays the payment method" do
|
|
expect(page).to have_content hidden_method.name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "summary step" do
|
|
let(:order) {
|
|
create(:order_ready_for_confirmation, distributor: distributor)
|
|
}
|
|
|
|
describe "display the delivery address and not the ship address" do
|
|
let(:ship_address) { create(:address, :randomized) }
|
|
let(:bill_address) { create(:address, :randomized) }
|
|
|
|
before do
|
|
order.update_attribute(:ship_address, ship_address)
|
|
order.update_attribute(:bill_address, bill_address)
|
|
visit checkout_step_path(:summary)
|
|
end
|
|
|
|
it "displays the ship address" do
|
|
expect(page).to have_content "Delivery address"
|
|
expect(page).to have_content order.ship_address.address1
|
|
expect(page).to have_content order.ship_address.city
|
|
expect(page).to have_content order.ship_address.zipcode
|
|
expect(page).to have_content order.ship_address.phone
|
|
end
|
|
|
|
it "and not the billing address" do
|
|
expect(page).not_to have_content order.bill_address.address1
|
|
expect(page).not_to have_content order.bill_address.city
|
|
expect(page).not_to have_content order.bill_address.zipcode
|
|
expect(page).not_to have_content order.bill_address.phone
|
|
end
|
|
end
|
|
|
|
describe "with an order with special instructions" do
|
|
before do
|
|
order.update_attribute(:special_instructions, "Please deliver on Tuesday")
|
|
visit checkout_step_path(:summary)
|
|
end
|
|
|
|
it "displays the special instructions" do
|
|
expect(page).to have_content "Please deliver on Tuesday"
|
|
end
|
|
end
|
|
|
|
describe "completing the checkout" do
|
|
it "keeps the distributor selected for the current user after completion" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
expect(page).to have_content "Shopping @ #{distributor.name}"
|
|
|
|
place_order
|
|
|
|
expect(page).to have_content "Back To Store"
|
|
expect(order.reload.state).to eq "complete"
|
|
|
|
expect(page).to have_content "Shopping @ #{distributor.name}"
|
|
end
|
|
end
|
|
|
|
describe "navigation available" do
|
|
it "redirect to Payment method step by clicking on 'Payment method' link" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
click_link "Payment method"
|
|
|
|
expect(page).to have_content("You can review and confirm your order in the next step " \
|
|
"which includes the final costs.")
|
|
end
|
|
end
|
|
|
|
describe "terms and conditions" do
|
|
let(:customer) { create(:customer, enterprise: order.distributor, user: user) }
|
|
let(:tos_url) { "https://example.org/tos" }
|
|
let(:system_terms_path) { Rails.public_path.join('Terms-of-service.pdf') }
|
|
let(:shop_terms_path) { Rails.public_path.join('Terms-of-ServiceUK.pdf') }
|
|
let(:system_terms) {
|
|
Rack::Test::UploadedFile.new(system_terms_path, "application/pdf")
|
|
}
|
|
let(:shop_terms) {
|
|
Rack::Test::UploadedFile.new(shop_terms_path, "application/pdf")
|
|
}
|
|
|
|
context "when none are required" do
|
|
it "doesn't show checkbox or links" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
within "#checkout" do
|
|
expect(page).to_not have_field "order_accept_terms"
|
|
expect(page).to_not have_link "Terms and Conditions"
|
|
expect(page).to_not have_link "Terms of service"
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when distributor has T&Cs" do
|
|
before do
|
|
order.distributor.update!(terms_and_conditions: shop_terms)
|
|
end
|
|
|
|
describe "when customer has not accepted T&Cs before" do
|
|
it "shows a link to the T&Cs and disables checkout button until terms are accepted" do
|
|
visit checkout_step_path(:summary)
|
|
expect(page).to have_link "Terms and Conditions", href: /#{shop_terms_path.basename}$/
|
|
expect(page).to have_field "order_accept_terms", checked: false
|
|
end
|
|
end
|
|
|
|
describe "when customer has already accepted T&Cs before" do
|
|
before do
|
|
customer.update terms_and_conditions_accepted_at: Time.zone.now
|
|
end
|
|
|
|
it "enables checkout button (because T&Cs are accepted by default)" do
|
|
visit checkout_step_path(:summary)
|
|
expect(page).to have_field "order_accept_terms", checked: true
|
|
end
|
|
|
|
describe "but afterwards the enterprise has uploaded a new T&Cs file" do
|
|
before { order.distributor.update!(terms_and_conditions: shop_terms) }
|
|
|
|
it "disables checkout button until terms are accepted" do
|
|
visit checkout_step_path(:summary)
|
|
expect(page).to have_field "order_accept_terms", checked: false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when the platform's terms of service have to be accepted" do
|
|
before do
|
|
allow(Spree::Config).to receive(:shoppers_require_tos).and_return(true)
|
|
allow(Spree::Config).to receive(:footer_tos_url).and_return(tos_url)
|
|
end
|
|
|
|
it "shows the terms which need to be accepted" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
expect(page).to have_link "Terms of service", href: tos_url
|
|
expect(find_link("Terms of service")[:target]).to eq "_blank"
|
|
expect(page).to have_field "order_accept_terms", checked: false
|
|
end
|
|
|
|
context "when the terms have been accepted in the past" do
|
|
context "with a dedicated ToS file" do
|
|
before do
|
|
TermsOfServiceFile.create!(
|
|
attachment: system_terms,
|
|
updated_at: 1.day.ago,
|
|
)
|
|
customer.update(terms_and_conditions_accepted_at: Time.zone.now)
|
|
end
|
|
|
|
it "remembers the selection" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
expect(page).to have_link("Terms of service", href: /Terms-of-service.pdf/)
|
|
expect(page).to have_field "order_accept_terms", checked: true
|
|
end
|
|
end
|
|
|
|
context "with the default ToS file" do
|
|
before do
|
|
customer.update(terms_and_conditions_accepted_at: Time.zone.now)
|
|
end
|
|
|
|
it "remembers the selection" do
|
|
pending "#10675"
|
|
|
|
visit checkout_step_path(:summary)
|
|
|
|
expect(page).to have_link("Terms of service", href: tos_url)
|
|
expect(page).to have_field "order_accept_terms", checked: true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when the seller's terms and the platform's terms have to be accepted" do
|
|
before do
|
|
order.distributor.update!(terms_and_conditions: shop_terms)
|
|
|
|
allow(Spree::Config).to receive(:shoppers_require_tos).and_return(true)
|
|
allow(Spree::Config).to receive(:footer_tos_url).and_return(tos_url)
|
|
end
|
|
|
|
it "shows links to both terms and all need accepting" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
expect(page).to have_link "Terms and Conditions", href: /#{shop_terms_path.basename}$/
|
|
expect(page).to have_link "Terms of service", href: tos_url
|
|
expect(page).to have_field "order_accept_terms", checked: false
|
|
end
|
|
end
|
|
end
|
|
|
|
context "handle the navigation when the order is ready for confirmation" do
|
|
it "redirect to summary step" do
|
|
visit "/checkout"
|
|
|
|
expect(page).to have_current_path checkout_step_path(:summary)
|
|
end
|
|
|
|
it "handle the navigation between each step by clicking tabs/buttons to submit the form" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
click_on "Your details"
|
|
|
|
expect(page).to have_current_path checkout_step_path(:details)
|
|
|
|
click_on "Next - Payment method"
|
|
|
|
expect(page).to have_current_path checkout_step_path(:payment)
|
|
end
|
|
end
|
|
|
|
describe "order state" do
|
|
before do
|
|
visit checkout_step_path(:summary)
|
|
end
|
|
|
|
it "emptying the cart changes the order state back to address" do
|
|
visit main_app.cart_path
|
|
expect {
|
|
find('#clear_cart_link').click
|
|
expect(page).to have_current_path enterprise_shop_path(distributor)
|
|
}.to change { order.reload.state }.from("confirmation").to("address")
|
|
end
|
|
end
|
|
|
|
describe "vouchers" do
|
|
let(:voucher) do
|
|
create(:voucher_flat_rate, code: 'some_code', enterprise: distributor, amount: 6)
|
|
end
|
|
|
|
before do
|
|
add_voucher_to_order(voucher, order)
|
|
end
|
|
|
|
it "shows the applied voucher" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
within ".summary-right" do
|
|
expect(page).to have_content "some_code"
|
|
expect(page).to have_content "-6"
|
|
end
|
|
end
|
|
|
|
context "with voucher deactivated after being added to an order" do
|
|
it "completes the order" do
|
|
visit checkout_step_path(:summary)
|
|
|
|
# Deactivate voucher
|
|
voucher.destroy
|
|
|
|
place_order
|
|
|
|
expect(order.reload.state).to eq "complete"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "with previous open orders" do
|
|
let(:order) {
|
|
create(:order_ready_for_confirmation, distributor: distributor,
|
|
order_cycle: order_cycle, user_id: user.id)
|
|
}
|
|
let!(:prev_order) {
|
|
create(:completed_order_with_totals,
|
|
order_cycle: order_cycle, distributor: distributor, user_id: order.user_id)
|
|
}
|
|
|
|
context "when distributor allows order changes" do
|
|
before do
|
|
order.distributor.allow_order_changes = true
|
|
order.distributor.save
|
|
visit checkout_step_path(:summary)
|
|
end
|
|
|
|
it "informs about previous orders" do
|
|
expect(page).to have_content("You have an order for this order cycle already.")
|
|
end
|
|
|
|
it "show a link to /cart#bought-products page" do
|
|
expect(page).to have_link("cart", href: "/cart#bought-products")
|
|
click_on "cart"
|
|
expect(page).to have_text(
|
|
"#{prev_order.line_items.length} " \
|
|
"additional items already confirmed for this order cycle"
|
|
)
|
|
end
|
|
end
|
|
|
|
it "don't display any message if distributor don't allow order changes" do
|
|
order.distributor.allow_order_changes = false
|
|
order.distributor.save
|
|
visit checkout_step_path(:summary)
|
|
|
|
expect(page).to_not have_content("You have an order for this order cycle already.")
|
|
end
|
|
end
|
|
end
|
|
|
|
def add_voucher_to_order(voucher, order)
|
|
voucher.create_adjustment(voucher.code, order)
|
|
VoucherAdjustmentsService.new(order).update
|
|
order.update_totals_and_states
|
|
end
|
|
end
|