mixpanel 2.2.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|