diff --git a/jquery.eventsource.js b/jquery.eventsource.js index 51281a9..848d51f 100644 --- a/jquery.eventsource.js +++ b/jquery.eventsource.js @@ -1,6 +1,6 @@ /*! * jQuery.EventSource (jQuery.eventsource) - * + * * Copyright (c) 2011 Rick Waldron * Dual licensed under the MIT and GPL licenses. */ @@ -12,7 +12,7 @@ }); var stream = { - + defaults: { // Stream identity label: null, @@ -23,9 +23,10 @@ message: jQuery.noop }, setup: { - stream: {}, + stream: {}, lastEventId: 0, isHostApi: false, + retry: 500, history: {}, options: {} }, @@ -35,26 +36,39 @@ pluginFns = { public: { - close: function ( label ) { + close: function( label ) { - var cache = {}; - - if ( label !== "*" ) { + var tmp = {}; + if ( !label || label === "*" ) { for ( var prop in stream.cache ) { - if ( label !== prop ) { - cache[ prop ] = stream.cache[ prop ]; + if ( stream.cache[ prop ].isHostApi ) { + stream.cache[ prop ].stream.close(); } } + + stream.cache = {}; + + return stream.cache; } - stream.cache = cache; + for ( var prop in stream.cache ) { + if ( label !== prop ) { + tmp[ prop ] = stream.cache[ prop ]; + } else { + if ( stream.cache[ prop ].isHostApi ) { + stream.cache[ prop ].stream.close(); + } + } + } + + stream.cache = tmp; return stream.cache; - }, - streams: function ( label ) { + }, + streams: function( label ) { - if ( label === "*" ) { + if ( !label || label === "*" ) { return stream.cache; } @@ -63,104 +77,116 @@ }, _private: { - // Open a host api event source - openEventSource: function ( options ) { + // Open a host api event source + openEventSource: function( options ) { var label = options.label; - stream.cache[ label ].stream.addEventListener("open", function (event) { - if ( stream.cache[label] ) { + stream.cache[ label ].stream.addEventListener("open", function(event) { + if ( stream.cache[ label ] ) { this.label = label; - stream.cache[label].options.open.call(this, event); + stream.cache[ label ].options.open.call(this, event); } }, false); - stream.cache[label].stream.addEventListener("message", function (event) { - + stream.cache[label].stream.addEventListener("message", function(event) { + var streamData = []; - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { streamData[ streamData.length ] = jQuery.parseJSON( event.data ); this.label = label; - stream.cache[label].lastEventId = +event.lastEventId; - stream.cache[label].history[stream.cache[label].lastEventId] = streamData; - stream.cache[label].options.message.call(this, streamData[0] ? streamData[0] : null, { + stream.cache[ label ].lastEventId = +event.lastEventId; + stream.cache[ label ].history[stream.cache[ label ].lastEventId] = streamData; + stream.cache[ label ].options.message.call(this, streamData[0] ? streamData[0] : null, { data: streamData, - lastEventId: stream.cache[label].lastEventId + lastEventId: stream.cache[ label ].lastEventId }, event); - // TODO: Add custom event triggering + // TODO: Add custom event triggering } }, false); - return stream.cache[label].stream; - }, + return stream.cache[ label ].stream; + }, // open fallback event source - openPollingSource: function ( options ) { - var label = options.label, + openPollingSource: function( options ) { + var label = options.label, source; - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { source = jQuery.ajax({ type: "GET", url: options.url, data: options.data, - beforeSend: function () { - if ( stream.cache[label] ) { + beforeSend: function() { + if ( stream.cache[ label ] ) { this.label = label; - stream.cache[label].options.open.call( this ); + stream.cache[ label ].options.open.call( this ); } }, - success: function ( data ) { + success: function( data ) { var tempdata, label = options.label, parsedData = [], - streamData = jQuery.map( data.split("\n"), function(sdata, i) { + streamData = jQuery.map( data.split("\n\n"), function(sdata, i) { return !!sdata && sdata; - }), - idx = 0, length = streamData.length; + }), + idx = 0, length = streamData.length, + rretryprefix = /retry/, + retries; - if ( jQuery.isArray(streamData) ) { + if ( jQuery.isArray( streamData ) ) { for ( ; idx < length; idx++ ) { - if ( streamData[idx] ) { - tempdata = streamData[idx].split("data: ")[ 1 ]; + if ( streamData[ idx ] ) { - // Convert `dataType` here - if ( options.dataType === "json" ) { - tempdata = jQuery.parseJSON( tempdata ); - } + if ( rretryprefix.test( streamData[ idx ] ) && + (retries = streamData[ idx ].split("retry: ")).length ) { + + if ( retries.length === 2 && !retries[ 0 ] ) { + + stream.cache[ label ].retry = stream.cache[ label ].options.retry = +retries[ 1 ]; + } + + } else { + tempdata = streamData[ idx ].split("data: ")[ 1 ]; + + // Convert `dataType` here + if ( options.dataType === "json" ) { + tempdata = jQuery.parseJSON( tempdata ); + } - parsedData[ parsedData.length ] = tempdata; + parsedData[ parsedData.length ] = tempdata; + } } } } - if ( stream.cache[label] ) { + if ( stream.cache[ label ] ) { this.label = label; - stream.cache[label].lastEventId++; - stream.cache[label].history[stream.cache[label].lastEventId] = parsedData; - stream.cache[label].options.message.call(this, parsedData[0] ? parsedData[0] : null, { + stream.cache[ label ].lastEventId++; + stream.cache[ label ].history[ stream.cache[ label ].lastEventId ] = parsedData; + stream.cache[ label ].options.message.call(this, parsedData[0] ? parsedData[0] : null, { data: parsedData, - lastEventId: stream.cache[label].lastEventId + lastEventId: stream.cache[ label ].lastEventId }); - setTimeout( - function () { + function() { pluginFns._private.openPollingSource.call( this, options ); }, - // matches speed of host api EventSource - 500 + // Use server sent retry time if exists or default retry time if not + ( stream.cache[ label ] && stream.cache[ label ].retry ) || 500 ); } }, @@ -181,7 +207,7 @@ // Plugin sub function if ( options && !jQuery.isPlainObject( options ) && pluginFns.public[ options ] ) { // If no label was passed, send message to all streams - return pluginFns.public[ options ]( + return pluginFns.public[ options ]( arguments[1] ? arguments[1] : "*" @@ -189,7 +215,7 @@ } // If params were passed in as an object, normalize to a query string - options.data = options.data && jQuery.isPlainObject( options.data ) ? + options.data = options.data && jQuery.isPlainObject( options.data ) ? jQuery.param( options.data ) : options.data; @@ -214,7 +240,7 @@ }; - // Determine and declare `event stream` source, + // Determine and declare `event stream` source, // whether will be host api or XHR fallback streamType = !isHostApi ? // If not host api, open a polling fallback @@ -236,5 +262,10 @@ return stream.cache; }; + jQuery.each( [ "close", "streams" ], function( idx, name ) { + jQuery.eventsource[ name ] = function( arg ) { + return jQuery.eventsource( name, arg || "*" ); + }; + }); })(jQuery, window); diff --git a/test-event-sources/event-source-2.php b/test-event-sources/event-source-2.php index 66e7121..0d71cb1 100644 --- a/test-event-sources/event-source-2.php +++ b/test-event-sources/event-source-2.php @@ -1,19 +1,19 @@ - array( - 'time' => time(), - 'message' => 'Some kind of foo' - ), - 1 => array( - 'time' => time(), - 'message' => 'Some kind of quux' - ) - ) - ) . "\n"; - -?> \ No newline at end of file + array( + 'time' => time(), + 'message' => 'Some kind of foo' + ), + 1 => array( + 'time' => time(), + 'message' => 'Some kind of quux' + ) + ) + ) . "\n"; + +?> diff --git a/test-event-sources/event-source-retry.php b/test-event-sources/event-source-retry.php new file mode 100644 index 0000000..5a44f36 --- /dev/null +++ b/test-event-sources/event-source-retry.php @@ -0,0 +1,20 @@ + array( + 'time' => time(), + 'message' => 'Some kind of foo' + ), + 1 => array( + 'time' => time(), + 'message' => 'Some kind of quux' + ) + ) + ) . "\n"; + + +?> diff --git a/test/index.html b/test/index.html index 41b7f08..b5ff890 100644 --- a/test/index.html +++ b/test/index.html @@ -3,12 +3,12 @@ jquery.eventsource.unit - - + + - - + + @@ -23,7 +23,7 @@

- + - + diff --git a/test/jquery.eventsource.specit.js b/test/jquery.eventsource.specit.js index d7d7377..eb2948c 100644 --- a/test/jquery.eventsource.specit.js +++ b/test/jquery.eventsource.specit.js @@ -12,11 +12,11 @@ describe("jQuery.EventSource", function() { var streams = {}, labelfor, stypeOf; before(function() { - labelfor = 'text-event-source'; + labelfor = "text-event-source"; stypeOf = window.EventSource ? EventSource : XMLHttpRequest; streams = $.eventsource({ label: labelfor, - url: '../test-event-sources/event-source-1.php' + url: "../test-event-sources/event-source-1.php" }); }); @@ -24,17 +24,17 @@ describe("jQuery.EventSource", function() { it("$.eventsource streams cache", function() { - assert($.eventsource('streams')).should(beAn, Object); - assert(sizeOf($.eventsource('streams'))).should(beLessThanOrEqualTo, 1); + assert($.eventsource("streams")).should(beAn, Object); + assert(sizeOf($.eventsource("streams"))).should(beLessThanOrEqualTo, 1); }); it("$.eventsource stream object", function() { - assert(streams[labelfor]).should(include, 'history'); - assert(streams[labelfor]).should(include, 'isHostApi'); - assert(streams[labelfor]).should(include, 'lastEventId'); - assert(streams[labelfor]).should(include, 'options'); - assert(streams[labelfor]).should(include, 'stream'); + assert(streams[labelfor]).should(include, "history"); + assert(streams[labelfor]).should(include, "isHostApi"); + assert(streams[labelfor]).should(include, "lastEventId"); + assert(streams[labelfor]).should(include, "options"); + assert(streams[labelfor]).should(include, "stream"); }); it("$.eventsource stream object should be", function() { @@ -49,10 +49,10 @@ describe("jQuery.EventSource", function() { it("$.eventsource stream options object", function() { - assert(streams[labelfor].options).should(include, 'url'); - assert(streams[labelfor].options).should(include, 'label'); - assert(streams[labelfor].options).should(include, 'message'); - assert(streams[labelfor].options).should(include, 'open'); + assert(streams[labelfor].options).should(include, "url"); + assert(streams[labelfor].options).should(include, "label"); + assert(streams[labelfor].options).should(include, "message"); + assert(streams[labelfor].options).should(include, "open"); }); it("$.eventsource stream options object should be", function() { @@ -66,10 +66,10 @@ describe("jQuery.EventSource", function() { it("$.eventsource stream closing", function() { - $.eventsource('close', labelfor); + $.eventsource("close", labelfor); - assert($.eventsource('streams')).should(beAn, Object); - assert(sizeOf($.eventsource('streams'))).should(beLessThanOrEqualTo, 0); + assert($.eventsource("streams")).should(beAn, Object); + assert(sizeOf($.eventsource("streams"))).should(beLessThanOrEqualTo, 0); }); @@ -78,4 +78,4 @@ describe("jQuery.EventSource", function() { streams = {}; }); -}); \ No newline at end of file +}); diff --git a/test/jquery.eventsource.unit.js b/test/jquery.eventsource.unit.js index edd581f..e39eb38 100644 --- a/test/jquery.eventsource.unit.js +++ b/test/jquery.eventsource.unit.js @@ -8,370 +8,424 @@ function sizeOf(obj) { } -test("$.eventsource is a function", function() { - ok( $.isFunction($.eventsource), "$.eventsource is a function" ); - - equals(sizeOf($.eventsource('streams')), 0, 'There are no streams'); +$(function() { + + var params = location.search.slice( 1 ).split( "&" ), + pairs = {}; + + $.each( params, function(idx, param) { + + var tmp = param.split("="); + + pairs[ tmp[0] ] = tmp[1]; }); - - test("$.eventsource callbacks", function() { - - stop(); - // PLAIN TEXT EXAMPLE - NO CONTENT TYPE GIVEN - $.eventsource({ - label: 'text-event-source', - url: '../test-event-sources/event-source-1.php', - open: function () { - ok( true, "#1 $.eventsource fires onopen callback" ); - }, - message: function (data) { - ok( true, "#1 $.eventsource fires onmessage callback" ); - - ok( data, "#1 $.eventsource returns data"); - - ok( typeof $.eventsource('close', 'text-event-source') === 'object', '$.eventsource("close", "text-event-source") must return an object' ); - } - }); - // PLAIN TEXT EXAMPLE - HAS CONTENT TYPE - $.eventsource({ - label: 'text-event-source-ct', - url: '../test-event-sources/event-source-1.php', - dataType: 'text', - open: function () { - ok( true, "#2 $.eventsource fires onopen callback" ); - }, - message: function (data) { - ok( true, "#2 $.eventsource fires onmessage callback" ); - - ok( data, "#2 $.eventsource returns data"); - - ok( typeof $.eventsource('close', 'text-event-source-ct') === 'object', '$.eventsource("close", "text-event-source-ct") must return an object' ); - } - }); - - // PLAIN TEXT EXAMPLE - HAS CONTENT TYPE - - $.eventsource({ - label: 'json-event-source', - url: '../test-event-sources/event-source-2.php', - dataType: 'json', - open: function () { - ok( true, "#3 $.eventsource fires onopen callback" ); - }, - message: function (data) { - - ok( true, "#3 $.eventsource fires onmessage callback" ); - - ok( data, "#3 $.eventsource returns data"); + if ( pairs.nospecit ) { + $("iframe").hide(); + } +}); - ok( typeof $.eventsource('close', 'json-event-source') === 'object', '$.eventsource("close", "json-event-source") must return an object' ); - } - }); - setTimeout(function(){ +test("is a function", function() { + + expect(7); + + ok( jQuery.eventsource, "exists" ); + equal( typeof jQuery.eventsource, "function", "jQuery.eventsource() is a Function" ); + + ok( jQuery.eventsource.streams, "jQuery.eventsource.streams exists" ); + equal( typeof jQuery.eventsource.streams, "function", "jQuery.eventsource.streams() is a Function" ); + + ok( jQuery.eventsource.close, "jQuery.eventsource.close exists" ); + equal( typeof jQuery.eventsource.close, "function", "jQuery.eventsource.close() is a Function" ); + + equal( sizeOf( jQuery.eventsource.streams() ), 0, "There are no streams"); + +}); + +test("callbacks", function() { + + var expects = 12, + count = 0; + + expect( expects ); + + function plus() { + if ( ++count === expects ) { start(); - }, 500); + } + } + + function okPlus() { + ok.apply(null, arguments); + plus(); + } + + stop(); + // PLAIN TEXT EXAMPLE NO CONTENT TYPE GIVEN + jQuery.eventsource({ + label: "text-event-source", + url: "../test-event-sources/event-source-1.php", + open: function() { + okPlus( true, "#1 fires onopen callback" ); + }, + message: function(data) { + okPlus( true, "#1 fires onmessage callback" ); + + okPlus( data, "#1 returns data"); + + okPlus( typeof jQuery.eventsource("close", "text-event-source") === "object", 'jQuery.eventsource("close", "text-event-source") must return an object' ); + } }); - - - - - - test("$.eventsource open/close", function() { - stop(); - - $.eventsource({ - label: 'json-event-source-stream', - url: '../test-event-sources/event-source-2.php', - dataType: 'json', - open: function () { - ok( true, "#4 $.eventsource fires onopen callback" ); - }, - message: function (data) { - - ok( true, "#4 $.eventsource fires onmessage callback" ); - - ok( data, "#4 $.eventsource returns data"); - - equals(sizeOf($.eventsource('streams')), 1, 'there is only 1 active stream'); - - ok( typeof $.eventsource('close', 'json-event-source-stream') === 'object', '$.eventsource("close", "json-event-source-stream") must return an object' ); - - equals(sizeOf($.eventsource('streams')), 0, 'there are 0 active streams'); - } - }); + // PLAIN TEXT EXAMPLE HAS CONTENT TYPE + jQuery.eventsource({ + label: "text-event-source-ct", + url: "../test-event-sources/event-source-1.php", + dataType: "text", + open: function() { + okPlus( true, "#2 fires onopen callback" ); + }, + message: function(data) { + + okPlus( true, "#2 fires onmessage callback" ); + okPlus( data, "#2 returns data"); + okPlus( typeof jQuery.eventsource("close", "text-event-source-ct") === "object", 'jQuery.eventsource("close", "text-event-source-ct") must return an object' ); + + } + }); - - setTimeout(function(){ - start(); - }, 1500); - - }); - - - test("$.eventsource - multiple concurrent sources - scope tests", function() { - stop(); - - $.eventsource({ - label: 'event-source-1', - url: '../test-event-sources/event-source-2.php', - dataType: 'json', - open: function () { - - ok( true, "event-source-1 fires onopen callback" ); - }, - message: function (data) { - - equals(this.label, 'event-source-1', 'Correct EventSource returned, looking for `event-source-1`'); - ok( true, "event-source-1 fires onmessage callback" ); - } - }); - - $.eventsource({ - label: 'event-source-2', - url: '../test-event-sources/event-source-2.php', - dataType: 'json', - open: function () { - - ok( true, "event-source-2 fires onopen callback" ); - }, - message: function (data) { - - equals(this.label, 'event-source-2', 'Correct EventSource returned, looking for `event-source-2`'); - ok( true, "event-source-2 fires onmessage callback" ); - } - }); + // PLAIN TEXT EXAMPLE HAS CONTENT TYPE - $.eventsource({ - label: 'event-source-3', - url: '../test-event-sources/event-source-2.php', - dataType: 'json', - open: function () { - ok( true, "event-source-3 fires onopen callback" ); - }, - message: function (data) { - - - equals(this.label, 'event-source-3', 'Correct EventSource returned, looking for `event-source-3`'); - ok( true, "event-source-3 fires onmessage callback" ); - } - }); - - - setTimeout(function(){ - start(); - }, 2000); - }); - - - test("$.eventsource - multiple concurrent sources - scope tests: closing sources one at a time", function() { - stop(); - - - setTimeout(function() { - equals(2, sizeOf($.eventsource('close', 'event-source-1')), 'Closing `event-source-1`, 2 event sources remaining'); - equals(1, sizeOf($.eventsource('close', 'event-source-2')), 'Closing `event-source-2`, 1 event sources remaining'); - equals(0, sizeOf($.eventsource('close', 'event-source-3')), 'Closing `event-source-3`, 0 event sources remaining'); + jQuery.eventsource({ + label: "json-event-source", + url: "../test-event-sources/event-source-2.php", + dataType: "json", + open: function() { + okPlus( true, "#3 fires onopen callback" ); + }, + message: function(data) { + + okPlus( true, "#3 fires onmessage callback" ); + okPlus( data, "#3 returns data"); + okPlus( typeof jQuery.eventsource("close", "json-event-source") === "object", 'jQuery.eventsource("close", "json-event-source") must return an object' ); + + } + }); + +}); + +test("open/close", function() { + var expects = 5, + count = 0; + + expect( expects ); + + function plus() { + if ( ++count === expects ) { start(); - }, 500); - }); - - - test("$.eventsource - breakage tests", function() { - - stop(); - - try { - $.eventsource({}); - - } catch(err) { - ok(true, 'Caught the error thrown by the instance not having any options set'); - } - - try { - $.eventsource({ - open: function () {}, - message: function (data) {} - }); - } catch(err) { - ok(true, 'Caught the error thrown by the instance not being provided a url'); - } - - try { - $.eventsource({ - url: null, - open: function () {}, - message: function (data) {} - }); - } catch(err) { - ok(true, 'Caught the error thrown by the instance options.url being `null`'); - } - - - try { - $.eventsource({ - url: undefined, - open: function () {}, - message: function (data) {} - }); - } catch(err) { - ok(true, 'Caught the error thrown by the instance options.url being `undefined`'); - } - - - try { - $.eventsource({ - url: '', - open: function () {}, - message: function (data) {} - }); - } catch(err) { - ok(true, 'Caught the error thrown by the instance options.url being an empty string'); - } - - - try { - $.eventsource({ - url: false, - open: function () {}, - message: function (data) {} - }); - } catch(err) { - ok(true, 'Caught the error thrown by the instance options.url being `false`'); - } - - - try { - $.eventsource({ - url: true, - open: function () {}, - message: function (data) {} - }); - } catch(err) { - ok(true, 'Caught the error thrown by the instance options.url being `true`'); - } - - setTimeout(function(){ + } + } + + stop(); + + jQuery.eventsource({ + label: "json-event-source-stream", + url: "../test-event-sources/event-source-2.php", + dataType: "json", + open: function() { + ok( true, "fires onopen callback" ); + plus(); + }, + message: function(data) { + + ok( true, "fires onmessage callback" ); + plus(); + + ok( data, "returns data"); + plus(); + + equal( typeof jQuery.eventsource.close("json-event-source-stream"), "object", 'jQuery.eventsource.close("json-event-source-stream") must return an object' ); + plus(); + + equal( sizeOf( jQuery.eventsource.streams() ), 0, "there are 0 active streams"); + plus(); + } + }); +}); + + +test("multiple concurrent sources scope tests", function() { + var expects = 12, + count = 0, + down = 3; + + expect( expects ); + + function plus() { + if ( ++count === expects ) { start(); - }, 3000); - /* - // this will error, but not testing? - $.eventsource({ - label: 'event-source-3', - url: '../test-event-sources/event-source-10.php', - dataType: 'json', - open: function () {}, - message: function (data) {} - }); - */ - + } + } - }); + stop(); + jQuery.each( [ 1, 2, 3 ], function( idx, stream ) { + jQuery.eventsource({ + label: "event-source-" + stream , + url: "../test-event-sources/event-source-2.php", + dataType: "json", + open: function() { + ok( true, "Stream #" + stream + ", event-source-" + stream + " fires onopen callback" ); + plus(); + }, + message: function(data) { + equal(this.label, "event-source-" + stream, "Stream #" + stream + ", Correct EventSource returned, looking for `event-source-" + stream + "`"); + plus(); + ok( true, "Stream #" + stream + ", event-source-" + stream + " fires onmessage callback" ); + plus(); + jQuery.eventsource.close( "event-source-" + stream ); + equal( sizeOf( jQuery.eventsource.streams() ), --down, "Stream #" + stream + " is closed" ); + plus(); + } + }); + }); +}); - test("$.eventsource streams object", function() { +test("breakage tests", function() { - stop(); + var expects = 7, + count = 0; - setTimeout(function(){ - // labeled stream - $.eventsource({ - label: 'labeled-stream', - url: '../test-event-sources/event-source-1.php', - open: function () { - }, - message: function (data) { - } - }); + expect( expects ); - // unlabeled stream - $.eventsource({ - url: '../test-event-sources/event-source-2.php', - open: function () { - }, - message: function (data) { - } - }); + function plus() { + if ( ++count === expects ) { + start(); + } + } + function okPlus() { + ok.apply(null, arguments); + plus(); + } - // no callbacks - $.eventsource({ - url: '../test-event-sources/event-source-2.php' - }); - - - var streamsObj = $.eventsource('streams'); - ok( typeof streamsObj === 'object', '$.eventsource("streams") must return an object' ); + stop(); - $.each(streamsObj, function (i, obj) { + try { + jQuery.eventsource({}); - equals( typeof obj.isHostApi, 'boolean', 'Stream.isHostApi exists and is a boolean value' ); + } catch(err) { + okPlus(true, "Caught the error thrown by the instance not having any options set"); + } - equals( typeof obj.lastEventId, 'number', 'Stream.lastEventId exists and is a boolean value' ); + try { + jQuery.eventsource({ + open: function() {}, + message: function(data) {} + }); + } catch(err) { + okPlus(true, "Caught the error thrown by the instance not being provided a url"); + } - equals( obj.options.label && obj.options.label !== '', true, 'Stream.options.label exists and not an empty string' ); + try { + jQuery.eventsource({ + url: null, + open: function() {}, + message: function(data) {} + }); + } catch(err) { + okPlus(true, "Caught the error thrown by the instance options.url being `null`"); + } - equals( obj.options.message && $.isFunction(obj.options.message), true, 'Stream.options.message exists and is a function' ); - equals( obj.options.open && $.isFunction(obj.options.open), true, 'Stream.options.message exists and is a function' ); + try { + jQuery.eventsource({ + url: undefined, + open: function() {}, + message: function(data) {} + }); + } catch(err) { + okPlus(true, "Caught the error thrown by the instance options.url being `undefined`"); + } + + + try { + jQuery.eventsource({ + url: "", + open: function() {}, + message: function(data) {} + }); + } catch(err) { + okPlus(true, "Caught the error thrown by the instance options.url being an empty string"); + } + + try { + jQuery.eventsource({ + url: false, + open: function() {}, + message: function(data) {} + }); + } catch(err) { + okPlus(true, "Caught the error thrown by the instance options.url being `false`"); + } - if ( obj.isHostApi ) { - equals( obj.stream.toString(), '[object EventSource]', 'Native Streams are [object EventSource]' ); - } - if ( !obj.isHostApi ) { - if ( window.XMLHttpRequest ) { - equals( obj.stream.toString(), '[object XMLHttpRequest]', 'Non-Native Streams are [object XMLHttpRequest]' ); - } - else { - ok( true, 'Missing IE Stream type test!!' ); - } - } + try { + jQuery.eventsource({ + url: true, + open: function() {}, + message: function(data) {} + }); + } catch(err) { + okPlus(true, "Caught the error thrown by the instance options.url being `true`"); + } +}); - }); +test("streams object", function() { - equals( typeof $.eventsource('close'), 'object', '$.eventsource("close") must return an object' ); + var expects = 13, + count = 0; - equals( typeof $.eventsource('streams'), 'object', '$.eventsource("streams") must return an object' ); + expect( expects ); + function plus() { + if ( ++count === expects ) { start(); + } + } - }, 4000); + // labeled stream + jQuery.eventsource({ + label: "labeled-stream", + url: "../test-event-sources/event-source-1.php", + open: function() { + }, + message: function(data) { + } + }); + // unlabeled stream + jQuery.eventsource({ + url: "../test-event-sources/event-source-2.php", + open: function() { + }, + message: function(data) { + } + }); + // no callbacks + jQuery.eventsource({ + url: "../test-event-sources/event-source-2.php" + }); + + stop(5000); + + var streamsObj = jQuery.eventsource.streams(); + + + + ok( typeof streamsObj === "object", "jQuery.eventsource('streams') must return an object" ); + plus(); + + jQuery.each( streamsObj, function(i, obj) { + equal( typeof obj.isHostApi, "boolean", "Stream.isHostApi exists and is a boolean value" ); + plus(); + equal( typeof obj.lastEventId, "number", "Stream.lastEventId exists and is a boolean value" ); + plus(); - // ADD TESTING FOR CONTENT TYPES, CHAR ENCODING + equal( obj.options.label && obj.options.label !== "", true, "Stream.options.label exists and not an empty string" ); + plus(); + equal( obj.options.message && jQuery.isFunction(obj.options.message), true, "Stream.options.message exists and is a function" ); + plus(); + equal( obj.options.open && jQuery.isFunction(obj.options.open), true, "Stream.options.message exists and is a function" ); + plus(); + + if ( obj.isHostApi ) { + equal( obj.stream.toString(), "[object EventSource]", "Native Streams are [object EventSource]" ); + plus(); + } else { + equal( obj.stream.toString(), "[object Object]", "Non-Native Streams are [object Object]" ); + plus(); + } }); - - test("$.eventsource streams Are Closed", function() { - - stop(); - - equals(sizeOf($.eventsource('streams')), 0, 'there are 0 active streams'); - - ok( typeof $.eventsource('streams') === 'object', '$.eventsource("streams") must return an object' ); +}); + + +test("settable retry time in ms", function() { + + var expects = 2, + count = 0, + stream; + expect( expects ); - setTimeout(function(){ + function plus() { + if ( ++count === expects ) { + jQuery.eventsource.close(); start(); - }, 1000); - + } + } + + stop(); + + // labeled stream + jQuery.eventsource({ + label: "retry-stream", + url: "../test-event-sources/event-source-retry.php", + dataType: "json", + message: function() { + + var stream = jQuery.eventsource.streams("retry-stream"), + streamretry = jQuery.eventsource.streams("retry-stream").retry; + + if ( !stream.isHostApi ) { + equal( streamretry, 1000, "jQuery.eventsource.streams('retry-stream') has a retry time of 1000ms" ); + } else { + ok( true, "retry time is managed by the implementation when provided from a server message" ); + } + plus(); + } }); +}); + + +test("streams Are Closed", function() { + + var expects = 2, + count = 0; + + expect( expects ); + + function plus() { + if ( ++count === expects ) { + start(); + } + } + + stop(); + + jQuery.eventsource.close(); + + equal(sizeOf(jQuery.eventsource.streams()), 0, "there are 0 active streams"); + plus(); + + ok( typeof jQuery.eventsource.streams() === "object", 'jQuery.eventsource.streams() must return an object' ); + plus(); +}); diff --git a/test/specit.html b/test/specit.html index 9214060..fef7eec 100644 --- a/test/specit.html +++ b/test/specit.html @@ -3,27 +3,27 @@ jquery.eventsource.specit - - + + - + - + diff --git a/test/test.php b/test/test.php new file mode 100644 index 0000000..3512aac --- /dev/null +++ b/test/test.php @@ -0,0 +1,45 @@ + + + + + + jQuery.eventsource.js + + + + + + +