rack-tracker 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -1
- data/README.md +79 -3
- data/lib/rack/tracker/criteo/criteo.rb +36 -0
- data/lib/rack/tracker/criteo/template/criteo.erb +9 -0
- data/lib/rack/tracker/google_analytics/google_analytics.rb +15 -2
- data/lib/rack/tracker/google_analytics/template/google_analytics.erb +1 -1
- data/lib/rack/tracker/version.rb +1 -1
- data/lib/rack/tracker/vwo/vwo.rb +1 -1
- data/lib/rack/tracker/zanox/template/zanox.erb +26 -0
- data/lib/rack/tracker/zanox/zanox.rb +37 -0
- data/lib/rack/tracker.rb +2 -0
- data/rack-tracker.gemspec +4 -4
- data/spec/handler/criteo_spec.rb +122 -0
- data/spec/handler/google_analytics_spec.rb +17 -28
- data/spec/handler/zanox_spec.rb +98 -0
- data/spec/integration/criteo_integration_spec.rb +44 -0
- data/spec/integration/google_analytics_integration_spec.rb +0 -1
- data/spec/integration/zanox_integration_spec.rb +25 -0
- data/spec/support/metal_controller.rb +18 -0
- metadata +25 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 656cd1cec1764543d2ab1814545365c34fc143b9
|
4
|
+
data.tar.gz: e801a731569b709bbe9ab85273c047a36e9be3ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3151dfd25013fc27de6cdb6dea1659164d2acb9541fbb128d98e2cc0b53f7dd25fd91d09c1f540a0f3142547068edc90d2374a46a7d2dd4ef2ef27425e192f05
|
7
|
+
data.tar.gz: ca4f109a8821ab137328b4c2f402e2e793d52882b3566ba128727049e36cc29dd68cd5ee9ada73db452eee08b972370544918c679380674c185cfffd01cc70e5
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -25,6 +25,8 @@ but to get you started we're shipping support for the following services out of
|
|
25
25
|
* [Facebook](#facebook)
|
26
26
|
* [Visual Website Optimizer (VWO)](#visual-website-optimizer-vwo)
|
27
27
|
* [GoSquared](#gosquared)
|
28
|
+
* [Criteo](#criteo)
|
29
|
+
* [Zanox](#zanox)
|
28
30
|
|
29
31
|
|
30
32
|
## Installation
|
@@ -328,6 +330,8 @@ It will render the following to the site source:
|
|
328
330
|
|
329
331
|
[Criteo](http://www.criteo.com/) retargeting service.
|
330
332
|
|
333
|
+
#### Basic configuration
|
334
|
+
|
331
335
|
```
|
332
336
|
config.middleware.use(Rack::Tracker) do
|
333
337
|
handler :criteo, { set_account: '1234' }
|
@@ -335,13 +339,85 @@ end
|
|
335
339
|
```
|
336
340
|
|
337
341
|
Other global criteo handler options are:
|
338
|
-
* `
|
339
|
-
* `
|
342
|
+
* `set_customer_id: 'x'`
|
343
|
+
* `set_site_type: 'd'` - possible values are `m` (mobile), `t` (tablet), `d` (desktop)
|
344
|
+
|
345
|
+
Option values can be either static or dynamic by providing a lambda being reevaluated for each request, e.g. `set_customer_id: lambda { |env| env['rack.session']['user_id'] }`
|
346
|
+
|
347
|
+
#### Tracking events
|
348
|
+
|
349
|
+
This will track a basic event:
|
350
|
+
|
351
|
+
```
|
352
|
+
def show
|
353
|
+
tracker do |t|
|
354
|
+
t.criteo :view_item, { item: 'P0001' }
|
355
|
+
end
|
356
|
+
end
|
357
|
+
```
|
358
|
+
|
359
|
+
This will render to the follwing code in the JS:
|
360
|
+
|
361
|
+
```
|
362
|
+
window.criteo_q.push({"event": "viewItem", "item": "P001" });
|
363
|
+
```
|
364
|
+
|
365
|
+
The first argument for `t.criteo` is always the criteo event (e.g. `:view_item`, `:view_list`, `:track_transaction`, `:view_basket`) and the second argument are additional properties for the event.
|
366
|
+
|
367
|
+
Another example
|
368
|
+
|
369
|
+
```
|
370
|
+
t.criteo :track_transaction, { id: 'id', item: { id: "P0038", price: "6.54", quantity: 1 } }
|
371
|
+
```
|
372
|
+
|
373
|
+
### Zanox
|
374
|
+
|
375
|
+
[Zanox](http://www.zanox.com/us/)
|
376
|
+
|
377
|
+
#### Basic Configuration
|
378
|
+
|
379
|
+
```
|
380
|
+
config.middleware.use(Rack::Tracker) do
|
381
|
+
handler :zanox, { account_id: '1234' }
|
382
|
+
end
|
383
|
+
```
|
384
|
+
|
385
|
+
#### Mastertag
|
386
|
+
|
387
|
+
This is an example of a mastertag:
|
388
|
+
|
389
|
+
```
|
390
|
+
def show
|
391
|
+
tracker do |t|
|
392
|
+
t.zanox :mastertag, { id: "25GHTE9A07DF67DFG90T" }
|
393
|
+
end
|
394
|
+
end
|
395
|
+
```
|
396
|
+
|
397
|
+
This will render to the follwing code in the JS:
|
398
|
+
|
399
|
+
```
|
400
|
+
window._zx.push({"id": "25GHTE9A07DF67DFG90T"});
|
401
|
+
```
|
402
|
+
|
403
|
+
#### Conversion tracking
|
404
|
+
|
405
|
+
This is an example of a lead event:
|
406
|
+
|
407
|
+
```
|
408
|
+
def show
|
409
|
+
tracker do |t|
|
410
|
+
t.zanox :track, { order_i_d: 'DEFC-4321'}
|
411
|
+
end
|
412
|
+
end
|
413
|
+
```
|
414
|
+
|
415
|
+
This is an example of a sale event:
|
340
416
|
|
341
417
|
```
|
342
418
|
def show
|
343
419
|
tracker do |t|
|
344
|
-
t.
|
420
|
+
t.zanox :track, { customer_i_d: '123456', order_i_d: 'DEFC-4321', currency_symbol: 'EUR', total_price: '150.00'}
|
345
421
|
end
|
346
422
|
end
|
347
423
|
```
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Rack::Tracker::Criteo < Rack::Tracker::Handler
|
2
|
+
|
3
|
+
TRACKER_EVENTS = {
|
4
|
+
# event name => event key name, e.g. { event: 'setSiteType', type: '' }
|
5
|
+
set_site_type: :type,
|
6
|
+
set_account: :account,
|
7
|
+
set_customer_id: :id
|
8
|
+
}
|
9
|
+
|
10
|
+
class Event < OpenStruct
|
11
|
+
def write
|
12
|
+
to_h.to_json
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
self.position = :body
|
17
|
+
|
18
|
+
# global events (setSiteType, setAccount, ...) for each tracker instance
|
19
|
+
def tracker_events
|
20
|
+
@tracker_events ||= [].tap do |tracker_events|
|
21
|
+
options.slice(*TRACKER_EVENTS.keys).each do |key, value|
|
22
|
+
if option_value = value.respond_to?(:call) ? value.call(env) : value
|
23
|
+
tracker_events << Event.new(:event => "#{key}".camelize(:lower), TRACKER_EVENTS[key] => "#{option_value}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def render
|
30
|
+
Tilt.new( File.join( File.dirname(__FILE__), 'template', 'criteo.erb') ).render(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.track(name, event_name, event_args = {})
|
34
|
+
{ name.to_s => [{ 'class_name' => 'Event', 'event' => event_name.to_s.camelize(:lower) }.merge(event_args)] }
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<% if events.any? %>
|
2
|
+
<script type='text/javascript' src='//static.criteo.net/js/ld/ld.js' async='true'></script>
|
3
|
+
<script type='text/javascript'>
|
4
|
+
window.criteo_q = window.criteo_q || [];
|
5
|
+
<% (tracker_events + events).each do |event| %>
|
6
|
+
window.criteo_q.push(<%= event.write %>);
|
7
|
+
<% end %>
|
8
|
+
</script>
|
9
|
+
<% end %>
|
@@ -23,13 +23,26 @@ class Rack::Tracker::GoogleAnalytics < Rack::Tracker::Handler
|
|
23
23
|
|
24
24
|
class EnhancedEcommerce < OpenStruct
|
25
25
|
def write
|
26
|
-
|
26
|
+
hash = self.to_h
|
27
|
+
label = hash[:label]
|
28
|
+
attributes = hash.except(:label, :type).compact.stringify_values
|
29
|
+
|
30
|
+
[
|
31
|
+
"ec:#{self.type}",
|
32
|
+
label,
|
33
|
+
attributes.empty? ? nil : attributes
|
34
|
+
].compact.to_json.gsub(/\[|\]/, '')
|
27
35
|
end
|
28
36
|
end
|
29
37
|
|
30
38
|
class Ecommerce < OpenStruct
|
31
39
|
def write
|
32
|
-
|
40
|
+
attributes = self.to_h.except(:type).compact.stringify_values
|
41
|
+
|
42
|
+
[
|
43
|
+
"ecommerce:#{self.type}",
|
44
|
+
attributes
|
45
|
+
].to_json.gsub(/\[|\]/, '')
|
33
46
|
end
|
34
47
|
end
|
35
48
|
|
@@ -14,7 +14,7 @@
|
|
14
14
|
<% if options[:advertising] %>
|
15
15
|
ga('require', 'displayfeatures');
|
16
16
|
<% end %>
|
17
|
-
<% if options[:enhanced_ecommerce]
|
17
|
+
<% if options[:enhanced_ecommerce] %>
|
18
18
|
ga('require', 'ec');
|
19
19
|
<% end %>
|
20
20
|
<% if options[:ecommerce] %>
|
data/lib/rack/tracker/version.rb
CHANGED
data/lib/rack/tracker/vwo/vwo.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
<% if mastertag %>
|
2
|
+
|
3
|
+
<div class="zx_<%= mastertag.id %> zx_mediaslot">
|
4
|
+
<script type="text/javascript">
|
5
|
+
window._zx = window._zx || [];
|
6
|
+
window._zx.push({"id": "<%= mastertag.id %>"});
|
7
|
+
(function(d) {
|
8
|
+
var s = d.createElement("script"); s.async = true;
|
9
|
+
s.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//static.zanox.com/scripts/zanox.js";
|
10
|
+
var a = d.getElementsByTagName("script")[0]; a.parentNode.insertBefore(s, a);
|
11
|
+
}(document));
|
12
|
+
</script>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<% tracking_events.each do |event| %>
|
18
|
+
|
19
|
+
<script type="text/javascript" src="https://ad.zanox.com/ppl/?<%= options[:account_id] %>&mode=[[1]]&<%= event.write %>">
|
20
|
+
</script>
|
21
|
+
|
22
|
+
<noscript>
|
23
|
+
<img src="https://ad.zanox.com/ppl/?<%= options[:account_id] %>&mode=[[2]]&<%= event.write %>" width="1" height="1" />
|
24
|
+
</noscript>
|
25
|
+
|
26
|
+
<% end %>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Rack::Tracker::Zanox < Rack::Tracker::Handler
|
2
|
+
|
3
|
+
# name of the handler
|
4
|
+
# everything after is passed as options
|
5
|
+
class Mastertag < OpenStruct
|
6
|
+
end
|
7
|
+
|
8
|
+
class Track < OpenStruct
|
9
|
+
# Example: OrderID=[[DEFC-4321]]&CurrencySymbol=[[EUR]]&TotalPrice=[[23.40]]
|
10
|
+
def write
|
11
|
+
to_h.map do |k,v|
|
12
|
+
"#{k.to_s.camelize}=[[#{v}]]"
|
13
|
+
end.join('&')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
self.position = :body
|
18
|
+
|
19
|
+
def mastertag
|
20
|
+
# First event should be stronger, e.g. one signs up and gets redirected to homepage
|
21
|
+
# "sign up" should be tracked instead of "view homepage"
|
22
|
+
events.select{ |event| event.class.to_s.demodulize == 'Mastertag' }.first
|
23
|
+
end
|
24
|
+
|
25
|
+
def tracking_events
|
26
|
+
events.select{ |event| event.class.to_s.demodulize == 'Track' }
|
27
|
+
end
|
28
|
+
|
29
|
+
def render
|
30
|
+
Tilt.new( File.join( File.dirname(__FILE__), 'template', 'zanox.erb') ).render(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
# this is called with additional arguments to t.zanox
|
34
|
+
def self.track(name, *event)
|
35
|
+
{ name.to_s => [event.last.merge('class_name' => event.first.to_s.capitalize)] }
|
36
|
+
end
|
37
|
+
end
|
data/lib/rack/tracker.rb
CHANGED
@@ -17,6 +17,8 @@ require "rack/tracker/google_adwords_conversion/google_adwords_conversion"
|
|
17
17
|
require "rack/tracker/facebook/facebook"
|
18
18
|
require "rack/tracker/vwo/vwo"
|
19
19
|
require "rack/tracker/go_squared/go_squared"
|
20
|
+
require "rack/tracker/criteo/criteo"
|
21
|
+
require "rack/tracker/zanox/zanox"
|
20
22
|
|
21
23
|
module Rack
|
22
24
|
class Tracker
|
data/rack-tracker.gemspec
CHANGED
@@ -18,14 +18,14 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "rack", ">= 1.4
|
22
|
-
spec.add_dependency "tilt", "
|
21
|
+
spec.add_dependency "rack", ">= 1.4"
|
22
|
+
spec.add_dependency "tilt", ">= 1.4"
|
23
23
|
spec.add_dependency 'activesupport', '>= 3.0'
|
24
24
|
|
25
25
|
spec.add_development_dependency 'actionpack', '>= 3.0'
|
26
26
|
spec.add_development_dependency "bundler", "~> 1.5"
|
27
27
|
spec.add_development_dependency "rake"
|
28
|
-
spec.add_development_dependency "rspec", "~> 3.
|
29
|
-
spec.add_development_dependency "capybara", "~> 2.4
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
29
|
+
spec.add_development_dependency "capybara", "~> 2.4"
|
30
30
|
spec.add_development_dependency "pry"
|
31
31
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
RSpec.describe Rack::Tracker::Criteo do
|
2
|
+
|
3
|
+
describe Rack::Tracker::Criteo::Event do
|
4
|
+
|
5
|
+
subject { described_class.new(event: "viewItem", item: 'P001') }
|
6
|
+
|
7
|
+
describe '#write' do
|
8
|
+
specify { expect(subject.write).to eq("{\"event\":\"viewItem\",\"item\":\"P001\"}") }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def env
|
13
|
+
{}
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'will be placed in the body' do
|
17
|
+
expect(described_class.position).to eq(:body)
|
18
|
+
expect(described_class.new(env).position).to eq(:body)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#render' do
|
22
|
+
context 'with events' do
|
23
|
+
let(:env) {
|
24
|
+
{
|
25
|
+
'tracker' => {
|
26
|
+
'criteo' =>
|
27
|
+
[
|
28
|
+
{
|
29
|
+
'event' => 'viewItem',
|
30
|
+
'item' => 'P001',
|
31
|
+
'class_name' => 'Event'
|
32
|
+
}
|
33
|
+
]
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
subject { described_class.new(env).render }
|
39
|
+
|
40
|
+
it 'will push the tracking events to the queue' do
|
41
|
+
expect(subject).to include 'window.criteo_q.push({"event":"viewItem","item":"P001"});'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'without events' do
|
46
|
+
let(:env) {
|
47
|
+
{
|
48
|
+
'tracker' => {
|
49
|
+
'criteo' => []
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
subject { described_class.new(env, { user_id: ->(env){ '123' } }).render }
|
55
|
+
|
56
|
+
it 'should render nothing' do
|
57
|
+
expect(subject).to eql ""
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#tracker_events' do
|
63
|
+
subject { described_class.new(env, options) }
|
64
|
+
|
65
|
+
context 'nil value' do
|
66
|
+
let(:options) { { set_account: nil } }
|
67
|
+
|
68
|
+
it 'should ignore option' do
|
69
|
+
expect(subject.tracker_events).to match_array []
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'static string value' do
|
74
|
+
let(:options) { { set_account: '1234' } }
|
75
|
+
|
76
|
+
it 'should set the value' do
|
77
|
+
expect(subject.tracker_events).to match_array [
|
78
|
+
Rack::Tracker::Criteo::Event.new(event: 'setAccount', account: '1234')
|
79
|
+
]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'static integer value' do
|
84
|
+
let(:options) { { set_customer_id: 1234 } }
|
85
|
+
|
86
|
+
it 'should set the value as string' do
|
87
|
+
expect(subject.tracker_events).to match_array [
|
88
|
+
Rack::Tracker::Criteo::Event.new(event: 'setCustomerId', id: '1234')
|
89
|
+
]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'unsupported option' do
|
94
|
+
let(:options) { { unsupported: "option" } }
|
95
|
+
|
96
|
+
subject { described_class.new(env, options) }
|
97
|
+
|
98
|
+
it 'should ignore the option' do
|
99
|
+
expect(subject.tracker_events).to match_array []
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'proc returning value' do
|
104
|
+
let(:options) { { set_site_type: ->(env){ 'm' } } }
|
105
|
+
|
106
|
+
it 'should set the value' do
|
107
|
+
expect(subject.tracker_events).to match_array [
|
108
|
+
Rack::Tracker::Criteo::Event.new(event: 'setSiteType', type: 'm')
|
109
|
+
]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'proc returning nil' do
|
114
|
+
let(:options) { { set_account: ->(env){ nil } } }
|
115
|
+
|
116
|
+
it 'should ignore the option' do
|
117
|
+
expect(subject.tracker_events).to match_array []
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -91,6 +91,8 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
|
|
91
91
|
end
|
92
92
|
|
93
93
|
describe "with events" do
|
94
|
+
subject { described_class.new(env, tracker: 'somebody').render }
|
95
|
+
|
94
96
|
describe "default" do
|
95
97
|
def env
|
96
98
|
{'tracker' => {
|
@@ -100,7 +102,6 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
|
|
100
102
|
}}
|
101
103
|
end
|
102
104
|
|
103
|
-
subject { described_class.new(env, tracker: 'somebody').render }
|
104
105
|
it "will show events" do
|
105
106
|
expect(subject).to match(%r{ga\(\"send\",{\"hitType\":\"event\",\"eventCategory\":\"Users\",\"eventAction\":\"Login\",\"eventLabel\":\"Standard\"}\)})
|
106
107
|
end
|
@@ -113,7 +114,6 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
|
|
113
114
|
]}}
|
114
115
|
end
|
115
116
|
|
116
|
-
subject { described_class.new(env, tracker: 'somebody').render }
|
117
117
|
it "will show events with values" do
|
118
118
|
expect(subject).to match(%r{ga\(\"send\",{\"hitType\":\"event\",\"eventCategory\":\"Users\",\"eventAction\":\"Login\",\"eventLabel\":\"Standard\",\"eventValue\":\"5\"}\)},)
|
119
119
|
end
|
@@ -132,12 +132,17 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
|
|
132
132
|
end
|
133
133
|
|
134
134
|
subject { described_class.new(env, tracker: 'somebody', ecommerce: true).render }
|
135
|
+
|
135
136
|
it "will add items" do
|
136
|
-
|
137
|
+
attributes = { id: '1234', name: 'Fluffy Pink Bunnies', sku: 'DD23444', category: 'Party Toys', price: '11.99', quantity: '1' }.to_json
|
138
|
+
expect(subject).to match(%r{ga\(\"ecommerce:addItem\",#{attributes}\);})
|
137
139
|
end
|
140
|
+
|
138
141
|
it "will add transaction" do
|
139
|
-
|
142
|
+
attributes = { id: '1234', affiliation: 'Acme Clothing', revenue: '11.99', shipping: '5', tax: '1.29', currency: 'EUR' }.to_json
|
143
|
+
expect(subject).to match(%r{ga\(\"ecommerce:addTransaction\",#{attributes}\);})
|
140
144
|
end
|
145
|
+
|
141
146
|
it "will submit cart" do
|
142
147
|
expect(subject).to match(%r{ga\('ecommerce:send'\);})
|
143
148
|
end
|
@@ -150,18 +155,20 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
|
|
150
155
|
{'tracker' => {
|
151
156
|
'google_analytics' => [
|
152
157
|
{ 'class_name' => 'EnhancedEcommerce', 'type' => 'addProduct', 'id' => 'P12345', 'name' => 'Android Warhol T-Shirt', 'category' => 'Apparel', 'brand' => 'Google', 'variant' => 'black', 'price' => '29.20', 'coupon' => 'APPARELSALE', 'quantity' => 1 },
|
153
|
-
{ 'class_name' => 'EnhancedEcommerce', 'type' => 'setAction', '
|
158
|
+
{ 'class_name' => 'EnhancedEcommerce', 'type' => 'setAction', 'label' => 'purchase' }
|
154
159
|
]
|
155
160
|
}}
|
156
161
|
end
|
157
162
|
|
158
163
|
subject { described_class.new(env, tracker: 'somebody', enhanced_ecommerce: true).render }
|
164
|
+
|
159
165
|
it "will add product" do
|
160
|
-
|
166
|
+
attributes = { id: 'P12345', name: 'Android Warhol T-Shirt', category: 'Apparel', brand: 'Google', variant: 'black', price: '29.20', coupon: 'APPARELSALE', quantity: '1' }.to_json
|
167
|
+
expect(subject).to match(%r{ga\(\"ec:addProduct\",#{attributes}\);})
|
161
168
|
end
|
162
169
|
|
163
170
|
it "will add action" do
|
164
|
-
expect(subject).to match(%r{ga\(\"ec:setAction\"
|
171
|
+
expect(subject).to match(%r{ga\(\"ec:setAction\",\"purchase\"\);})
|
165
172
|
end
|
166
173
|
end
|
167
174
|
end
|
@@ -217,28 +224,10 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do
|
|
217
224
|
end
|
218
225
|
|
219
226
|
describe "with enhanced ecommerce" do
|
220
|
-
|
221
|
-
subject { described_class.new(env, tracker: 'happy', enhanced_ecommerce: true).render }
|
227
|
+
subject { described_class.new(env, tracker: 'happy', enhanced_ecommerce: true).render }
|
222
228
|
|
223
|
-
|
224
|
-
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
describe "with events" do
|
229
|
-
def env
|
230
|
-
{'tracker' => {
|
231
|
-
'google_analytics' => [
|
232
|
-
{ 'class_name' => 'EnhancedEcommerce', 'type' => 'addProduct', 'id' => 'P12345', 'name' => 'Android Warhol T-Shirt', 'category' => 'Apparel', 'brand' => 'Google', 'variant' => 'black', 'price' => '29.20', 'coupon' => 'APPARELSALE', 'quantity' => 1 },
|
233
|
-
]
|
234
|
-
}}
|
235
|
-
end
|
236
|
-
|
237
|
-
subject { described_class.new(env, tracker: 'happy', enhanced_ecommerce: true).render }
|
238
|
-
|
239
|
-
it "will require the enhanced ecommerce plugin" do
|
240
|
-
expect(subject).to match(%r{ga\('require', 'ec'\)})
|
241
|
-
end
|
229
|
+
it "will require the enhanced ecommerce plugin" do
|
230
|
+
expect(subject).to match(%r{ga\('require', 'ec'\)})
|
242
231
|
end
|
243
232
|
end
|
244
233
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
RSpec.describe Rack::Tracker::Zanox do
|
2
|
+
|
3
|
+
describe Rack::Tracker::Zanox::Track do
|
4
|
+
|
5
|
+
subject { described_class.new(order_i_d: 'DEFC-4321', currency_symbol: 'EUR', total_price: '150.00') }
|
6
|
+
|
7
|
+
describe '#write' do
|
8
|
+
specify { expect(subject.write).to eq "OrderID=[[DEFC-4321]]&CurrencySymbol=[[EUR]]&TotalPrice=[[150.00]]" }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def env
|
13
|
+
{}
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'will be placed in the body' do
|
17
|
+
expect(described_class.position).to eq(:body)
|
18
|
+
expect(described_class.new(env).position).to eq(:body)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#render a sale #tracking_event' do
|
22
|
+
context 'with events' do
|
23
|
+
let(:env) {
|
24
|
+
{
|
25
|
+
'tracker' => {
|
26
|
+
'zanox' =>
|
27
|
+
[
|
28
|
+
{
|
29
|
+
'CustomerID' => '123456',
|
30
|
+
'OrderId' => 'DEFC-4321',
|
31
|
+
'CurrencySymbol' => 'EUR',
|
32
|
+
'TotalPrice' => '150.00',
|
33
|
+
'class_name' => 'Track'
|
34
|
+
}
|
35
|
+
]
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
subject { described_class.new(env, options).render }
|
41
|
+
let(:options) { { account_id: '123456H123456' } }
|
42
|
+
|
43
|
+
it 'will display the correct tracking events' do
|
44
|
+
expect(subject).to include "https://ad.zanox.com/ppl/?123456H123456&mode=[[1]]&CustomerID=[[123456]]&OrderId=[[DEFC-4321]]&CurrencySymbol=[[EUR]]&TotalPrice=[[150.00]]"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#render a lead #tracking_event' do
|
50
|
+
context 'with events' do
|
51
|
+
let(:env) {
|
52
|
+
{
|
53
|
+
'tracker' => {
|
54
|
+
'zanox' =>
|
55
|
+
[
|
56
|
+
{
|
57
|
+
'OrderId' => 'DEFC-4321',
|
58
|
+
'class_name' => 'Track'
|
59
|
+
}
|
60
|
+
]
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
subject { described_class.new(env, options).render }
|
66
|
+
let(:options) { { account_id: '123456H123456' } }
|
67
|
+
|
68
|
+
it 'will display the correct tracking events' do
|
69
|
+
expect(subject).to include "https://ad.zanox.com/ppl/?123456H123456&mode=[[1]]&OrderId=[[DEFC-4321]]"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#render a #mastertag event' do
|
75
|
+
context 'with events' do
|
76
|
+
let(:env) {
|
77
|
+
{
|
78
|
+
'tracker' => {
|
79
|
+
'zanox' =>
|
80
|
+
[
|
81
|
+
{
|
82
|
+
'id' => '12345678D2345',
|
83
|
+
'class_name' => 'Mastertag'
|
84
|
+
}
|
85
|
+
]
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
subject { described_class.new(env, options).render }
|
91
|
+
let(:options) { { account_id: '123456H123456' } }
|
92
|
+
|
93
|
+
it 'will display the correct tracking events' do
|
94
|
+
expect(subject).to include 'window._zx.push({"id": "12345678D2345"});'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'support/capybara_app_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Criteo Integration" do
|
4
|
+
before do
|
5
|
+
setup_app(action: :criteo) do |tracker|
|
6
|
+
tracker.handler(:criteo, {
|
7
|
+
set_account: '1234',
|
8
|
+
set_customer_id: ->(env){ '4711' },
|
9
|
+
set_site_type: ->(env){ 'm' }
|
10
|
+
})
|
11
|
+
end
|
12
|
+
visit '/'
|
13
|
+
end
|
14
|
+
|
15
|
+
subject { page }
|
16
|
+
|
17
|
+
it 'should include all the events' do
|
18
|
+
# tracker_events
|
19
|
+
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"setAccount\",\"account\":\"1234\"});"
|
20
|
+
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"setSiteType\",\"type\":\"m\"});"
|
21
|
+
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"setCustomerId\",\"id\":\"4711\"});"
|
22
|
+
|
23
|
+
# events
|
24
|
+
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"viewItem\",\"item\":\"P001\"});"
|
25
|
+
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"viewList\",\"item\":[\"P001\",\"P002\"]});"
|
26
|
+
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"trackTransaction\",\"id\":\"id\",\"item\":{\"id\":\"P0038\",\"price\":\"6.54\",\"quantity\":1}});"
|
27
|
+
expect(page.find("body")).to have_content "window.criteo_q.push({\"event\":\"viewBasket\",\"item\":[{\"id\":\"P001\",\"price\":\"6.54\",\"quantity\":1},{\"id\":\"P0038\",\"price\":\"2.99\",\"quantity\":1}]});"
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'adjust tracker position via options' do
|
31
|
+
before do
|
32
|
+
setup_app(action: :criteo) do |tracker|
|
33
|
+
tracker.handler :criteo, { set_account: '1234', position: :head }
|
34
|
+
end
|
35
|
+
visit '/'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "will be placed in the specified tag" do
|
39
|
+
expect(page.find("body")).to_not have_content('criteo')
|
40
|
+
expect(page.find("head")).to have_content("{\"event\":\"setAccount\",\"account\":\"1234\"}")
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -28,6 +28,5 @@ RSpec.describe "Google Analytics Integration" do
|
|
28
28
|
expect(page.find("head")).to_not have_content('U-XXX-Y')
|
29
29
|
expect(page.find("body")).to have_content('ga("ecommerce:addItem",{"id":"1234","name":"Fluffy Pink Bunnies","sku":"DD23444","category":"Party Toys","price":"11.99","quantity":"1"})')
|
30
30
|
end
|
31
|
-
|
32
31
|
end
|
33
32
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'support/capybara_app_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Zanox Integration" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
setup_app(action: :zanox) do |tracker|
|
7
|
+
tracker.handler(:zanox, { account_id: '12345H123456789' } )
|
8
|
+
end
|
9
|
+
|
10
|
+
visit '/'
|
11
|
+
end
|
12
|
+
|
13
|
+
subject { page }
|
14
|
+
|
15
|
+
it 'should include the mastertag event' do
|
16
|
+
expect(page.find("body")).to have_content "window._zx.push({\"id\": \"blurg567\"});"
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should include the track event' do
|
20
|
+
expect(page).to have_xpath "//script[contains(@src,'12345H123456789&mode=[[1]]&CustomerID=[[123456]]&OrderID=[[DEFC-4321]]&CurrencySymbol=[[EUR]]&TotalPrice=[[150.00]]')]"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -64,4 +64,22 @@ class MetalController < ActionController::Metal
|
|
64
64
|
end
|
65
65
|
render "metal/index"
|
66
66
|
end
|
67
|
+
|
68
|
+
def criteo
|
69
|
+
tracker do |t|
|
70
|
+
t.criteo :view_item, { item: 'P001' }
|
71
|
+
t.criteo :view_list, { item: ['P001', 'P002'] }
|
72
|
+
t.criteo :track_transaction, { id: 'id', item: { id: "P0038", price:"6.54", quantity:1 } }
|
73
|
+
t.criteo :view_basket, { item: [{ id: "P001", price:"6.54", quantity:1 }, { id: "P0038", price:"2.99", quantity:1 }] }
|
74
|
+
end
|
75
|
+
render 'metal/index'
|
76
|
+
end
|
77
|
+
|
78
|
+
def zanox
|
79
|
+
tracker do |t|
|
80
|
+
t.zanox :mastertag, { id: 'blurg567'}
|
81
|
+
t.zanox :track, { customer_i_d: '123456', order_i_d: 'DEFC-4321', currency_symbol: 'EUR', total_price: '150.00'}
|
82
|
+
end
|
83
|
+
render 'metal/index'
|
84
|
+
end
|
67
85
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Brillert
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-05-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -17,28 +17,28 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 1.4
|
20
|
+
version: '1.4'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 1.4
|
27
|
+
version: '1.4'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: tilt
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- - "
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 1.4
|
34
|
+
version: '1.4'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- - "
|
39
|
+
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 1.4
|
41
|
+
version: '1.4'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: activesupport
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -101,28 +101,28 @@ dependencies:
|
|
101
101
|
requirements:
|
102
102
|
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version: 3.
|
104
|
+
version: '3.2'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
109
|
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: 3.
|
111
|
+
version: '3.2'
|
112
112
|
- !ruby/object:Gem::Dependency
|
113
113
|
name: capybara
|
114
114
|
requirement: !ruby/object:Gem::Requirement
|
115
115
|
requirements:
|
116
116
|
- - "~>"
|
117
117
|
- !ruby/object:Gem::Version
|
118
|
-
version: 2.4
|
118
|
+
version: '2.4'
|
119
119
|
type: :development
|
120
120
|
prerelease: false
|
121
121
|
version_requirements: !ruby/object:Gem::Requirement
|
122
122
|
requirements:
|
123
123
|
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: 2.4
|
125
|
+
version: '2.4'
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: pry
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,6 +156,8 @@ files:
|
|
156
156
|
- Rakefile
|
157
157
|
- lib/rack/tracker.rb
|
158
158
|
- lib/rack/tracker/controller.rb
|
159
|
+
- lib/rack/tracker/criteo/criteo.rb
|
160
|
+
- lib/rack/tracker/criteo/template/criteo.erb
|
159
161
|
- lib/rack/tracker/extensions.rb
|
160
162
|
- lib/rack/tracker/facebook/facebook.rb
|
161
163
|
- lib/rack/tracker/facebook/template/facebook.erb
|
@@ -173,18 +175,23 @@ files:
|
|
173
175
|
- lib/rack/tracker/version.rb
|
174
176
|
- lib/rack/tracker/vwo/template/vwo.erb
|
175
177
|
- lib/rack/tracker/vwo/vwo.rb
|
178
|
+
- lib/rack/tracker/zanox/template/zanox.erb
|
179
|
+
- lib/rack/tracker/zanox/zanox.rb
|
176
180
|
- rack-tracker.gemspec
|
177
181
|
- spec/fixtures/another_handler.erb
|
178
182
|
- spec/fixtures/dummy.erb
|
179
183
|
- spec/fixtures/track_all_the_things.erb
|
180
184
|
- spec/fixtures/views/layouts/application.html.erb
|
181
185
|
- spec/fixtures/views/metal/index.html.erb
|
186
|
+
- spec/handler/criteo_spec.rb
|
182
187
|
- spec/handler/facebook_spec.rb
|
183
188
|
- spec/handler/go_squared_spec.rb
|
184
189
|
- spec/handler/google_adwords_conversion_spec.rb
|
185
190
|
- spec/handler/google_analytics_spec.rb
|
186
191
|
- spec/handler/google_tag_manager_spec.rb
|
187
192
|
- spec/handler/vwo_spec.rb
|
193
|
+
- spec/handler/zanox_spec.rb
|
194
|
+
- spec/integration/criteo_integration_spec.rb
|
188
195
|
- spec/integration/facebook_integration_spec.rb
|
189
196
|
- spec/integration/go_squared_integration_spec.rb
|
190
197
|
- spec/integration/google_adwords_conversion_integration_spec.rb
|
@@ -192,6 +199,7 @@ files:
|
|
192
199
|
- spec/integration/google_tag_manager_integration_spec.rb
|
193
200
|
- spec/integration/rails_integration_spec.rb
|
194
201
|
- spec/integration/vwo_integration_spec.rb
|
202
|
+
- spec/integration/zanox_integration_spec.rb
|
195
203
|
- spec/spec_helper.rb
|
196
204
|
- spec/support/capybara_app_helper.rb
|
197
205
|
- spec/support/fake_handler.rb
|
@@ -220,7 +228,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
220
228
|
version: '0'
|
221
229
|
requirements: []
|
222
230
|
rubyforge_project:
|
223
|
-
rubygems_version: 2.
|
231
|
+
rubygems_version: 2.2.2
|
224
232
|
signing_key:
|
225
233
|
specification_version: 4
|
226
234
|
summary: Tracking made easy
|
@@ -230,12 +238,15 @@ test_files:
|
|
230
238
|
- spec/fixtures/track_all_the_things.erb
|
231
239
|
- spec/fixtures/views/layouts/application.html.erb
|
232
240
|
- spec/fixtures/views/metal/index.html.erb
|
241
|
+
- spec/handler/criteo_spec.rb
|
233
242
|
- spec/handler/facebook_spec.rb
|
234
243
|
- spec/handler/go_squared_spec.rb
|
235
244
|
- spec/handler/google_adwords_conversion_spec.rb
|
236
245
|
- spec/handler/google_analytics_spec.rb
|
237
246
|
- spec/handler/google_tag_manager_spec.rb
|
238
247
|
- spec/handler/vwo_spec.rb
|
248
|
+
- spec/handler/zanox_spec.rb
|
249
|
+
- spec/integration/criteo_integration_spec.rb
|
239
250
|
- spec/integration/facebook_integration_spec.rb
|
240
251
|
- spec/integration/go_squared_integration_spec.rb
|
241
252
|
- spec/integration/google_adwords_conversion_integration_spec.rb
|
@@ -243,6 +254,7 @@ test_files:
|
|
243
254
|
- spec/integration/google_tag_manager_integration_spec.rb
|
244
255
|
- spec/integration/rails_integration_spec.rb
|
245
256
|
- spec/integration/vwo_integration_spec.rb
|
257
|
+
- spec/integration/zanox_integration_spec.rb
|
246
258
|
- spec/spec_helper.rb
|
247
259
|
- spec/support/capybara_app_helper.rb
|
248
260
|
- spec/support/fake_handler.rb
|