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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +44 -0
- data/Appraisals +11 -0
- data/Gemfile +7 -0
- data/LICENSE +26 -0
- data/README.md +77 -0
- data/Rakefile +21 -0
- data/app/assets/javascripts/spree/frontend/add_to_cart_analytics.js +46 -0
- data/app/controllers/spree/admin/trackers_controller.rb +6 -0
- data/app/controllers/spree_analytics_trackers/store_controller_decorator.rb +14 -0
- data/app/helpers/spree/trackers_helper.rb +70 -0
- data/app/models/spree/tracker.rb +25 -0
- data/app/models/spree_analytics_trackers/user_decorator.rb +9 -0
- data/app/overrides/add_analytics_to_admin_sidebar.rb +8 -0
- data/app/overrides/add_cart_viewed_to_orders_edit.rb +10 -0
- data/app/overrides/add_checkout_step_viewed_to_checkout_edit.rb +18 -0
- data/app/overrides/add_google_analytics_page_view_to_spree_application.rb +18 -0
- data/app/overrides/add_google_analytics_to_spree_application.rb +17 -0
- data/app/overrides/add_google_purchase_to_orders_show.rb +9 -0
- data/app/overrides/add_order_complete_to_orders_show.rb +10 -0
- data/app/overrides/add_product_list_filtered_to_taxons_show.rb +10 -0
- data/app/overrides/add_product_list_viewed_to_products_list.rb +10 -0
- data/app/overrides/add_product_viewed_to_products_show.rb +10 -0
- data/app/overrides/add_products_searched_to_products_list.rb +10 -0
- data/app/overrides/add_segment_initializer_to_layout.rb +18 -0
- data/app/overrides/add_segment_page_viewed_to_layout.rb +18 -0
- data/app/presenters/spree_analytics_trackers/base_presenter.rb +14 -0
- data/app/presenters/spree_analytics_trackers/segment/order_presenter.rb +32 -0
- data/app/presenters/spree_analytics_trackers/segment/product_presenter.rb +40 -0
- data/app/views/spree/admin/shared/_analytics_sidebar_menu.html.erb +3 -0
- data/app/views/spree/admin/trackers/_form.html.erb +36 -0
- data/app/views/spree/admin/trackers/edit.html.erb +13 -0
- data/app/views/spree/admin/trackers/index.html.erb +40 -0
- data/app/views/spree/admin/trackers/new.html.erb +13 -0
- data/app/views/spree/shared/trackers/google_analytics/_checkout_step_viewed.js.erb +21 -0
- data/app/views/spree/shared/trackers/google_analytics/_initializer.js.erb +11 -0
- data/app/views/spree/shared/trackers/google_analytics/_page_viewed.js.erb +13 -0
- data/app/views/spree/shared/trackers/google_analytics/_purchase.js.erb +19 -0
- data/app/views/spree/shared/trackers/segment/_cart_viewed.js.erb +22 -0
- data/app/views/spree/shared/trackers/segment/_checkout_step_viewed.js.erb +14 -0
- data/app/views/spree/shared/trackers/segment/_initializer.js.erb +7 -0
- data/app/views/spree/shared/trackers/segment/_order_complete.js.erb +8 -0
- data/app/views/spree/shared/trackers/segment/_page_viewed.js.erb +7 -0
- data/app/views/spree/shared/trackers/segment/_product_list_filtered.js.erb +21 -0
- data/app/views/spree/shared/trackers/segment/_product_list_viewed.js.erb +17 -0
- data/app/views/spree/shared/trackers/segment/_product_viewed.js.erb +10 -0
- data/app/views/spree/shared/trackers/segment/_products_searched.js.erb +12 -0
- data/bin/rails +7 -0
- data/config/locales/en.yml +18 -0
- data/config/locales/zh-TW.yml +19 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20171013160337_create_spree_trackers.rb +20 -0
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/spree_4_1.gemfile +9 -0
- data/gemfiles/spree_master.gemfile +9 -0
- data/lib/generators/spree_analytics_trackers/install/install_generator.rb +27 -0
- data/lib/spree_analytics_trackers.rb +5 -0
- data/lib/spree_analytics_trackers/engine.rb +20 -0
- data/lib/spree_analytics_trackers/factories.rb +9 -0
- data/lib/spree_analytics_trackers/version.rb +18 -0
- data/spec/features/admin/configuration/analytics_tracker_spec.rb +52 -0
- data/spec/features/products_spec.rb +315 -0
- data/spec/fixtures/thinking-cat.jpg +0 -0
- data/spec/models/spree/tracker_spec.rb +17 -0
- data/spec/presenters/spree_analytics_trackers/segment/order_presenter_spec.rb +34 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/custom_products.rb +26 -0
- data/spree_analytics_trackers.gemspec +31 -0
- 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,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 %>
|
data/bin/rails
ADDED
@@ -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
|
+
|
data/config/routes.rb
ADDED
@@ -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,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,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,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
|