From a0c7dc2ccbf4ca07e847b9db61f44183aa42cb7e Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 24 Jun 2020 11:47:26 +1000 Subject: [PATCH 1/3] Remove leftover empty spec context --- spec/features/consumer/shopping/shopping_spec.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index b947b23d3d..6d37432902 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -148,17 +148,6 @@ feature "As a consumer I want to shop with a distributor", js: true do end end end - - context "when logged in" do - let!(:prev_order) { create(:completed_order_with_totals, order_cycle: oc1, distributor: distributor, user: order.user) } - - before do - distributor.allow_order_changes = true - distributor.save - quick_login_as order.user - visit shop_path - end - end end end From 70347148a18b31800ea47978f06930cc14433774 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 19 Jun 2020 16:36:44 +1000 Subject: [PATCH 2/3] Stabilise shopping specs and open them for change The way we add items to the cart will change. Encapsulating that code in a common place will make the mobile ux work clearer and avoid merge conflicts. The waiting for background requests has also been improved and made more consistent which should make these specs more reliable. --- .../shopping/embedded_shopfronts_spec.rb | 2 +- .../consumer/shopping/shopping_spec.rb | 89 ++++++------------- .../shopping/variant_overrides_spec.rb | 26 +++--- spec/support/request/checkout_workflow.rb | 2 +- spec/support/request/shop_workflow.rb | 73 ++++++++++++++- spec/support/request/ui_component_helper.rb | 4 - spec/support/request/web_helper.rb | 4 - 7 files changed, 112 insertions(+), 88 deletions(-) diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index 20c7bfccb8..445a92186f 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -45,7 +45,7 @@ feature "Using embedded shopfront functionality", js: true do it "allows shopping and checkout" do on_embedded_page do - fill_in "variants[#{variant.id}]", with: 1 + click_add_to_cart edit_cart diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index 6d37432902..cf825ca475 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -104,9 +104,8 @@ feature "As a consumer I want to shop with a distributor", js: true do expect(page).to have_content with_currency(1020.99) # -- Cart shows correct price - fill_in "variants[#{variant.id}]", with: 1 - toggle_cart - within(".cart-sidebar") { expect(page).to have_content with_currency(1020.99) } + click_add_to_cart variant + expect(page).to have_in_cart with_currency(1020.99) toggle_cart # -- Changing order cycle @@ -119,10 +118,8 @@ feature "As a consumer I want to shop with a distributor", js: true do # ng-animate means that the old product row is likely to be present, so we ensure # that we are not filling in the quantity on the outgoing row expect(page).not_to have_selector "tr.product-cart" - within('product:not(.ng-leave)') { fill_in "variants[#{variant.id}]", with: 1 } - - wait_for_cart - within(".cart-sidebar") { expect(page).to have_content with_currency(19.99) } + within('product:not(.ng-leave)') { click_add_to_cart variant } + expect(page).to have_in_cart with_currency(19.99) end describe "declining to clear the cart" do @@ -132,15 +129,14 @@ feature "As a consumer I want to shop with a distributor", js: true do visit shop_path select "turtles", from: "order_cycle_id" - fill_in "variants[#{variant.id}]", with: 1 + click_add_to_cart variant end it "leaves the cart untouched when the user declines" do handle_js_confirm(false) do select "frogs", from: "order_cycle_id" - toggle_cart + expect(page).to have_in_cart "1" expect(page).to have_selector "tr.product-cart" - expect(page).to have_selector '.cart-sidebar', text: '1' # The order cycle choice should not have changed expect(page).to have_select 'order_cycle_id', selected: 'turtles' @@ -219,11 +215,8 @@ feature "As a consumer I want to shop with a distributor", js: true do visit shop_path expect(page).to have_content product.name - # Add product to cart - fill_in "variants[#{variant.id}]", with: '1' - wait_for_debounce + click_add_to_cart variant expect(page).to have_in_cart product.name - wait_until { !cart_dirty } # Try to go to cart visit main_app.cart_path @@ -249,17 +242,14 @@ feature "As a consumer I want to shop with a distributor", js: true do it "should save group buy data to the cart and display it on shopfront reload" do # -- Quantity - fill_in "variants[#{variant.id}]", with: 6 - wait_for_debounce + click_add_bulk_to_cart variant, 6 expect(page).to have_in_cart product.name - wait_until { !cart_dirty } + toggle_cart expect(order.reload.line_items.first.quantity).to eq(6) # -- Max quantity - fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7 - wait_for_debounce - wait_until { !cart_dirty } + click_add_bulk_max_to_cart variant, 7 expect(order.reload.line_items.first.max_quantity).to eq(7) @@ -285,15 +275,15 @@ feature "As a consumer I want to shop with a distributor", js: true do end it "lets us add and remove products from our cart" do - fill_in "variants[#{variant.id}]", with: '1' + click_add_to_cart variant expect(page).to have_in_cart product.name - wait_until { !cart_dirty } li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last expect(li.quantity).to eq(1) - fill_in "variants[#{variant.id}]", with: '0' + toggle_cart + click_remove_from_cart variant + toggle_cart within('.cart-sidebar') { expect(page).not_to have_content product.name } - wait_until { !cart_dirty } expect(Spree::LineItem.where(id: li)).to be_empty end @@ -302,7 +292,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update on_hand: 5, on_demand: true visit shop_path - fill_in "variants[#{variant.id}]", with: '10' + click_add_to_cart variant, 10 expect(page).to have_field "variants[#{variant.id}]", with: '10' end @@ -311,6 +301,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update on_hand: 5 visit shop_path + accept_alert 'Insufficient stock available, only 5 remaining' do fill_in "variants[#{variant.id}]", with: '10' end @@ -325,9 +316,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update! on_hand: 0 # -- Messaging - expect(page).to have_input "variants[#{variant.id}]" - fill_in "variants[#{variant.id}]", with: '1' - wait_until { !cart_dirty } + click_add_to_cart variant within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -342,8 +331,6 @@ feature "As a consumer I want to shop with a distributor", js: true do # Update amount available in product list # If amount falls to zero, variant should be greyed out and input disabled expect(page).to have_selector "#variant-#{variant.id}.out-of-stock" - expect(page).to have_selector "#variants_#{variant.id}[ofn-on-hand='0']" - expect(page).to have_selector "#variants_#{variant.id}[disabled='disabled']" end it 'does not show out of stock modal if product is on_demand' do @@ -351,9 +338,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update! on_hand: 0, on_demand: true - expect(page).to have_input "variants[#{variant.id}]" - fill_in "variants[#{variant.id}]", with: '1' - wait_until { !cart_dirty } + click_add_to_cart variant expect(page).to_not have_selector '.out-of-stock-modal' end @@ -363,13 +348,11 @@ feature "As a consumer I want to shop with a distributor", js: true do it "does the same" do # -- Place in cart so we can set max_quantity, then make out of stock - fill_in "variants[#{variant.id}]", with: '1' - wait_until { !cart_dirty } + click_add_bulk_to_cart variant variant.update! on_hand: 0 # -- Messaging - fill_in "variant_attributes[#{variant.id}][max_quantity]", with: '1' - wait_until { !cart_dirty } + click_add_bulk_max_to_cart variant within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -389,13 +372,11 @@ feature "As a consumer I want to shop with a distributor", js: true do context "when the update is for another product" do it "updates quantity" do - fill_in "variants[#{variant.id}]", with: '2' - wait_until { !cart_dirty } + click_add_to_cart variant, 2 variant.update! on_hand: 1 - fill_in "variants[#{variant2.id}]", with: '1' - wait_until { !cart_dirty } + click_add_to_cart variant2 within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -407,13 +388,12 @@ feature "As a consumer I want to shop with a distributor", js: true do let(:product) { create(:simple_product, group_buy: true) } it "does not update max_quantity" do - fill_in "variants[#{variant.id}]", with: '2' - fill_in "variant_attributes[#{variant.id}][max_quantity]", with: '3' - wait_until { !cart_dirty } + click_add_bulk_to_cart variant, 2 + click_add_bulk_max_to_cart variant, 3 + variant.update! on_hand: 1 - fill_in "variants[#{variant2.id}]", with: '1' - wait_until { !cart_dirty } + click_add_bulk_to_cart variant2 within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -432,7 +412,7 @@ feature "As a consumer I want to shop with a distributor", js: true do it "handles it as if the variant has gone out of stock" do variant.delete - fill_in "variants[#{variant.id}]", with: '1' + click_add_to_cart variant expect_out_of_stock_behavior end @@ -447,7 +427,7 @@ feature "As a consumer I want to shop with a distributor", js: true do it "handles it as if the variant has gone out of stock" do variant.delete - fill_in "variants[#{variant.id}]", with: '1' + click_add_to_cart variant expect_out_of_stock_behavior end @@ -567,16 +547,7 @@ feature "As a consumer I want to shop with a distributor", js: true do expect(page).to have_content product.name end - def wait_for_debounce - # The auto-submit on these specific form elements (add to cart) now has a small built-in - # waiting period before submitting the data... - sleep 0.6 - end - def expect_out_of_stock_behavior - wait_for_debounce - wait_until { !cart_dirty } - # Shows an "out of stock" modal, with helpful user feedback within(".out-of-stock-modal") do expect(page).to have_content I18n.t('js.out_of_stock.out_of_stock_text') @@ -587,9 +558,5 @@ feature "As a consumer I want to shop with a distributor", js: true do expect(page).to have_selector "#variant-#{variant.id}.out-of-stock" expect(page).to have_selector "#variants_#{variant.id}[ofn-on-hand='0']" expect(page).to have_selector "#variants_#{variant.id}[disabled='disabled']" - - # We need to wait again for the cart to finish updating in Angular or the test can fail - # as the session cannot be reset properly (after the test) while it's still loading - wait_until { !cart_dirty } end end diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index 6dfed074a7..eec53d5871 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -66,9 +66,7 @@ feature "shopping with variant overrides defined", js: true do end it "shows the correct prices when products are in the cart" do - fill_in "variants[#{product1_variant1.id}]", with: "2" - toggle_cart - wait_until_enabled '.cart-sidebar a.edit-cart' + click_add_to_cart product1_variant1, 2 visit shop_path expect(page).to have_price with_currency(61.11) end @@ -77,14 +75,14 @@ feature "shopping with variant overrides defined", js: true do # https://github.com/openfoodfoundation/openfoodnetwork/issues/312 it "shows the overridden price with fees in the quick cart" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 toggle_cart expect(page).to have_selector "#cart-variant-#{product1_variant1.id} .quantity", text: '2' expect(page).to have_selector "#cart-variant-#{product1_variant1.id} .total-price", text: with_currency(122.22) end it "shows the correct prices in the shopping cart" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 edit_cart expect(page).to have_selector "tr.line-item.variant-#{product1_variant1.id} .cart-item-price", text: with_currency(61.11) @@ -96,7 +94,7 @@ feature "shopping with variant overrides defined", js: true do end it "shows the correct prices in the checkout" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 click_checkout expect(page).to have_selector 'form.edit_order .cart-total', text: with_currency(122.22) @@ -107,7 +105,7 @@ feature "shopping with variant overrides defined", js: true do describe "creating orders" do it "creates the order with the correct prices" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 click_checkout complete_checkout @@ -118,7 +116,7 @@ feature "shopping with variant overrides defined", js: true do end it "subtracts stock from the override" do - fill_in "variants[#{product1_variant3.id}]", with: "2" + click_add_to_cart product1_variant3, 2 click_checkout expect do @@ -129,7 +127,7 @@ feature "shopping with variant overrides defined", js: true do end it "subtracts stock from stock-overridden on_demand variants" do - fill_in "variants[#{product3_variant2.id}]", with: "2" + click_add_to_cart product3_variant2, 2 click_checkout expect do @@ -140,7 +138,7 @@ feature "shopping with variant overrides defined", js: true do end it "does not subtract stock from overrides that do not override count_on_hand" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 click_checkout expect do complete_checkout @@ -149,7 +147,7 @@ feature "shopping with variant overrides defined", js: true do end it "does not subtract stock from variants where the override has on_demand: true" do - fill_in "variants[#{product4_variant1.id}]", with: "2" + click_add_to_cart product4_variant1, 2 click_checkout expect do complete_checkout @@ -159,7 +157,7 @@ feature "shopping with variant overrides defined", js: true do it "does not show out of stock flags on order confirmation page" do product1_variant3.on_hand = 0 - fill_in "variants[#{product1_variant3.id}]", with: "2" + click_add_to_cart product1_variant3, 2 click_checkout complete_checkout @@ -202,7 +200,7 @@ feature "shopping with variant overrides defined", js: true do def click_checkout toggle_cart - wait_until_enabled '.cart-sidebar a.edit-cart' - first(:link, I18n.t('shared.menu.cart_sidebar.checkout')).click + wait_for_cart + click_link I18n.t('shared.menu.cart_sidebar.checkout') end end diff --git a/spec/support/request/checkout_workflow.rb b/spec/support/request/checkout_workflow.rb index 8a4ea7974d..c6863a1bf5 100644 --- a/spec/support/request/checkout_workflow.rb +++ b/spec/support/request/checkout_workflow.rb @@ -4,7 +4,7 @@ module CheckoutWorkflow end def checkout_as_guest - find("button", text: "Checkout as guest").click + click_button "Checkout as guest" end def place_order diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index e5123715e0..c6a469e6c4 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -1,13 +1,28 @@ module ShopWorkflow + # If a spec uses `within` but we want to check something outside of that + # scope, we can search from the body element instead. + def find_body + page.all("body").first || page.find(:xpath, "ancestor::body") + end + def wait_for_cart - first("#cart").click - within '.cart-sidebar' do - expect(page).to_not have_link "Updating cart..." + # Wait for debounce + # + # The auto-submit on these specific form elements (add to cart) now has a small built-in + # waiting period before submitting the data... + sleep 0.6 + + within find_body do + # We ignore visibility in case the cart dropdown is not open. + within '.cart-sidebar', visible: false do + expect(page).to_not have_link "Updating cart...", visible: false + end end end def edit_cart wait_for_cart + toggle_cart within '.cart-sidebar' do expect(page).to have_link I18n.t('shared.menu.cart_sidebar.edit_cart') end @@ -34,6 +49,58 @@ module ShopWorkflow order.update_distribution_charge! end + # Add an item to the cart + # + # At the moment, the user enters the quantity into an input field. + # But with the coming mobile-friendly UX, the user will click a button to + # add an item, hence the naming. + # + # This is temporary code. The duplication will be removed by the mobile + # product listings feature. This has been backported to avoid merge + # conflicts and to make the current build more stable. + def click_add_to_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find("input") + new_quantity = input.value.to_i + quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def click_remove_from_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find("input") + new_quantity = input.value.to_i - quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def click_add_bulk_to_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find("input") + new_quantity = input.value.to_i + quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def click_add_bulk_max_to_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find(:field, "variant_attributes[#{variant.id}][max_quantity]") + new_quantity = input.value.to_i + quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def within_variant(variant = nil) + selector = variant ? "#variant-#{variant.id}" : ".variants" + within(selector) do + yield + end + end + def toggle_accordion(name) find("dd a", text: name).click end diff --git a/spec/support/request/ui_component_helper.rb b/spec/support/request/ui_component_helper.rb index b23002e3d7..dd2f38bd46 100644 --- a/spec/support/request/ui_component_helper.rb +++ b/spec/support/request/ui_component_helper.rb @@ -69,10 +69,6 @@ module UIComponentHelper page.find("#cart").click end - def cart_dirty - page.find("span.cart-span")[:class].include? 'pure-dirty' - end - def wait_for_ajax counter = 0 while page.execute_script("return $.active").to_i > 0 diff --git a/spec/support/request/web_helper.rb b/spec/support/request/web_helper.rb index 732e306a29..25ae07bbc1 100644 --- a/spec/support/request/web_helper.rb +++ b/spec/support/request/web_helper.rb @@ -95,10 +95,6 @@ module WebHelper end end - def wait_until_enabled(selector) - wait_until(10) { first("#{selector}:not([disabled='disabled'])") } - end - def select2_select(value, options) id = options[:from] options[:from] = "#s2id_#{id}" From d7c9bb2e5afb7f39274343e69ad9cc504c9fa296 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 25 Jun 2020 16:36:39 +1000 Subject: [PATCH 3/3] Navigate more efficiently in spec The spec is not supposed to test the navigation to the shop. Going directly to the shop reduces the test execution time by 7%. --- spec/features/consumer/shopping/variant_overrides_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index eec53d5871..9c7ca0a5d1 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -37,8 +37,7 @@ feature "shopping with variant overrides defined", js: true do outgoing_exchange.variants = [product1_variant1, product1_variant2, product2_variant1, product1_variant3, product3_variant1, product3_variant2, product4_variant1] outgoing_exchange.enterprise_fees << enterprise_fee sm.calculator.preferred_amount = 0 - visit shops_path - click_link hub.name + visit enterprise_shop_path(hub) end describe "viewing products" do