spree_analytics_trackers 2.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +2 -0
  5. data/.travis.yml +44 -0
  6. data/Appraisals +11 -0
  7. data/Gemfile +7 -0
  8. data/LICENSE +26 -0
  9. data/README.md +77 -0
  10. data/Rakefile +21 -0
  11. data/app/assets/javascripts/spree/frontend/add_to_cart_analytics.js +46 -0
  12. data/app/controllers/spree/admin/trackers_controller.rb +6 -0
  13. data/app/controllers/spree_analytics_trackers/store_controller_decorator.rb +14 -0
  14. data/app/helpers/spree/trackers_helper.rb +70 -0
  15. data/app/models/spree/tracker.rb +25 -0
  16. data/app/models/spree_analytics_trackers/user_decorator.rb +9 -0
  17. data/app/overrides/add_analytics_to_admin_sidebar.rb +8 -0
  18. data/app/overrides/add_cart_viewed_to_orders_edit.rb +10 -0
  19. data/app/overrides/add_checkout_step_viewed_to_checkout_edit.rb +18 -0
  20. data/app/overrides/add_google_analytics_page_view_to_spree_application.rb +18 -0
  21. data/app/overrides/add_google_analytics_to_spree_application.rb +17 -0
  22. data/app/overrides/add_google_purchase_to_orders_show.rb +9 -0
  23. data/app/overrides/add_order_complete_to_orders_show.rb +10 -0
  24. data/app/overrides/add_product_list_filtered_to_taxons_show.rb +10 -0
  25. data/app/overrides/add_product_list_viewed_to_products_list.rb +10 -0
  26. data/app/overrides/add_product_viewed_to_products_show.rb +10 -0
  27. data/app/overrides/add_products_searched_to_products_list.rb +10 -0
  28. data/app/overrides/add_segment_initializer_to_layout.rb +18 -0
  29. data/app/overrides/add_segment_page_viewed_to_layout.rb +18 -0
  30. data/app/presenters/spree_analytics_trackers/base_presenter.rb +14 -0
  31. data/app/presenters/spree_analytics_trackers/segment/order_presenter.rb +32 -0
  32. data/app/presenters/spree_analytics_trackers/segment/product_presenter.rb +40 -0
  33. data/app/views/spree/admin/shared/_analytics_sidebar_menu.html.erb +3 -0
  34. data/app/views/spree/admin/trackers/_form.html.erb +36 -0
  35. data/app/views/spree/admin/trackers/edit.html.erb +13 -0
  36. data/app/views/spree/admin/trackers/index.html.erb +40 -0
  37. data/app/views/spree/admin/trackers/new.html.erb +13 -0
  38. data/app/views/spree/shared/trackers/google_analytics/_checkout_step_viewed.js.erb +21 -0
  39. data/app/views/spree/shared/trackers/google_analytics/_initializer.js.erb +11 -0
  40. data/app/views/spree/shared/trackers/google_analytics/_page_viewed.js.erb +13 -0
  41. data/app/views/spree/shared/trackers/google_analytics/_purchase.js.erb +19 -0
  42. data/app/views/spree/shared/trackers/segment/_cart_viewed.js.erb +22 -0
  43. data/app/views/spree/shared/trackers/segment/_checkout_step_viewed.js.erb +14 -0
  44. data/app/views/spree/shared/trackers/segment/_initializer.js.erb +7 -0
  45. data/app/views/spree/shared/trackers/segment/_order_complete.js.erb +8 -0
  46. data/app/views/spree/shared/trackers/segment/_page_viewed.js.erb +7 -0
  47. data/app/views/spree/shared/trackers/segment/_product_list_filtered.js.erb +21 -0
  48. data/app/views/spree/shared/trackers/segment/_product_list_viewed.js.erb +17 -0
  49. data/app/views/spree/shared/trackers/segment/_product_viewed.js.erb +10 -0
  50. data/app/views/spree/shared/trackers/segment/_products_searched.js.erb +12 -0
  51. data/bin/rails +7 -0
  52. data/config/locales/en.yml +18 -0
  53. data/config/locales/zh-TW.yml +19 -0
  54. data/config/routes.rb +5 -0
  55. data/db/migrate/20171013160337_create_spree_trackers.rb +20 -0
  56. data/gemfiles/.bundle/config +2 -0
  57. data/gemfiles/spree_4_1.gemfile +9 -0
  58. data/gemfiles/spree_master.gemfile +9 -0
  59. data/lib/generators/spree_analytics_trackers/install/install_generator.rb +27 -0
  60. data/lib/spree_analytics_trackers.rb +5 -0
  61. data/lib/spree_analytics_trackers/engine.rb +20 -0
  62. data/lib/spree_analytics_trackers/factories.rb +9 -0
  63. data/lib/spree_analytics_trackers/version.rb +18 -0
  64. data/spec/features/admin/configuration/analytics_tracker_spec.rb +52 -0
  65. data/spec/features/products_spec.rb +315 -0
  66. data/spec/fixtures/thinking-cat.jpg +0 -0
  67. data/spec/models/spree/tracker_spec.rb +17 -0
  68. data/spec/presenters/spree_analytics_trackers/segment/order_presenter_spec.rb +34 -0
  69. data/spec/spec_helper.rb +18 -0
  70. data/spec/support/custom_products.rb +26 -0
  71. data/spree_analytics_trackers.gemspec +31 -0
  72. metadata +202 -0
@@ -0,0 +1,14 @@
1
+ <% if @order.present? && !@order.completed? && Spree::Tracker.current(:segment) %>
2
+ <script>
3
+ if (typeof analytics !== 'undefined') {
4
+ analytics.track('Checkout Step Viewed', {
5
+ checkout_id: '<%= @order.number %>',
6
+ step: '<%= (@order.checkout_steps.index(@order.state) + 1) %>'
7
+ });
8
+ analytics.page('Checkout Step Viewed', {
9
+ checkout_id: '<%= @order.number %>',
10
+ step: '<%= (@order.checkout_steps.index(@order.state) + 1) %>'
11
+ });
12
+ }
13
+ </script>
14
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if tracker = Spree::Tracker.current(:segment) %>
2
+ <script>
3
+ !function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on"];analytics.factory=function(t){return function(){var e=Array.prototype.slice.call(arguments);e.unshift(t);analytics.push(e);return analytics}};for(var t=0;t<analytics.methods.length;t++){var e=analytics.methods[t];analytics[e]=analytics.factory(e)}analytics.load=function(t,e){var n=document.createElement("script");n.type="text/javascript";n.async=!0;n.src="https://cdn.segment.com/analytics.js/v1/"+t+"/analytics.min.js";var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(n,a);analytics._loadOptions=e};analytics.SNIPPET_VERSION="4.1.0";
4
+ analytics.load('<%=tracker.analytics_id%>'.replace(/^\s+|\s+$/g, ''));
5
+ }}();
6
+ </script>
7
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <% if @order.present? && order_just_completed?(@order) && Spree::Tracker.current(:segment) %>
2
+ <% order_json = SpreeAnalyticsTrackers::Segment::OrderPresenter.new(@order).to_json %>
3
+ <script>
4
+ if (typeof analytics !== 'undefined') {
5
+ analytics.page('Order Completed', <%= order_json.html_safe %>);
6
+ }
7
+ </script>
8
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if tracker = Spree::Tracker.current(:segment) %>
2
+ <script>
3
+ if (typeof analytics !== 'undefined') {
4
+ analytics.page();
5
+ }
6
+ </script>
7
+ <% end %>
@@ -0,0 +1,21 @@
1
+ <% if any_filtering_params? && Spree::Tracker.current(:segment) %>
2
+ <script>
3
+ if (typeof analytics !== 'undefined') {
4
+ var segmentProductListFilteredJson = {
5
+ filters: [
6
+ <% filtering_params_with_values.each do |type, value| %>
7
+ <%= { type: type, value: value } .to_json.html_safe %>,
8
+ <% end %>
9
+ ],
10
+ products: [
11
+ <% @products.each_with_index do |product, index| %>
12
+ <%= product_for_segment(product, position: index+1) %>,
13
+ <% end %>
14
+ ]
15
+ }
16
+
17
+ analytics.track('Product List Filtered', segmentProductListFilteredJson);
18
+ analytics.page('Product List Filtered', segmentProductListFilteredJson);
19
+ }
20
+ </script>
21
+ <% end %>
@@ -0,0 +1,17 @@
1
+ <% if defined?(products) && products.present? && Spree::Tracker.current(:segment) %>
2
+ <script>
3
+ if (typeof analytics !== 'undefined') {
4
+ var segmentProductListViewedJson = {
5
+ category: '<%= @taxon&.name %>',
6
+ products: [
7
+ <% products.each_with_index do |product, index| %>
8
+ <%= product_for_segment(product, position: index+1, image: default_image_for_product_or_variant(product)) %>,
9
+ <% end %>
10
+ ]
11
+ }
12
+
13
+ analytics.track('Product List Viewed', segmentProductListViewedJson);
14
+ analytics.page('Product List Viewed', segmentProductListViewedJson);
15
+ }
16
+ </script>
17
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <% if @product.present? && Spree::Tracker.current(:segment) %>
2
+ <script>
3
+ if (typeof analytics !== 'undefined') {
4
+ var segmentProductViewed = <%= product_for_segment(@product, image: default_image_for_product_or_variant(@product)) %>;
5
+
6
+ analytics.page('Product Viewed', segmentProductViewed);
7
+ analytics.track('Product Viewed', segmentProductViewed);
8
+ }
9
+ </script>
10
+ <% end %>
@@ -0,0 +1,12 @@
1
+ <% if params.key?(:keywords) && params[:keywords].present? && Spree::Tracker.current(:segment) %>
2
+ <script>
3
+ if (typeof analytics !== 'undefined') {
4
+ analytics.track('Products Searched', {
5
+ query: '<%= params[:keywords] %>',
6
+ });
7
+ analytics.page('Products Searched', {
8
+ query: '<%= params[:keywords] %>',
9
+ });
10
+ }
11
+ </script>
12
+ <% end %>
@@ -0,0 +1,7 @@
1
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
2
+
3
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
4
+ ENGINE_PATH = File.expand_path('../../lib/spree_analytics_trackers/engine', __FILE__)
5
+
6
+ require 'rails/all'
7
+ require 'rails/engine/commands'
@@ -0,0 +1,18 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ spree/tracker:
5
+ one: Tracker
6
+ other: Trackers
7
+ spree:
8
+ analytics_engine: Analytics Engine
9
+ analytics_trackers: Analytics Trackers
10
+ new_tracker: New Tracker
11
+ google_analytics: Google Analytics
12
+ google_analytics_id: Analytics ID
13
+ analytics_desc_header_1: Spree Analytics
14
+ analytics_desc_header_2: Live analytics integrated into your Spree dashboard
15
+ analytics_desc_list_1: Get live sales information as it happens
16
+ analytics_desc_list_2: Requires only a free Spree account to activate
17
+ analytics_desc_list_3: Absolutely no code to install
18
+ analytics_desc_list_4: It's completely free!
@@ -0,0 +1,19 @@
1
+ zh-TW:
2
+ activerecord:
3
+ attributes:
4
+ spree/tracker:
5
+ one: 追蹤器
6
+ other: 追蹤器
7
+ spree:
8
+ analytics_engine: 分析引擎
9
+ analytics_trackers: 分析追蹤器
10
+ new_tracker: 新增追蹤器
11
+ google_analytics: Google 分析
12
+ google_analytics_id: Google 追蹤器代碼
13
+ analytics_desc_header_1: Spree 分析
14
+ analytics_desc_header_2: 新增即時分析到 Spree 的後台
15
+ analytics_desc_list_1: 獲得即時銷售數據
16
+ analytics_desc_list_2: 免費安裝
17
+ analytics_desc_list_3: 不需要寫任何代碼安裝
18
+ analytics_desc_list_4: 完全免費!
19
+
@@ -0,0 +1,5 @@
1
+ Spree::Core::Engine.add_routes do
2
+ namespace :admin, path: Spree.admin_path do
3
+ resources :trackers
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ class CreateSpreeTrackers < SpreeExtension::Migration[4.2]
2
+ def change
3
+ if table_exists?(:spree_trackers)
4
+ add_index :spree_trackers, :active unless index_exists?(:spree_trackers, :active)
5
+ remove_column :spree_trackers, :environment if column_exists?(:spree_trackers, :environment)
6
+ unless column_exists?(:spree_trackers, :engine)
7
+ add_column :spree_trackers, :kind, :integer, default: 0, null: false, index: true unless column_exists?(:spree_trackers, :kind)
8
+ rename_column :spree_trackers, :kind, :engine if column_exists?(:spree_trackers, :kind)
9
+ end
10
+ else
11
+ create_table :spree_trackers do |t|
12
+ t.string 'analytics_id'
13
+ t.boolean 'active', default: true, index: true
14
+ t.datetime 'created_at', null: false
15
+ t.datetime 'updated_at', null: false
16
+ t.integer 'engine', default: 0, null: false, index: true
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_RETRY: "1"
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "spree", "~> 4.1.0"
6
+ gem "spree_auth_devise", "~> 4.1.0"
7
+ gem "rails-controller-testing"
8
+
9
+ gemspec path: "../"
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "spree", github: "spree/spree", branch: "master"
6
+ gem "spree_auth_devise", github: "spree/spree_auth_devise", branch: "master"
7
+ gem "rails-controller-testing"
8
+
9
+ gemspec path: "../"
@@ -0,0 +1,27 @@
1
+ module SpreeAnalyticsTrackers
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ class_option :auto_run_migrations, type: :boolean, default: false
5
+
6
+ def add_javascripts
7
+ javascripts_path = 'vendor/assets/javascripts/spree/frontend/all.js'
8
+ return unless File.file?(javascripts_path)
9
+
10
+ append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/add_to_cart_analytics\n"
11
+ end
12
+
13
+ def add_migrations
14
+ run 'bundle exec rake railties:install:migrations FROM=spree_analytics_trackers'
15
+ end
16
+
17
+ def run_migrations
18
+ run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask 'Would you like to run the migrations now? [Y/n]')
19
+ if run_migrations
20
+ run 'bundle exec rake db:migrate'
21
+ else
22
+ puts 'Skipping rake db:migrate, don\'t forget to run it!'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ require 'spree_core'
2
+ require 'spree_extension'
3
+ require 'spree_analytics_trackers/engine'
4
+ require 'spree_analytics_trackers/version'
5
+ require 'deface'
@@ -0,0 +1,20 @@
1
+ module SpreeAnalyticsTrackers
2
+ class Engine < Rails::Engine
3
+ require 'spree/core'
4
+ isolate_namespace Spree
5
+ engine_name 'spree_analytics_trackers'
6
+
7
+ # use rspec for tests
8
+ config.generators do |g|
9
+ g.test_framework :rspec
10
+ end
11
+
12
+ def self.activate
13
+ Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
14
+ Rails.configuration.cache_classes ? require(c) : load(c)
15
+ end
16
+ end
17
+
18
+ config.to_prepare &method(:activate).to_proc
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ unless FactoryBot.factories.registered?(:tracker)
2
+ FactoryBot.define do
3
+ factory :tracker, class: Spree::Tracker do
4
+ analytics_id { 'A100' }
5
+ active { true }
6
+ engine { :google_analytics }
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module SpreeAnalyticsTrackers
2
+ module_function
3
+
4
+ # Returns the version of the currently loaded SpreeAnalyticsTrackers as a
5
+ # <tt>Gem::Version</tt>.
6
+ def version
7
+ Gem::Version.new VERSION::STRING
8
+ end
9
+
10
+ module VERSION
11
+ MAJOR = 2
12
+ MINOR = 0
13
+ TINY = 0
14
+ PRE = 'rc1'
15
+
16
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
17
+ end
18
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Analytics Tracker', type: :feature do
4
+ stub_authorization!
5
+
6
+ context 'index' do
7
+ before(:each) do
8
+ create(:tracker)
9
+ create(:tracker, analytics_id: 'A200')
10
+ visit spree.admin_trackers_path
11
+ end
12
+
13
+ it 'should have the right content' do
14
+ expect(page).to have_content('Analytics Trackers')
15
+ end
16
+
17
+ it 'should have the right tabular values displayed' do
18
+ within_row(1) do
19
+ expect(column_text(1)).to eq('A100')
20
+ expect(column_text(2)).to eq('Google analytics')
21
+ expect(column_text(3)).to eq('Yes')
22
+ end
23
+
24
+ within_row(2) do
25
+ expect(column_text(1)).to eq('A200')
26
+ expect(column_text(2)).to eq('Google analytics')
27
+ expect(column_text(3)).to eq('Yes')
28
+ end
29
+ end
30
+ end
31
+
32
+ context 'create' do
33
+ before(:each) do
34
+ visit spree.admin_trackers_path
35
+ end
36
+
37
+ it 'should be able to create a new analytics tracker' do
38
+ within('.content-header') do
39
+ click_link 'admin_new_tracker_link'
40
+ end
41
+ fill_in 'tracker_analytics_id', with: 'A100'
42
+ click_button 'Create'
43
+
44
+ expect(page).to have_content('successfully created!')
45
+ within_row(1) do
46
+ expect(column_text(1)).to eq('A100')
47
+ expect(column_text(2)).to eq('Google analytics')
48
+ expect(column_text(3)).to eq('Yes')
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,315 @@
1
+ # coding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Visiting Products', type: :feature, js: true do
5
+ include_context 'custom products'
6
+
7
+ let(:store) { Spree::Store.default }
8
+
9
+ let(:store_name) do
10
+ ((first_store = Spree::Store.first) && first_store.name).to_s
11
+ end
12
+
13
+ let!(:ga_tracker) { create(:tracker) }
14
+ let!(:segment_tracker) { create(:tracker, engine: :segment) }
15
+
16
+ before do
17
+ visit spree.products_path
18
+ allow(ENV).to receive(:[]).and_call_original
19
+ end
20
+
21
+ it 'is able to show the shopping cart after adding a product to it' do
22
+ click_link 'Ruby on Rails Ringer T-Shirt'
23
+ expect(page).to have_content('$159.99')
24
+
25
+ expect(page).to have_selector('form#add-to-cart-form')
26
+ expect(page).to have_selector(:button, id: 'add-to-cart-button', disabled: false)
27
+ click_button 'add-to-cart-button'
28
+ expect(page).to have_content(Spree.t(:added_to_cart))
29
+ end
30
+
31
+ context 'using Russian Rubles as a currency' do
32
+ before do
33
+ store.update(default_currency: 'RUB')
34
+ end
35
+
36
+ let!(:product) do
37
+ product = Spree::Product.find_by(name: 'Ruby on Rails Ringer T-Shirt')
38
+ product.master.prices.create(amount: 19.99, currency: 'RUB')
39
+ product.tap(&:save)
40
+ end
41
+
42
+ # Regression tests for #2737
43
+ context 'uses руб as the currency symbol' do
44
+ it 'on products page' do
45
+ visit spree.products_path
46
+ within("#product_#{product.id}") do
47
+ within('.product-component-price') do
48
+ expect(page).to have_content('19.99 ₽')
49
+ end
50
+ end
51
+ end
52
+
53
+ it 'on product page' do
54
+ visit spree.product_path(product)
55
+ within('.price') do
56
+ expect(page).to have_content('19.99 ₽')
57
+ end
58
+ end
59
+
60
+ it 'when adding a product to the cart' do
61
+ add_to_cart(product)
62
+
63
+ within('.shopping-cart-total-amount') do
64
+ expect(page).to have_content('19.99 ₽')
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ it 'is able to search for a product' do
71
+ find('.search-icons').click
72
+ fill_in 'keywords', with: 'shirt'
73
+
74
+ if Spree.version.to_f > 4.1
75
+ first('button[type=submit]').click
76
+ else
77
+ find('#search-dropdown label').click
78
+ end
79
+
80
+ expect(page).to have_css('.product-component-name').once
81
+ end
82
+
83
+ context 'a product with variants' do
84
+ let(:product) { Spree::Product.find_by(name: 'Ruby on Rails Baseball Jersey') }
85
+ let(:option_value) { create(:option_value) }
86
+ let!(:variant) { build(:variant, price: 5.59, product: product, option_values: []) }
87
+
88
+ before do
89
+ image = File.open(File.expand_path('../fixtures/thinking-cat.jpg', __dir__))
90
+ create_image(product, image)
91
+
92
+ product.option_types << option_value.option_type
93
+ variant.option_values << option_value
94
+ variant.save!
95
+ end
96
+
97
+ it 'is displayed' do
98
+ expect { click_link product.name }.not_to raise_error
99
+ end
100
+
101
+ it 'displays price of first variant listed' do
102
+ click_link product.name
103
+ within('#product-price') do
104
+ expect(page).to have_content variant.price
105
+ expect(page).not_to have_content Spree.t(:out_of_stock)
106
+ end
107
+ end
108
+
109
+ it "doesn't display out of stock for master product" do
110
+ product.master.stock_items.update_all count_on_hand: 0, backorderable: false
111
+
112
+ click_link product.name
113
+ within('#product-price') do
114
+ expect(page).not_to have_content Spree.t(:out_of_stock)
115
+ end
116
+ end
117
+
118
+ it "doesn't display cart form if all variants (including master) are out of stock" do
119
+ product.variants_including_master.each { |v| v.stock_items.update_all count_on_hand: 0, backorderable: false }
120
+
121
+ click_link product.name
122
+ within('[data-hook=product_price]') do
123
+ expect(page).not_to have_content Spree.t(:add_to_cart)
124
+ end
125
+ end
126
+ end
127
+
128
+ context 'a product with variants, images only for the variants' do
129
+ let(:product) { Spree::Product.find_by(name: 'Ruby on Rails Baseball Jersey') }
130
+ let(:variant1) { create(:variant, product: product, price: 9.99) }
131
+ let(:variant2) { create(:variant, product: product, price: 10.99) }
132
+
133
+ before do
134
+ image = File.open(File.expand_path('../fixtures/thinking-cat.jpg', __dir__))
135
+ create_image(variant1, image)
136
+ end
137
+
138
+ it 'does not display no image available' do
139
+ visit spree.products_path
140
+ expect(page).to have_selector("img[data-src$='thinking-cat.jpg']")
141
+ end
142
+ end
143
+
144
+ context 'an out of stock product without variants' do
145
+ let(:product) { Spree::Product.find_by(name: 'Ruby on Rails Tote') }
146
+
147
+ before do
148
+ product.master.stock_items.update_all count_on_hand: 0, backorderable: false
149
+ end
150
+
151
+ it 'does display out of stock for master product' do
152
+ click_link product.name
153
+ within('#inside-product-cart-form') do
154
+ expect(page).to have_content Spree.t(:out_of_stock).upcase
155
+ end
156
+ end
157
+
158
+ it "doesn't display cart form if master is out of stock" do
159
+ click_link product.name
160
+ within('[data-hook=product_price]') do
161
+ expect(page).not_to have_content Spree.t(:add_to_cart)
162
+ end
163
+ end
164
+ end
165
+
166
+ context 'pagination' do
167
+ before { Spree::Config.products_per_page = 3 }
168
+
169
+ it 'is able to display products priced between 151 and 200 dollars across multiple pages' do
170
+ find(:css, '#filtersPrice').click
171
+ within(:css, '#collapseFilterPrice') { click_on '$151 - $200' }
172
+ expect(page).to have_css('.product-component-name').exactly(3).times
173
+ next_page = find_all(:css, '.next_page')
174
+ within(next_page[0]) { find(:css, '.page-link').click }
175
+ expect(page).to have_css('.product-component-name').once
176
+ end
177
+ end
178
+
179
+ it 'returns the correct title when displaying a single product' do
180
+ product = Spree::Product.find_by(name: 'Ruby on Rails Baseball Jersey')
181
+ click_link product.name
182
+
183
+ within('div#product-description') do
184
+ within('h1.product-details-title') do
185
+ expect(page).to have_content('Ruby on Rails Baseball Jersey')
186
+ end
187
+ end
188
+ end
189
+
190
+ context 'product is on sale' do
191
+ let(:product) do
192
+ FactoryBot.create(:base_product, description: 'Testing sample', name: 'Sample', price: '19.99')
193
+ end
194
+ let(:option_type) { create(:option_type) }
195
+ let(:option_value1) { create(:option_value, name: 'small', presentation: 'S', option_type: option_type) }
196
+ let(:option_value2) { create(:option_value, name: 'medium', presentation: 'M', option_type: option_type) }
197
+ let(:option_value3) { create(:option_value, name: 'large', presentation: 'L', option_type: option_type) }
198
+ let(:variant1) { create(:variant, product: product, option_values: [option_value1], price: '49.99') }
199
+ let(:variant2) { create(:variant, product: product, option_values: [option_value2], price: '69.99') }
200
+ let(:variant3) { create(:variant, product: product, option_values: [option_value3], price: '89.99') }
201
+
202
+ before do
203
+ if Spree.version.to_f > 4.1
204
+ price1 = Spree::Price.find_by(variant: variant1)
205
+ price2 = Spree::Price.find_by(variant: variant2)
206
+ price3 = Spree::Price.find_by(variant: variant3)
207
+ price1.update(compare_at_amount: '149.99')
208
+ price2.update(compare_at_amount: '169.99')
209
+ price3.update(compare_at_amount: '79.99')
210
+ price1.save
211
+ price2.save
212
+ price3.save
213
+
214
+ product.master.prices.first.update(compare_at_amount: 29.99)
215
+ end
216
+
217
+ product.master.stock_items.update_all count_on_hand: 10, backorderable: true
218
+ product.option_types << option_type
219
+ product.variants << [variant1, variant2, variant3]
220
+ product.tap(&:save)
221
+
222
+ visit spree.product_path(product)
223
+ end
224
+
225
+ it 'shows pre sales price on PDP' do
226
+ expect(page).to have_content('$49.99')
227
+ end
228
+
229
+ it 'shows both pre sales and current prices on PDP' do
230
+ if Spree.version.to_f > 4.1
231
+ expect(page).to have_content('$49.99')
232
+ expect(page).to have_content('$149.99')
233
+ end
234
+ end
235
+
236
+ it 'shows prices for other variants' do
237
+ within('.product-variants-variant-values') do
238
+ find('li', text: 'M').click
239
+ end
240
+
241
+ expect(page).to have_content('$69.99')
242
+
243
+ if Spree.version.to_f > 4.1
244
+ expect(page).to have_content('$169.99')
245
+ end
246
+ end
247
+
248
+ it 'does not show pre sales price when it is bigger than price' do
249
+ if Spree.version.to_f > 4.1
250
+ within('.product-variants-variant-values') do
251
+ find('li', text: 'L').click
252
+ end
253
+
254
+ expect(page).to have_content('$89.99')
255
+ expect(page).not_to have_content('$79.99')
256
+ end
257
+ end
258
+ end
259
+
260
+ xdescribe 'When Requesting A Product By Variant Using URL Query String' do
261
+ let(:product) do
262
+ FactoryBot.create(:base_product, description: 'Testing sample', name: 'Sample', price: '19.99')
263
+ end
264
+
265
+ let(:option_type) { create(:option_type) }
266
+ let(:option_value1) { create(:option_value, name: 'small', presentation: 'S', option_type: option_type) }
267
+ let(:option_value2) { create(:option_value, name: 'medium', presentation: 'M', option_type: option_type) }
268
+ let(:option_value3) { create(:option_value, name: 'large', presentation: 'L', option_type: option_type) }
269
+ let(:variant1) { create(:variant, product: product, option_values: [option_value1], price: '49.99', sku: 'VAR-1') }
270
+ let(:variant2) { create(:variant, product: product, option_values: [option_value2], price: '69.99', sku: 'VAR-2') }
271
+ let(:variant3) { create(:variant, product: product, option_values: [option_value3], price: '89.99', sku: 'VAR-3') }
272
+
273
+ before do
274
+ product.option_types << option_type
275
+ product.variants << [variant1, variant2, variant3]
276
+ product.tap(&:save)
277
+ product.stock_items.last.update count_on_hand: 0, backorderable: false
278
+ end
279
+
280
+ context 'Make sure the requested variant' do
281
+ it 'shows the correct price in the HTML' do
282
+ visit spree.product_path(product) + '?variant=' + variant3.id.to_s
283
+ expect(page).to have_content(variant3.price.to_s)
284
+ end
285
+
286
+ it 'shows back-ordered in the HTML when product is on backorder' do
287
+ visit spree.product_path(product) + '?variant=' + variant2.id.to_s
288
+ expect(page).to have_content('BACKORDERED')
289
+ end
290
+
291
+ it 'shows out of stock in the HTML when the product is unavailable' do
292
+ visit spree.product_path(product) + '?variant=' + variant3.id.to_s
293
+ expect(page).to have_content('OUT OF STOCK')
294
+ end
295
+
296
+ it 'does not update the variant HTML details if no variant is matched' do
297
+ visit spree.product_path(product) + '?variant=9283923297832973283'
298
+ expect(page).to have_content(variant1.price.to_s)
299
+ expect(page).to have_content('BACKORDERED')
300
+ end
301
+
302
+ it 'sets JSON in the Schema.org SKU, URL, price and availability' do
303
+ visit spree.product_path(product) + '?variant=' + variant3.id.to_s
304
+
305
+ jsonld = page.find('script[type="application/ld+json"]', visible: false).text(:all)
306
+ jsonstring = Capybara.string(jsonld)
307
+
308
+ expect(jsonstring).to have_text('?variant=' + variant3.id.to_s)
309
+ expect(jsonstring).to have_text('"availability":"OutOfStock"')
310
+ expect(jsonstring).to have_text('"sku":"VAR-3"')
311
+ expect(jsonstring).to have_text('"price":"89.99"')
312
+ end
313
+ end
314
+ end
315
+ end