UNPKG

12.1 kBJavaScriptView Raw
1let Mixpanel;
2const Sinon = require('sinon');
3const proxyquire = require('proxyquire');
4const https = require('https');
5const events = require('events');
6const httpProxyOrig = process.env.HTTP_PROXY;
7const httpsProxyOrig = process.env.HTTPS_PROXY;
8let HttpsProxyAgent;
9
10exports.send_request = {
11 setUp: function(next) {
12 HttpsProxyAgent = Sinon.stub();
13 Mixpanel = proxyquire('../lib/mixpanel-node', {
14 'https-proxy-agent': HttpsProxyAgent,
15 });
16
17 Sinon.stub(https, 'request');
18
19 this.http_emitter = new events.EventEmitter;
20 this.http_end_spy = Sinon.spy();
21 this.http_write_spy = Sinon.spy();
22 this.http_emitter.write = this.http_write_spy;
23 this.http_emitter.end = this.http_end_spy;
24 this.res = new events.EventEmitter;
25 https.request.returns(this.http_emitter);
26 https.request.callsArgWith(1, this.res);
27
28 this.mixpanel = Mixpanel.init('token');
29
30 next();
31 },
32
33 tearDown: function(next) {
34 https.request.restore();
35
36 // restore proxy variables
37 process.env.HTTP_PROXY = httpProxyOrig;
38 process.env.HTTPS_PROXY = httpsProxyOrig;
39
40 next();
41 },
42
43 "sends correct data on GET": function(test) {
44 var endpoint = "/track",
45 data = {
46 event: 'test',
47 properties: {
48 key1: 'val1',
49 token: 'token',
50 time: 1346876621
51 }
52 },
53 expected_http_request = {
54 method: 'GET',
55 host: 'api.mixpanel.com',
56 headers: {},
57 path: '/track?ip=0&verbose=0&data=eyJldmVudCI6InRlc3QiLCJwcm9wZXJ0aWVzIjp7ImtleTEiOiJ2YWwxIiwidG9rZW4iOiJ0b2tlbiIsInRpbWUiOjEzNDY4NzY2MjF9fQ%3D%3D'
58 };
59
60 this.mixpanel.send_request({ method: 'get', endpoint: endpoint, data: data });
61
62 test.expect(3);
63 test.ok(https.request.calledWithMatch(expected_http_request), "send_request didn't call https.request with correct arguments");
64 test.ok(this.http_end_spy.callCount === 1, "send_request didn't end https.request");
65 test.ok(this.http_write_spy.callCount === 0, "send_request called write for a GET");
66
67 test.done();
68 },
69
70 "defaults to GET": function(test) {
71 var endpoint = "/track",
72 data = {
73 event: 'test',
74 properties: {
75 key1: 'val1',
76 token: 'token',
77 time: 1346876621
78 }
79 },
80 expected_http_request = {
81 method: 'GET',
82 host: 'api.mixpanel.com',
83 headers: {},
84 path: '/track?ip=0&verbose=0&data=eyJldmVudCI6InRlc3QiLCJwcm9wZXJ0aWVzIjp7ImtleTEiOiJ2YWwxIiwidG9rZW4iOiJ0b2tlbiIsInRpbWUiOjEzNDY4NzY2MjF9fQ%3D%3D'
85 };
86
87 this.mixpanel.send_request({ endpoint: endpoint, data: data }); // method option not defined
88
89 test.ok(https.request.calledWithMatch(expected_http_request), "send_request didn't call https.request with correct method argument");
90
91 test.done();
92 },
93
94 "sends correct data on POST": function(test) {
95 var endpoint = "/track",
96 data = {
97 event: 'test',
98 properties: {
99 key1: 'val1',
100 token: 'token',
101 time: 1346876621
102 }
103 },
104 expected_http_request = {
105 method: 'POST',
106 host: 'api.mixpanel.com',
107 headers: {},
108 path: '/track?ip=0&verbose=0'
109 },
110 expected_http_request_body = "data=eyJldmVudCI6InRlc3QiLCJwcm9wZXJ0aWVzIjp7ImtleTEiOiJ2YWwxIiwidG9rZW4iOiJ0b2tlbiIsInRpbWUiOjEzNDY4NzY2MjF9fQ==";
111
112 this.mixpanel.send_request({ method: 'post', endpoint: endpoint, data: data });
113
114 test.expect(3);
115 test.ok(https.request.calledWithMatch(expected_http_request), "send_request didn't call https.request with correct arguments");
116 test.ok(this.http_end_spy.callCount === 1, "send_request didn't end https.request");
117 test.ok(this.http_write_spy.calledWithExactly(expected_http_request_body), "send_request did not write data correctly for a POST");
118
119 test.done();
120 },
121
122 "sets ip=1 when geolocate option is on": function(test) {
123 this.mixpanel.set_config({ geolocate: true });
124
125 this.mixpanel.send_request({ method: "get", endpoint: "/track", event: "test", data: {} });
126
127 test.ok(https.request.calledWithMatch({ path: Sinon.match('ip=1') }), "send_request didn't call http.get with correct request data");
128
129 test.done();
130 },
131
132 "handles mixpanel errors": function(test) {
133 test.expect(1);
134 this.mixpanel.send_request({ endpoint: "/track", data: { event: "test" } }, function(e) {
135 test.equal(e.message, 'Mixpanel Server Error: 0', "error did not get passed back to callback");
136 test.done();
137 });
138
139 this.res.emit('data', '0');
140 this.res.emit('end');
141 },
142
143 "handles https.request errors": function(test) {
144 test.expect(1);
145 this.mixpanel.send_request({ endpoint: "/track", data: { event: "test" } }, function(e) {
146 test.equal(e, 'error', "error did not get passed back to callback");
147 test.done();
148 });
149
150 this.http_emitter.emit('error', 'error');
151 },
152
153 "default use keepAlive agent": function(test) {
154 test.expect(2);
155 var agent = new https.Agent({ keepAlive: false });
156 var httpsStub = {
157 request: Sinon.stub().returns(this.http_emitter).callsArgWith(1, this.res),
158 Agent: Sinon.stub().returns(agent),
159 };
160 // force SDK not use `undefined` string to initialize proxy-agent
161 delete process.env.HTTP_PROXY
162 delete process.env.HTTPS_PROXY
163 Mixpanel = proxyquire('../lib/mixpanel-node', {
164 'https': httpsStub
165 });
166 var proxyMixpanel = Mixpanel.init('token');
167 proxyMixpanel.send_request({ endpoint: '', data: {} });
168
169 var getConfig = httpsStub.request.firstCall.args[0];
170 var agentOpts = httpsStub.Agent.firstCall.args[0];
171 test.ok(agentOpts.keepAlive === true, "HTTP Agent wasn't initialized with keepAlive by default");
172 test.ok(getConfig.agent === agent, "send_request didn't call https.request with agent");
173
174 test.done();
175 },
176
177 "uses correct hostname": function(test) {
178 var host = 'testhost.fakedomain';
179 var customHostnameMixpanel = Mixpanel.init('token', { host: host });
180 var expected_http_request = {
181 host: host
182 };
183
184 customHostnameMixpanel.send_request({ endpoint: "", data: {} });
185
186 test.ok(https.request.calledWithMatch(expected_http_request), "send_request didn't call https.request with correct hostname");
187
188 test.done();
189 },
190
191 "uses correct port": function(test) {
192 var host = 'testhost.fakedomain:1337';
193 var customHostnameMixpanel = Mixpanel.init('token', { host: host });
194 var expected_http_request = {
195 host: 'testhost.fakedomain',
196 port: 1337
197 };
198
199 customHostnameMixpanel.send_request({ endpoint: "", data: {} });
200
201 test.ok(https.request.calledWithMatch(expected_http_request), "send_request didn't call https.request with correct hostname and port");
202
203 test.done();
204 },
205
206 "uses correct path": function(test) {
207 var host = 'testhost.fakedomain';
208 var customPath = '/mypath';
209 var customHostnameMixpanel = Mixpanel.init('token', {
210 host,
211 path: customPath,
212 });
213 var expected_http_request = {
214 host,
215 path: '/mypath?ip=0&verbose=0&data=e30%3D',
216 };
217
218 customHostnameMixpanel.send_request({endpoint: "", data: {}});
219 test.ok(https.request.calledWithMatch(expected_http_request), "send_request didn't call https.request with correct hostname and port");
220
221 test.done();
222 },
223
224 "combines custom path and endpoint": function(test) {
225 var host = 'testhost.fakedomain';
226 var customPath = '/mypath';
227 var customHostnameMixpanel = Mixpanel.init('token', {
228 host,
229 path: customPath,
230 });
231 var expected_http_request = {
232 host,
233 path: '/mypath/track?ip=0&verbose=0&data=e30%3D',
234 };
235
236 customHostnameMixpanel.send_request({endpoint: '/track', data: {}});
237 test.ok(https.request.calledWithMatch(expected_http_request), "send_request didn't call https.request with correct hostname and port");
238
239 test.done();
240 },
241
242 "uses HTTP_PROXY if set": function(test) {
243 HttpsProxyAgent.reset(); // Mixpanel is instantiated in setup, need to reset callcount
244 delete process.env.HTTPS_PROXY;
245 process.env.HTTP_PROXY = 'this.aint.real.https';
246
247 var proxyMixpanel = Mixpanel.init('token');
248 proxyMixpanel.send_request({ endpoint: '', data: {} });
249
250 test.ok(HttpsProxyAgent.calledOnce, "HttpsProxyAgent was not called when process.env.HTTP_PROXY was set");
251
252 var agentOpts = HttpsProxyAgent.firstCall.args[0];
253 test.ok(agentOpts.pathname === "this.aint.real.https", "HttpsProxyAgent was not called with the correct proxy path");
254 test.ok(agentOpts.keepAlive === true, "HttpsProxyAgent was not called with the correct proxy path");
255
256 var getConfig = https.request.firstCall.args[0];
257 test.ok(getConfig.agent !== undefined, "send_request didn't call https.request with agent");
258
259 test.done();
260 },
261
262 "uses HTTPS_PROXY if set": function(test) {
263 HttpsProxyAgent.reset(); // Mixpanel is instantiated in setup, need to reset callcount
264 delete process.env.HTTP_PROXY;
265 process.env.HTTPS_PROXY = 'this.aint.real.https';
266
267 var proxyMixpanel = Mixpanel.init('token');
268 proxyMixpanel.send_request({ endpoint: '', data: {} });
269
270 test.ok(HttpsProxyAgent.calledOnce, "HttpsProxyAgent was not called when process.env.HTTPS_PROXY was set");
271
272 var proxyOpts = HttpsProxyAgent.firstCall.args[0];
273 test.ok(proxyOpts.pathname === 'this.aint.real.https', "HttpsProxyAgent was not called with the correct proxy path");
274
275 var getConfig = https.request.firstCall.args[0];
276 test.ok(getConfig.agent !== undefined, "send_request didn't call https.request with agent");
277
278 test.done();
279 },
280
281 "requires credentials for import requests": function(test) {
282 test.throws(
283 this.mixpanel.send_request.bind(this, {
284 endpoint: `/import`,
285 data: {event: `test event`},
286 }),
287 /The Mixpanel Client needs a Mixpanel API Secret when importing old events/,
288 "import request didn't throw error when no credentials provided"
289 );
290 test.done();
291 },
292
293 "sets basic auth header if API secret is provided": function(test) {
294 this.mixpanel.set_config({secret: `foobar`});
295 this.mixpanel.send_request({
296 endpoint: `/import`,
297 data: {event: `test event`},
298 });
299 test.ok(https.request.calledOnce);
300 test.deepEqual(https.request.args[0][0].headers, {
301 'Authorization': `Basic Zm9vYmFyOg==`, // base64 of "foobar:"
302 }, "send_request didn't pass correct auth header to https.request");
303 test.done();
304 },
305
306 "still supports import with api_key (legacy)": function(test) {
307 this.mixpanel.set_config({key: `barbaz`});
308 this.mixpanel.send_request({
309 endpoint: `/import`,
310 data: {},
311 });
312 test.ok(https.request.calledOnce);
313 test.equal(
314 https.request.args[0][0].path,
315 `/import?ip=0&verbose=0&data=e30%3D&api_key=barbaz`,
316 "send_request didn't pass correct query params to https.request"
317 );
318 test.done();
319 },
320};