spree_analytics_trackers 1.0.1 → 2.1.1

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.bundle/config +2 -0
  3. data/.rubocop.yml +2 -0
  4. data/.travis.yml +30 -15
  5. data/Appraisals +3 -9
  6. data/LICENSE +1 -1
  7. data/README.md +7 -3
  8. data/app/assets/javascripts/spree/frontend/add_to_cart_analytics.js +50 -0
  9. data/app/assets/javascripts/spree/frontend/remove_from_cart_analytics.js +34 -0
  10. data/app/controllers/spree/admin/trackers_controller.rb +8 -0
  11. data/app/controllers/spree_analytics_trackers/checkout_controller_decorator.rb +11 -0
  12. data/app/controllers/spree_analytics_trackers/store_controller_decorator.rb +13 -0
  13. data/app/controllers/spree_analytics_trackers/user_confirmations_controller_decorator.rb +11 -0
  14. data/app/controllers/spree_analytics_trackers/user_passwords_controller_decorator.rb +11 -0
  15. data/app/controllers/spree_analytics_trackers/user_registrations_controller_decorator.rb +11 -0
  16. data/app/controllers/spree_analytics_trackers/user_sessions_controller_decorator.rb +11 -0
  17. data/app/helpers/spree/trackers_helper.rb +79 -16
  18. data/app/models/spree/tracker.rb +11 -5
  19. data/app/models/spree_analytics_trackers/user_decorator.rb +9 -0
  20. data/app/overrides/add_analytics_to_admin_sidebar.rb +2 -3
  21. data/app/overrides/add_cart_viewed_to_orders_edit.rb +1 -1
  22. data/app/overrides/add_checkout_step_viewed_to_checkout_edit.rb +11 -3
  23. data/app/overrides/add_google_analytics_page_view_to_spree_application.rb +10 -0
  24. data/app/overrides/add_google_analytics_to_spree_application.rb +4 -4
  25. data/app/overrides/add_google_purchase_to_orders_show.rb +1 -1
  26. data/app/overrides/add_product_list_filtered_to_taxons_show.rb +1 -1
  27. data/app/overrides/add_product_list_viewed_to_products_list.rb +1 -1
  28. data/app/overrides/add_product_viewed_to_products_show.rb +2 -2
  29. data/app/overrides/add_products_searched_to_products_list.rb +2 -2
  30. data/app/overrides/add_segment_initializer_to_layout.rb +3 -3
  31. data/app/overrides/add_segment_page_viewed_to_layout.rb +10 -0
  32. data/app/presenters/spree_analytics_trackers/base_presenter.rb +14 -0
  33. data/app/presenters/spree_analytics_trackers/segment/order_presenter.rb +32 -0
  34. data/app/presenters/spree_analytics_trackers/segment/product_presenter.rb +40 -0
  35. data/app/views/spree/admin/shared/_analytics_sidebar_menu.html.erb +3 -5
  36. data/app/views/spree/admin/trackers/_form.html.erb +13 -7
  37. data/app/views/spree/admin/trackers/index.html.erb +6 -8
  38. data/app/views/spree/shared/trackers/google_analytics/_checkout_step_viewed.js.erb +19 -0
  39. data/app/views/spree/shared/trackers/google_analytics/_initializer.js.erb +25 -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 +22 -0
  42. data/app/views/spree/shared/trackers/segment/_cart_viewed.js.erb +24 -19
  43. data/app/views/spree/shared/trackers/segment/_checkout_step_viewed.js.erb +20 -11
  44. data/app/views/spree/shared/trackers/segment/_initializer.js.erb +2 -3
  45. data/app/views/spree/shared/trackers/segment/_order_complete.js.erb +8 -45
  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 +19 -28
  48. data/app/views/spree/shared/trackers/segment/_product_list_viewed.js.erb +17 -20
  49. data/app/views/spree/shared/trackers/segment/_product_viewed.js.erb +12 -6
  50. data/app/views/spree/shared/trackers/segment/_products_searched.js.erb +7 -9
  51. data/config/locales/en.yml +0 -2
  52. data/config/locales/zh-TW.yml +19 -0
  53. data/db/migrate/20200721163729_add_store_id_to_spree_trackers.rb +14 -0
  54. data/gemfiles/{spree_3_5.gemfile → spree_4_1.gemfile} +2 -2
  55. data/gemfiles/spree_master.gemfile +0 -1
  56. data/lib/generators/spree_analytics_trackers/install/install_generator.rb +8 -0
  57. data/lib/spree_analytics_trackers.rb +1 -0
  58. data/lib/spree_analytics_trackers/factories.rb +1 -0
  59. data/lib/spree_analytics_trackers/version.rb +3 -9
  60. data/spec/features/admin/configuration/analytics_tracker_spec.rb +18 -7
  61. data/spec/features/checkout_spec.rb +15 -0
  62. data/spec/features/products_spec.rb +315 -0
  63. data/spec/features/user_login_spec.rb +7 -0
  64. data/spec/features/user_password_recovery_spec.rb +7 -0
  65. data/spec/features/user_registration_spec.rb +7 -0
  66. data/spec/fixtures/thinking-cat.jpg +0 -0
  67. data/spec/models/spree/tracker_spec.rb +15 -0
  68. data/spec/presenters/spree_analytics_trackers/segment/order_presenter_spec.rb +34 -0
  69. data/spec/spec_helper.rb +7 -82
  70. data/spec/support/custom_products.rb +26 -0
  71. data/spree_analytics_trackers.gemspec +4 -17
  72. metadata +56 -212
  73. data/app/controllers/spree/store_controller_decorator.rb +0 -5
  74. data/app/models/spree/line_item_decorator.rb +0 -6
  75. data/app/models/spree/order_decorator.rb +0 -7
  76. data/app/models/spree/product_decorator.rb +0 -11
  77. data/app/models/spree/user_decorator.rb +0 -5
  78. data/app/overrides/add_google_checkout_to_checkout_edit.rb +0 -9
  79. data/app/overrides/add_product_added_to_orders_edit.rb +0 -10
  80. data/app/views/spree/shared/_google_add_items.html.erb +0 -13
  81. data/app/views/spree/shared/_google_analytics.html.erb +0 -18
  82. data/app/views/spree/shared/_google_checkout.html.erb +0 -14
  83. data/app/views/spree/shared/_google_purchase.html.erb +0 -19
  84. data/app/views/spree/shared/trackers/segment/_product_added.js.erb +0 -9
  85. data/gemfiles/spree_3_7.gemfile +0 -9
@@ -1,12 +1,21 @@
1
- <script>
2
- if (typeof analytics !== 'undefined') {
3
- analytics.track('Checkout Step Viewed', {
4
- checkout_id: '<%= @order.number %>',
5
- step: '<%= (@order.checkout_steps.index(@order.state) + 1) %>'
1
+ <% if segment_enabled? && @order.present? && !@order.completed? %>
2
+ <script>
3
+ window.addEventListener('turbolinks:load', function() {
4
+ if (typeof analytics !== 'undefined') {
5
+ analytics.track('Checkout Step Viewed',
6
+ {
7
+ checkout_id: '<%= @order.number %>',
8
+ step: '<%= (@order.checkout_steps.index(@order.state) + 1) %>'
9
+ }
10
+ );
11
+
12
+ analytics.page('Checkout Step Viewed',
13
+ {
14
+ checkout_id: '<%= @order.number %>',
15
+ step: '<%= (@order.checkout_steps.index(@order.state) + 1) %>'
16
+ }
17
+ );
18
+ }
6
19
  });
7
- analytics.page('Checkout Step Viewed', {
8
- checkout_id: '<%= @order.number %>',
9
- step: '<%= (@order.checkout_steps.index(@order.state) + 1) %>'
10
- });
11
- }
12
- </script>
20
+ </script>
21
+ <% end %>
@@ -1,8 +1,7 @@
1
- <% if tracker = Spree::Tracker.current(:segment) %>
1
+ <% if segment_enabled? %>
2
2
  <script>
3
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
- analytics.page()
4
+ analytics.load('<%=segment_tracker.analytics_id%>'.replace(/^\s+|\s+$/g, ''));
6
5
  }}();
7
6
  </script>
8
7
  <% end %>
@@ -1,48 +1,11 @@
1
- <% if order_just_completed?(@order) %>
1
+ <% if segment_enabled? && @order.present? && order_just_completed?(@order) %>
2
+ <% order_json = SpreeAnalyticsTrackers::Segment::OrderPresenter.new(@order).to_json %>
2
3
  <script>
3
- if (typeof analytics !== 'undefined') {
4
- analytics.track('Order Completed', {
5
- order_id: '<%= @order.number %>',
6
- total: <%= @order.total %>,
7
- shipping: <%= @order.shipment_total %>,
8
- tax: <%= @order.additional_tax_total %>,
9
- discount: <%= @order.promo_total %>,
10
- coupon: '<%= @order.promo_code %>',
11
- currency: '<%= @order.currency %>',
12
- products: [
13
- <% @order.line_items.each do |line_item| %>
14
- {
15
- product_id: '<%= line_item.product.id %>',
16
- sku: '<%= line_item.variant.sku %>',
17
- name: '<%= line_item.product.name %>',
18
- price: <%= line_item.price %>,
19
- quantity: <%= line_item.quantity %>
20
- },
21
- <% end %>
22
- ]
23
- });
24
-
25
- analytics.page('Order Completed', {
26
- order_id: '<%= @order.number %>',
27
- total: <%= @order.total %>,
28
- shipping: <%= @order.shipment_total %>,
29
- tax: <%= @order.additional_tax_total %>,
30
- discount: <%= @order.promo_total %>,
31
- coupon: '<%= @order.promo_code %>',
32
- currency: '<%= @order.currency %>',
33
- products: [
34
- <% @order.line_items.each do |line_item| %>
35
- {
36
- product_id: '<%= line_item.product.id %>',
37
- sku: '<%= line_item.variant.sku %>',
38
- name: '<%= line_item.product.name %>',
39
- price: <%= line_item.price %>,
40
- quantity: <%= line_item.quantity %>
41
- },
42
- <% end %>
43
- ]
44
- });
45
-
46
- }
4
+ window.addEventListener('turbolinks:load', function() {
5
+ if (typeof analytics !== 'undefined') {
6
+ analytics.page('Order Completed', <%= order_json.html_safe %>);
7
+ analytics.track('Order Completed', <%= order_json.html_safe %>);
8
+ }
9
+ });
47
10
  </script>
48
11
  <% end %>
@@ -0,0 +1,7 @@
1
+ <% if segment_enabled? %>
2
+ <script>
3
+ if (typeof analytics !== 'undefined') {
4
+ analytics.page();
5
+ }
6
+ </script>
7
+ <% end %>
@@ -1,32 +1,23 @@
1
- <% if params[:search].present? %>
1
+ <% if segment_enabled? && any_filtering_params? %>
2
2
  <script>
3
- if (typeof analytics !== 'undefined') {
4
- analytics.track('Product List Filtered', {
5
- filters: [
6
- <% params[:search].to_unsafe_h.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, image: product.images.first) %>,
13
- <% end %>
14
- ]
15
- });
3
+ window.addEventListener('turbolinks:load', function() {
4
+ if (typeof analytics !== 'undefined') {
5
+ var segmentProductListFilteredJson = {
6
+ filters: [
7
+ <% filtering_params_with_values.each do |type, value| %>
8
+ <%= { type: type, value: value } .to_json.html_safe %>,
9
+ <% end %>
10
+ ],
11
+ products: [
12
+ <% @products.each_with_index do |product, index| %>
13
+ <%= product_for_segment(product, position: index + 1) %>,
14
+ <% end %>
15
+ ]
16
+ }
16
17
 
17
- analytics.page('Product List Filtered', {
18
- filters: [
19
- <% params[:search].to_unsafe_h.each do |type, value| %>
20
- <%= { type: type, value: value } .to_json.html_safe %>,
21
- <% end %>
22
- ],
23
- products: [
24
- <% @products.each_with_index do |product, index| %>
25
- <%= product_for_segment(product, position: index+1, image: product.images.first) %>,
26
- <% end %>
27
- ]
28
- });
29
-
30
- }
18
+ analytics.track('Product List Filtered', segmentProductListFilteredJson);
19
+ analytics.page('Product List Filtered', segmentProductListFilteredJson);
20
+ }
21
+ });
31
22
  </script>
32
23
  <% end %>
@@ -1,22 +1,19 @@
1
- <script>
2
- if (typeof analytics !== 'undefined') {
3
- analytics.track('Product List Viewed', {
4
- category: '<%= @taxon.try(:name) %>',
5
- products: [
6
- <% products.each_with_index do |product, index| %>
7
- <%= product_for_segment(product, position: index+1, image: product.images.first) %>,
8
- <% end %>
9
- ]
10
- });
1
+ <% if segment_enabled? && defined?(products) && products.present? %>
2
+ <script>
3
+ window.addEventListener('turbolinks:load', function() {
4
+ if (typeof analytics !== 'undefined') {
5
+ var segmentProductListViewedJson = {
6
+ category: '<%= @taxon&.name %>',
7
+ products: [
8
+ <% products.each_with_index do |product, index| %>
9
+ <%= product_for_segment(product, position: index+1, image: default_image_for_product_or_variant(product)) %>,
10
+ <% end %>
11
+ ]
12
+ }
11
13
 
12
- analytics.page('Product List Viewed', {
13
- category: '<%= @taxon.try(:name) %>',
14
- products: [
15
- <% products.each_with_index do |product, index| %>
16
- <%= product_for_segment(product, position: index+1, image: product.images.first) %>,
17
- <% end %>
18
- ]
14
+ analytics.track('Product List Viewed', segmentProductListViewedJson);
15
+ analytics.page('Product List Viewed', segmentProductListViewedJson);
16
+ }
19
17
  });
20
-
21
- }
22
- </script>
18
+ </script>
19
+ <% end %>
@@ -1,6 +1,12 @@
1
- <script>
2
- if (typeof analytics !== 'undefined') {
3
- analytics.track('Product Viewed', <%= product_for_segment(@product, image: @product.images.first) %>);
4
- analytics.page('Product Viewed', <%= product_for_segment(@product, image: @product.images.first) %>);
5
- }
6
- </script>
1
+ <% if segment_enabled? && @product.present? %>
2
+ <script>
3
+ window.addEventListener('turbolinks:load', function() {
4
+ if (typeof analytics !== 'undefined') {
5
+ var segmentProductViewed = <%= product_for_segment(@product, image: default_image_for_product_or_variant(@product)) %>;
6
+
7
+ analytics.page('Product Viewed', segmentProductViewed);
8
+ analytics.track('Product Viewed', segmentProductViewed);
9
+ }
10
+ });
11
+ </script>
12
+ <% end %>
@@ -1,12 +1,10 @@
1
- <% if params.key?(:keywords) %>
1
+ <% if segment_enabled? && params.key?(:keywords) && params[:keywords].present? %>
2
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
- }
3
+ window.addEventListener('turbolinks:load', function() {
4
+ if (typeof analytics !== 'undefined') {
5
+ analytics.track('Products Searched', { query: '<%= params[:keywords] %>' });
6
+ analytics.page('Products Searched', { query: '<%= params[:keywords] %>' });
7
+ }
8
+ });
11
9
  </script>
12
10
  <% end %>
@@ -16,5 +16,3 @@ en:
16
16
  analytics_desc_list_2: Requires only a free Spree account to activate
17
17
  analytics_desc_list_3: Absolutely no code to install
18
18
  analytics_desc_list_4: It's completely free!
19
- analytics_engine: Analytics Engine
20
- analytics_trackers: Analytics Trackers
@@ -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,14 @@
1
+ class AddStoreIdToSpreeTrackers < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :spree_trackers, :store_id, :integer
4
+ add_index :spree_trackers, :store_id
5
+
6
+ Spree::Tracker.reset_column_information
7
+
8
+ default_store = Spree::Store.default
9
+ Spree::Tracker.all.each do |tracker|
10
+ tracker.store = default_store
11
+ tracker.save
12
+ end
13
+ end
14
+ end
@@ -2,8 +2,8 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "spree", "~> 3.5.0"
6
- gem "spree_auth_devise", "~> 3.3.0"
5
+ gem "spree", "~> 4.1.0"
6
+ gem "spree_auth_devise", "~> 4.1.0"
7
7
  gem "rails-controller-testing"
8
8
 
9
9
  gemspec path: "../"
@@ -4,7 +4,6 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "spree", github: "spree/spree", branch: "master"
6
6
  gem "spree_auth_devise", github: "spree/spree_auth_devise", branch: "master"
7
- gem "mysql2", "~> 0.5.1"
8
7
  gem "rails-controller-testing"
9
8
 
10
9
  gemspec path: "../"
@@ -3,6 +3,14 @@ module SpreeAnalyticsTrackers
3
3
  class InstallGenerator < Rails::Generators::Base
4
4
  class_option :auto_run_migrations, type: :boolean, default: false
5
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
+ append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/remove_from_cart_analytics\n"
12
+ end
13
+
6
14
  def add_migrations
7
15
  run 'bundle exec rake railties:install:migrations FROM=spree_analytics_trackers'
8
16
  end
@@ -2,3 +2,4 @@ require 'spree_core'
2
2
  require 'spree_extension'
3
3
  require 'spree_analytics_trackers/engine'
4
4
  require 'spree_analytics_trackers/version'
5
+ require 'deface'
@@ -4,6 +4,7 @@ unless FactoryBot.factories.registered?(:tracker)
4
4
  analytics_id { 'A100' }
5
5
  active { true }
6
6
  engine { :google_analytics }
7
+ store { Spree::Store.default || create(:store) }
7
8
  end
8
9
  end
9
10
  end
@@ -1,17 +1,11 @@
1
1
  module SpreeAnalyticsTrackers
2
+ VERSION = '2.1.1'.freeze
3
+
2
4
  module_function
3
5
 
4
6
  # Returns the version of the currently loaded SpreeAnalyticsTrackers as a
5
7
  # <tt>Gem::Version</tt>.
6
8
  def version
7
- Gem::Version.new VERSION::STRING
8
- end
9
-
10
- module VERSION
11
- MAJOR = 1
12
- MINOR = 0
13
- TINY = 1
14
-
15
- STRING = [MAJOR, MINOR, TINY].compact.join('.')
9
+ Gem::Version.new VERSION
16
10
  end
17
11
  end
@@ -3,10 +3,13 @@ require 'spec_helper'
3
3
  describe 'Analytics Tracker', type: :feature do
4
4
  stub_authorization!
5
5
 
6
+ let!(:default_store) { Spree::Store.default }
7
+ let!(:another_store) { create(:store, name: 'Eurozone') }
8
+
6
9
  context 'index' do
7
10
  before(:each) do
8
- create(:tracker)
9
- create(:tracker, analytics_id: 'A200')
11
+ create(:tracker, store: default_store)
12
+ create(:tracker, analytics_id: 'A200', store: another_store)
10
13
  visit spree.admin_trackers_path
11
14
  end
12
15
 
@@ -18,13 +21,15 @@ describe 'Analytics Tracker', type: :feature do
18
21
  within_row(1) do
19
22
  expect(column_text(1)).to eq('A100')
20
23
  expect(column_text(2)).to eq('Google analytics')
21
- expect(column_text(3)).to eq('Yes')
24
+ expect(column_text(3)).to eq(default_store.name)
25
+ expect(column_text(4)).to eq('Yes')
22
26
  end
23
27
 
24
28
  within_row(2) do
25
29
  expect(column_text(1)).to eq('A200')
26
30
  expect(column_text(2)).to eq('Google analytics')
27
- expect(column_text(3)).to eq('Yes')
31
+ expect(column_text(3)).to eq('Eurozone')
32
+ expect(column_text(4)).to eq('Yes')
28
33
  end
29
34
  end
30
35
  end
@@ -34,16 +39,22 @@ describe 'Analytics Tracker', type: :feature do
34
39
  visit spree.admin_trackers_path
35
40
  end
36
41
 
37
- it 'should be able to create a new analytics tracker' do
38
- click_link 'admin_new_tracker_link'
42
+ it 'should be able to create a new analytics tracker', js: true do
43
+ within('.content-header') do
44
+ click_link 'admin_new_tracker_link'
45
+ end
39
46
  fill_in 'tracker_analytics_id', with: 'A100'
47
+
48
+ select2 default_store.name, from: 'Store'
49
+
40
50
  click_button 'Create'
41
51
 
42
52
  expect(page).to have_content('successfully created!')
43
53
  within_row(1) do
44
54
  expect(column_text(1)).to eq('A100')
45
55
  expect(column_text(2)).to eq('Google analytics')
46
- expect(column_text(3)).to eq('Yes')
56
+ expect(column_text(3)).to eq(default_store.name)
57
+ expect(column_text(4)).to eq('Yes')
47
58
  end
48
59
  end
49
60
  end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Visiting Checkout page', type: :feature, js: true do
4
+ let(:mug) { create(:product, name: 'RoR Mug') }
5
+ let(:user) { create(:user) }
6
+
7
+ before do
8
+ allow_any_instance_of(Spree::OrdersController).to receive_messages(try_spree_current_user: user)
9
+ end
10
+
11
+ it 'is available' do
12
+ add_to_cart(mug)
13
+ expect { visit spree.checkout_path }.not_to raise_error
14
+ end
15
+ 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