send.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. var request = require("request");
  2. var qs = require("querystring");
  3. var uuid = require("uuid");
  4. var should = require("should");
  5. var sinon = require("sinon");
  6. var url = require("url");
  7. var ua = require("../lib/index.js");
  8. var utils = require("../lib/utils.js")
  9. var config = require("../lib/config.js")
  10. describe("ua", function () {
  11. describe("#send", function () {
  12. var post;
  13. beforeEach(function () {
  14. post = sinon.stub(request, "post").callsArg(2);
  15. });
  16. afterEach(function () {
  17. post.restore()
  18. });
  19. it("should immidiately return with an empty queue", function () {
  20. var visitor = ua();
  21. var fn = sinon.spy();
  22. visitor.send(fn);
  23. post.called.should.equal(false, "no request should have been sent")
  24. fn.calledOnce.should.equal(true, "callback should have been called once")
  25. fn.thisValues[0].should.equal(visitor, "callback should be called in the context of the visitor instance");
  26. fn.args[0].should.eql([null, 0], "no error, no requests");
  27. });
  28. it("should include data in POST body", function (done) {
  29. var paramSets = [
  30. {first: "123"}
  31. ]
  32. var fn = sinon.spy(function () {
  33. fn.calledOnce.should.equal(true, "callback should have been called once")
  34. fn.thisValues[0].should.equal(visitor, "callback should be called in the context of the visitor instance");
  35. fn.args[0].should.eql([null, 1], "no error, 1 requests");
  36. post.callCount.should.equal(paramSets.length, "each param set should have been POSTed");
  37. for (var i = 0; i < paramSets.length; i++) {
  38. var params = paramSets[i];
  39. var args = post.args[i];
  40. var parsedUrl = url.parse(args[0]);
  41. Math.random(); // I have absolutely no idea why it fails unless there was some processing to be done after url.parse…
  42. (parsedUrl.protocol + "//" + parsedUrl.host).should.equal(config.hostname);
  43. args[1].body.should.equal(qs.stringify(params));
  44. }
  45. done();
  46. });
  47. var visitor = ua();
  48. visitor._queue.push.apply(visitor._queue, paramSets);
  49. visitor.send(fn);
  50. });
  51. it("should send individual requests when batchting is false", function(done) {
  52. var paramSets = [
  53. {first: Math.random()},
  54. {second: Math.random()},
  55. {third: Math.random()}
  56. ]
  57. var fn = sinon.spy(function () {
  58. fn.calledOnce.should.equal(true, "callback should have been called once")
  59. fn.thisValues[0].should.equal(visitor, "callback should be called in the context of the visitor instance");
  60. fn.args[0].should.eql([null, 3], "no error, 3 requests");
  61. done();
  62. });
  63. var visitor = ua({enableBatching:false});
  64. visitor._queue.push.apply(visitor._queue, paramSets)
  65. visitor.send(fn);
  66. });
  67. describe("#batching is true", function() {
  68. it("should send request to collect path when only one payload", function(done) {
  69. var paramSets = [
  70. {first: Math.random()}
  71. ]
  72. var fn = sinon.spy(function () {
  73. fn.args[0].should.eql([null, 1], "no error, 1 requests");
  74. var args = post.args[0];
  75. var parsedUrl = url.parse(args[0]);
  76. parsedUrl.pathname.should.eql(config.path);
  77. done();
  78. });
  79. var visitor = ua({enableBatching:true});
  80. visitor._queue.push.apply(visitor._queue, paramSets)
  81. visitor.send(fn);
  82. });
  83. it("should send request to batch path when more than one payload sent", function(done) {
  84. var paramSets = [
  85. {first: Math.random()},
  86. {second: Math.random()},
  87. {third: Math.random()}
  88. ]
  89. var fn = sinon.spy(function () {
  90. fn.args[0].should.eql([null, 1], "no error, 1 requests");
  91. var args = post.args[0];
  92. var parsedUrl = url.parse(args[0]);
  93. parsedUrl.pathname.should.eql(config.batchPath);
  94. done();
  95. });
  96. var visitor = ua({enableBatching:true});
  97. visitor._queue.push.apply(visitor._queue, paramSets)
  98. visitor.send(fn);
  99. });
  100. it("should batch data in Post form", function(done) {
  101. var paramSets = [
  102. {first: Math.random()},
  103. {second: Math.random()},
  104. {third: Math.random()}
  105. ]
  106. var fn = sinon.spy(function () {
  107. fn.calledOnce.should.equal(true, "callback should have been called once")
  108. fn.thisValues[0].should.equal(visitor, "callback should be called in the context of the visitor instance");
  109. fn.args[0].should.eql([null, 1], "no error, 1 requests");
  110. var args = post.args[0];
  111. var params = paramSets;
  112. var formParams = args[1].body.split("\n");
  113. formParams.should.have.lengthOf(3);
  114. formParams[0].should.equal(qs.stringify(params[0]));
  115. done();
  116. });
  117. var visitor = ua({enableBatching:true});
  118. visitor._queue.push.apply(visitor._queue, paramSets)
  119. visitor.send(fn);
  120. })
  121. it("should batch data based on batchSize", function(done) {
  122. var paramSets = [
  123. {first: Math.random()},
  124. {second: Math.random()},
  125. {third: Math.random()}
  126. ]
  127. var fn = sinon.spy(function () {
  128. fn.calledOnce.should.equal(true, "callback should have been called once")
  129. fn.thisValues[0].should.equal(visitor, "callback should be called in the context of the visitor instance");
  130. fn.args[0].should.eql([null, 2], "no error, 2 requests");
  131. var body = post.args[0][1].body;
  132. body.split("\n").should.have.lengthOf(2);
  133. done();
  134. });
  135. var visitor = ua({enableBatching:true, batchSize: 2});
  136. visitor._queue.push.apply(visitor._queue, paramSets)
  137. visitor.send(fn);
  138. });
  139. });
  140. it("should add custom headers to request header", function (done) {
  141. var fn = sinon.spy(function () {
  142. fn.calledOnce.should.equal(true, "callback should have been called once");
  143. fn.thisValues[0].should.equal(visitor, "callback should be called in the context of the visitor instance");
  144. post.calledOnce.should.equal(true, "request should have been POSTed");
  145. var parsedUrl = url.parse(post.args[0][0]);
  146. var options = post.args[0][1];
  147. (parsedUrl.protocol + "//" + parsedUrl.host).should.equal(config.hostname);
  148. options.should.have.keys("headers","body")
  149. options.headers.should.have.key("User-Agent");
  150. options.headers["User-Agent"].should.equal("Test User Agent");
  151. done();
  152. });
  153. var visitor = ua({
  154. headers: {'User-Agent': 'Test User Agent'}
  155. });
  156. visitor._queue.push({});
  157. visitor.send(fn);
  158. });
  159. })
  160. });