mixpal 0.0.5 → 0.1.0
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 +4 -4
- data/.rubocop.yml +23 -0
- data/.travis.yml +5 -0
- data/README.md +7 -11
- data/Rakefile +8 -1
- data/lib/mixpal.rb +7 -7
- data/lib/mixpal/event.rb +4 -4
- data/lib/mixpal/integration.rb +7 -7
- data/lib/mixpal/tracker.rb +29 -26
- data/lib/mixpal/user.rb +9 -7
- data/lib/mixpal/util.rb +3 -3
- data/lib/mixpal/version.rb +1 -1
- data/mixpanel_assistant.gemspec +1 -0
- data/spec/lib/mixpal/event_spec.rb +19 -17
- data/spec/lib/mixpal/tracker_spec.rb +127 -149
- data/spec/lib/mixpal/user_spec.rb +36 -30
- data/spec/lib/mixpal/util_spec.rb +15 -14
- data/spec/lib/mixpal_spec.rb +2 -2
- data/spec/spec_helper.rb +4 -6
- data/spec/support/matchers/element_matchers.rb +2 -2
- data/test_app/.gitignore +16 -0
- data/test_app/Gemfile +11 -0
- data/test_app/README.rdoc +28 -0
- data/test_app/Rakefile +6 -0
- data/test_app/app/assets/images/.keep +0 -0
- data/test_app/app/assets/javascripts/application.js +16 -0
- data/test_app/app/assets/stylesheets/application.css +15 -0
- data/test_app/app/controllers/application_controller.rb +12 -0
- data/test_app/app/controllers/concerns/.keep +0 -0
- data/test_app/app/controllers/redirects_controller.rb +10 -0
- data/test_app/app/helpers/application_helper.rb +2 -0
- data/test_app/app/mailers/.keep +0 -0
- data/test_app/app/models/.keep +0 -0
- data/test_app/app/models/concerns/.keep +0 -0
- data/test_app/app/views/layouts/application.html.erb +16 -0
- data/test_app/app/views/redirects/new.html.erb +1 -0
- data/test_app/bin/bundle +3 -0
- data/test_app/bin/rails +8 -0
- data/test_app/bin/rake +8 -0
- data/test_app/bin/spring +18 -0
- data/test_app/config.ru +4 -0
- data/test_app/config/application.rb +30 -0
- data/test_app/config/boot.rb +4 -0
- data/test_app/config/environment.rb +5 -0
- data/test_app/config/environments/development.rb +37 -0
- data/test_app/config/environments/production.rb +82 -0
- data/test_app/config/environments/test.rb +39 -0
- data/test_app/config/initializers/assets.rb +8 -0
- data/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test_app/config/initializers/cookies_serializer.rb +3 -0
- data/test_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/test_app/config/initializers/inflections.rb +16 -0
- data/test_app/config/initializers/mime_types.rb +4 -0
- data/test_app/config/initializers/session_store.rb +3 -0
- data/test_app/config/initializers/wrap_parameters.rb +14 -0
- data/test_app/config/locales/en.yml +23 -0
- data/test_app/config/routes.rb +4 -0
- data/test_app/config/secrets.yml +22 -0
- data/test_app/db/seeds.rb +7 -0
- data/test_app/lib/assets/.keep +0 -0
- data/test_app/lib/tasks/.keep +0 -0
- data/test_app/log/.keep +0 -0
- data/test_app/public/404.html +67 -0
- data/test_app/public/422.html +67 -0
- data/test_app/public/500.html +66 -0
- data/test_app/public/favicon.ico +0 -0
- data/test_app/public/robots.txt +5 -0
- data/test_app/vendor/assets/javascripts/.keep +0 -0
- data/test_app/vendor/assets/stylesheets/.keep +0 -0
- metadata +67 -6
- data/spec/support/mock_rails.rb +0 -6
- data/spec/support/mock_storage.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c04724d3a3e803dfd392c4635ee4480a41e959d4
|
4
|
+
data.tar.gz: 0ddb3d1b74618d3523cf32ed59ddbbbf39df457a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33668e11499b7a84380c2421d710213af257c858ed45cdc017c4e1aec0855277c73f65f818a323dc35ef520cc3484f8cbd320ff9dff3d9a0940dfebfbe25633f
|
7
|
+
data.tar.gz: 2ac2f904b86d599230c60b0d9a7f31327f03c3920ed60b2ce221ac1414992a556ed021951001852060bb3d88eabd38e0122697fa8d2a64a6f3d475568b47215f
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Encoding:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Documentation:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
ClassAndModuleChildren:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
ClassLength:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
MethodLength:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
DoubleNegation:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
AllCops:
|
20
|
+
Include:
|
21
|
+
- "Rakefile"
|
22
|
+
Exclude:
|
23
|
+
- "test_app/**/*"
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Mixpal
|
1
|
+
# Mixpal [](https://travis-ci.org/patbenatar/mixpal) [](https://codeclimate.com/github/patbenatar/mixpal)
|
2
2
|
|
3
3
|
As the JavaScript library is Mixpanel's preferred method of usage,
|
4
4
|
Mixpal aims to make it easier to work with from your Rails backend.
|
@@ -80,7 +80,7 @@ As with `register_user`, this method will also identify "special properties".
|
|
80
80
|
|
81
81
|
### Persistance Across Redirects
|
82
82
|
|
83
|
-
Mixpal stores any tracked events or user data in
|
83
|
+
Mixpal stores any tracked events or user data in the session when
|
84
84
|
it detects a redirect so it can output the appropriate Mixpanel JS integration
|
85
85
|
code to the client on the following render. This enables us to do cool things
|
86
86
|
like:
|
@@ -104,16 +104,12 @@ class UsersController < ActionController::Base
|
|
104
104
|
end
|
105
105
|
```
|
106
106
|
|
107
|
-
####
|
107
|
+
#### A note about `CookieStore` size limit
|
108
108
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
```
|
114
|
-
|
115
|
-
Storage adapters must implement the following API: `write(key, value)`,
|
116
|
-
`read(key)`, and `delete(key)`.
|
109
|
+
When using Rails' default `ActionDispatch::Session::CookieStore`, a 4K cookie
|
110
|
+
size limit is enforced. This cookie is shared by anything using the session.
|
111
|
+
If you anticipate tracking many events or large data sets to Mixpal,
|
112
|
+
[consider a different session store](http://guides.rubyonrails.org/action_controller_overview.html#session).
|
117
113
|
|
118
114
|
## Contributing
|
119
115
|
|
data/Rakefile
CHANGED
data/lib/mixpal.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'mixpal/version'
|
2
|
+
require 'active_support/core_ext'
|
3
3
|
|
4
4
|
module Mixpal
|
5
|
-
autoload :Util,
|
6
|
-
autoload :Tracker,
|
7
|
-
autoload :Event,
|
8
|
-
autoload :User,
|
9
|
-
autoload :Integration,
|
5
|
+
autoload :Util, 'mixpal/util'
|
6
|
+
autoload :Tracker, 'mixpal/tracker'
|
7
|
+
autoload :Event, 'mixpal/event'
|
8
|
+
autoload :User, 'mixpal/user'
|
9
|
+
autoload :Integration, 'mixpal/integration'
|
10
10
|
end
|
data/lib/mixpal/event.rb
CHANGED
@@ -14,13 +14,13 @@ module Mixpal
|
|
14
14
|
|
15
15
|
def to_store
|
16
16
|
{
|
17
|
-
name
|
18
|
-
properties
|
17
|
+
'name' => name,
|
18
|
+
'properties' => properties
|
19
19
|
}
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.from_store(data)
|
23
|
-
new(data[
|
23
|
+
new(data['name'], data['properties'])
|
24
24
|
end
|
25
25
|
end
|
26
|
-
end
|
26
|
+
end
|
data/lib/mixpal/integration.rb
CHANGED
@@ -10,25 +10,25 @@ module Mixpal
|
|
10
10
|
def self.mixpanel_identity(object_method, attribute_method)
|
11
11
|
self.mixpanel_identity_data = {
|
12
12
|
object_method: object_method,
|
13
|
-
attribute_method: attribute_method
|
13
|
+
attribute_method: attribute_method
|
14
14
|
}
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
def mixpanel
|
19
19
|
@mixpanel ||= begin
|
20
|
-
identity = if data = self.class.mixpanel_identity_data
|
21
|
-
|
22
|
-
|
20
|
+
identity = if (data = self.class.mixpanel_identity_data)
|
21
|
+
send(data[:object_method]).try(data[:attribute_method])
|
22
|
+
end
|
23
23
|
|
24
|
-
Mixpal::Tracker.new(identity: identity)
|
24
|
+
Mixpal::Tracker.new(identity: identity).tap { |t| t.restore!(session) }
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def store_mixpanel_if_redirecting
|
31
|
-
mixpanel.store! if status == 302
|
31
|
+
mixpanel.store!(session) if status == 302
|
32
32
|
end
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
data/lib/mixpal/tracker.rb
CHANGED
@@ -2,16 +2,12 @@ module Mixpal
|
|
2
2
|
class Tracker
|
3
3
|
attr_reader :events, :user_updates, :identity, :alias_user
|
4
4
|
|
5
|
-
STORAGE_KEY =
|
6
|
-
class_attribute :storage
|
7
|
-
self.storage = Rails.cache
|
5
|
+
STORAGE_KEY = 'mixpal'
|
8
6
|
|
9
|
-
def initialize(args={})
|
7
|
+
def initialize(args = {})
|
10
8
|
@events = []
|
11
9
|
@user_updates = []
|
12
10
|
|
13
|
-
restore!
|
14
|
-
|
15
11
|
@identity = args[:identity]
|
16
12
|
end
|
17
13
|
|
@@ -24,44 +20,51 @@ module Mixpal
|
|
24
20
|
user_updates << Mixpal::User.new(properties)
|
25
21
|
end
|
26
22
|
|
27
|
-
def track(name, properties={})
|
23
|
+
def track(name, properties = {})
|
28
24
|
events << Mixpal::Event.new(name, properties)
|
29
25
|
end
|
30
26
|
|
31
27
|
def render
|
32
|
-
|
33
|
-
html <<
|
28
|
+
''.tap do |html|
|
29
|
+
html << '<script type="text/javascript">'
|
34
30
|
html << "mixpanel.alias(\"#{identity}\");" if alias_user
|
35
31
|
html << "mixpanel.identify(\"#{identity}\");" if identity
|
36
|
-
html << events.map(&:render).join(
|
37
|
-
html << user_updates.map(&:render).join(
|
38
|
-
html <<
|
32
|
+
html << events.map(&:render).join('')
|
33
|
+
html << user_updates.map(&:render).join('')
|
34
|
+
html << '</script>'
|
39
35
|
end.html_safe
|
40
36
|
end
|
41
37
|
|
42
|
-
def store!
|
43
|
-
|
38
|
+
def store!(session)
|
39
|
+
session[STORAGE_KEY] = to_store
|
44
40
|
end
|
45
41
|
|
46
|
-
|
42
|
+
def restore!(session)
|
43
|
+
data = session[STORAGE_KEY] || {}
|
44
|
+
|
45
|
+
@alias_user = data['alias_user']
|
46
|
+
@identity ||= data['identity']
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
if data['events']
|
49
|
+
@events = data['events'].map { |e| Mixpal::Event.from_store(e) }
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
if data['user_updates']
|
53
|
+
@user_updates = data['user_updates']
|
54
|
+
.map { |u| Mixpal::User.from_store(u) }
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
+
session.delete(STORAGE_KEY)
|
57
58
|
end
|
58
59
|
|
60
|
+
private
|
61
|
+
|
59
62
|
def to_store
|
60
63
|
{
|
61
|
-
alias_user
|
62
|
-
identity
|
63
|
-
events
|
64
|
-
user_updates
|
64
|
+
'alias_user' => alias_user,
|
65
|
+
'identity' => identity,
|
66
|
+
'events' => events.map(&:to_store),
|
67
|
+
'user_updates' => user_updates.map(&:to_store)
|
65
68
|
}
|
66
69
|
end
|
67
70
|
end
|
data/lib/mixpal/user.rb
CHANGED
@@ -12,12 +12,12 @@ module Mixpal
|
|
12
12
|
|
13
13
|
def to_store
|
14
14
|
{
|
15
|
-
properties
|
15
|
+
'properties' => properties
|
16
16
|
}
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.from_store(data)
|
20
|
-
new(data[
|
20
|
+
new(data['properties'])
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
@@ -29,15 +29,17 @@ module Mixpal
|
|
29
29
|
# Isolate special properties and rename their keys to align with
|
30
30
|
# Mixpanel's naming.
|
31
31
|
def properties_for_mixpanel
|
32
|
-
Hash[
|
32
|
+
Hash[
|
33
|
+
properties.map { |k, v| [mixpanel_special_properties_map[k] || k, v] }
|
34
|
+
]
|
33
35
|
end
|
34
36
|
|
35
37
|
def mixpanel_special_properties_map
|
36
38
|
{
|
37
|
-
name:
|
38
|
-
email:
|
39
|
-
created_at:
|
39
|
+
name: '$name',
|
40
|
+
email: '$email',
|
41
|
+
created_at: '$created'
|
40
42
|
}.with_indifferent_access
|
41
43
|
end
|
42
44
|
end
|
43
|
-
end
|
45
|
+
end
|
data/lib/mixpal/util.rb
CHANGED
@@ -2,12 +2,12 @@ module Mixpal
|
|
2
2
|
module Util
|
3
3
|
class << self
|
4
4
|
def hash_to_js_object_string(hash)
|
5
|
-
hash.reject! { |
|
5
|
+
hash.reject! { |_, v| v.nil? }
|
6
6
|
|
7
|
-
contents = hash.map do |k,v|
|
7
|
+
contents = hash.map do |k, v|
|
8
8
|
js_value = v.is_a?(String) || v.is_a?(Time) ? "\"#{v}\"" : v
|
9
9
|
"\"#{k}\": #{js_value}"
|
10
|
-
end.join(
|
10
|
+
end.join(',').html_safe
|
11
11
|
|
12
12
|
"{#{contents}}"
|
13
13
|
end
|
data/lib/mixpal/version.rb
CHANGED
data/mixpanel_assistant.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
23
|
spec.add_development_dependency "pry"
|
24
|
+
spec.add_development_dependency "rubocop", "~> 0.24.1"
|
24
25
|
spec.add_development_dependency "rspec", "~> 2.14.0"
|
25
26
|
spec.add_development_dependency "guard-rspec", "~> 3.0.3"
|
26
27
|
spec.add_development_dependency "rb-fsevent", "~> 0.9.3"
|
@@ -1,48 +1,50 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Mixpal::Event do
|
4
|
-
let(:name) {
|
5
|
-
let(:properties) { { title:
|
4
|
+
let(:name) { 'Event 1' }
|
5
|
+
let(:properties) { { title: 'Awesome Product' } }
|
6
6
|
subject { described_class.new(name, properties) }
|
7
7
|
|
8
|
-
describe
|
9
|
-
it
|
8
|
+
describe '#render' do
|
9
|
+
it 'delegates to Util for js_object composition' do
|
10
10
|
Mixpal::Util.should_receive(:hash_to_js_object_string).with(properties)
|
11
11
|
subject.render
|
12
12
|
end
|
13
13
|
|
14
|
-
it
|
14
|
+
it 'outputs a call to track' do
|
15
15
|
js_object = Mixpal::Util.hash_to_js_object_string(properties)
|
16
16
|
expect(subject.render).to eq "mixpanel.track(\"#{name}\", #{js_object});"
|
17
17
|
end
|
18
18
|
|
19
|
-
it
|
19
|
+
it 'outputs an html safe string' do
|
20
20
|
expect(subject.render).to be_html_safe
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
describe
|
25
|
-
it
|
24
|
+
describe '#to_store' do
|
25
|
+
it 'returns a hash with its data' do
|
26
26
|
expect(subject.to_store).to eq(
|
27
|
-
name
|
28
|
-
properties
|
27
|
+
'name' => name,
|
28
|
+
'properties' => properties
|
29
29
|
)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
describe
|
34
|
-
let(:result)
|
33
|
+
describe '.from_store' do
|
34
|
+
let(:result) do
|
35
|
+
described_class.from_store('name' => name, 'properties' => properties)
|
36
|
+
end
|
35
37
|
|
36
|
-
it
|
38
|
+
it 'instantiates a new instance' do
|
37
39
|
expect(result).to be_an_instance_of(described_class)
|
38
40
|
end
|
39
41
|
|
40
|
-
it
|
42
|
+
it 'sets its name from the data' do
|
41
43
|
expect(result.name).to eq name
|
42
44
|
end
|
43
45
|
|
44
|
-
it
|
46
|
+
it 'sets its properties from the data' do
|
45
47
|
expect(result.properties).to eq properties
|
46
48
|
end
|
47
49
|
end
|
48
|
-
end
|
50
|
+
end
|
@@ -1,278 +1,256 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Mixpal::Tracker do
|
4
4
|
subject { Mixpal::Tracker.new }
|
5
|
-
let(:identity) {
|
5
|
+
let(:identity) { 'nick' }
|
6
6
|
let(:subject_with_identity) { Mixpal::Tracker.new(identity: identity) }
|
7
7
|
|
8
|
-
describe
|
9
|
-
|
10
|
-
@original_adapter = described_class.storage
|
11
|
-
|
12
|
-
MyCustomStorageAdapter = Class.new(MockStorage)
|
13
|
-
@adapter_instance = MyCustomStorageAdapter.new
|
14
|
-
|
15
|
-
described_class.storage = @adapter_instance
|
16
|
-
end
|
17
|
-
|
18
|
-
after { described_class.storage = @original_adapter }
|
19
|
-
|
20
|
-
it "uses the specified adapter" do
|
21
|
-
@adapter_instance.should_receive :write
|
22
|
-
subject.store!
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe "#initialize" do
|
27
|
-
it "creates an empty set of events" do
|
8
|
+
describe '#initialize' do
|
9
|
+
it 'creates an empty set of events' do
|
28
10
|
expect(subject.events).to eq []
|
29
11
|
end
|
30
12
|
|
31
|
-
it
|
13
|
+
it 'creates an empty set of user_updates' do
|
32
14
|
expect(subject.user_updates).to eq []
|
33
15
|
end
|
34
16
|
|
35
|
-
context
|
17
|
+
context 'with an :identity arg' do
|
36
18
|
subject { subject_with_identity }
|
37
19
|
|
38
|
-
it
|
39
|
-
expect(subject.identity).to eq
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context "when data exists in storage" do
|
44
|
-
let(:old_tracker) { Mixpal::Tracker.new(identity: identity) }
|
45
|
-
|
46
|
-
before do
|
47
|
-
old_tracker.track "Event 1"
|
48
|
-
old_tracker.register_user name: "Nick Giancola"
|
49
|
-
old_tracker.store!
|
50
|
-
end
|
51
|
-
|
52
|
-
it "restores the alias_user property" do
|
53
|
-
expect(subject.alias_user).to eq true
|
54
|
-
end
|
55
|
-
|
56
|
-
it "restores the events" do
|
57
|
-
expect(subject.events.size).to eq 1
|
58
|
-
end
|
59
|
-
|
60
|
-
it "delegates event restoration to the Event class" do
|
61
|
-
Mixpal::Event.should_receive(:from_store).
|
62
|
-
with(old_tracker.events.first.to_store)
|
63
|
-
|
64
|
-
subject
|
65
|
-
end
|
66
|
-
|
67
|
-
it "restores the events" do
|
68
|
-
expect(subject.events.size).to eq 1
|
69
|
-
end
|
70
|
-
|
71
|
-
context "when initialized with an identity" do
|
72
|
-
subject { Mixpal::Tracker.new(identity: "Franky") }
|
73
|
-
|
74
|
-
it "overrides anything from storage" do
|
75
|
-
expect(subject.identity).to eq "Franky"
|
76
|
-
end
|
20
|
+
it 'sets the identity' do
|
21
|
+
expect(subject.identity).to eq 'nick'
|
77
22
|
end
|
78
23
|
end
|
79
24
|
end
|
80
25
|
|
81
|
-
describe
|
82
|
-
it
|
83
|
-
subject.register_user(name:
|
26
|
+
describe '#register_user' do
|
27
|
+
it 'sets the alias_user flag so we render the alias call' do
|
28
|
+
subject.register_user(name: 'Nick')
|
84
29
|
expect(subject.alias_user).to be_true
|
85
30
|
end
|
86
31
|
|
87
|
-
it
|
88
|
-
properties = { name:
|
32
|
+
it 'delegates to #update_user for tracking user properties' do
|
33
|
+
properties = { name: 'Nick' }
|
89
34
|
subject.should_receive(:update_user).with(properties)
|
90
35
|
subject.register_user(properties)
|
91
36
|
end
|
92
37
|
end
|
93
38
|
|
94
|
-
describe
|
95
|
-
it
|
96
|
-
properties = { name:
|
39
|
+
describe '#update_user' do
|
40
|
+
it 'instantiates a new User object with properties' do
|
41
|
+
properties = { name: 'Nick' }
|
97
42
|
Mixpal::User.should_receive(:new).with(properties)
|
98
43
|
subject.update_user(properties)
|
99
44
|
end
|
100
45
|
|
101
|
-
it
|
46
|
+
it 'adds the User to user_updates for rendering later' do
|
102
47
|
expect do
|
103
|
-
subject.update_user(name:
|
48
|
+
subject.update_user(name: 'Nick')
|
104
49
|
end.to change(subject.user_updates, :size).by(1)
|
105
50
|
|
106
51
|
subject.user_updates.first.should be_an_instance_of(Mixpal::User)
|
107
52
|
end
|
108
53
|
end
|
109
54
|
|
110
|
-
describe
|
111
|
-
it
|
112
|
-
name =
|
113
|
-
properties = { color:
|
55
|
+
describe '#track' do
|
56
|
+
it 'instantiates a new Event object with properties' do
|
57
|
+
name = 'Clicked Button'
|
58
|
+
properties = { color: 'Green' }
|
114
59
|
|
115
60
|
Mixpal::Event.should_receive(:new).with(name, properties)
|
116
61
|
subject.track(name, properties)
|
117
62
|
end
|
118
63
|
|
119
|
-
it
|
64
|
+
it 'adds the Event to events for rendering later' do
|
120
65
|
expect do
|
121
|
-
subject.track(
|
66
|
+
subject.track('Clicked Button', color: 'Green')
|
122
67
|
end.to change(subject.events, :size).by(1)
|
123
68
|
|
124
69
|
subject.events.first.should be_an_instance_of(Mixpal::Event)
|
125
70
|
end
|
126
71
|
end
|
127
72
|
|
128
|
-
describe
|
129
|
-
it
|
130
|
-
expect(subject.render).to have_tag(
|
73
|
+
describe '#render' do
|
74
|
+
it 'outputs script tag' do
|
75
|
+
expect(subject.render).to have_tag('script')
|
131
76
|
end
|
132
77
|
|
133
|
-
it
|
78
|
+
it 'outputs an html safe string' do
|
134
79
|
expect(subject.render).to be_html_safe
|
135
80
|
end
|
136
81
|
|
137
|
-
context
|
82
|
+
context 'with an identity' do
|
138
83
|
subject { subject_with_identity }
|
139
84
|
|
140
|
-
it
|
85
|
+
it 'outputs call to identify' do
|
141
86
|
expect(subject.render).to include "mixpanel.identify(\"#{identity}\");"
|
142
87
|
end
|
143
88
|
|
144
|
-
context
|
145
|
-
before { subject.register_user(
|
89
|
+
context 'when user is being registered' do
|
90
|
+
before { subject.register_user(name: 'Nick Giancola') }
|
146
91
|
|
147
|
-
it
|
92
|
+
it 'outputs call to alias by identity' do
|
148
93
|
expect(subject.render).to include "mixpanel.alias(\"#{identity}\");"
|
149
94
|
end
|
150
95
|
end
|
151
96
|
end
|
152
97
|
|
153
|
-
context
|
154
|
-
it
|
155
|
-
expect(subject.render).not_to include
|
98
|
+
context 'with no registered user' do
|
99
|
+
it 'does not output call to alias' do
|
100
|
+
expect(subject.render).not_to include 'mixpanel.alias'
|
156
101
|
end
|
157
102
|
end
|
158
103
|
|
159
|
-
context
|
160
|
-
it
|
161
|
-
expect(subject.render).not_to include
|
104
|
+
context 'without an identity' do
|
105
|
+
it 'does not output call to identify' do
|
106
|
+
expect(subject.render).not_to include 'mixpanel.indentify'
|
162
107
|
end
|
163
108
|
end
|
164
109
|
|
165
|
-
context
|
110
|
+
context 'with tracked events' do
|
166
111
|
before do
|
167
|
-
subject.track(
|
168
|
-
subject.track(
|
112
|
+
subject.track('Event 1', color: 'Green')
|
113
|
+
subject.track('Event 2', title: 'Something Awesome')
|
169
114
|
end
|
170
115
|
|
171
|
-
it
|
116
|
+
it 'delegates render to the events' do
|
172
117
|
subject.events.each { |event| event.should_receive :render }
|
173
118
|
subject.render
|
174
119
|
end
|
175
120
|
|
176
|
-
it
|
121
|
+
it 'joins each rendered event' do
|
177
122
|
joined = subject.events[0].render + subject.events[1].render
|
178
123
|
expect(subject.render).to include joined
|
179
124
|
end
|
180
125
|
end
|
181
126
|
|
182
|
-
context
|
127
|
+
context 'with user properties' do
|
183
128
|
before do
|
184
|
-
subject.update_user(
|
185
|
-
subject.update_user(
|
129
|
+
subject.update_user(name: 'Hank')
|
130
|
+
subject.update_user(location: 'Los Angeles')
|
186
131
|
end
|
187
132
|
|
188
|
-
it
|
133
|
+
it 'delegates render to the users' do
|
189
134
|
subject.user_updates.each { |user| user.should_receive :render }
|
190
135
|
subject.render
|
191
136
|
end
|
192
137
|
|
193
|
-
it
|
138
|
+
it 'joins each rendered user' do
|
194
139
|
joined = subject.user_updates[0].render + subject.user_updates[1].render
|
195
140
|
expect(subject.render).to include joined
|
196
141
|
end
|
197
142
|
end
|
198
143
|
end
|
199
144
|
|
200
|
-
describe
|
201
|
-
let(:
|
202
|
-
|
203
|
-
after { MockRails.cache.delete(described_class::STORAGE_KEY) }
|
145
|
+
describe '#store!' do
|
146
|
+
let(:session) { {} }
|
204
147
|
|
205
148
|
def storage_should_include(hash_fragment)
|
206
|
-
|
207
|
-
described_class::STORAGE_KEY,
|
208
|
-
hash_including(hash_fragment)
|
209
|
-
)
|
210
|
-
end
|
211
|
-
|
212
|
-
it "writes to the storage adapter" do
|
213
|
-
storage.should_receive(:write)
|
214
|
-
subject.store!
|
149
|
+
expect(session[described_class::STORAGE_KEY]).to include hash_fragment
|
215
150
|
end
|
216
151
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
storage_should_include(alias_user: true)
|
222
|
-
subject.store!
|
223
|
-
end
|
152
|
+
it 'stores the alias_user property' do
|
153
|
+
subject.register_user({})
|
154
|
+
subject.store!(session)
|
155
|
+
storage_should_include('alias_user' => true)
|
224
156
|
end
|
225
157
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
it "stores the identity" do
|
230
|
-
storage_should_include(identity: identity)
|
231
|
-
subject.store!
|
232
|
-
end
|
158
|
+
it 'stores the identity' do
|
159
|
+
subject_with_identity.store!(session)
|
160
|
+
storage_should_include('identity' => identity)
|
233
161
|
end
|
234
162
|
|
235
|
-
context
|
163
|
+
context 'when events have been tracked' do
|
236
164
|
before do
|
237
|
-
subject.track(
|
238
|
-
subject.track(
|
165
|
+
subject.track('Event 1', color: 'Green')
|
166
|
+
subject.track('Event 2', title: 'Something Awesome')
|
239
167
|
end
|
240
168
|
|
241
|
-
it
|
169
|
+
it 'delegates composition to the events' do
|
242
170
|
subject.events.each { |event| event.should_receive :to_store }
|
243
|
-
subject.store!
|
171
|
+
subject.store!(session)
|
244
172
|
end
|
245
173
|
|
246
|
-
it
|
174
|
+
it 'stores the events composed hashes in an array' do
|
175
|
+
subject.store!(session)
|
247
176
|
storage_should_include(
|
248
|
-
events
|
177
|
+
'events' => [subject.events[0].to_store, subject.events[1].to_store]
|
249
178
|
)
|
250
|
-
|
251
|
-
subject.store!
|
252
179
|
end
|
253
180
|
end
|
254
181
|
|
255
|
-
context
|
182
|
+
context 'when user properties have been updated' do
|
256
183
|
before do
|
257
|
-
subject.update_user(
|
258
|
-
subject.update_user(
|
184
|
+
subject.update_user(name: 'Hank')
|
185
|
+
subject.update_user(location: 'Los Angeles')
|
259
186
|
end
|
260
187
|
|
261
|
-
it
|
188
|
+
it 'delegates composition to the users' do
|
262
189
|
subject.user_updates.each { |user| user.should_receive :to_store }
|
263
|
-
subject.store!
|
190
|
+
subject.store!(session)
|
264
191
|
end
|
265
192
|
|
266
|
-
it
|
193
|
+
it 'stores the users composed hashes in an array' do
|
194
|
+
subject.store!(session)
|
195
|
+
|
267
196
|
storage_should_include(
|
268
|
-
user_updates
|
197
|
+
'user_updates' => [
|
269
198
|
subject.user_updates[0].to_store,
|
270
199
|
subject.user_updates[1].to_store
|
271
200
|
]
|
272
201
|
)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe '#restore!' do
|
207
|
+
let(:old_tracker) { Mixpal::Tracker.new(identity: identity) }
|
208
|
+
let(:session) { {} }
|
209
|
+
|
210
|
+
before do
|
211
|
+
old_tracker.track 'Event 1'
|
212
|
+
old_tracker.register_user name: 'Nick Giancola'
|
213
|
+
old_tracker.store!(session)
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'restores the alias_user property' do
|
217
|
+
subject.restore!(session)
|
218
|
+
expect(subject.alias_user).to eq true
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'restores the events' do
|
222
|
+
subject.restore!(session)
|
223
|
+
expect(subject.events.size).to eq 1
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'delegates event restoration to the Event class' do
|
227
|
+
Mixpal::Event.should_receive(:from_store)
|
228
|
+
.with(old_tracker.events.first.to_store)
|
229
|
+
|
230
|
+
subject.restore!(session)
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'restores the events' do
|
234
|
+
subject.restore!(session)
|
235
|
+
expect(subject.events.size).to eq 1
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'with a different identity (e.g. after login)' do
|
239
|
+
subject { Mixpal::Tracker.new(identity: "#{identity}-2") }
|
240
|
+
|
241
|
+
it 'does not override identity with value in storage' do
|
242
|
+
subject.restore!(session)
|
243
|
+
expect(subject.identity).to eq "#{identity}-2"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
context 'with no identity (e.g. after logout)' do
|
248
|
+
subject { Mixpal::Tracker.new(identity: nil) }
|
273
249
|
|
274
|
-
|
250
|
+
it 'overrides identity with value in storage' do
|
251
|
+
subject.restore!(session)
|
252
|
+
expect(subject.identity).to eq identity
|
275
253
|
end
|
276
254
|
end
|
277
255
|
end
|
278
|
-
end
|
256
|
+
end
|