mixpanel 2.2.0 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +233 -105
- data/lib/mixpanel/async.rb +31 -0
- data/lib/mixpanel/event.rb +41 -0
- data/lib/mixpanel/middleware.rb +142 -0
- data/lib/mixpanel/person.rb +41 -0
- data/lib/mixpanel/subprocess.rb +27 -0
- data/lib/mixpanel/tracker.rb +54 -151
- data/lib/mixpanel.rb +1 -0
- data/mixpanel.gemspec +2 -1
- data/spec/mixpanel/{tracker/middleware_spec.rb → middleware_spec.rb} +10 -10
- data/spec/mixpanel/tracker_spec.rb +33 -90
- data/spec/spec_helper.rb +13 -3
- data/spec/support/rack_apps.rb +1 -1
- metadata +37 -24
- data/lib/mixpanel/tracker/middleware.rb +0 -144
- data/lib/mixpanel/tracker/subprocess.rb +0 -29
- data/spec/mixpanel/mixpanel_spec.rb +0 -11
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mixpanel::Person
|
2
|
+
PERSON_PROPERTIES = %w{email created first_name last_name last_login username country_code}
|
3
|
+
PERSON_URL = 'http://api.mixpanel.com/engage/'
|
4
|
+
|
5
|
+
def set(distinct_id, properties={}, options={})
|
6
|
+
engage :set, distinct_id, properties, options
|
7
|
+
end
|
8
|
+
|
9
|
+
def increment(distinct_id, properties={}, options={})
|
10
|
+
engage :add, distinct_id, properties, options
|
11
|
+
end
|
12
|
+
|
13
|
+
def append_set(properties={})
|
14
|
+
append 'people.set', properties_hash(properties, PERSON_PROPERTIES)
|
15
|
+
end
|
16
|
+
|
17
|
+
def append_increment(property, increment=1)
|
18
|
+
append 'people.increment', property, increment
|
19
|
+
end
|
20
|
+
|
21
|
+
def append_register(properties={})
|
22
|
+
append 'register', properties_hash(properties, PERSON_PROPERTIES)
|
23
|
+
end
|
24
|
+
|
25
|
+
def append_identify(distinct_id)
|
26
|
+
append 'identify', distinct_id
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def engage(action, distinct_id, properties, options)
|
32
|
+
options.reverse_merge! :async => @async, :url => PERSON_URL
|
33
|
+
data = build_person action, distinct_id, properties
|
34
|
+
url = "#{options[:url]}?data=#{encoded_data(data)}"
|
35
|
+
parse_response request(url, options[:async])
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_person(action, distinct_id, properties)
|
39
|
+
{ "$#{action}".to_sym => properties_hash(properties, PERSON_PROPERTIES), :$token => @token, :$distinct_id => distinct_id }
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Mixpanel
|
5
|
+
class Subprocess
|
6
|
+
Q = Queue.new
|
7
|
+
ENDMARKER = Object.new
|
8
|
+
|
9
|
+
Thread.abort_on_exception = true
|
10
|
+
producer = Thread.new do
|
11
|
+
STDIN.each_line() do |url|
|
12
|
+
STDERR.puts("Dropped: #{url}") && next if Q.length > 10000
|
13
|
+
Q << url
|
14
|
+
end
|
15
|
+
Q << ENDMARKER
|
16
|
+
end
|
17
|
+
|
18
|
+
loop do
|
19
|
+
url = Q.pop
|
20
|
+
break if(url == ENDMARKER)
|
21
|
+
url.chomp!
|
22
|
+
next if(url.empty?) #for testing
|
23
|
+
open(url).read
|
24
|
+
end
|
25
|
+
producer.join
|
26
|
+
end
|
27
|
+
end
|
data/lib/mixpanel/tracker.rb
CHANGED
@@ -2,171 +2,74 @@ require "open-uri"
|
|
2
2
|
require 'base64'
|
3
3
|
require 'json'
|
4
4
|
require 'thread'
|
5
|
-
require 'mixpanel/tracker/middleware'
|
6
5
|
|
7
6
|
module Mixpanel
|
8
7
|
class Tracker
|
8
|
+
require 'mixpanel/async'
|
9
|
+
require 'mixpanel/event'
|
10
|
+
require 'mixpanel/person'
|
11
|
+
|
12
|
+
extend Mixpanel::Async
|
13
|
+
include Mixpanel::Event
|
14
|
+
include Mixpanel::Person
|
15
|
+
|
16
|
+
def initialize(token, options={})
|
17
|
+
@token = token
|
18
|
+
@async = !!options.fetch(:async, false)
|
19
|
+
@persist = !!options.fetch(:persist, false)
|
20
|
+
@env = options.fetch :env, {}
|
21
|
+
@api_key = options.fetch :api_key, nil
|
9
22
|
|
10
|
-
|
11
|
-
TRACK_ENDPOINT = '/track/?data='.freeze
|
12
|
-
ENGAGE_ENDPOINT = '/engage/?data='.freeze
|
13
|
-
IMPORT_ENDPOINT = '/import/?data='.freeze
|
14
|
-
|
15
|
-
PERSON_PROPERTIES = %w(email first_name last_name created last_login username country_code).freeze
|
16
|
-
|
17
|
-
def initialize(token, env, options = {})
|
18
|
-
@token = token
|
19
|
-
@api_key = options.fetch(:api_key, "")
|
20
|
-
@env = env
|
21
|
-
@async = options.fetch(:async, false)
|
22
|
-
@import = options.fetch(:import, false)
|
23
|
-
@url = options.fetch(:url, MIXPANEL_API_URL)
|
24
|
-
@persist = options.fetch(:persist, false)
|
25
|
-
|
23
|
+
# Make sure queue object is instantiated to an array. If not persisted, set queue object to empty array.
|
26
24
|
if @persist
|
27
|
-
@env[
|
28
|
-
|
29
|
-
clear_queue
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def append_event(event, properties = {})
|
34
|
-
append_api('track', event, properties)
|
35
|
-
end
|
36
|
-
|
37
|
-
def append_person_event(properties = {})
|
38
|
-
append_api('people.set', person_properties(properties))
|
39
|
-
end
|
40
|
-
|
41
|
-
def append_person_increment_event(property, increment=1)
|
42
|
-
append_api('people.increment', property, increment)
|
43
|
-
end
|
44
|
-
|
45
|
-
def append_api(type, *args)
|
46
|
-
queue << [type, args.map {|arg| arg.to_json}]
|
47
|
-
end
|
48
|
-
|
49
|
-
def track_event(event, properties = {})
|
50
|
-
options = { :time => Time.now.utc.to_i, :ip => ip }
|
51
|
-
options.merge!( :token => @token ) if @token
|
52
|
-
parse_response request(:track,
|
53
|
-
:event => event,
|
54
|
-
:properties => options.merge(properties)
|
55
|
-
)
|
56
|
-
end
|
57
|
-
|
58
|
-
def engage(action, distinct_id, properties = {})
|
59
|
-
options = { }
|
60
|
-
options.merge!( :$token => @token ) if @token
|
61
|
-
parse_response request(:engage, options.merge(
|
62
|
-
:$distinct_id => distinct_id,
|
63
|
-
"$#{action}".to_sym => person_properties(properties)
|
64
|
-
))
|
65
|
-
end
|
66
|
-
|
67
|
-
def engage_set(distinct_id, properties = {})
|
68
|
-
engage(:set, distinct_id, properties)
|
69
|
-
end
|
70
|
-
|
71
|
-
def engage_add(distinct_id, properties = {})
|
72
|
-
engage(:add, distinct_id, properties)
|
73
|
-
end
|
74
|
-
|
75
|
-
def ip
|
76
|
-
if @env.has_key?("HTTP_X_FORWARDED_FOR")
|
77
|
-
@env["HTTP_X_FORWARDED_FOR"].split(",").last
|
78
|
-
elsif @env.has_key?("REMOTE_ADDR")
|
79
|
-
@env["REMOTE_ADDR"]
|
25
|
+
@env['rack.session'] ||= {}
|
26
|
+
@env['rack.session']['mixpanel_events'] ||= []
|
80
27
|
else
|
81
|
-
|
28
|
+
@env['mixpanel_events'] = []
|
82
29
|
end
|
83
30
|
end
|
84
|
-
|
31
|
+
|
85
32
|
def queue
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
33
|
+
@persist ? @env['rack.session']['mixpanel_events'] : @env['mixpanel_events']
|
34
|
+
end
|
35
|
+
|
36
|
+
def append(type, *args)
|
37
|
+
queue << [type, args.collect {|arg| arg.to_json}]
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
# Walk through each property and see if it is in the special_properties. If so, change the key to have a $ in front of it.
|
43
|
+
def properties_hash(properties, special_properties)
|
44
|
+
properties.inject({}) do |props, (key, value)|
|
45
|
+
key = "$#{key}" if special_properties.include?(key.to_s)
|
46
|
+
props[key.to_sym] = value
|
47
|
+
props
|
90
48
|
end
|
91
49
|
end
|
92
|
-
|
93
|
-
def
|
94
|
-
|
95
|
-
@env["rack.session"]["mixpanel_events"] = []
|
96
|
-
else
|
97
|
-
@env["mixpanel_events"] = []
|
98
|
-
end
|
50
|
+
|
51
|
+
def encoded_data(parameters)
|
52
|
+
Base64.encode64(JSON.generate(parameters)).gsub(/\n/,'')
|
99
53
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
def worker
|
105
|
-
WORKER_MUTEX.synchronize do
|
106
|
-
@worker || (@worker = IO.popen(self.cmd, 'w'))
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def dispose_worker(w)
|
111
|
-
WORKER_MUTEX.synchronize do
|
112
|
-
if(@worker == w)
|
113
|
-
@worker = nil
|
114
|
-
w.close
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def cmd
|
120
|
-
@cmd || begin
|
121
|
-
require 'escape'
|
122
|
-
require 'rbconfig'
|
123
|
-
interpreter = File.join(*RbConfig::CONFIG.values_at("bindir", "ruby_install_name")) + RbConfig::CONFIG["EXEEXT"]
|
124
|
-
subprocess = File.join(File.dirname(__FILE__), 'tracker/subprocess.rb')
|
125
|
-
@cmd = Escape.shell_command([interpreter, subprocess])
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
private
|
131
|
-
|
132
|
-
def person_properties(properties = {})
|
133
|
-
properties.inject({}) do |out, (k, v)|
|
134
|
-
if PERSON_PROPERTIES.member?(k.to_s)
|
135
|
-
out["$#{k}".to_sym] = v
|
136
|
-
else
|
137
|
-
out[k] = v
|
138
|
-
end
|
139
|
-
out
|
140
|
-
end
|
54
|
+
|
55
|
+
def request(url, async)
|
56
|
+
async ? send_async(url) : open(url).read
|
141
57
|
end
|
142
|
-
|
58
|
+
|
143
59
|
def parse_response(response)
|
144
|
-
response ==
|
145
|
-
end
|
146
|
-
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
url = "#{@url}#{endpoint}#{data}"
|
157
|
-
url += "&api_key=#{@api_key}" if mode == :import
|
158
|
-
|
159
|
-
if(@async)
|
160
|
-
w = Tracker.worker
|
161
|
-
begin
|
162
|
-
url << "\n"
|
163
|
-
w.write(url)
|
164
|
-
rescue Errno::EPIPE => e
|
165
|
-
Tracker.dispose_worker(w)
|
166
|
-
end
|
167
|
-
else
|
168
|
-
open(url).read
|
60
|
+
response.to_i == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
def send_async(url)
|
64
|
+
w = Mixpanel::Tracker.worker
|
65
|
+
begin
|
66
|
+
url << "\n"
|
67
|
+
w.write url
|
68
|
+
1
|
69
|
+
rescue Errno::EPIPE => e
|
70
|
+
Mixpanel::Tracker.dispose_worker w
|
71
|
+
0
|
169
72
|
end
|
170
73
|
end
|
171
74
|
end
|
172
|
-
end
|
75
|
+
end
|
data/lib/mixpanel.rb
CHANGED
data/mixpanel.gemspec
CHANGED
@@ -2,7 +2,7 @@ files = ['README.md', 'LICENSE', 'Rakefile', 'mixpanel.gemspec', '{spec,lib}/**/
|
|
2
2
|
|
3
3
|
spec = Gem::Specification.new do |s|
|
4
4
|
s.name = "mixpanel"
|
5
|
-
s.version = "
|
5
|
+
s.version = "3.0.1"
|
6
6
|
s.rubyforge_project = "mixpanel"
|
7
7
|
s.description = "Simple lib to track events in Mixpanel service. It can be used in any rack based framework."
|
8
8
|
s.author = "Alvaro Gil"
|
@@ -17,6 +17,7 @@ spec = Gem::Specification.new do |s|
|
|
17
17
|
s.add_dependency 'json'
|
18
18
|
s.add_dependency 'rack'
|
19
19
|
s.add_dependency 'escape'
|
20
|
+
s.add_development_dependency 'active_support'
|
20
21
|
s.add_development_dependency 'rspec'
|
21
22
|
s.add_development_dependency 'rack-test'
|
22
23
|
s.add_development_dependency 'fakeweb'
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
def exec_default_appends_on(mixpanel)
|
4
|
-
mixpanel.
|
5
|
-
mixpanel.
|
6
|
-
mixpanel.
|
7
|
-
mixpanel.
|
4
|
+
mixpanel.append_track("Visit", {:article => 1})
|
5
|
+
mixpanel.append_track("Sign in")
|
6
|
+
mixpanel.append_set(:first_name => "foo", :last_name => "bar", :username => "foobar")
|
7
|
+
mixpanel.append_increment(:sign_in_rate)
|
8
8
|
end
|
9
9
|
|
10
10
|
def check_for_default_appends_on(txt)
|
11
|
-
txt.should =~ /mixpanel\.track\("Visit",\s?\{"article":1\
|
12
|
-
txt.should =~ /mixpanel\.track\("Sign in",\s?\{
|
11
|
+
txt.should =~ /mixpanel\.track\("Visit",\s?\{.*"article":1[\{|,]/
|
12
|
+
txt.should =~ /mixpanel\.track\("Sign in",\s?\{.*"time":.*\}/
|
13
13
|
txt.should =~ /mixpanel\.people\.set\(.*\);\nmixpanel.people.increment\(\"sign_in_rate\",\s?1\);/
|
14
14
|
match = txt.match(/mixpanel\.people\.set\((.*\));/)
|
15
15
|
match[1].should =~ /\"\$first_name\":\"foo\"/
|
@@ -18,9 +18,9 @@ def check_for_default_appends_on(txt)
|
|
18
18
|
txt.should =~ /mixpanel\.people\.increment\(\"sign_in_rate\"\s?,\s?1\)/
|
19
19
|
end
|
20
20
|
|
21
|
-
describe Mixpanel::
|
21
|
+
describe Mixpanel::Middleware do
|
22
22
|
include Rack::Test::Methods
|
23
|
-
|
23
|
+
|
24
24
|
describe "Dummy apps, no text/html" do
|
25
25
|
before do
|
26
26
|
setup_rack_application(DummyApp, :body => html_document, :headers => {})
|
@@ -198,7 +198,7 @@ describe Mixpanel::Tracker::Middleware do
|
|
198
198
|
|
199
199
|
describe "Tracking async appended events" do
|
200
200
|
before do
|
201
|
-
@mixpanel = Mixpanel::Tracker.new
|
201
|
+
@mixpanel = Mixpanel::Tracker.new MIX_PANEL_TOKEN
|
202
202
|
exec_default_appends_on @mixpanel
|
203
203
|
end
|
204
204
|
|
@@ -266,7 +266,7 @@ describe Mixpanel::Tracker::Middleware do
|
|
266
266
|
|
267
267
|
describe "Tracking appended events" do
|
268
268
|
before do
|
269
|
-
@mixpanel = Mixpanel::Tracker.new
|
269
|
+
@mixpanel = Mixpanel::Tracker.new MIX_PANEL_TOKEN
|
270
270
|
exec_default_appends_on @mixpanel
|
271
271
|
end
|
272
272
|
|
@@ -2,20 +2,20 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Mixpanel::Tracker do
|
4
4
|
before(:each) do
|
5
|
-
@mixpanel = Mixpanel::Tracker.new
|
5
|
+
@mixpanel = Mixpanel::Tracker.new MIX_PANEL_TOKEN, { :env => {"REMOTE_ADDR" => "127.0.0.1"} }
|
6
6
|
end
|
7
7
|
|
8
8
|
context "Initializing object" do
|
9
9
|
it "should have an instance variable for token and events" do
|
10
|
-
@mixpanel.instance_variables.map(&:to_s).should include(
|
10
|
+
@mixpanel.instance_variables.map(&:to_s).should include('@token', '@async', '@persist', '@env')
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
context "Cleaning appended events" do
|
15
15
|
it "should clear the queue" do
|
16
|
-
@mixpanel.
|
16
|
+
@mixpanel.append_track("Sign up")
|
17
17
|
@mixpanel.queue.size.should == 1
|
18
|
-
@mixpanel.
|
18
|
+
@mixpanel.queue.clear
|
19
19
|
@mixpanel.queue.size.should == 0
|
20
20
|
end
|
21
21
|
end
|
@@ -23,60 +23,31 @@ describe Mixpanel::Tracker do
|
|
23
23
|
context "Accessing Mixpanel through direct request" do
|
24
24
|
context "Tracking events" do
|
25
25
|
it "should track simple events" do
|
26
|
-
@mixpanel.
|
26
|
+
@mixpanel.track("Sign up").should == true
|
27
27
|
end
|
28
|
-
|
29
|
-
it "should
|
30
|
-
|
31
|
-
|
32
|
-
@mixpanel.should_receive(:request).with(:track, params).and_return("1")
|
33
|
-
@mixpanel.track_event("Sign up").should == true
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should call request method with token, and send ip address from HTTP_X_FORWARDED_FOR" do
|
37
|
-
@mixpanel = Mixpanel::Tracker.new(MIX_PANEL_TOKEN, @env = {"HTTP_X_FORWARDED_FOR" => "10.1.0.2"})
|
38
|
-
|
39
|
-
params = {:event => "Sign up", :properties => {:token => MIX_PANEL_TOKEN, :time => Time.now.utc.to_i, :ip => "10.1.0.2"}}
|
40
|
-
|
41
|
-
@mixpanel.should_receive(:request).with(:track, params).and_return("1")
|
42
|
-
@mixpanel.track_event("Sign up")
|
28
|
+
|
29
|
+
it "should track events with properties" do
|
30
|
+
@mixpanel.track('Sign up', { :likeable => true }, { :api_key => 'asdf' }).should == true
|
43
31
|
end
|
44
32
|
end
|
45
33
|
|
46
|
-
context "
|
47
|
-
it "should
|
48
|
-
@mixpanel.
|
34
|
+
context "Importing events" do
|
35
|
+
it "should import simple events" do
|
36
|
+
@mixpanel.import('Sign up').should == true
|
49
37
|
end
|
50
38
|
|
51
|
-
it "should
|
52
|
-
@mixpanel.
|
39
|
+
it "should import events with properties" do
|
40
|
+
@mixpanel.import('Sign up', { :likeable => true }, { :api_key => 'asdf' }).should == true
|
53
41
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
it "should call request method for setting" do
|
60
|
-
params = {
|
61
|
-
:$token => MIX_PANEL_TOKEN,
|
62
|
-
:$distinct_id => DISTINCT_ID,
|
63
|
-
:$set => {
|
64
|
-
:$email => 'test@example.com',
|
65
|
-
:custom => 'test'
|
66
|
-
}}
|
67
|
-
@mixpanel.should_receive(:request).with(:engage, params).and_return("1")
|
68
|
-
@mixpanel.engage(:set, DISTINCT_ID, :email => 'test@example.com', :custom => 'test')
|
42
|
+
end
|
43
|
+
|
44
|
+
context "Engaging people" do
|
45
|
+
it "should set attributes" do
|
46
|
+
@mixpanel.set('person-a', { :email => 'me@domain.com', :likeable => false }).should == true
|
69
47
|
end
|
70
48
|
|
71
|
-
it "should
|
72
|
-
|
73
|
-
:$token => MIX_PANEL_TOKEN,
|
74
|
-
:$distinct_id => DISTINCT_ID,
|
75
|
-
:$add => {
|
76
|
-
:custom => 99
|
77
|
-
}}
|
78
|
-
@mixpanel.should_receive(:request).with(:engage, params).and_return("1")
|
79
|
-
@mixpanel.engage(:add, DISTINCT_ID, :custom => 99)
|
49
|
+
it "should increment attributes" do
|
50
|
+
@mixpanel.increment('person-a', { :tokens => 3, :money => -1 }).should == true
|
80
51
|
end
|
81
52
|
end
|
82
53
|
end
|
@@ -84,47 +55,39 @@ describe Mixpanel::Tracker do
|
|
84
55
|
context "Accessing Mixpanel through javascript API" do
|
85
56
|
context "Appending events" do
|
86
57
|
it "should store the event under the appropriate key" do
|
87
|
-
@mixpanel.
|
88
|
-
@env.has_key?("mixpanel_events").should == true
|
58
|
+
@mixpanel.instance_variable_get(:@env).has_key?("mixpanel_events").should == true
|
89
59
|
end
|
90
60
|
|
91
61
|
it "should be the same the queue than env['mixpanel_events']" do
|
92
|
-
@env['mixpanel_events'].object_id.should == @mixpanel.queue.object_id
|
62
|
+
@mixpanel.instance_variable_get(:@env)['mixpanel_events'].object_id.should == @mixpanel.queue.object_id
|
93
63
|
end
|
94
64
|
|
95
65
|
it "should append simple events" do
|
96
|
-
|
97
|
-
|
66
|
+
props = { :time => Time.now, :ip => 'ASDF' }
|
67
|
+
@mixpanel.append_track "Sign up", props
|
68
|
+
mixpanel_queue_should_include(@mixpanel, "track", "Sign up", props)
|
98
69
|
end
|
99
70
|
|
100
71
|
it "should append events with properties" do
|
101
|
-
|
102
|
-
|
72
|
+
props = { :referer => 'http://example.com', :time => Time.now, :ip => 'ASDF' }
|
73
|
+
@mixpanel.append_track "Sign up", props
|
74
|
+
mixpanel_queue_should_include(@mixpanel, "track", "Sign up", props)
|
103
75
|
end
|
104
76
|
|
105
77
|
it "should give direct access to queue" do
|
106
|
-
@mixpanel.
|
78
|
+
@mixpanel.append_track("Sign up", {:referer => 'http://example.com'})
|
107
79
|
@mixpanel.queue.size.should == 1
|
108
80
|
end
|
109
81
|
|
110
|
-
it "should provide direct access to the JS api" do
|
111
|
-
@mixpanel.append_api('track', "Sign up", {:referer => 'http://example.com'})
|
112
|
-
mixpanel_queue_should_include(@mixpanel, "track", "Sign up", {:referer => 'http://example.com'})
|
113
|
-
end
|
114
|
-
|
115
|
-
it "should allow identify to be called through the JS api" do
|
116
|
-
@mixpanel.append_api('identify', "some@one.com")
|
117
|
-
mixpanel_queue_should_include(@mixpanel, "identify", "some@one.com")
|
118
|
-
end
|
119
|
-
|
120
82
|
it "should allow identify to be called through the JS api" do
|
121
|
-
@mixpanel.
|
83
|
+
@mixpanel.append_identify "some@one.com"
|
122
84
|
mixpanel_queue_should_include(@mixpanel, "identify", "some@one.com")
|
123
85
|
end
|
124
86
|
|
125
87
|
it "should allow the tracking of super properties in JS" do
|
126
|
-
|
127
|
-
|
88
|
+
props = {:user_id => 12345, :gender => 'male'}
|
89
|
+
@mixpanel.append_register props
|
90
|
+
mixpanel_queue_should_include(@mixpanel, 'register', props)
|
128
91
|
end
|
129
92
|
end
|
130
93
|
end
|
@@ -156,24 +119,4 @@ describe Mixpanel::Tracker do
|
|
156
119
|
w2.should_not == w
|
157
120
|
end
|
158
121
|
end
|
159
|
-
|
160
|
-
context "Request modes" do
|
161
|
-
it "should use the track URL" do
|
162
|
-
@mixpanel.track_event("Sign up")
|
163
|
-
FakeWeb.last_request.path.to_s.include?(Mixpanel::Tracker::TRACK_ENDPOINT).should == true
|
164
|
-
end
|
165
|
-
|
166
|
-
it "should use the engage URL" do
|
167
|
-
@mixpanel.engage(:set, DISTINCT_ID, :email => 'test@example.com')
|
168
|
-
FakeWeb.last_request.path.to_s.include?(Mixpanel::Tracker::ENGAGE_ENDPOINT).should == true
|
169
|
-
end
|
170
|
-
|
171
|
-
it "should use the import URL" do
|
172
|
-
@mixpanel = Mixpanel::Tracker.new(MIX_PANEL_TOKEN, @env = {"REMOTE_ADDR" => "127.0.0.1"}, { :import => true, :api_key => "ABCDEFG" })
|
173
|
-
@mixpanel.track_event("Sign up")
|
174
|
-
path = FakeWeb.last_request.path.to_s
|
175
|
-
path.include?(Mixpanel::Tracker::IMPORT_ENDPOINT).should == true
|
176
|
-
path.include?("&api_key=ABCDEFG").should == true
|
177
|
-
end
|
178
|
-
end
|
179
122
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -3,18 +3,28 @@ require File.join(File.dirname(__FILE__), "../lib", "mixpanel")
|
|
3
3
|
require 'rack/test'
|
4
4
|
require 'fakeweb'
|
5
5
|
require 'nokogiri'
|
6
|
+
require 'active_support/core_ext/hash'
|
7
|
+
|
6
8
|
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
7
9
|
|
8
10
|
MIX_PANEL_TOKEN = "e2d8b0bea559147844ffab3d607d26a6"
|
9
|
-
|
11
|
+
|
10
12
|
|
11
13
|
def mixpanel_queue_should_include(mixpanel, type, *arguments)
|
12
14
|
mixpanel.queue.each do |event_type, event_arguments|
|
13
|
-
|
14
|
-
|
15
|
+
# hashes store keys in an undetermined order. convert to json and back and compare hash to hash, not json to json
|
16
|
+
unjsonify(event_arguments).should == json_and_back(arguments)
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
20
|
+
def json_and_back array
|
21
|
+
unjsonify array.collect { |arg| arg.to_json }
|
22
|
+
end
|
23
|
+
|
24
|
+
def unjsonify array
|
25
|
+
array.collect { |arg| JSON.parse(arg) rescue arg }
|
26
|
+
end
|
27
|
+
|
18
28
|
# Fakeweb
|
19
29
|
FakeWeb.allow_net_connect = false
|
20
30
|
FakeWeb.register_uri(:any, /http:\/\/api\.mixpanel\.com.*/, :body => "1")
|
data/spec/support/rack_apps.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
def setup_rack_application(application, options = {}, mixpanel_options = {})
|
2
|
-
stub!(:app).and_return(Mixpanel::
|
2
|
+
stub!(:app).and_return(Mixpanel::Middleware.new(application.new(options), MIX_PANEL_TOKEN, mixpanel_options))
|
3
3
|
end
|
4
4
|
|
5
5
|
def html_document
|