eventsource_test.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. var EventSource = require('../lib/eventsource')
  2. , http = require('http')
  3. , https = require('https')
  4. , fs = require('fs')
  5. , assert = require('assert')
  6. , u = require('url');
  7. var _port = 20000;
  8. var servers = 0;
  9. process.on('exit', function () {
  10. if (servers != 0) {
  11. console.error("************ Didn't kill all servers - there is still %d running.", servers);
  12. }
  13. });
  14. function createServer(callback) {
  15. var server = http.createServer();
  16. configureServer(server, 'http', _port++, callback);
  17. }
  18. function createHttpsServer(callback) {
  19. var options = {
  20. key: fs.readFileSync(__dirname + '/key.pem'),
  21. cert: fs.readFileSync(__dirname + '/certificate.pem')
  22. };
  23. var server = https.createServer(options);
  24. configureServer(server, 'https', _port++, callback);
  25. }
  26. function configureServer(server, protocol, port, callback) {
  27. var responses = [];
  28. var oldClose = server.close;
  29. server.close = function() {
  30. responses.forEach(function (res) {
  31. res.end();
  32. });
  33. servers--;
  34. oldClose.apply(this, arguments);
  35. };
  36. server.on('request', function (req, res) {
  37. responses.push(res);
  38. });
  39. server.url = protocol + '://localhost:' + port;
  40. server.listen(port, function onOpen(err) {
  41. servers++;
  42. callback(err, server);
  43. });
  44. }
  45. function writeEvents(chunks) {
  46. return function (req, res) {
  47. res.writeHead(200, {'Content-Type': 'text/event-stream'});
  48. chunks.forEach(function (chunk) {
  49. res.write(chunk);
  50. });
  51. res.write(':'); // send a dummy comment to ensure that the head is flushed
  52. };
  53. }
  54. describe('Parser', function () {
  55. it('parses multibyte characters', function (done) {
  56. createServer(function (err, server) {
  57. if (err) return done(err);
  58. server.on('request', writeEvents(["id: 1\ndata: €豆腐\n\n"]));
  59. var es = new EventSource(server.url);
  60. es.onmessage = function (m) {
  61. assert.equal("€豆腐", m.data);
  62. server.close(done);
  63. };
  64. });
  65. });
  66. it('parses empty lines with multibyte characters', function (done) {
  67. createServer(function (err, server) {
  68. if (err) return done(err);
  69. server.on('request', writeEvents(["\n\n\n\nid: 1\ndata: 我現在都看實況不玩遊戲\n\n"]));
  70. var es = new EventSource(server.url);
  71. es.onmessage = function (m) {
  72. assert.equal("我現在都看實況不玩遊戲", m.data);
  73. server.close(done);
  74. };
  75. });
  76. });
  77. it('parses one one-line message in one chunk', function (done) {
  78. createServer(function (err, server) {
  79. if (err) return done(err);
  80. server.on('request', writeEvents(["data: Hello\n\n"]));
  81. var es = new EventSource(server.url);
  82. es.onmessage = function (m) {
  83. assert.equal("Hello", m.data);
  84. server.close(done);
  85. };
  86. });
  87. });
  88. it('parses one one-line message in two chunks', function (done) {
  89. createServer(function (err, server) {
  90. if (err) return done(err);
  91. server.on('request', writeEvents(["data: Hel", "lo\n\n"]));
  92. var es = new EventSource(server.url);
  93. es.onmessage = function (m) {
  94. assert.equal("Hello", m.data);
  95. server.close(done);
  96. };
  97. });
  98. });
  99. it('parses two one-line messages in one chunk', function (done) {
  100. createServer(function (err, server) {
  101. if (err) return done(err);
  102. server.on('request', writeEvents(["data: Hello\n\n", "data: World\n\n"]));
  103. var es = new EventSource(server.url);
  104. es.onmessage = first;
  105. function first(m) {
  106. assert.equal("Hello", m.data);
  107. es.onmessage = second;
  108. }
  109. function second(m) {
  110. assert.equal("World", m.data);
  111. server.close(done);
  112. }
  113. });
  114. });
  115. it('parses one two-line message in one chunk', function (done) {
  116. createServer(function (err, server) {
  117. if (err) return done(err);
  118. server.on('request', writeEvents(["data: Hello\ndata:World\n\n"]));
  119. var es = new EventSource(server.url);
  120. es.onmessage = function (m) {
  121. assert.equal("Hello\nWorld", m.data);
  122. server.close(done);
  123. };
  124. });
  125. });
  126. it('parses really chopped up unicode data', function (done) {
  127. createServer(function (err, server) {
  128. if (err) return done(err);
  129. var chopped = "data: Aslak\n\ndata: Hellesøy\n\n".split("");
  130. server.on('request', writeEvents(chopped));
  131. var es = new EventSource(server.url);
  132. es.onmessage = first;
  133. function first(m) {
  134. assert.equal("Aslak", m.data);
  135. es.onmessage = second;
  136. }
  137. function second(m) {
  138. assert.equal("Hellesøy", m.data);
  139. server.close(done);
  140. }
  141. });
  142. });
  143. it('accepts CRLF as separator', function (done) {
  144. createServer(function (err, server) {
  145. if (err) return done(err);
  146. var chopped = "data: Aslak\r\n\r\ndata: Hellesøy\r\n\r\n".split("");
  147. server.on('request', writeEvents(chopped));
  148. var es = new EventSource(server.url);
  149. es.onmessage = first;
  150. function first(m) {
  151. assert.equal("Aslak", m.data);
  152. es.onmessage = second;
  153. }
  154. function second(m) {
  155. assert.equal("Hellesøy", m.data);
  156. server.close(done);
  157. }
  158. });
  159. });
  160. it('accepts CR as separator', function (done) {
  161. createServer(function (err, server) {
  162. if (err) return done(err);
  163. var chopped = "data: Aslak\r\rdata: Hellesøy\r\r".split("");
  164. server.on('request', writeEvents(chopped));
  165. var es = new EventSource(server.url);
  166. es.onmessage = first;
  167. function first(m) {
  168. assert.equal("Aslak", m.data);
  169. es.onmessage = second;
  170. }
  171. function second(m) {
  172. assert.equal("Hellesøy", m.data);
  173. server.close(done);
  174. }
  175. });
  176. });
  177. it('delivers message with explicit event', function (done) {
  178. createServer(function (err, server) {
  179. if (err) return done(err);
  180. server.on('request', writeEvents(["event: greeting\ndata: Hello\n\n"]));
  181. var es = new EventSource(server.url);
  182. es.addEventListener('greeting', function (m) {
  183. assert.equal("Hello", m.data);
  184. server.close(done);
  185. });
  186. });
  187. });
  188. it('ignores comments', function (done) {
  189. createServer(function (err, server) {
  190. if (err) return done(err);
  191. server.on('request', writeEvents(["data: Hello\n\n:nothing to see here\n\ndata: World\n\n"]));
  192. var es = new EventSource(server.url);
  193. es.onmessage = first;
  194. function first(m) {
  195. assert.equal("Hello", m.data);
  196. es.onmessage = second;
  197. }
  198. function second(m) {
  199. assert.equal("World", m.data);
  200. server.close(done);
  201. }
  202. });
  203. });
  204. it('ignores empty comments', function (done) {
  205. createServer(function (err, server) {
  206. if (err) return done(err);
  207. server.on('request', writeEvents(["data: Hello\n\n:\n\ndata: World\n\n"]));
  208. var es = new EventSource(server.url);
  209. es.onmessage = first;
  210. function first(m) {
  211. assert.equal("Hello", m.data);
  212. es.onmessage = second;
  213. }
  214. function second(m) {
  215. assert.equal("World", m.data);
  216. server.close(done);
  217. }
  218. });
  219. });
  220. it('does not ignore multilines strings', function (done) {
  221. createServer(function (err, server) {
  222. if (err) return done(err);
  223. server.on('request', writeEvents(["data: line one\ndata:\ndata: line two\n\n"]));
  224. var es = new EventSource(server.url);
  225. es.onmessage = function (m) {
  226. assert.equal('line one\n\nline two', m.data);
  227. server.close(done);
  228. };
  229. });
  230. });
  231. it('does not ignore multilines strings even in data beginning', function (done) {
  232. createServer(function (err, server) {
  233. if (err) return done(err);
  234. server.on('request', writeEvents(["data:\ndata:line one\ndata: line two\n\n"]));
  235. var es = new EventSource(server.url);
  236. es.onmessage = function (m) {
  237. assert.equal('\nline one\nline two', m.data);
  238. server.close(done);
  239. };
  240. });
  241. });
  242. it('causes entire event to be ignored for empty event field', function (done) {
  243. createServer(function (err, server) {
  244. if (err) return done(err);
  245. server.on('request', writeEvents(["event:\n\ndata: Hello\n\n"]));
  246. var es = new EventSource(server.url);
  247. var originalEmit = es.emit;
  248. es.emit = function (event) {
  249. assert.ok(event === 'message' || event === 'newListener');
  250. return originalEmit.apply(this, arguments);
  251. };
  252. es.onmessage = function (m) {
  253. assert.equal('Hello', m.data);
  254. server.close(done);
  255. };
  256. });
  257. });
  258. it('parses relatively huge messages efficiently', function (done) {
  259. this.timeout(1000);
  260. createServer(function (err, server) {
  261. if (err) return done(err);
  262. var longMessage = "data: " + new Array(100000).join('a') + "\n\n";
  263. server.on('request', writeEvents([longMessage]));
  264. var es = new EventSource(server.url);
  265. es.onmessage = function () {
  266. server.close(done);
  267. };
  268. });
  269. });
  270. });
  271. describe('HTTP Request', function () {
  272. it('passes cache-control: no-cache to server', function (done) {
  273. createServer(function (err, server) {
  274. if (err) return done(err);
  275. server.on('request', function (req) {
  276. assert.equal('no-cache', req.headers['cache-control']);
  277. server.close(done);
  278. });
  279. new EventSource(server.url);
  280. });
  281. });
  282. it('sets request headers', function (done) {
  283. var server = createServer(function (err, server) {
  284. if (err) return done(err);
  285. server.on('request', function (req) {
  286. assert.equal(req.headers['user-agent'], 'test');
  287. assert.equal(req.headers['cookie'], 'test=test');
  288. assert.equal(req.headers['last-event-id'], '99');
  289. server.close(done);
  290. });
  291. var headers = {
  292. 'User-Agent': 'test',
  293. 'Cookie': 'test=test',
  294. 'Last-Event-ID': '99'
  295. };
  296. new EventSource(server.url, {headers: headers});
  297. });
  298. });
  299. it("does not set request headers that don't have a value", function (done) {
  300. var server = createServer(function (err, server) {
  301. if (err) return done(err);
  302. server.on('request', function (req) {
  303. assert.equal(req.headers['user-agent'], 'test');
  304. assert.equal(req.headers['cookie'], 'test=test');
  305. assert.equal(req.headers['last-event-id'], '99');
  306. assert.equal(req.headers['X-Something'], undefined);
  307. server.close(done);
  308. });
  309. var headers = {
  310. 'User-Agent': 'test',
  311. 'Cookie': 'test=test',
  312. 'Last-Event-ID': '99',
  313. 'X-Something': null
  314. };
  315. assert.doesNotThrow(
  316. function() {
  317. new EventSource(server.url, {headers: headers});
  318. }
  319. );
  320. });
  321. });
  322. [301, 307].forEach(function (status) {
  323. it('follows http ' + status + ' redirect', function (done) {
  324. var redirectSuffix = '/foobar';
  325. var clientRequestedRedirectUrl = false;
  326. createServer(function (err, server) {
  327. if(err) return done(err);
  328. server.on('request', function (req, res) {
  329. if (req.url === '/') {
  330. res.writeHead(status, {
  331. 'Connection': 'Close',
  332. 'Location': server.url + redirectSuffix
  333. });
  334. res.end();
  335. } else if (req.url === redirectSuffix) {
  336. clientRequestedRedirectUrl = true;
  337. res.writeHead(200, {'Content-Type': 'text/event-stream'});
  338. res.end();
  339. }
  340. });
  341. var es = new EventSource(server.url);
  342. es.onopen = function () {
  343. assert.ok(clientRequestedRedirectUrl);
  344. assert.equal(server.url + redirectSuffix, es.url);
  345. server.close(done);
  346. };
  347. });
  348. });
  349. it('causes error event when response is ' + status + ' with missing location', function (done) {
  350. var redirectSuffix = '/foobar';
  351. var clientRequestedRedirectUrl = false;
  352. createServer(function (err, server) {
  353. if(err) return done(err);
  354. server.on('request', function (req, res) {
  355. res.writeHead(status, {
  356. 'Connection': 'Close'
  357. });
  358. res.end();
  359. });
  360. var es = new EventSource(server.url);
  361. es.onerror = function (err) {
  362. assert.equal(err.status, status);
  363. server.close(done);
  364. };
  365. });
  366. });
  367. });
  368. [401, 403].forEach(function (status) {
  369. it('causes error event when response status is ' + status, function (done) {
  370. createServer(function (err, server) {
  371. if(err) return done(err);
  372. server.on('request', function (req, res) {
  373. res.writeHead(status, {'Content-Type': 'text/html'});
  374. res.end();
  375. });
  376. var es = new EventSource(server.url);
  377. es.onerror = function (err) {
  378. assert.equal(err.status, status);
  379. server.close(done);
  380. };
  381. });
  382. });
  383. });
  384. });
  385. describe('HTTPS Support', function () {
  386. it('uses https for https urls', function (done) {
  387. createHttpsServer(function (err, server) {
  388. if(err) return done(err);
  389. server.on('request', writeEvents(["data: hello\n\n"]));
  390. var es = new EventSource(server.url, {rejectUnauthorized: false});
  391. es.onmessage = function (m) {
  392. assert.equal("hello", m.data);
  393. server.close(done);
  394. }
  395. });
  396. });
  397. });
  398. describe('Reconnection', function () {
  399. it('is attempted when server is down', function (done) {
  400. var es = new EventSource('http://localhost:' + _port);
  401. es.reconnectInterval = 0;
  402. es.onerror = function () {
  403. es.onerror = null;
  404. createServer(function (err, server) {
  405. if(err) return done(err);
  406. server.on('request', writeEvents(["data: hello\n\n"]));
  407. es.onmessage = function (m) {
  408. assert.equal("hello", m.data);
  409. server.close(done);
  410. }
  411. });
  412. };
  413. });
  414. it('is attempted when server goes down after connection', function (done) {
  415. createServer(function (err, server) {
  416. if(err) return done(err);
  417. server.on('request', writeEvents(["data: hello\n\n"]));
  418. var es = new EventSource(server.url);
  419. es.reconnectInterval = 0;
  420. es.onmessage = function (m) {
  421. assert.equal("hello", m.data);
  422. server.close(function (err) {
  423. if(err) return done(err);
  424. var port = u.parse(es.url).port;
  425. configureServer(http.createServer(), 'http', port, function (err, server2) {
  426. if(err) return done(err);
  427. server2.on('request', writeEvents(["data: world\n\n"]));
  428. es.onmessage = function (m) {
  429. assert.equal("world", m.data);
  430. server2.close(done);
  431. };
  432. });
  433. });
  434. };
  435. });
  436. });
  437. it('is stopped when server goes down and eventsource is being closed', function (done) {
  438. createServer(function (err, server) {
  439. if(err) return done(err);
  440. server.on('request', writeEvents(["data: hello\n\n"]));
  441. var es = new EventSource(server.url);
  442. es.reconnectInterval = 0;
  443. es.onmessage = function (m) {
  444. assert.equal("hello", m.data);
  445. server.close(function (err) {
  446. if(err) return done(err);
  447. // The server has closed down. es.onerror should now get called,
  448. // because es's remote connection was dropped.
  449. });
  450. };
  451. es.onerror = function () {
  452. // We received an error because the remote connection was closed.
  453. // We close es, so we do not want es to reconnect.
  454. es.close();
  455. var port = u.parse(es.url).port;
  456. configureServer(http.createServer(), 'http', port, function (err, server2) {
  457. if(err) return done(err);
  458. server2.on('request', writeEvents(["data: world\n\n"]));
  459. es.onmessage = function (m) {
  460. return done(new Error("Unexpected message: " + m.data));
  461. };
  462. setTimeout(function () {
  463. // We have not received any message within 100ms, we can
  464. // presume this works correctly.
  465. server2.close(done);
  466. }, 100);
  467. });
  468. };
  469. });
  470. });
  471. it('is not attempted when server responds with HTTP 204', function (done) {
  472. createServer(function (err, server) {
  473. if(err) return done(err);
  474. server.on('request', function (req, res) {
  475. res.writeHead(204);
  476. res.end();
  477. });
  478. var es = new EventSource(server.url);
  479. es.reconnectInterval = 0;
  480. es.onerror = function (e) {
  481. assert.equal(e.status, 204);
  482. server.close(function (err) {
  483. if(err) return done(err);
  484. var port = u.parse(es.url).port;
  485. configureServer(http.createServer(), 'http', port, function (err, server2) {
  486. if(err) return done(err);
  487. // this will be verified by the readyState
  488. // going from CONNECTING to CLOSED,
  489. // along with the tests verifying that the
  490. // state is CONNECTING when a server closes.
  491. // it's next to impossible to write a fail-safe
  492. // test for this, though.
  493. var ival = setInterval(function () {
  494. if (es.readyState == EventSource.CLOSED) {
  495. clearInterval(ival);
  496. server2.close(done);
  497. }
  498. }, 5);
  499. });
  500. });
  501. };
  502. });
  503. });
  504. it('sends Last-Event-ID http header when it has previously been passed in an event from the server', function (done) {
  505. createServer(function (err, server) {
  506. if(err) return done(err);
  507. server.on('request', writeEvents(['id: 10\ndata: Hello\n\n']));
  508. var es = new EventSource(server.url);
  509. es.reconnectInterval = 0;
  510. es.onmessage = function () {
  511. server.close(function (err) {
  512. if(err) return done(err);
  513. var port = u.parse(es.url).port;
  514. configureServer(http.createServer(), 'http', port, function (err, server2) {
  515. server2.on('request', function (req, res) {
  516. assert.equal('10', req.headers['last-event-id']);
  517. server2.close(done);
  518. });
  519. });
  520. });
  521. };
  522. });
  523. });
  524. it('sends correct Last-Event-ID http header when an initial Last-Event-ID header was specified in the constructor', function (done) {
  525. createServer(function (err, server) {
  526. if(err) return done(err);
  527. server.on('request', function (req, res) {
  528. assert.equal('9', req.headers['last-event-id']);
  529. server.close(done);
  530. });
  531. new EventSource(server.url, {headers: {'Last-Event-ID': '9'}});
  532. });
  533. });
  534. it('does not send Last-Event-ID http header when it has not been previously sent by the server', function (done) {
  535. createServer(function (err, server) {
  536. if(err) return done(err);
  537. server.on('request', writeEvents(['data: Hello\n\n']));
  538. var es = new EventSource(server.url);
  539. es.reconnectInterval = 0;
  540. es.onmessage = function () {
  541. server.close(function (err) {
  542. if(err) return done(err);
  543. var port = u.parse(es.url).port;
  544. configureServer(http.createServer(), 'http', port, function (err, server2) {
  545. server2.on('request', function (req, res) {
  546. assert.equal(undefined, req.headers['last-event-id']);
  547. server2.close(done);
  548. });
  549. });
  550. });
  551. };
  552. });
  553. });
  554. });
  555. describe('readyState', function () {
  556. it('has CONNECTING constant', function () {
  557. assert.equal(0, EventSource.CONNECTING);
  558. });
  559. it('has OPEN constant', function () {
  560. assert.equal(1, EventSource.OPEN);
  561. });
  562. it('has CLOSED constant', function () {
  563. assert.equal(2, EventSource.CLOSED);
  564. });
  565. it('is CONNECTING before connection has been established', function (done) {
  566. var es = new EventSource('http://localhost:' + _port);
  567. assert.equal(EventSource.CONNECTING, es.readyState);
  568. es.onerror = function () {
  569. es.close();
  570. done();
  571. }
  572. });
  573. it('is CONNECTING when server has closed the connection', function (done) {
  574. createServer(function (err, server) {
  575. if(err) return done(err);
  576. server.on('request', writeEvents([]));
  577. var es = new EventSource(server.url);
  578. es.reconnectInterval = 0;
  579. es.onopen = function (m) {
  580. server.close(function (err) {
  581. if(err) return done(err);
  582. es.onerror = function () {
  583. es.onerror = null;
  584. assert.equal(EventSource.CONNECTING, es.readyState);
  585. done();
  586. };
  587. });
  588. };
  589. });
  590. });
  591. it('is OPEN when connection has been established', function (done) {
  592. createServer(function (err, server) {
  593. if(err) return done(err);
  594. server.on('request', writeEvents([]));
  595. var es = new EventSource(server.url);
  596. es.onopen = function () {
  597. assert.equal(EventSource.OPEN, es.readyState);
  598. server.close(done);
  599. }
  600. });
  601. });
  602. it('is CLOSED after connection has been closed', function (done) {
  603. createServer(function (err, server) {
  604. if(err) return done(err);
  605. server.on('request', writeEvents([]));
  606. var es = new EventSource(server.url);
  607. es.onopen = function () {
  608. es.close();
  609. assert.equal(EventSource.CLOSED, es.readyState);
  610. server.close(done);
  611. }
  612. });
  613. });
  614. });
  615. describe('Properties', function () {
  616. it('url exposes original request url', function () {
  617. var url = 'http://localhost:' + _port;
  618. var es = new EventSource(url);
  619. assert.equal(url, es.url);
  620. });
  621. });
  622. describe('Events', function () {
  623. it('calls onopen when connection is established', function (done) {
  624. createServer(function (err, server) {
  625. if(err) return done(err);
  626. server.on('request', writeEvents([]));
  627. var es = new EventSource(server.url);
  628. es.onopen = function (event) {
  629. assert.equal(event.type, 'open');
  630. server.close(done);
  631. }
  632. });
  633. });
  634. it('supplies the correct origin', function (done) {
  635. createServer(function (err, server) {
  636. if(err) return done(err);
  637. server.on('request', writeEvents(["data: hello\n\n"]));
  638. var es = new EventSource(server.url);
  639. es.onmessage = function (event) {
  640. assert.equal(event.origin, server.url);
  641. server.close(done);
  642. }
  643. });
  644. });
  645. it('emits open event when connection is established', function (done) {
  646. createServer(function (err, server) {
  647. if(err) return done(err);
  648. server.on('request', writeEvents([]));
  649. var es = new EventSource(server.url);
  650. es.addEventListener('open', function (event) {
  651. assert.equal(event.type, 'open');
  652. server.close(done);
  653. });
  654. });
  655. });
  656. it('does not emit error when connection is closed by client', function (done) {
  657. createServer(function (err, server) {
  658. if(err) return done(err);
  659. server.on('request', writeEvents([]));
  660. var es = new EventSource(server.url);
  661. es.addEventListener('open', function () {
  662. es.close();
  663. process.nextTick(function () {
  664. server.close(done);
  665. });
  666. });
  667. es.addEventListener('error', function () {
  668. done(new Error('error should not be emitted'));
  669. });
  670. });
  671. });
  672. it('populates message\'s lastEventId correctly when the last event has an associated id', function (done) {
  673. createServer(function (err, server) {
  674. if(err) return done(err);
  675. server.on('request', writeEvents(["id: 123\ndata: hello\n\n"]));
  676. var es = new EventSource(server.url);
  677. es.onmessage = function (m) {
  678. assert.equal(m.lastEventId, "123");
  679. server.close(done);
  680. };
  681. });
  682. });
  683. it('populates message\'s lastEventId correctly when the last event doesn\'t have an associated id', function (done) {
  684. createServer(function (err, server) {
  685. if(err) return done(err);
  686. server.on('request', writeEvents(["id: 123\ndata: Hello\n\n", "data: World\n\n"]));
  687. var es = new EventSource(server.url);
  688. es.onmessage = first;
  689. function first() {
  690. es.onmessage = second;
  691. }
  692. function second(m) {
  693. assert.equal(m.data, "World");
  694. assert.equal(m.lastEventId, "123"); //expect to get back the previous event id
  695. server.close(done);
  696. }
  697. });
  698. });
  699. it('populates messages with enumerable properties so they can be inspected via console.log().', function (done) {
  700. createServer(function (err, server) {
  701. if(err) return done(err);
  702. server.on('request', writeEvents(["data: World\n\n"]));
  703. var es = new EventSource(server.url);
  704. es.onmessage = function (m) {
  705. var enumerableAttributes = Object.keys(m);
  706. assert.notEqual(enumerableAttributes.indexOf("data"), -1);
  707. assert.notEqual(enumerableAttributes.indexOf("type"), -1);
  708. server.close(done);
  709. };
  710. });
  711. });
  712. });