mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-11 16:08:24 -05:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5308452b8a | ||
|
|
2ee09436ce | ||
|
|
d2ecaff462 | ||
|
|
023566e03b | ||
|
|
c306a3c303 | ||
|
|
80f1d9780b | ||
|
|
ff10eeecba | ||
|
|
cd9cbb500b | ||
|
|
de8d573948 | ||
|
|
ea9e5ed2cc | ||
|
|
109a59ca9a | ||
|
|
d304ce19d1 | ||
|
|
f534a260b3 | ||
|
|
cff4669d57 | ||
|
|
4b0a1f22c8 | ||
|
|
e79bdb00e9 | ||
|
|
d11ca00b49 | ||
|
|
f3ba4173c7 | ||
|
|
569103e19a | ||
|
|
06445a0faa | ||
|
|
2506b06961 | ||
|
|
992eda86b4 | ||
|
|
6fa8b1f051 | ||
|
|
a91c6f26f4 | ||
|
|
aa9f2596cb | ||
|
|
e2a97588ef | ||
|
|
0b904d79c2 | ||
|
|
f99ac54df5 |
54
History.md
54
History.md
@@ -1,4 +1,58 @@
|
||||
|
||||
0.6.15 / 2011-02-23
|
||||
===================
|
||||
|
||||
* Fixed memory leak in WebSocket transport [belorion]
|
||||
|
||||
0.6.14 / 2011-02-18
|
||||
===================
|
||||
|
||||
* Fixed logging scope issue [shripad]
|
||||
|
||||
0.6.13 / 2011-02-18
|
||||
===================
|
||||
|
||||
* Fixed references to listener when logging
|
||||
|
||||
0.6.12 / 2011-02-18
|
||||
===================
|
||||
|
||||
* Fixed noDelay missing file descriptor problem
|
||||
|
||||
0.6.11 / 2011-02-15
|
||||
===================
|
||||
|
||||
* Fixed; Make sure to not execute any other connection operations after WebSocket
|
||||
write error.
|
||||
* Added more error logging
|
||||
|
||||
0.6.10 / 2011-02-09
|
||||
===================
|
||||
|
||||
* Added SSL chat example (`make example-ssl`)
|
||||
* Fixed; possible write errors when a connection error event fires
|
||||
|
||||
0.6.9 / 2011-02-06
|
||||
==================
|
||||
|
||||
* 0.3 compatibility
|
||||
* Updated socket.io client to 0.6.2
|
||||
* Fixed Flash inline policy serving for Firefox 4
|
||||
* Updated expresso
|
||||
* Added comments and version number to socket.io/index
|
||||
|
||||
0.6.8 / 2011-01-10
|
||||
==================
|
||||
|
||||
* Fixed issue with terminating connection twice
|
||||
|
||||
0.6.7 / 2011-01-09
|
||||
==================
|
||||
|
||||
* Fixed situation where the connection drops but the client can still autoreconnect
|
||||
through a different socket. In this case we still want to clear the FD but not
|
||||
call onDisconnect immediately.
|
||||
|
||||
0.6.6 / 2011-01-09
|
||||
==================
|
||||
|
||||
|
||||
5
Makefile
5
Makefile
@@ -7,4 +7,7 @@ test-cov:
|
||||
example:
|
||||
node ./example/server.js
|
||||
|
||||
.PHONY: example
|
||||
example-ssl:
|
||||
node ./example/server-ssl.js
|
||||
|
||||
.PHONY: example
|
||||
|
||||
21
example/cert.crt
Normal file
21
example/cert.crt
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXTCCAkWgAwIBAgIJAMUSOvlaeyQHMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQwHhcNMTAxMTE2MDkzMjQ5WhcNMTMxMTE1MDkzMjQ5WjBF
|
||||
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||
CgKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEVwfPQQp4X
|
||||
wtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+1FAE0c5o
|
||||
exPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404WthquTqg
|
||||
S7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy25IyBK3QJ
|
||||
c+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWAQsqW+COL
|
||||
0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABo1AwTjAdBgNVHQ4EFgQUDnV4d6mD
|
||||
tOnluLoCjkUHTX/n4agwHwYDVR0jBBgwFoAUDnV4d6mDtOnluLoCjkUHTX/n4agw
|
||||
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAFwV4MQfTo+qMv9JMiyno
|
||||
IEiqfOz4RgtmBqRnXUffcjS2dhc7/z+FPZnM79Kej8eLHoVfxCyWRHFlzm93vEdv
|
||||
wxOCrD13EDOi08OOZfxWyIlCa6Bg8cMAKqQzd2OvQOWqlRWBTThBJIhWflU33izX
|
||||
Qn5GdmYqhfpc+9ZHHGhvXNydtRQkdxVK2dZNzLBvBlLlRmtoClU7xm3A+/5dddeP
|
||||
AQHEPtyFlUw49VYtZ3ru6KqPms7MKvcRhYLsy9rwSfuuniMlx4d0bDR7TOkw0QQS
|
||||
A0N8MGQRQpzl4mw4jLzyM5d5QtuGBh2P6hPGa0YQxtI3RPT/p6ENzzBiAKXiSfzo
|
||||
xw==
|
||||
-----END CERTIFICATE-----
|
||||
61
example/chat-ssl.html
Normal file
61
example/chat-ssl.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>socket.io client test</title>
|
||||
|
||||
<script src="/json.js"></script> <!-- for ie -->
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
function message(obj){
|
||||
var el = document.createElement('p');
|
||||
if ('announcement' in obj) el.innerHTML = '<em>' + esc(obj.announcement) + '</em>';
|
||||
else if ('message' in obj) el.innerHTML = '<b>' + esc(obj.message[0]) + ':</b> ' + esc(obj.message[1]);
|
||||
document.getElementById('chat').appendChild(el);
|
||||
document.getElementById('chat').scrollTop = 1000000;
|
||||
}
|
||||
|
||||
function send(){
|
||||
var val = document.getElementById('text').value;
|
||||
socket.send(val);
|
||||
message({ message: ['you', val] });
|
||||
document.getElementById('text').value = '';
|
||||
}
|
||||
|
||||
function esc(msg){
|
||||
return msg.replace(/</g, '<').replace(/>/g, '>');
|
||||
};
|
||||
|
||||
var socket = new io.Socket(null, {port: 443, secure: true, rememberTransport: false});
|
||||
socket.connect();
|
||||
socket.on('message', function(obj){
|
||||
if ('buffer' in obj){
|
||||
document.getElementById('form').style.display='block';
|
||||
document.getElementById('chat').innerHTML = '';
|
||||
|
||||
for (var i in obj.buffer) message(obj.buffer[i]);
|
||||
} else message(obj);
|
||||
});
|
||||
</script>
|
||||
|
||||
<h1>Sample chat client</h1>
|
||||
<div id="chat"><p>Connecting...</p></div>
|
||||
<form id="form" onsubmit="send(); return false">
|
||||
<input type="text" autocomplete="off" id="text"><input type="submit" value="Send">
|
||||
</form>
|
||||
|
||||
<style>
|
||||
#chat { height: 300px; overflow: auto; width: 800px; border: 1px solid #eee; font: 13px Helvetica, Arial; }
|
||||
#chat p { padding: 8px; margin: 0; }
|
||||
#chat p:nth-child(odd) { background: #F6F6F6; }
|
||||
#form { width: 782px; background: #333; padding: 5px 10px; display: none; }
|
||||
#form input[type=text] { width: 700px; padding: 5px; background: #fff; border: 1px solid #fff; }
|
||||
#form input[type=submit] { cursor: pointer; background: #999; border: none; padding: 6px 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; margin-left: 5px; text-shadow: 0 1px 0 #fff; }
|
||||
#form input[type=submit]:hover { background: #A2A2A2; }
|
||||
#form input[type=submit]:active { position: relative; top: 2px; }
|
||||
</style>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
27
example/key.key
Normal file
27
example/key.key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAz+LXZOjcQCJq3+ZKUFabj71oo/ex/XsBcFqtBThjjTw9CVEV
|
||||
wfPQQp4XwtPiB204vnYXwQ1/R2NdTQqCZu47l79LssL/u2a5Y9+0NEU3nQA5qdt+
|
||||
1FAE0c5oexPimXOrR3GWfKz7PmZ2O0117IeCUUXPG5U8umhDe/4mDF4ZNJiKc404
|
||||
WthquTqgS7rLQZHhZ6D0EnGnOkzlmxJMYPNHSOY1/6ivdNUUcC87awNEA3lgfhy2
|
||||
5IyBK3QJc+aYKNTbt70Lery3bu2wWLFGtmNiGlQTS4JsxImRsECTI727ObS7/FWA
|
||||
QsqW+COL0Sa5BuMFrFIpjPrEe0ih7vRRbdmXRwIDAQABAoIBAGe4+9VqZfJN+dsq
|
||||
8Osyuz01uQ8OmC0sAWTIqUlQgENIyf9rCJsUBlYmwR5BT6Z69XP6QhHdpSK+TiAR
|
||||
XUz0EqG9HYzcxHIBaACP7j6iRoQ8R4kbbiWKo0z3WqQGIOqFjvD/mKEuQdE5mEYw
|
||||
eOUCG6BnX1WY2Yr8WKd2AA/tp0/Y4d8z04u9eodMpSTbHTzYMJb5SbBN1vo6FY7q
|
||||
8zSuO0BMzXlAxUsCwHsk1GQHFr8Oh3zIR7bQGtMBouI+6Lhh7sjFYsfxJboqMTBV
|
||||
IKaA216M6ggHG7MU1/jeKcMGDmEfqQLQoyWp29rMK6TklUgipME2L3UD7vTyAVzz
|
||||
xbVOpZkCgYEA8CXW4sZBBrSSrLR5SB+Ubu9qNTggLowOsC/kVKB2WJ4+xooc5HQo
|
||||
mFhq1v/WxPQoWIxdYsfg2odlL+JclK5Qcy6vXmRSdAQ5lK9gBDKxZSYc3NwAw2HA
|
||||
zyHCTK+I0n8PBYQ+yGcrxu0WqTGnlLW+Otk4CejO34WlgHwbH9bbY5UCgYEA3ZvT
|
||||
C4+OoMHXlmICSt29zUrYiL33IWsR3/MaONxTEDuvgkOSXXQOl/8Ebd6Nu+3WbsSN
|
||||
bjiPC/JyL1YCVmijdvFpl4gjtgvfJifs4G+QHvO6YfsYoVANk4u6g6rUuBIOwNK4
|
||||
RwYxwDc0oysp+g7tPxoSgDHReEVKJNzGBe9NGGsCgYEA4O4QP4gCEA3B9BF2J5+s
|
||||
n9uPVxmiyvZUK6Iv8zP4pThTBBMIzNIf09G9AHPQ7djikU2nioY8jXKTzC3xGTHM
|
||||
GJZ5m6fLsu7iH+nDvSreDSeNkTBfZqGAvoGYQ8uGE+L+ZuRfCcXYsxIOT5s6o4c3
|
||||
Dle2rVFpsuKzCY00urW796ECgYBn3go75+xEwrYGQSer6WR1nTgCV29GVYXKPooy
|
||||
zmmMOT1Yw80NSkEw0pFD4cTyqVYREsTrPU0mn1sPfrOXxnGfZSVFpcR/Je9QVfQ7
|
||||
eW7GYxwfom335aqHVj10SxRqteP+UoWWnHujCPz94VRKZMakBddYCIGSan+G6YdS
|
||||
7sdmwwKBgBc2qj0wvGXDF2kCLwSGfWoMf8CS1+5fIiUIdT1e/+7MfDdbmLMIFVjF
|
||||
QKS3zVViXCbrG5SY6wS9hxoc57f6E2A8vcaX6zy2xkZlGHQCpWRtEM5R01OWJQaH
|
||||
HsHMmQZGUQVoDm1oRkDhrTFK4K3ukc3rAxzeTZ96utOQN8/KJsTv
|
||||
-----END RSA PRIVATE KEY-----
|
||||
66
example/server-ssl.js
Normal file
66
example/server-ssl.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Important note: this application is not suitable for benchmarks!
|
||||
*/
|
||||
|
||||
var https = require('https')
|
||||
, url = require('url')
|
||||
, fs = require('fs')
|
||||
, io = require('../')
|
||||
, sys = require(process.binding('natives').util ? 'util' : 'sys')
|
||||
, server;
|
||||
|
||||
server = https.createServer({
|
||||
key: fs.readFileSync(__dirname + '/key.key')
|
||||
, cert: fs.readFileSync(__dirname + '/cert.crt')
|
||||
}, function(req, res){
|
||||
// your normal server code
|
||||
var path = url.parse(req.url).pathname;
|
||||
switch (path){
|
||||
case '/':
|
||||
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||
res.write('<h1>Welcome. Try the <a href="/chat-ssl.html">SSL Chat</a> example.</h1>');
|
||||
res.end();
|
||||
break;
|
||||
|
||||
case '/json.js':
|
||||
case '/chat-ssl.html':
|
||||
fs.readFile(__dirname + path, function(err, data){
|
||||
if (err) return send404(res);
|
||||
res.writeHead(200, {'Content-Type': path == 'json.js' ? 'text/javascript' : 'text/html'})
|
||||
res.write(data, 'utf8');
|
||||
res.end();
|
||||
});
|
||||
break;
|
||||
|
||||
default: send404(res);
|
||||
}
|
||||
}),
|
||||
|
||||
send404 = function(res){
|
||||
res.writeHead(404);
|
||||
res.write('404');
|
||||
res.end();
|
||||
};
|
||||
|
||||
server.listen(443);
|
||||
|
||||
// socket.io, I choose you
|
||||
// simplest chat application evar
|
||||
var io = io.listen(server)
|
||||
, buffer = [];
|
||||
|
||||
io.on('connection', function(client){
|
||||
client.send({ buffer: buffer });
|
||||
client.broadcast({ announcement: client.sessionId + ' connected' });
|
||||
|
||||
client.on('message', function(message){
|
||||
var msg = { message: [client.sessionId, message] };
|
||||
buffer.push(msg);
|
||||
if (buffer.length > 15) buffer.shift();
|
||||
client.broadcast(msg);
|
||||
});
|
||||
|
||||
client.on('disconnect', function(){
|
||||
client.broadcast({ announcement: client.sessionId + ' disconnected' });
|
||||
});
|
||||
});
|
||||
@@ -69,17 +69,19 @@ Client.prototype._onConnect = function(req, res){
|
||||
|
||||
this.connection.addListener('end', function(){
|
||||
self._onClose();
|
||||
if (self.connection)
|
||||
self.connection.destroy();
|
||||
});
|
||||
|
||||
if (req){
|
||||
req.addListener('error', function(err){
|
||||
req.end && req.end() || req.destroy && req.destroy();
|
||||
req.destroy && req.destroy();
|
||||
});
|
||||
if (res) res.addListener('error', function(err){
|
||||
res.end && res.end() || res.destroy && res.destroy();
|
||||
res.destroy && res.destroy();
|
||||
});
|
||||
req.connection.addListener('error', function(err){
|
||||
req.connection.end && req.connection.end() || req.connection.destroy && req.connection.destroy();
|
||||
req.connection.destroy && req.connection.destroy();
|
||||
});
|
||||
|
||||
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
|
||||
@@ -145,11 +147,6 @@ Client.prototype._onClose = function(skipDisconnect){
|
||||
Client.prototype._onDisconnect = function(){
|
||||
if (this._open) this._onClose(true);
|
||||
if (this._disconnectTimeout) clearTimeout(this._disconnectTimeout);
|
||||
if (this.connection){
|
||||
this.connection.end();
|
||||
this.connection.destroy();
|
||||
this.connection = null;
|
||||
}
|
||||
this._writeQueue = [];
|
||||
this.connected = false;
|
||||
if (this.handshaked){
|
||||
|
||||
@@ -1,4 +1,26 @@
|
||||
exports.Listener = require('./listener');
|
||||
|
||||
/**
|
||||
* Listener creation shorcut
|
||||
*
|
||||
* @param {Server} node HTTP server
|
||||
* @param {Object} options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.listen = function(server, options){
|
||||
return new exports.Listener(server, options);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Listener constructor
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Listener = require('./listener');
|
||||
|
||||
/**
|
||||
* Version
|
||||
*/
|
||||
|
||||
exports.version = '0.6.15';
|
||||
|
||||
@@ -21,7 +21,9 @@ Flashsocket.init = function(listener){
|
||||
if (listeners.length === 0 && netserver){
|
||||
try {
|
||||
netserver.close();
|
||||
} catch(e){}
|
||||
} catch(e){
|
||||
listener.options.log('flashsocket netserver close error - ' + e.stack)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -45,8 +47,7 @@ Flashsocket.init = function(listener){
|
||||
listener.options.log('Your node instance does not have root privileges. '
|
||||
+ 'This means that the flash XML policy file will be '
|
||||
+ 'served inline instead of on port 843. This will slow '
|
||||
+ 'down initial connections slightly. NOTE: this fails '
|
||||
+ 'with Firefox 4 betas.');
|
||||
+ 'down initial connections slightly.');
|
||||
netserver = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,9 @@ HTMLFile.prototype._onConnect = function(req, res){
|
||||
try {
|
||||
var msg = qs.parse(body);
|
||||
self._onMessage(msg.data);
|
||||
} catch(e){}
|
||||
} catch(e){
|
||||
self.listener.options.log('htmlfile message handler error - ' + e.stack);
|
||||
}
|
||||
res.writeHead(200, {'Content-Type': 'text/plain'});
|
||||
res.write('ok');
|
||||
res.end();
|
||||
|
||||
@@ -78,14 +78,14 @@ WebSocket.prototype._onConnect = function(req, socket){
|
||||
|
||||
try {
|
||||
this.connection.write(headers.concat('', '').join('\r\n'));
|
||||
this.connection.setTimeout(0);
|
||||
this.connection.setNoDelay(true);
|
||||
this.connection.setEncoding('utf-8');
|
||||
} catch(e){
|
||||
this._onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
this.connection.setTimeout(0);
|
||||
this.connection.setNoDelay(true);
|
||||
this.connection.setEncoding('utf-8');
|
||||
|
||||
if (this.waitingForNonce) {
|
||||
// Since we will be receiving the binary nonce through the normal HTTP
|
||||
// data event, set the connection to 'binary' temporarily
|
||||
@@ -99,18 +99,16 @@ WebSocket.prototype._onConnect = function(req, socket){
|
||||
this.buffer = "";
|
||||
|
||||
this.connection.addListener('data', function(data){
|
||||
self.buffer += data;
|
||||
if (self.waitingForNonce) {
|
||||
self.buffer += data;
|
||||
|
||||
if (self.buffer.length < 8) { return; }
|
||||
// Restore the connection to utf8 encoding after receiving the nonce
|
||||
self.connection.setEncoding('utf8');
|
||||
self.waitingForNonce = false;
|
||||
// Stuff the nonce into the location where it's expected to be
|
||||
self.upgradeHead = self.buffer.substr(0,8);
|
||||
self.buffer = self.buffer.substr(8);
|
||||
if (self.buffer.length > 0) {
|
||||
self.parser.add(self.buffer);
|
||||
}
|
||||
self.buffer = '';
|
||||
if (self._proveReception(self._headers)) { self._payload(); }
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,9 @@ Multipart.prototype._onConnect = function(req, res){
|
||||
try {
|
||||
var msg = qs.parse(body);
|
||||
self._onMessage(msg.data);
|
||||
} catch(e){}
|
||||
} catch(e){
|
||||
self.listener.options.log('xhr-multipart message handler error - ' + e.stack);
|
||||
}
|
||||
res.writeHead(200, headers);
|
||||
res.write('ok');
|
||||
res.end();
|
||||
|
||||
@@ -48,7 +48,9 @@ Polling.prototype._onConnect = function(req, res){
|
||||
// optimization: just strip first 5 characters here?
|
||||
var msg = qs.parse(body);
|
||||
self._onMessage(msg.data);
|
||||
} catch(e){}
|
||||
} catch(e){
|
||||
self.listener.options.log('xhr-polling message handler error - ' + e.stack);
|
||||
}
|
||||
res.writeHead(200, headers);
|
||||
res.write('ok');
|
||||
res.end();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ "name" : "socket.io"
|
||||
, "description" : "The cross-browser WebSocket"
|
||||
, "version" : "0.6.6"
|
||||
, "version" : "0.6.15"
|
||||
, "author" : "LearnBoost"
|
||||
, "licenses" :
|
||||
[ { "type" : "MIT"
|
||||
|
||||
@@ -1,4 +1,35 @@
|
||||
|
||||
0.7.2 / 2010-12-29
|
||||
==================
|
||||
|
||||
* Fixed problem with `listen()` sometimes firing on the same tick [guillermo]
|
||||
|
||||
0.7.1 / 2010-12-28
|
||||
==================
|
||||
|
||||
* Fixed `assert.request()` client logic into an issue() function, fired upon the `listen()` callback if the server doesn't have an assigned fd. [guillermo]
|
||||
* Removed `--watch`
|
||||
|
||||
0.7.0 / 2010-11-19
|
||||
==================
|
||||
|
||||
* Removed `assert` from test function signature
|
||||
Just use `require('assert')` :) this will make integration
|
||||
with libraries like [should](http://github.com/visionmedia/should) cleaner.
|
||||
|
||||
0.6.4 / 2010-11-02
|
||||
==================
|
||||
|
||||
* Added regexp support to `assert.response()` headers
|
||||
* Removed `waitForExit` code, causing issues
|
||||
|
||||
0.6.3 / 2010-11-02
|
||||
==================
|
||||
|
||||
* Added `assert.response()` body RegExp support
|
||||
* Fixed issue with _--serial_ not executing files sequentially. Closes #42
|
||||
* Fixed hang when modules use `setInterval` - monitor running tests & force the process to quit after all have completed + timeout [Steve Mason]
|
||||
|
||||
0.6.2 / 2010-09-17
|
||||
==================
|
||||
|
||||
|
||||
@@ -35,5 +35,27 @@ Install via npm:
|
||||
|
||||
$ npm install expresso
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2010 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/*!
|
||||
/*
|
||||
* Expresso
|
||||
* Copyright(c) TJ Holowaychuk <tj@vision-media.ca>
|
||||
* (MIT Licensed)
|
||||
@@ -23,7 +23,7 @@ var assert = require('assert'),
|
||||
* Expresso version.
|
||||
*/
|
||||
|
||||
var version = '0.6.2';
|
||||
var version = '0.7.2';
|
||||
|
||||
/**
|
||||
* Failure count.
|
||||
@@ -62,12 +62,6 @@ var growl = false;
|
||||
|
||||
var port = 5555;
|
||||
|
||||
/**
|
||||
* Watch mode.
|
||||
*/
|
||||
|
||||
var watch = false;
|
||||
|
||||
/**
|
||||
* Execute serially.
|
||||
*/
|
||||
@@ -80,6 +74,12 @@ var serial = false;
|
||||
|
||||
var timeout = 2000;
|
||||
|
||||
/**
|
||||
* Quiet output.
|
||||
*/
|
||||
|
||||
var quiet = false;
|
||||
|
||||
/**
|
||||
* Usage documentation.
|
||||
*/
|
||||
@@ -88,9 +88,9 @@ var usage = ''
|
||||
+ '[bold]{Usage}: expresso [options] <file ...>'
|
||||
+ '\n'
|
||||
+ '\n[bold]{Options}:'
|
||||
+ '\n -w, --watch Watch for modifications and re-execute tests'
|
||||
+ '\n -g, --growl Enable growl notifications'
|
||||
+ '\n -c, --coverage Generate and report test coverage'
|
||||
+ '\n -q, --quiet Suppress coverage report if 100%'
|
||||
+ '\n -t, --timeout MS Timeout in milliseconds, defaults to 2000'
|
||||
+ '\n -r, --require PATH Require the given module path'
|
||||
+ '\n -o, --only TESTS Execute only the comma sperated TESTS (can be set several times)'
|
||||
@@ -171,14 +171,14 @@ while (args.length) {
|
||||
run(files);
|
||||
})
|
||||
break;
|
||||
case '-q':
|
||||
case '--quiet':
|
||||
quiet = true;
|
||||
break;
|
||||
case '-b':
|
||||
case '--boring':
|
||||
boring = true;
|
||||
break;
|
||||
case '-w':
|
||||
case '--watch':
|
||||
watch = true;
|
||||
break;
|
||||
case '-g':
|
||||
case '--growl':
|
||||
growl = true;
|
||||
@@ -339,6 +339,27 @@ assert.length = function(val, n, msg) {
|
||||
*/
|
||||
|
||||
assert.response = function(server, req, res, msg){
|
||||
// Check that the server is ready or defer
|
||||
if (!server.fd) {
|
||||
if (!('__deferred' in server)) {
|
||||
server.__deferred = [];
|
||||
}
|
||||
server.__deferred.push(arguments);
|
||||
if (!server.__started) {
|
||||
server.listen(server.__port = port++, '127.0.0.1', function(){
|
||||
if (server.__deferred) {
|
||||
process.nextTick(function(){
|
||||
server.__deferred.forEach(function(args){
|
||||
assert.response.apply(assert, args);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
server.__started = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Callback as third or fourth arg
|
||||
var callback = typeof res === 'function'
|
||||
? res
|
||||
@@ -357,84 +378,92 @@ assert.response = function(server, req, res, msg){
|
||||
|
||||
// Create client
|
||||
if (!server.fd) {
|
||||
server.listen(server.__port = port++, '127.0.0.1');
|
||||
server.client = http.createClient(server.__port);
|
||||
server.listen(server.__port = port++, '127.0.0.1', issue);
|
||||
} else {
|
||||
issue();
|
||||
}
|
||||
|
||||
// Issue request
|
||||
var timer,
|
||||
client = server.client,
|
||||
method = req.method || 'GET',
|
||||
status = res.status || res.statusCode,
|
||||
data = req.data || req.body,
|
||||
timeout = req.timeout || 0;
|
||||
function issue(){
|
||||
if (!server.client)
|
||||
server.client = http.createClient(server.__port);
|
||||
|
||||
var request = client.request(method, req.url, req.headers);
|
||||
// Issue request
|
||||
var timer,
|
||||
client = server.client,
|
||||
method = req.method || 'GET',
|
||||
status = res.status || res.statusCode,
|
||||
data = req.data || req.body,
|
||||
requestTimeout = req.timeout || 0;
|
||||
|
||||
// Timeout
|
||||
if (timeout) {
|
||||
timer = setTimeout(function(){
|
||||
--server.__pending || server.close();
|
||||
delete req.timeout;
|
||||
assert.fail(msg + 'Request timed out after ' + timeout + 'ms.');
|
||||
}, timeout);
|
||||
}
|
||||
var request = client.request(method, req.url, req.headers);
|
||||
|
||||
if (data) request.write(data);
|
||||
request.addListener('response', function(response){
|
||||
response.body = '';
|
||||
response.setEncoding('utf8');
|
||||
response.addListener('data', function(chunk){ response.body += chunk; });
|
||||
response.addListener('end', function(){
|
||||
--server.__pending || server.close();
|
||||
if (timer) clearTimeout(timer);
|
||||
// Timeout
|
||||
if (requestTimeout) {
|
||||
timer = setTimeout(function(){
|
||||
--server.__pending || server.close();
|
||||
delete req.timeout;
|
||||
assert.fail(msg + 'Request timed out after ' + requestTimeout + 'ms.');
|
||||
}, requestTimeout);
|
||||
}
|
||||
|
||||
// Assert response body
|
||||
if (res.body !== undefined) {
|
||||
var eql = res.body instanceof RegExp
|
||||
? res.body.test(response.body)
|
||||
: res.body === response.body;
|
||||
assert.ok(
|
||||
eql,
|
||||
msg + 'Invalid response body.\n'
|
||||
+ ' Expected: ' + sys.inspect(res.body) + '\n'
|
||||
+ ' Got: ' + sys.inspect(response.body)
|
||||
);
|
||||
}
|
||||
if (data) request.write(data);
|
||||
request.on('response', function(response){
|
||||
response.body = '';
|
||||
response.setEncoding('utf8');
|
||||
response.on('data', function(chunk){ response.body += chunk; });
|
||||
response.on('end', function(){
|
||||
--server.__pending || server.close();
|
||||
if (timer) clearTimeout(timer);
|
||||
|
||||
// Assert response status
|
||||
if (typeof status === 'number') {
|
||||
assert.equal(
|
||||
response.statusCode,
|
||||
status,
|
||||
msg + colorize('Invalid response status code.\n'
|
||||
+ ' Expected: [green]{' + status + '}\n'
|
||||
+ ' Got: [red]{' + response.statusCode + '}')
|
||||
);
|
||||
}
|
||||
|
||||
// Assert response headers
|
||||
if (res.headers) {
|
||||
var keys = Object.keys(res.headers);
|
||||
for (var i = 0, len = keys.length; i < len; ++i) {
|
||||
var name = keys[i],
|
||||
actual = response.headers[name.toLowerCase()],
|
||||
expected = res.headers[name];
|
||||
assert.equal(
|
||||
actual,
|
||||
expected,
|
||||
msg + colorize('Invalid response header [bold]{' + name + '}.\n'
|
||||
+ ' Expected: [green]{' + expected + '}\n'
|
||||
+ ' Got: [red]{' + actual + '}')
|
||||
// Assert response body
|
||||
if (res.body !== undefined) {
|
||||
var eql = res.body instanceof RegExp
|
||||
? res.body.test(response.body)
|
||||
: res.body === response.body;
|
||||
assert.ok(
|
||||
eql,
|
||||
msg + 'Invalid response body.\n'
|
||||
+ ' Expected: ' + sys.inspect(res.body) + '\n'
|
||||
+ ' Got: ' + sys.inspect(response.body)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback
|
||||
callback(response);
|
||||
// Assert response status
|
||||
if (typeof status === 'number') {
|
||||
assert.equal(
|
||||
response.statusCode,
|
||||
status,
|
||||
msg + colorize('Invalid response status code.\n'
|
||||
+ ' Expected: [green]{' + status + '}\n'
|
||||
+ ' Got: [red]{' + response.statusCode + '}')
|
||||
);
|
||||
}
|
||||
|
||||
// Assert response headers
|
||||
if (res.headers) {
|
||||
var keys = Object.keys(res.headers);
|
||||
for (var i = 0, len = keys.length; i < len; ++i) {
|
||||
var name = keys[i],
|
||||
actual = response.headers[name.toLowerCase()],
|
||||
expected = res.headers[name],
|
||||
eql = expected instanceof RegExp
|
||||
? expected.test(actual)
|
||||
: expected == actual;
|
||||
assert.ok(
|
||||
eql,
|
||||
msg + colorize('Invalid response header [bold]{' + name + '}.\n'
|
||||
+ ' Expected: [green]{' + expected + '}\n'
|
||||
+ ' Got: [red]{' + actual + '}')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback
|
||||
callback(response);
|
||||
});
|
||||
});
|
||||
});
|
||||
request.end();
|
||||
request.end();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -476,7 +505,6 @@ function rpad(str, width) {
|
||||
*/
|
||||
|
||||
function reportCoverage(cov) {
|
||||
populateCoverage(cov);
|
||||
// Stats
|
||||
print('\n [bold]{Test Coverage}\n');
|
||||
var sep = ' +------------------------------------------+----------+------+------+--------+',
|
||||
@@ -507,9 +535,11 @@ function reportCoverage(cov) {
|
||||
for (var name in cov) {
|
||||
if (name.match(/\.js$/)) {
|
||||
var file = cov[name];
|
||||
print('\n [bold]{' + name + '}:');
|
||||
print(file.source);
|
||||
sys.print('\n');
|
||||
if ((file.coverage < 100) || !quiet) {
|
||||
print('\n [bold]{' + name + '}:');
|
||||
print(file.source);
|
||||
sys.print('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,6 +604,25 @@ function coverage(data, val) {
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if all files have 100% coverage
|
||||
*
|
||||
* @param {Object} cov
|
||||
* @return {Boolean}
|
||||
*/
|
||||
|
||||
function hasFullCoverage(cov) {
|
||||
for (var name in cov) {
|
||||
var file = cov[name];
|
||||
if (file instanceof Array) {
|
||||
if (file.coverage !== 100) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given test `files`, or try _test/*_.
|
||||
*
|
||||
@@ -581,6 +630,7 @@ function coverage(data, val) {
|
||||
*/
|
||||
|
||||
function run(files) {
|
||||
cursor(false);
|
||||
if (!files.length) {
|
||||
try {
|
||||
files = fs.readdirSync('test').map(function(file){
|
||||
@@ -592,7 +642,6 @@ function run(files) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
if (watch) watchFiles(files);
|
||||
runFiles(files);
|
||||
}
|
||||
|
||||
@@ -617,16 +666,25 @@ function cursor(show) {
|
||||
*/
|
||||
|
||||
function runFiles(files) {
|
||||
files.forEach(runFile);
|
||||
if (serial) {
|
||||
(function next(){
|
||||
if (files.length) {
|
||||
runFile(files.shift(), next);
|
||||
}
|
||||
})();
|
||||
} else {
|
||||
files.forEach(runFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run tests for the given `file`.
|
||||
* Run tests for the given `file`, callback `fn()` when finished.
|
||||
*
|
||||
* @param {String} file
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function runFile(file) {
|
||||
function runFile(file, fn) {
|
||||
if (file.match(/\.js$/)) {
|
||||
var title = path.basename(file),
|
||||
file = path.join(cwd, file),
|
||||
@@ -634,7 +692,7 @@ function runFile(file) {
|
||||
(function check(){
|
||||
var len = Object.keys(mod).length;
|
||||
if (len) {
|
||||
runSuite(title, mod);
|
||||
runSuite(title, mod, fn);
|
||||
} else {
|
||||
setTimeout(check, 20);
|
||||
}
|
||||
@@ -642,49 +700,6 @@ function runFile(file) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the module cache for the given `file`.
|
||||
*
|
||||
* @param {String} file
|
||||
*/
|
||||
|
||||
function clearCache(file) {
|
||||
var keys = Object.keys(module.moduleCache);
|
||||
for (var i = 0, len = keys.length; i < len; ++i) {
|
||||
var key = keys[i];
|
||||
if (key.indexOf(file) === key.length - file.length) {
|
||||
delete module.moduleCache[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch the given `files` for changes.
|
||||
*
|
||||
* @param {Array} files
|
||||
*/
|
||||
|
||||
function watchFiles(files) {
|
||||
var p = 0,
|
||||
c = ['▫ ', '▫▫ ', '▫▫▫ ', ' ▫▫▫',
|
||||
' ▫▫', ' ▫', ' ▫', ' ▫▫',
|
||||
'▫▫▫ ', '▫▫ ', '▫ '],
|
||||
l = c.length;
|
||||
cursor(false);
|
||||
setInterval(function(){
|
||||
sys.print(colorize(' [green]{' + c[p++ % l] + '} watching\r'));
|
||||
}, 100);
|
||||
files.forEach(function(file){
|
||||
fs.watchFile(file, { interval: 100 }, function(curr, prev){
|
||||
if (curr.mtime > prev.mtime) {
|
||||
print(' [yellow]{◦} ' + file);
|
||||
clearCache(file);
|
||||
runFile(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Report `err` for the given `test` and `suite`.
|
||||
*
|
||||
@@ -696,23 +711,23 @@ function watchFiles(files) {
|
||||
function error(suite, test, err) {
|
||||
++failures;
|
||||
var name = err.name,
|
||||
stack = err.stack.replace(err.name, ''),
|
||||
stack = err.stack ? err.stack.replace(err.name, '') : '',
|
||||
label = test === 'uncaught'
|
||||
? test
|
||||
: suite + ' ' + test;
|
||||
print('\n [bold]{' + label + '}: [red]{' + name + '}' + stack + '\n');
|
||||
if (watch) notify(label + ' failed');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given tests.
|
||||
* Run the given tests, callback `fn()` when finished.
|
||||
*
|
||||
* @param {String} title
|
||||
* @param {Object} tests
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
var dots = 0;
|
||||
function runSuite(title, tests) {
|
||||
function runSuite(title, tests, fn) {
|
||||
// Keys
|
||||
var keys = only.length
|
||||
? only.slice(0)
|
||||
@@ -720,7 +735,7 @@ function runSuite(title, tests) {
|
||||
|
||||
// Setup
|
||||
var setup = tests.setup || function(fn){ fn(); };
|
||||
|
||||
|
||||
// Iterate tests
|
||||
(function next(){
|
||||
if (keys.length) {
|
||||
@@ -735,27 +750,25 @@ function runSuite(title, tests) {
|
||||
++testcount;
|
||||
assert.testTitle = key;
|
||||
if (serial) {
|
||||
if (!watch) {
|
||||
sys.print('.');
|
||||
if (++dots % 25 === 0) sys.print('\n');
|
||||
}
|
||||
sys.print('.');
|
||||
if (++dots % 25 === 0) sys.print('\n');
|
||||
setup(function(){
|
||||
if (test.length < 2) {
|
||||
test(assert);
|
||||
if (test.length < 1) {
|
||||
test();
|
||||
next();
|
||||
} else {
|
||||
var id = setTimeout(function(){
|
||||
throw new Error("'" + key + "' timed out");
|
||||
}, timeout);
|
||||
test(assert, function(){
|
||||
test(function(){
|
||||
clearTimeout(id);
|
||||
next();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
test(assert, function(fn){
|
||||
process.addListener('beforeExit', function(){
|
||||
test(function(fn){
|
||||
process.on('beforeExit', function(){
|
||||
try {
|
||||
fn();
|
||||
} catch (err) {
|
||||
@@ -769,6 +782,8 @@ function runSuite(title, tests) {
|
||||
}
|
||||
}
|
||||
if (!serial) next();
|
||||
} else if (serial) {
|
||||
fn();
|
||||
}
|
||||
})();
|
||||
}
|
||||
@@ -778,6 +793,7 @@ function runSuite(title, tests) {
|
||||
*/
|
||||
|
||||
function report() {
|
||||
cursor(true);
|
||||
process.emit('beforeExit');
|
||||
if (failures) {
|
||||
print('\n [bold]{Failures}: [red]{' + failures + '}\n\n');
|
||||
@@ -788,7 +804,10 @@ function report() {
|
||||
notify('100% ok');
|
||||
}
|
||||
if (typeof _$jscoverage === 'object') {
|
||||
reportCoverage(_$jscoverage);
|
||||
populateCoverage(_$jscoverage);
|
||||
if (!hasFullCoverage(_$jscoverage) || !quiet) {
|
||||
reportCoverage(_$jscoverage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,14 +825,14 @@ function notify(msg) {
|
||||
|
||||
// Report uncaught exceptions
|
||||
|
||||
process.addListener('uncaughtException', function(err){
|
||||
process.on('uncaughtException', function(err){
|
||||
error('uncaught', 'uncaught', err);
|
||||
});
|
||||
|
||||
// Show cursor
|
||||
|
||||
['INT', 'TERM', 'QUIT'].forEach(function(sig){
|
||||
process.addListener('SIG' + sig, function(){
|
||||
process.on('SIG' + sig, function(){
|
||||
cursor(true);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -113,7 +113,7 @@ code .this { color: #19469D; }</style>
|
||||
<h1>!/usr/bin/env node</h1>
|
||||
</td>
|
||||
<td class="code">
|
||||
<pre><code>!
|
||||
<pre><code>
|
||||
* <span class="class">Expresso</span>
|
||||
* <span class="class">Copyright</span>(<span class="variable">c</span>) <span class="class">TJ</span> <span class="class">Holowaychuk</span> &<span class="variable">lt</span>;<span class="variable">tj</span>@<span class="variable">vision</span>-<span class="variable">media</span>.<span class="variable">ca</span>&<span class="variable">gt</span>;
|
||||
* (<span class="class">MIT</span> <span class="class">Licensed</span>)
|
||||
@@ -142,7 +142,7 @@ code .this { color: #19469D; }</style>
|
||||
</p>
|
||||
</td>
|
||||
<td class="code">
|
||||
<pre><code><span class="keyword">var</span> <span class="variable">version</span> = <span class="string">'0.6.1'</span>;</code></pre>
|
||||
<pre><code><span class="keyword">var</span> <span class="variable">version</span> = <span class="string">'0.6.4'</span>;</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="code">
|
||||
@@ -219,6 +219,15 @@ code .this { color: #19469D; }</style>
|
||||
</tr>
|
||||
<tr class="code">
|
||||
<td class="docs">
|
||||
<p>Default timeout.
|
||||
</p>
|
||||
</td>
|
||||
<td class="code">
|
||||
<pre><code><span class="keyword">var</span> <span class="variable">timeout</span> = <span class="number integer">2000</span>;</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="code">
|
||||
<td class="docs">
|
||||
<p>Usage documentation.
|
||||
</p>
|
||||
</td>
|
||||
@@ -230,6 +239,7 @@ code .this { color: #19469D; }</style>
|
||||
+ <span class="string">'\n -w, --watch Watch for modifications and re-execute tests'</span>
|
||||
+ <span class="string">'\n -g, --growl Enable growl notifications'</span>
|
||||
+ <span class="string">'\n -c, --coverage Generate and report test coverage'</span>
|
||||
+ <span class="string">'\n -t, --timeout MS Timeout in milliseconds, defaults to 2000'</span>
|
||||
+ <span class="string">'\n -r, --require PATH Require the given module path'</span>
|
||||
+ <span class="string">'\n -o, --only TESTS Execute only the comma sperated TESTS (can be set several times)'</span>
|
||||
+ <span class="string">'\n -I, --include PATH Unshift the given path to require.paths'</span>
|
||||
@@ -291,6 +301,14 @@ code .this { color: #19469D; }</style>
|
||||
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">Error</span>(<span class="string">'--require requires a path'</span>);
|
||||
}
|
||||
<span class="keyword">break</span>;
|
||||
<span class="keyword">case</span> <span class="string">'-t'</span>:
|
||||
<span class="keyword">case</span> <span class="string">'--timeout'</span>:
|
||||
<span class="keyword">if</span> (<span class="variable">arg</span> = <span class="variable">args</span>.<span class="variable">shift</span>()) {
|
||||
<span class="variable">timeout</span> = <span class="variable">parseInt</span>(<span class="variable">arg</span>, <span class="number integer">10</span>);
|
||||
} <span class="keyword">else</span> {
|
||||
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">Error</span>(<span class="string">'--timeout requires an argument'</span>);
|
||||
}
|
||||
<span class="keyword">break</span>;
|
||||
<span class="keyword">case</span> <span class="string">'-c'</span>:
|
||||
<span class="keyword">case</span> <span class="string">'--cov'</span>:
|
||||
<span class="keyword">case</span> <span class="string">'--coverage'</span>:
|
||||
@@ -525,17 +543,17 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
<span class="variable">method</span> = <span class="variable">req</span>.<span class="variable">method</span> || <span class="string">'GET'</span>,
|
||||
<span class="variable">status</span> = <span class="variable">res</span>.<span class="variable">status</span> || <span class="variable">res</span>.<span class="variable">statusCode</span>,
|
||||
<span class="variable">data</span> = <span class="variable">req</span>.<span class="variable">data</span> || <span class="variable">req</span>.<span class="variable">body</span>,
|
||||
<span class="variable">timeout</span> = <span class="variable">req</span>.<span class="variable">timeout</span> || <span class="number integer">0</span>;
|
||||
<span class="variable">requestTimeout</span> = <span class="variable">req</span>.<span class="variable">timeout</span> || <span class="number integer">0</span>;
|
||||
|
||||
<span class="keyword">var</span> <span class="variable">request</span> = <span class="variable">client</span>.<span class="variable">request</span>(<span class="variable">method</span>, <span class="variable">req</span>.<span class="variable">url</span>, <span class="variable">req</span>.<span class="variable">headers</span>);
|
||||
|
||||
<span class="comment">// Timeout</span>
|
||||
<span class="keyword">if</span> (<span class="variable">timeout</span>) {
|
||||
<span class="keyword">if</span> (<span class="variable">requestTimeout</span>) {
|
||||
<span class="variable">timer</span> = <span class="variable">setTimeout</span>(<span class="keyword">function</span>(){
|
||||
--<span class="variable">server</span>.<span class="variable">__pending</span> || <span class="variable">server</span>.<span class="variable">close</span>();
|
||||
<span class="keyword">delete</span> <span class="variable">req</span>.<span class="variable">timeout</span>;
|
||||
<span class="variable">assert</span>.<span class="variable">fail</span>(<span class="variable">msg</span> + <span class="string">'Request timed out after '</span> + <span class="variable">timeout</span> + <span class="string">'ms.'</span>);
|
||||
}, <span class="variable">timeout</span>);
|
||||
<span class="variable">assert</span>.<span class="variable">fail</span>(<span class="variable">msg</span> + <span class="string">'Request timed out after '</span> + <span class="variable">requestTimeout</span> + <span class="string">'ms.'</span>);
|
||||
}, <span class="variable">requestTimeout</span>);
|
||||
}
|
||||
|
||||
<span class="keyword">if</span> (<span class="variable">data</span>) <span class="variable">request</span>.<span class="variable">write</span>(<span class="variable">data</span>);
|
||||
@@ -549,9 +567,11 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
|
||||
<span class="comment">// Assert response body</span>
|
||||
<span class="keyword">if</span> (<span class="variable">res</span>.<span class="variable">body</span> !== <span class="variable">undefined</span>) {
|
||||
<span class="variable">assert</span>.<span class="variable">equal</span>(
|
||||
<span class="variable">response</span>.<span class="variable">body</span>,
|
||||
<span class="variable">res</span>.<span class="variable">body</span>,
|
||||
<span class="keyword">var</span> <span class="variable">eql</span> = <span class="variable">res</span>.<span class="variable">body</span> <span class="variable">instanceof</span> <span class="class">RegExp</span>
|
||||
? <span class="variable">res</span>.<span class="variable">body</span>.<span class="variable">test</span>(<span class="variable">response</span>.<span class="variable">body</span>)
|
||||
: <span class="variable">res</span>.<span class="variable">body</span> === <span class="variable">response</span>.<span class="variable">body</span>;
|
||||
<span class="variable">assert</span>.<span class="variable">ok</span>(
|
||||
<span class="variable">eql</span>,
|
||||
<span class="variable">msg</span> + <span class="string">'Invalid response body.\n'</span>
|
||||
+ <span class="string">' Expected: '</span> + <span class="variable">sys</span>.<span class="variable">inspect</span>(<span class="variable">res</span>.<span class="variable">body</span>) + <span class="string">'\n'</span>
|
||||
+ <span class="string">' Got: '</span> + <span class="variable">sys</span>.<span class="variable">inspect</span>(<span class="variable">response</span>.<span class="variable">body</span>)
|
||||
@@ -575,10 +595,12 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
<span class="keyword">for</span> (<span class="keyword">var</span> <span class="variable">i</span> = <span class="number integer">0</span>, <span class="variable">len</span> = <span class="variable">keys</span>.<span class="variable">length</span>; <span class="variable">i</span> &<span class="variable">lt</span>; <span class="variable">len</span>; ++<span class="variable">i</span>) {
|
||||
<span class="keyword">var</span> <span class="variable">name</span> = <span class="variable">keys</span>[<span class="variable">i</span>],
|
||||
<span class="variable">actual</span> = <span class="variable">response</span>.<span class="variable">headers</span>[<span class="variable">name</span>.<span class="variable">toLowerCase</span>()],
|
||||
<span class="variable">expected</span> = <span class="variable">res</span>.<span class="variable">headers</span>[<span class="variable">name</span>];
|
||||
<span class="variable">assert</span>.<span class="variable">equal</span>(
|
||||
<span class="variable">actual</span>,
|
||||
<span class="variable">expected</span>,
|
||||
<span class="variable">expected</span> = <span class="variable">res</span>.<span class="variable">headers</span>[<span class="variable">name</span>],
|
||||
<span class="variable">eql</span> = <span class="variable">expected</span> <span class="variable">instanceof</span> <span class="class">RegExp</span>
|
||||
? <span class="variable">expected</span>.<span class="variable">test</span>(<span class="variable">actual</span>)
|
||||
: <span class="variable">expected</span> == <span class="variable">actual</span>;
|
||||
<span class="variable">assert</span>.<span class="variable">ok</span>(
|
||||
<span class="variable">eql</span>,
|
||||
<span class="variable">msg</span> + <span class="variable">colorize</span>(<span class="string">'Invalid response header [bold]{'</span> + <span class="variable">name</span> + <span class="string">'}.\n'</span>
|
||||
+ <span class="string">' Expected: [green]{'</span> + <span class="variable">expected</span> + <span class="string">'}\n'</span>
|
||||
+ <span class="string">' Got: [red]{'</span> + <span class="variable">actual</span> + <span class="string">'}'</span>)
|
||||
@@ -800,20 +822,28 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
</td>
|
||||
<td class="code">
|
||||
<pre><code><span class="keyword">function</span> <span class="variable">runFiles</span>(<span class="variable">files</span>) {
|
||||
<span class="variable">files</span>.<span class="variable">forEach</span>(<span class="variable">runFile</span>);
|
||||
<span class="keyword">if</span> (<span class="variable">serial</span>) {
|
||||
(<span class="keyword">function</span> <span class="variable">next</span>(){
|
||||
<span class="keyword">if</span> (<span class="variable">files</span>.<span class="variable">length</span>) {
|
||||
<span class="variable">runFile</span>(<span class="variable">files</span>.<span class="variable">shift</span>(), <span class="variable">next</span>);
|
||||
}
|
||||
})();
|
||||
} <span class="keyword">else</span> {
|
||||
<span class="variable">files</span>.<span class="variable">forEach</span>(<span class="variable">runFile</span>);
|
||||
}
|
||||
}</code></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="code">
|
||||
<td class="docs">
|
||||
<p>Run tests for the given <code>file</code>.</p>
|
||||
<p>Run tests for the given <code>file</code>, callback <code>fn()</code> when finished.</p>
|
||||
|
||||
<h2></h2>
|
||||
|
||||
<ul><li><p><strong>param</strong>: <em>String</em> file</p></li></ul>
|
||||
<ul><li><p><strong>param</strong>: <em>String</em> file</p></li><li><p><strong>param</strong>: <em>Function</em> fn</p></li></ul>
|
||||
</td>
|
||||
<td class="code">
|
||||
<pre><code><span class="keyword">function</span> <span class="variable">runFile</span>(<span class="variable">file</span>) {
|
||||
<pre><code><span class="keyword">function</span> <span class="variable">runFile</span>(<span class="variable">file</span>, <span class="variable">fn</span>) {
|
||||
<span class="keyword">if</span> (<span class="variable">file</span>.<span class="variable">match</span>(<span class="regexp">/\.js$/</span>)) {
|
||||
<span class="keyword">var</span> <span class="variable">title</span> = <span class="variable">path</span>.<span class="variable">basename</span>(<span class="variable">file</span>),
|
||||
<span class="variable">file</span> = <span class="variable">path</span>.<span class="variable">join</span>(<span class="variable">cwd</span>, <span class="variable">file</span>),
|
||||
@@ -821,7 +851,7 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
(<span class="keyword">function</span> <span class="variable">check</span>(){
|
||||
<span class="keyword">var</span> <span class="variable">len</span> = <span class="class">Object</span>.<span class="variable">keys</span>(<span class="variable">mod</span>).<span class="variable">length</span>;
|
||||
<span class="keyword">if</span> (<span class="variable">len</span>) {
|
||||
<span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">mod</span>);
|
||||
<span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">mod</span>, <span class="variable">fn</span>);
|
||||
} <span class="keyword">else</span> {
|
||||
<span class="variable">setTimeout</span>(<span class="variable">check</span>, <span class="number integer">20</span>);
|
||||
}
|
||||
@@ -904,15 +934,15 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
</tr>
|
||||
<tr class="code">
|
||||
<td class="docs">
|
||||
<p>Run the given tests.</p>
|
||||
<p>Run the given tests, callback <code>fn()</code> when finished.</p>
|
||||
|
||||
<h2></h2>
|
||||
|
||||
<ul><li><p><strong>param</strong>: <em>String</em> title</p></li><li><p><strong>param</strong>: <em>Object</em> tests</p></li></ul>
|
||||
<ul><li><p><strong>param</strong>: <em>String</em> title</p></li><li><p><strong>param</strong>: <em>Object</em> tests</p></li><li><p><strong>param</strong>: <em>Function</em> fn</p></li></ul>
|
||||
</td>
|
||||
<td class="code">
|
||||
<pre><code><span class="keyword">var</span> <span class="variable">dots</span> = <span class="number integer">0</span>;
|
||||
<span class="keyword">function</span> <span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">tests</span>) {
|
||||
<span class="keyword">function</span> <span class="variable">runSuite</span>(<span class="variable">title</span>, <span class="variable">tests</span>, <span class="variable">fn</span>) {
|
||||
<span class="comment">// Keys</span>
|
||||
<span class="keyword">var</span> <span class="variable">keys</span> = <span class="variable">only</span>.<span class="variable">length</span>
|
||||
? <span class="variable">only</span>.<span class="variable">slice</span>(<span class="number integer">0</span>)
|
||||
@@ -920,7 +950,7 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
|
||||
<span class="comment">// Setup</span>
|
||||
<span class="keyword">var</span> <span class="variable">setup</span> = <span class="variable">tests</span>.<span class="variable">setup</span> || <span class="keyword">function</span>(<span class="variable">fn</span>){ <span class="variable">fn</span>(); };
|
||||
|
||||
|
||||
<span class="comment">// Iterate tests</span>
|
||||
(<span class="keyword">function</span> <span class="variable">next</span>(){
|
||||
<span class="keyword">if</span> (<span class="variable">keys</span>.<span class="variable">length</span>) {
|
||||
@@ -940,21 +970,21 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
<span class="keyword">if</span> (++<span class="variable">dots</span> % <span class="number integer">25</span> === <span class="number integer">0</span>) <span class="variable">sys</span>.<span class="variable">print</span>(<span class="string">'\n'</span>);
|
||||
}
|
||||
<span class="variable">setup</span>(<span class="keyword">function</span>(){
|
||||
<span class="keyword">if</span> (<span class="variable">test</span>.<span class="variable">length</span> &<span class="variable">lt</span>; <span class="number integer">2</span>) {
|
||||
<span class="variable">test</span>(<span class="variable">assert</span>);
|
||||
<span class="keyword">if</span> (<span class="variable">test</span>.<span class="variable">length</span> &<span class="variable">lt</span>; <span class="number integer">1</span>) {
|
||||
<span class="variable">test</span>();
|
||||
<span class="variable">next</span>();
|
||||
} <span class="keyword">else</span> {
|
||||
<span class="keyword">var</span> <span class="variable">id</span> = <span class="variable">setTimeout</span>(<span class="keyword">function</span>(){
|
||||
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">Error</span>(&<span class="variable">quot</span>;<span class="string">'" + key + "'</span> <span class="variable">timed</span> <span class="variable">out</span>&<span class="variable">quot</span>;);
|
||||
}, <span class="number integer">2000</span>);
|
||||
<span class="variable">test</span>(<span class="variable">assert</span>, <span class="keyword">function</span>(){
|
||||
}, <span class="variable">timeout</span>);
|
||||
<span class="variable">test</span>(<span class="keyword">function</span>(){
|
||||
<span class="variable">clearTimeout</span>(<span class="variable">id</span>);
|
||||
<span class="variable">next</span>();
|
||||
});
|
||||
}
|
||||
});
|
||||
} <span class="keyword">else</span> {
|
||||
<span class="variable">test</span>(<span class="variable">assert</span>, <span class="keyword">function</span>(<span class="variable">fn</span>){
|
||||
<span class="variable">test</span>(<span class="keyword">function</span>(<span class="variable">fn</span>){
|
||||
<span class="variable">process</span>.<span class="variable">addListener</span>(<span class="string">'beforeExit'</span>, <span class="keyword">function</span>(){
|
||||
<span class="keyword">try</span> {
|
||||
<span class="variable">fn</span>();
|
||||
@@ -969,6 +999,8 @@ the given <code>req</code> object and <code>res</code> assertions object.</p>
|
||||
}
|
||||
}
|
||||
<span class="keyword">if</span> (!<span class="variable">serial</span>) <span class="variable">next</span>();
|
||||
} <span class="keyword">else</span> <span class="keyword">if</span> (<span class="variable">serial</span>) {
|
||||
<span class="variable">fn</span>();
|
||||
}
|
||||
})();
|
||||
}</code></pre>
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
<div id="wrapper">
|
||||
<h1>Expresso</h1>
|
||||
<div class='mp'>
|
||||
<h2 id="NAME">NAME</h2>
|
||||
<p class="man-name">
|
||||
<code>index</code>
|
||||
</p>
|
||||
<p><a href="http://github.com/visionmedia/expresso">Expresso</a> is a JavaScript <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> framework written for <a href="http://nodejs.org">nodejs</a>. Expresso is extremely fast, and is packed with features such as additional assertion methods, code coverage reporting, CI support, and more.</p>
|
||||
|
||||
<h2 id="Features">Features</h2>
|
||||
@@ -85,7 +89,7 @@ the command below, which will first compile node-jscoverage:</p>
|
||||
|
||||
<p>To define tests we simply export several functions:</p>
|
||||
|
||||
<pre><code>exports['test String#length'] = function(assert){
|
||||
<pre><code>exports['test String#length'] = function(){
|
||||
assert.equal(6, 'foobar'.length);
|
||||
};
|
||||
</code></pre>
|
||||
@@ -95,7 +99,7 @@ export your own object containing the tests, however this
|
||||
is essentially the as above:</p>
|
||||
|
||||
<pre><code>module.exports = {
|
||||
'test String#length': function(assert){
|
||||
'test String#length': function(){
|
||||
assert.equal(6, 'foobar'.length);
|
||||
}
|
||||
};
|
||||
@@ -103,16 +107,16 @@ is essentially the as above:</p>
|
||||
|
||||
<p>If you prefer not to use quoted keys:</p>
|
||||
|
||||
<pre><code>exports.testsStringLength = function(assert){
|
||||
<pre><code>exports.testsStringLength = function(){
|
||||
assert.equal(6, 'foobar'.length);
|
||||
};
|
||||
</code></pre>
|
||||
|
||||
<p>The second argument passed to each callback is <em>beforeExit</em>,
|
||||
<p>The argument passed to each callback is <em>beforeExit</em>,
|
||||
which is typically used to assert that callbacks have been
|
||||
invoked.</p>
|
||||
|
||||
<pre><code>exports.testAsync = function(assert, beforeExit){
|
||||
<pre><code>exports.testAsync = function(beforeExit){
|
||||
var n = 0;
|
||||
setTimeout(function(){
|
||||
++n;
|
||||
@@ -229,9 +233,9 @@ which is then used to perform several assertions
|
||||
on the response with the following properties:</p>
|
||||
|
||||
<ul>
|
||||
<li><em>body</em> assert response body</li>
|
||||
<li><em>body</em> assert response body (regexp or string)</li>
|
||||
<li><em>status</em> assert response status code</li>
|
||||
<li><em>header</em> assert that all given headers match (unspecified are ignored)</li>
|
||||
<li><em>header</em> assert that all given headers match (unspecified are ignored, use a regexp or string)</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -361,7 +365,7 @@ future <code>--cov</code> will most likely accept a path.</p>
|
||||
<p>Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the <em>exports.foo = function(){};</em> syntax is supported for this:</p>
|
||||
|
||||
<pre><code>setTimeout(function(){
|
||||
exports['test async exports'] = function(assert){
|
||||
exports['test async exports'] = function(){
|
||||
assert.ok('wahoo');
|
||||
};
|
||||
}, 100);
|
||||
|
||||
@@ -37,7 +37,7 @@ Install via npm:
|
||||
|
||||
To define tests we simply export several functions:
|
||||
|
||||
exports['test String#length'] = function(assert){
|
||||
exports['test String#length'] = function(){
|
||||
assert.equal(6, 'foobar'.length);
|
||||
};
|
||||
|
||||
@@ -46,22 +46,22 @@ export your own object containing the tests, however this
|
||||
is essentially the as above:
|
||||
|
||||
module.exports = {
|
||||
'test String#length': function(assert){
|
||||
'test String#length': function(){
|
||||
assert.equal(6, 'foobar'.length);
|
||||
}
|
||||
};
|
||||
|
||||
If you prefer not to use quoted keys:
|
||||
|
||||
exports.testsStringLength = function(assert){
|
||||
exports.testsStringLength = function(){
|
||||
assert.equal(6, 'foobar'.length);
|
||||
};
|
||||
|
||||
The second argument passed to each callback is _beforeExit_,
|
||||
The argument passed to each callback is _beforeExit_,
|
||||
which is typically used to assert that callbacks have been
|
||||
invoked.
|
||||
|
||||
exports.testAsync = function(assert, beforeExit){
|
||||
exports.testAsync = function(beforeExit){
|
||||
var n = 0;
|
||||
setTimeout(function(){
|
||||
++n;
|
||||
@@ -164,9 +164,9 @@ receives the response for assertions, or an object
|
||||
which is then used to perform several assertions
|
||||
on the response with the following properties:
|
||||
|
||||
- _body_ assert response body
|
||||
- _body_ assert response body (regexp or string)
|
||||
- _status_ assert response status code
|
||||
- _header_ assert that all given headers match (unspecified are ignored)
|
||||
- _header_ assert that all given headers match (unspecified are ignored, use a regexp or string)
|
||||
|
||||
When providing _res_ you may then also pass a callback function
|
||||
as the fourth argument for additional assertions.
|
||||
@@ -284,7 +284,7 @@ future `--cov` will most likely accept a path.
|
||||
Sometimes it is useful to postpone running of tests until a callback or event has fired, currently the _exports.foo = function(){};_ syntax is supported for this:
|
||||
|
||||
setTimeout(function(){
|
||||
exports['test async exports'] = function(assert){
|
||||
exports['test async exports'] = function(){
|
||||
assert.ok('wahoo');
|
||||
};
|
||||
}, 100);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{ "name": "expresso",
|
||||
"version": "0.6.2",
|
||||
"version": "0.7.2",
|
||||
"description": "TDD framework, light-weight, fast, CI-friendly",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"bin": {
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
module.exports = {
|
||||
'assert.eql()': function(assert){
|
||||
'assert.eql()': function(){
|
||||
assert.equal(assert.deepEqual, assert.eql);
|
||||
},
|
||||
|
||||
'assert.type()': function(assert){
|
||||
'assert.type()': function(){
|
||||
assert.type('foobar', 'string');
|
||||
assert.type(2, 'number');
|
||||
assert.throws(function(){
|
||||
@@ -11,7 +18,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'assert.includes()': function(assert){
|
||||
'assert.includes()': function(){
|
||||
assert.includes('some random string', 'dom');
|
||||
assert.throws(function(){
|
||||
assert.include('some random string', 'foobar');
|
||||
@@ -31,7 +38,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'assert.isNull()': function(assert){
|
||||
'assert.isNull()': function(){
|
||||
assert.isNull(null);
|
||||
assert.throws(function(){
|
||||
assert.isNull(undefined);
|
||||
@@ -41,7 +48,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'assert.isUndefined()': function(assert){
|
||||
'assert.isUndefined()': function(){
|
||||
assert.isUndefined(undefined);
|
||||
assert.throws(function(){
|
||||
assert.isUndefined(null);
|
||||
@@ -51,7 +58,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'assert.isNotNull()': function(assert){
|
||||
'assert.isNotNull()': function(){
|
||||
assert.isNotNull(false);
|
||||
assert.isNotNull(undefined);
|
||||
assert.throws(function(){
|
||||
@@ -59,7 +66,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'assert.isDefined()': function(assert){
|
||||
'assert.isDefined()': function(){
|
||||
assert.isDefined(false);
|
||||
assert.isDefined(null);
|
||||
assert.throws(function(){
|
||||
@@ -67,14 +74,14 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'assert.match()': function(assert){
|
||||
'assert.match()': function(){
|
||||
assert.match('foobar', /foo(bar)?/);
|
||||
assert.throws(function(){
|
||||
assert.match('something', /rawr/);
|
||||
});
|
||||
},
|
||||
|
||||
'assert.length()': function(assert){
|
||||
'assert.length()': function(){
|
||||
assert.length('test', 4);
|
||||
assert.length([1,2,3,4], 4);
|
||||
assert.throws(function(){
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var assert = require('assert');
|
||||
|
||||
setTimeout(function(){
|
||||
exports['test async exports'] = function(assert){
|
||||
exports['test async exports'] = function(){
|
||||
assert.ok('wahoo');
|
||||
};
|
||||
}, 100);
|
||||
@@ -3,10 +3,11 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var bar = require('bar');
|
||||
var assert = require('assert')
|
||||
, bar = require('bar');
|
||||
|
||||
module.exports = {
|
||||
'bar()': function(assert){
|
||||
'bar()': function(){
|
||||
assert.equal('bar', bar.bar());
|
||||
}
|
||||
};
|
||||
@@ -3,10 +3,11 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var foo = require('foo');
|
||||
var assert = require('assert')
|
||||
, foo = require('foo');
|
||||
|
||||
module.exports = {
|
||||
'foo()': function(assert){
|
||||
'foo()': function(){
|
||||
assert.equal('foo', foo.foo());
|
||||
assert.equal('foo', foo.foo());
|
||||
}
|
||||
|
||||
@@ -3,80 +3,144 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http');
|
||||
var assert = require('assert')
|
||||
, http = require('http');
|
||||
|
||||
var server = http.createServer(function(req, res){
|
||||
if (req.method === 'GET') {
|
||||
if (req.url === '/delay') {
|
||||
setTimeout(function(){
|
||||
res.writeHead(200, {});
|
||||
res.end('delayed');
|
||||
}, 200);
|
||||
} else {
|
||||
var body = JSON.stringify({ name: 'tj' });
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/json; charset=utf8',
|
||||
'Content-Length': body.length
|
||||
});
|
||||
res.end(body);
|
||||
}
|
||||
if (req.method === 'GET') {
|
||||
if (req.url === '/delay') {
|
||||
setTimeout(function(){
|
||||
res.writeHead(200, {});
|
||||
res.end('delayed');
|
||||
}, 200);
|
||||
} else {
|
||||
var body = '';
|
||||
req.setEncoding('utf8');
|
||||
req.addListener('data', function(chunk){ body += chunk });
|
||||
req.addListener('end', function(){
|
||||
res.writeHead(200, {});
|
||||
res.end(req.url + ' ' + body);
|
||||
});
|
||||
var body = JSON.stringify({ name: 'tj' });
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'application/json; charset=utf8',
|
||||
'Content-Length': body.length
|
||||
});
|
||||
res.end(body);
|
||||
}
|
||||
} else {
|
||||
var body = '';
|
||||
req.setEncoding('utf8');
|
||||
req.on('data', function(chunk){ body += chunk });
|
||||
req.on('end', function(){
|
||||
res.writeHead(200, {});
|
||||
res.end(req.url + ' ' + body);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
'test assert.response()': function(assert, beforeExit){
|
||||
var called = 0;
|
||||
var delayedServer = http.createServer(function(req, res){
|
||||
res.writeHead(200);
|
||||
res.end('it worked');
|
||||
});
|
||||
|
||||
assert.response(server, {
|
||||
url: '/',
|
||||
method: 'GET'
|
||||
},{
|
||||
body: '{"name":"tj"}',
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf8'
|
||||
}
|
||||
});
|
||||
|
||||
assert.response(server, {
|
||||
url: '/foo',
|
||||
method: 'POST',
|
||||
data: 'bar baz'
|
||||
},{
|
||||
body: '/foo bar baz',
|
||||
status: 200
|
||||
}, function(res){
|
||||
++called;
|
||||
assert.ok(res);
|
||||
});
|
||||
|
||||
assert.response(server, {
|
||||
url: '/foo'
|
||||
}, function(res){
|
||||
++called;
|
||||
assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
|
||||
});
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/delay', timeout: 300 },
|
||||
{ body: 'delayed' });
|
||||
|
||||
beforeExit(function(){
|
||||
assert.equal(2, called);
|
||||
});
|
||||
},
|
||||
var oldListen = delayedServer.listen;
|
||||
delayedServer.listen = function(){
|
||||
var args = arguments;
|
||||
setTimeout(function(){
|
||||
oldListen.apply(delayedServer, args);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
'test assert.response(req, res, fn)': function(beforeExit){
|
||||
var calls = 0;
|
||||
|
||||
assert.response(server, {
|
||||
url: '/',
|
||||
method: 'GET'
|
||||
},{
|
||||
body: '{"name":"tj"}',
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf8'
|
||||
}
|
||||
}, function(res){
|
||||
++calls;
|
||||
assert.ok(res);
|
||||
});
|
||||
|
||||
'test assert.response() regexp': function(assert){
|
||||
assert.response(server,
|
||||
{ url: '/foo', method: 'POST', data: 'foobar' },
|
||||
{ body: /^\/foo foo(bar)?/ });
|
||||
}
|
||||
};
|
||||
beforeExit(function(){
|
||||
assert.equal(1, calls);
|
||||
})
|
||||
},
|
||||
|
||||
'test assert.response(req, fn)': function(beforeExit){
|
||||
var calls = 0;
|
||||
|
||||
assert.response(server, {
|
||||
url: '/foo'
|
||||
}, function(res){
|
||||
++calls;
|
||||
assert.ok(res.body.indexOf('tj') >= 0, 'Test assert.response() callback');
|
||||
});
|
||||
|
||||
beforeExit(function(){
|
||||
assert.equal(1, calls);
|
||||
});
|
||||
},
|
||||
|
||||
'test assert.response() delay': function(beforeExit){
|
||||
var calls = 0;
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/delay', timeout: 1500 },
|
||||
{ body: 'delayed' },
|
||||
function(){
|
||||
++calls;
|
||||
});
|
||||
|
||||
beforeExit(function(){
|
||||
assert.equal(1, calls);
|
||||
});
|
||||
},
|
||||
|
||||
'test assert.response() regexp': function(beforeExit){
|
||||
var calls = 0;
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/foo', method: 'POST', data: 'foobar' },
|
||||
{ body: /^\/foo foo(bar)?/ },
|
||||
function(){
|
||||
++calls;
|
||||
});
|
||||
|
||||
beforeExit(function(){
|
||||
assert.equal(1, calls);
|
||||
});
|
||||
},
|
||||
|
||||
'test assert.response() regexp headers': function(beforeExit){
|
||||
var calls = 0;
|
||||
|
||||
assert.response(server,
|
||||
{ url: '/' },
|
||||
{ body: '{"name":"tj"}', headers: { 'Content-Type': /^application\/json/ } },
|
||||
function(){
|
||||
++calls;
|
||||
});
|
||||
|
||||
beforeExit(function(){
|
||||
assert.equal(1, calls);
|
||||
});
|
||||
},
|
||||
|
||||
// [!] if this test doesn't pass, an uncaught ECONNREFUSED will display
|
||||
'test assert.response() with deferred listen()': function(beforeExit){
|
||||
var calls = 0;
|
||||
|
||||
assert.response(delayedServer,
|
||||
{ url: '/' },
|
||||
{ body: 'it worked' },
|
||||
function(){
|
||||
++calls;
|
||||
});
|
||||
|
||||
beforeExit(function(){
|
||||
assert.equal(1, calls);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
var setup = 0,
|
||||
order = [];
|
||||
var assert = require('assert')
|
||||
, setup = 0
|
||||
, order = [];
|
||||
|
||||
module.exports = {
|
||||
setup: function(done){
|
||||
@@ -8,7 +9,7 @@ module.exports = {
|
||||
done();
|
||||
},
|
||||
|
||||
a: function(assert, done){
|
||||
a: function(done){
|
||||
assert.equal(1, setup);
|
||||
order.push('a');
|
||||
setTimeout(function(){
|
||||
@@ -16,7 +17,7 @@ module.exports = {
|
||||
}, 500);
|
||||
},
|
||||
|
||||
b: function(assert, done){
|
||||
b: function(done){
|
||||
assert.equal(2, setup);
|
||||
order.push('b');
|
||||
setTimeout(function(){
|
||||
@@ -24,7 +25,7 @@ module.exports = {
|
||||
}, 200);
|
||||
},
|
||||
|
||||
c: function(assert, done){
|
||||
c: function(done){
|
||||
assert.equal(3, setup);
|
||||
order.push('c');
|
||||
setTimeout(function(){
|
||||
@@ -32,7 +33,7 @@ module.exports = {
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
d: function(assert){
|
||||
d: function(){
|
||||
assert.eql(order, ['a', 'b', 'c']);
|
||||
}
|
||||
};
|
||||
@@ -3,7 +3,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http');
|
||||
var assert = require('assert')
|
||||
, http = require('http');
|
||||
|
||||
var server = http.createServer(function(req, res){
|
||||
if (req.method === 'GET') {
|
||||
@@ -32,7 +33,7 @@ var server = http.createServer(function(req, res){
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
'test assert.response()': function(assert, done){
|
||||
'test assert.response()': function(done){
|
||||
assert.response(server, {
|
||||
url: '/',
|
||||
method: 'GET'
|
||||
|
||||
3
support/socket.io-client/.gitmodules
vendored
3
support/socket.io-client/.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "lib/vendor/web-socket-js"]
|
||||
path = lib/vendor/web-socket-js
|
||||
url = git://github.com/gimite/web-socket-js.git
|
||||
@@ -46,14 +46,6 @@ The `socket.io` client is basically a simple HTTP Socket interface implementatio
|
||||
- Easy to use! See [socket.io-node](http://github.com/LearnBoost/Socket.IO-node) for the server to connect to.
|
||||
|
||||
### How to use
|
||||
|
||||
The recommended way of including the Socket.IO client is through the Socket.IO CDN:
|
||||
|
||||
In your <head>
|
||||
|
||||
<script src="http://cdn.socket.io/stable/socket.io.js"></script>
|
||||
|
||||
Then, in your code
|
||||
|
||||
socket = new io.Socket('localhost');
|
||||
socket.connect();
|
||||
@@ -163,6 +155,17 @@ Events:
|
||||
|
||||
Fired when the connection is established and the handshake successful
|
||||
|
||||
- *connecting(transport_type)*
|
||||
|
||||
Fired when a connection is attempted, passing the transport name
|
||||
|
||||
- *connect_failed*
|
||||
|
||||
Fired when the connection timeout occurs after the last connection attempt.
|
||||
This only fires if the `connectTimeout` option is set.
|
||||
If the `tryTransportsOnConnectTimeout` option is set, this only fires once all
|
||||
possible transports have been tried.
|
||||
|
||||
- *message(message)*
|
||||
|
||||
Fired when a message arrives from the server
|
||||
@@ -175,14 +178,6 @@ Events:
|
||||
|
||||
Fired when the connection is considered disconnected.
|
||||
|
||||
### Changelog
|
||||
|
||||
2010 08 02 - **0.5.4** (9.95KB)
|
||||
|
||||
* Added io.util.load as a reusable onload handler
|
||||
* Added io.util.ios which reports if the UA is running on iPhone or iPad
|
||||
* No more loading bar on iPhone: XHR-Polling now connects `onload` for the iOS WebKit, and waits 10 ms to launch the initial connection.
|
||||
|
||||
### Credits
|
||||
|
||||
Guillermo Rauch <guillermo@learnboost.com>
|
||||
@@ -210,4 +205,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
this.io = {
|
||||
version: '0.6.1',
|
||||
version: '0.6.2',
|
||||
|
||||
setPath: function(path){
|
||||
if (window.console && console.error) console.error('io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf');
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
if (this.transport && !this.connected){
|
||||
if (this.connecting) this.disconnect();
|
||||
this.connecting = true;
|
||||
this.emit('connecting', [this.transport.type]);
|
||||
this.transport.connect();
|
||||
if (this.options.connectTimeout){
|
||||
var self = this;
|
||||
@@ -66,16 +67,17 @@
|
||||
if (!self.connected){
|
||||
self.disconnect();
|
||||
if (self.options.tryTransportsOnConnectTimeout && !self._rememberedTransport){
|
||||
var remainingTransports = [], transports = self.options.transports;
|
||||
for (var i = 0, transport; transport = transports[i]; i++){
|
||||
if (transport != self.transport.type) remainingTransports.push(transport);
|
||||
}
|
||||
if (remainingTransports.length){
|
||||
self.transport = self.getTransport(remainingTransports);
|
||||
if(!self._remainingTransports) self._remainingTransports = self.options.transports.slice(0);
|
||||
var transports = self._remainingTransports;
|
||||
while(transports.length > 0 && transports.splice(0,1)[0] != self.transport.type){}
|
||||
if(transports.length){
|
||||
self.transport = self.getTransport(transports);
|
||||
self.connect();
|
||||
}
|
||||
}
|
||||
if(!self._remainingTransports || self._remainingTransports.length == 0) self.emit('connect_failed');
|
||||
}
|
||||
if(self._remainingTransports && self._remainingTransports.length == 0) delete self._remainingTransports;
|
||||
}, this.options.connectTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
var self = this;
|
||||
this._xhr = this._request('', 'GET', true);
|
||||
this._xhr.onreadystatechange = function(){
|
||||
if (self._xhr.readyState == 3) self._onData(self._xhr.responseText);
|
||||
if (self._xhr.readyState == 4) self._onData(self._xhr.responseText);
|
||||
};
|
||||
this._xhr.send(null);
|
||||
};
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -22,11 +22,7 @@ import com.hurlant.crypto.tls.TLSEngine;
|
||||
import com.hurlant.crypto.tls.TLSSecurityParameters;
|
||||
import com.gsolo.encryption.MD5;
|
||||
|
||||
[Event(name="message", type="flash.events.Event")]
|
||||
[Event(name="open", type="flash.events.Event")]
|
||||
[Event(name="close", type="flash.events.Event")]
|
||||
[Event(name="error", type="flash.events.Event")]
|
||||
[Event(name="stateChange", type="WebSocketStateEvent")]
|
||||
[Event(name="event", type="flash.events.Event")]
|
||||
public class WebSocket extends EventDispatcher {
|
||||
|
||||
private static var CONNECTING:int = 0;
|
||||
@@ -47,10 +43,9 @@ public class WebSocket extends EventDispatcher {
|
||||
private var origin:String;
|
||||
private var protocol:String;
|
||||
private var buffer:ByteArray = new ByteArray();
|
||||
private var dataQueue:Array;
|
||||
private var eventQueue:Array = [];
|
||||
private var headerState:int = 0;
|
||||
private var readyState:int = CONNECTING;
|
||||
private var bufferedAmount:int = 0;
|
||||
private var headers:String;
|
||||
private var noiseChars:Array;
|
||||
private var expectedDigest:String;
|
||||
@@ -115,23 +110,19 @@ public class WebSocket extends EventDispatcher {
|
||||
socket.flush();
|
||||
main.log("sent: " + data);
|
||||
return -1;
|
||||
} else if (readyState == CLOSED) {
|
||||
} else if (readyState == CLOSING || readyState == CLOSED) {
|
||||
var bytes:ByteArray = new ByteArray();
|
||||
bytes.writeUTFBytes(data);
|
||||
bufferedAmount += bytes.length; // not sure whether it should include \x00 and \xff
|
||||
// We use return value to let caller know bufferedAmount because we cannot fire
|
||||
// stateChange event here which causes weird error:
|
||||
// > You are trying to call recursively into the Flash Player which is not allowed.
|
||||
return bufferedAmount;
|
||||
return bytes.length; // not sure whether it should include \x00 and \xff
|
||||
} else {
|
||||
main.fatal("INVALID_STATE_ERR: invalid state");
|
||||
main.fatal("invalid state");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public function close():void {
|
||||
main.log("close");
|
||||
dataQueue = [];
|
||||
eventQueue = [];
|
||||
try {
|
||||
if (readyState == OPEN) {
|
||||
socket.writeByte(0xff);
|
||||
@@ -146,14 +137,6 @@ public class WebSocket extends EventDispatcher {
|
||||
// We do something equivalent in JavaScript WebSocket#close instead.
|
||||
}
|
||||
|
||||
public function getReadyState():int {
|
||||
return readyState;
|
||||
}
|
||||
|
||||
public function getBufferedAmount():int {
|
||||
return bufferedAmount;
|
||||
}
|
||||
|
||||
private function onSocketConnect(event:Event):void {
|
||||
main.log("connected");
|
||||
|
||||
@@ -162,7 +145,6 @@ public class WebSocket extends EventDispatcher {
|
||||
tlsSocket.startTLS(rawSocket, host, tlsConfig);
|
||||
}
|
||||
|
||||
dataQueue = [];
|
||||
var hostValue:String = host + (port == 80 ? "" : ":" + port);
|
||||
var cookie:String = "";
|
||||
if (main.getCallerHost() == host) {
|
||||
@@ -199,8 +181,7 @@ public class WebSocket extends EventDispatcher {
|
||||
private function onSocketClose(event:Event):void {
|
||||
main.log("closed");
|
||||
readyState = CLOSED;
|
||||
notifyStateChange();
|
||||
dispatchEvent(new Event("close"));
|
||||
fireEvent({type: "close"}, true);
|
||||
}
|
||||
|
||||
private function onSocketIoError(event:IOErrorEvent):void {
|
||||
@@ -230,8 +211,7 @@ public class WebSocket extends EventDispatcher {
|
||||
if (state == CLOSED) return;
|
||||
main.error(message);
|
||||
close();
|
||||
notifyStateChange();
|
||||
dispatchEvent(new Event(state == CONNECTING ? "close" : "error"));
|
||||
fireEvent({type: state == CONNECTING ? "close" : "error"}, true);
|
||||
}
|
||||
|
||||
private function onSocketData(event:ProgressEvent):void {
|
||||
@@ -248,8 +228,7 @@ public class WebSocket extends EventDispatcher {
|
||||
headerState = 0;
|
||||
}
|
||||
if (headerState == 4) {
|
||||
buffer.position = 0;
|
||||
var headerStr:String = buffer.readUTFBytes(pos + 1);
|
||||
var headerStr:String = readUTFBytes(buffer, 0, pos + 1);
|
||||
main.log("response header:\n" + headerStr);
|
||||
if (!validateHeader(headerStr)) return;
|
||||
removeBufferBefore(pos + 1);
|
||||
@@ -257,8 +236,7 @@ public class WebSocket extends EventDispatcher {
|
||||
}
|
||||
} else if (headerState == 4) {
|
||||
if (pos == 15) {
|
||||
buffer.position = 0;
|
||||
var replyDigest:String = readBytes(buffer, 16);
|
||||
var replyDigest:String = readBytes(buffer, 0, 16);
|
||||
main.log("reply digest: " + replyDigest);
|
||||
if (replyDigest != expectedDigest) {
|
||||
onError("digest doesn't match: " + replyDigest + " != " + expectedDigest);
|
||||
@@ -268,8 +246,7 @@ public class WebSocket extends EventDispatcher {
|
||||
removeBufferBefore(pos + 1);
|
||||
pos = -1;
|
||||
readyState = OPEN;
|
||||
notifyStateChange();
|
||||
dispatchEvent(new Event("open"));
|
||||
fireEvent({type: "open"}, true);
|
||||
}
|
||||
} else {
|
||||
if (buffer[pos] == 0xff && pos > 0) {
|
||||
@@ -277,11 +254,9 @@ public class WebSocket extends EventDispatcher {
|
||||
onError("data must start with \\x00");
|
||||
return;
|
||||
}
|
||||
buffer.position = 1;
|
||||
var data:String = buffer.readUTFBytes(pos - 1);
|
||||
var data:String = readUTFBytes(buffer, 1, pos - 1);
|
||||
main.log("received: " + data);
|
||||
dataQueue.push(encodeURIComponent(data));
|
||||
dispatchEvent(new Event("message"));
|
||||
fireEvent({type: "message", data: encodeURIComponent(data)}, false);
|
||||
removeBufferBefore(pos + 1);
|
||||
pos = -1;
|
||||
} else if (pos == 1 && buffer[0] == 0xff && buffer[1] == 0x00) { // closing
|
||||
@@ -289,18 +264,15 @@ public class WebSocket extends EventDispatcher {
|
||||
removeBufferBefore(pos + 1);
|
||||
pos = -1;
|
||||
close();
|
||||
notifyStateChange();
|
||||
dispatchEvent(new Event("close"));
|
||||
fireEvent({type: "close"}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function readSocketData():Array {
|
||||
var q:Array = dataQueue;
|
||||
if (dataQueue.length > 0) {
|
||||
dataQueue = [];
|
||||
}
|
||||
public function receiveEvents():Array {
|
||||
var q:Array = eventQueue;
|
||||
eventQueue = [];
|
||||
return q;
|
||||
}
|
||||
|
||||
@@ -363,8 +335,12 @@ public class WebSocket extends EventDispatcher {
|
||||
buffer = nextBuffer;
|
||||
}
|
||||
|
||||
private function notifyStateChange():void {
|
||||
dispatchEvent(new WebSocketStateEvent("stateChange", readyState, bufferedAmount));
|
||||
private function fireEvent(event:Object, stateChanged:Boolean):void {
|
||||
if (stateChanged) {
|
||||
event.readyState = readyState;
|
||||
}
|
||||
eventQueue.push(event);
|
||||
dispatchEvent(new Event("event"));
|
||||
}
|
||||
|
||||
private function initNoiseChars():void {
|
||||
@@ -434,7 +410,8 @@ public class WebSocket extends EventDispatcher {
|
||||
|
||||
// Reads specified number of bytes from buffer, and returns it as special format String
|
||||
// where bytes[i] is i-th byte (not i-th character).
|
||||
private function readBytes(buffer:ByteArray, numBytes:int):String {
|
||||
private function readBytes(buffer:ByteArray, start:int, numBytes:int):String {
|
||||
buffer.position = start;
|
||||
var bytes:String = "";
|
||||
for (var i:int = 0; i < numBytes; ++i) {
|
||||
// & 0xff is to make \x80-\xff positive number.
|
||||
@@ -443,6 +420,20 @@ public class WebSocket extends EventDispatcher {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private function readUTFBytes(buffer:ByteArray, start:int, numBytes:int):String {
|
||||
buffer.position = start;
|
||||
var data:String = "";
|
||||
for(var i:int = start; i < start + numBytes; ++i) {
|
||||
// Workaround of a bug of ByteArray#readUTFBytes() that bytes after "\x00" is discarded.
|
||||
if (buffer[i] == 0x00) {
|
||||
data += buffer.readUTFBytes(i - buffer.position) + "\x00";
|
||||
buffer.position = i + 1;
|
||||
}
|
||||
}
|
||||
data += buffer.readUTFBytes(start + numBytes - buffer.position);
|
||||
return data;
|
||||
}
|
||||
|
||||
private function randomInt(min:uint, max:uint):uint {
|
||||
return min + Math.floor(Math.random() * (Number(max) - min + 1));
|
||||
}
|
||||
|
||||
@@ -19,24 +19,14 @@ import bridge.FABridge;
|
||||
|
||||
public class WebSocketMain extends Sprite {
|
||||
|
||||
private var policyLoaded:Boolean = false;
|
||||
private var callerUrl:String;
|
||||
private var debug:Boolean = false;
|
||||
private var manualPolicyFileLoaded:Boolean = false;
|
||||
|
||||
public function WebSocketMain() {
|
||||
|
||||
// This is to avoid "You are trying to call recursively into the Flash Player ..."
|
||||
// error which (I heard) happens when you pass bunch of messages.
|
||||
// This workaround was written here:
|
||||
// http://www.themorphicgroup.com/blog/2009/02/14/fabridge-error-you-are-trying-to-call-recursively-into-the-flash-player-which-is-not-allowed/
|
||||
FABridge.EventsToCallLater["flash.events::Event"] = "true";
|
||||
FABridge.EventsToCallLater["WebSocketMessageEvent"] = "true";
|
||||
FABridge.EventsToCallLater["WebSocketStateEvent"] = "true";
|
||||
|
||||
var fab:FABridge = new FABridge();
|
||||
fab.rootObject = this;
|
||||
//log("Flash initialized");
|
||||
|
||||
}
|
||||
|
||||
public function setCallerUrl(url:String):void {
|
||||
@@ -51,7 +41,9 @@ public class WebSocketMain extends Sprite {
|
||||
url:String, protocol:String,
|
||||
proxyHost:String = null, proxyPort:int = 0,
|
||||
headers:String = null):WebSocket {
|
||||
loadPolicyFile(null);
|
||||
if (!manualPolicyFileLoaded) {
|
||||
loadDefaultPolicyFile(url);
|
||||
}
|
||||
return new WebSocket(this, url, protocol, proxyHost, proxyPort, headers);
|
||||
}
|
||||
|
||||
@@ -64,14 +56,16 @@ public class WebSocketMain extends Sprite {
|
||||
return URLUtil.getServerName(this.callerUrl);
|
||||
}
|
||||
|
||||
public function loadPolicyFile(url:String):void {
|
||||
if (policyLoaded && !url) return;
|
||||
if (!url) {
|
||||
url = "xmlsocket://" + URLUtil.getServerName(this.callerUrl) + ":843";
|
||||
}
|
||||
log("policy file: " + url);
|
||||
Security.loadPolicyFile(url);
|
||||
policyLoaded = true;
|
||||
private function loadDefaultPolicyFile(wsUrl:String):void {
|
||||
var policyUrl:String = "xmlsocket://" + URLUtil.getServerName(wsUrl) + ":843";
|
||||
log("policy file: " + policyUrl);
|
||||
Security.loadPolicyFile(policyUrl);
|
||||
}
|
||||
|
||||
public function loadManualPolicyFile(policyUrl:String):void {
|
||||
log("policy file: " + policyUrl);
|
||||
Security.loadPolicyFile(policyUrl);
|
||||
manualPolicyFileLoaded = true;
|
||||
}
|
||||
|
||||
public function log(message:String):void {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
|
||||
// License: New BSD License
|
||||
// Reference: http://dev.w3.org/html5/websockets/
|
||||
// Reference: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-31
|
||||
|
||||
package {
|
||||
|
||||
import flash.display.*;
|
||||
import flash.events.*;
|
||||
import flash.external.*;
|
||||
import flash.net.*;
|
||||
import flash.system.*;
|
||||
import flash.utils.*;
|
||||
import mx.core.*;
|
||||
import mx.controls.*;
|
||||
import mx.events.*;
|
||||
import mx.utils.*;
|
||||
|
||||
public class WebSocketStateEvent extends Event {
|
||||
|
||||
public var readyState:int;
|
||||
public var bufferedAmount:int;
|
||||
|
||||
public function WebSocketStateEvent(type:String, readyState:int, bufferedAmount:int) {
|
||||
super(type);
|
||||
this.readyState = readyState;
|
||||
this.bufferedAmount = bufferedAmount;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,8 +8,10 @@
|
||||
if (window.WebSocket) return;
|
||||
|
||||
var console = window.console;
|
||||
if (!console) console = {log: function(){ }, error: function(){ }};
|
||||
|
||||
if (!console || !console.log || !console.error) {
|
||||
console = {log: function(){ }, error: function(){ }};
|
||||
}
|
||||
|
||||
if (!swfobject.hasFlashPlayerVersion("9.0.0")) {
|
||||
console.error("Flash Player is not installed.");
|
||||
return;
|
||||
@@ -31,73 +33,22 @@
|
||||
WebSocket.__addTask(function() {
|
||||
self.__createFlash(url, protocol, proxyHost, proxyPort, headers);
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
WebSocket.prototype.__createFlash = function(url, protocol, proxyHost, proxyPort, headers) {
|
||||
var self = this;
|
||||
self.__flash =
|
||||
WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
|
||||
|
||||
self.__flash.addEventListener("open", function(fe) {
|
||||
try {
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
if (self.__timer) clearInterval(self.__timer);
|
||||
if (window.opera) {
|
||||
// Workaround for weird behavior of Opera which sometimes drops events.
|
||||
self.__timer = setInterval(function () {
|
||||
self.__handleMessages();
|
||||
}, 500);
|
||||
}
|
||||
if (self.onopen) self.onopen();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
self.__flash.addEventListener("event", function(fe) {
|
||||
// Uses setTimeout() to workaround the error:
|
||||
// > You are trying to call recursively into the Flash Player which is not allowed.
|
||||
setTimeout(function() { self.__handleEvents(); }, 0);
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("close", function(fe) {
|
||||
try {
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
if (self.__timer) clearInterval(self.__timer);
|
||||
if (self.onclose) self.onclose();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("message", function() {
|
||||
try {
|
||||
self.__handleMessages();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("error", function(fe) {
|
||||
try {
|
||||
if (self.__timer) clearInterval(self.__timer);
|
||||
if (self.onerror) self.onerror();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("stateChange", function(fe) {
|
||||
try {
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
self.bufferedAmount = fe.getBufferedAmount();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
//console.log("[WebSocket] Flash object is ready");
|
||||
};
|
||||
|
||||
WebSocket.prototype.send = function(data) {
|
||||
if (this.__flash) {
|
||||
this.readyState = this.__flash.getReadyState();
|
||||
}
|
||||
if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
|
||||
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
|
||||
}
|
||||
@@ -111,7 +62,7 @@
|
||||
if (result < 0) { // success
|
||||
return true;
|
||||
} else {
|
||||
this.bufferedAmount = result;
|
||||
this.bufferedAmount += result;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -119,7 +70,6 @@
|
||||
WebSocket.prototype.close = function() {
|
||||
var self = this;
|
||||
if (!self.__flash) return;
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
if (self.readyState == WebSocket.CLOSED || self.readyState == WebSocket.CLOSING) return;
|
||||
self.__flash.close();
|
||||
// Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
|
||||
@@ -130,7 +80,7 @@
|
||||
if (self.onclose) {
|
||||
// Make it asynchronous so that it looks more like an actual
|
||||
// close event
|
||||
setTimeout(self.onclose, 1);
|
||||
setTimeout(self.onclose, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -199,30 +149,62 @@
|
||||
}
|
||||
};
|
||||
|
||||
WebSocket.prototype.__handleMessages = function() {
|
||||
// Gets data using readSocketData() instead of getting it from event object
|
||||
WebSocket.prototype.__handleEvents = function() {
|
||||
// Gets events using receiveEvents() instead of getting it from event object
|
||||
// of Flash event. This is to make sure to keep message order.
|
||||
// It seems sometimes Flash events don't arrive in the same order as they are sent.
|
||||
var arr = this.__flash.readSocketData();
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var data = decodeURIComponent(arr[i]);
|
||||
var events = this.__flash.receiveEvents();
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
try {
|
||||
if (this.onmessage) {
|
||||
var e;
|
||||
if (window.MessageEvent) {
|
||||
e = document.createEvent("MessageEvent");
|
||||
e.initMessageEvent("message", false, false, data, null, null, window, null);
|
||||
} else { // IE
|
||||
e = {data: data};
|
||||
var event = events[i];
|
||||
if ("readyState" in event) {
|
||||
this.readyState = event.readyState;
|
||||
}
|
||||
if (event.type == "open") {
|
||||
|
||||
if (this.__timer) clearInterval(this.__timer);
|
||||
if (window.opera) {
|
||||
// Workaround for weird behavior of Opera which sometimes drops events.
|
||||
this.__timer = setInterval(function () {
|
||||
this.__handleEvents();
|
||||
}, 500);
|
||||
}
|
||||
this.onmessage(e);
|
||||
if (this.onopen) this.onopen();
|
||||
|
||||
} else if (event.type == "close") {
|
||||
|
||||
if (this.__timer) clearInterval(this.__timer);
|
||||
if (this.onclose) this.onclose();
|
||||
|
||||
} else if (event.type == "message") {
|
||||
|
||||
if (this.onmessage) {
|
||||
var data = decodeURIComponent(event.data);
|
||||
var e;
|
||||
if (window.MessageEvent && !window.opera) {
|
||||
e = document.createEvent("MessageEvent");
|
||||
e.initMessageEvent("message", false, false, data, null, null, window, null);
|
||||
} else {
|
||||
// IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
|
||||
e = {data: data};
|
||||
}
|
||||
this.onmessage(e);
|
||||
}
|
||||
|
||||
} else if (event.type == "error") {
|
||||
|
||||
if (this.__timer) clearInterval(this.__timer);
|
||||
if (this.onerror) this.onerror();
|
||||
|
||||
} else {
|
||||
throw "unknown event type: " + event.type;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {object} object
|
||||
* @param {string} type
|
||||
@@ -237,7 +219,7 @@
|
||||
}
|
||||
object.dispatchEvent(event, arguments);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
|
||||
@@ -298,6 +280,12 @@
|
||||
|
||||
WebSocket.__tasks = [];
|
||||
|
||||
WebSocket.loadFlashPolicyFile = function(url) {
|
||||
WebSocket.__addTask(function() {
|
||||
WebSocket.__flash.loadManualPolicyFile(url);
|
||||
});
|
||||
}
|
||||
|
||||
WebSocket.__initialize = function() {
|
||||
if (WebSocket.__swfLocation) {
|
||||
// For backword compatibility.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/** Socket.IO 0.6.1 - Built with build.js */
|
||||
/** Socket.IO 0.6.2 - Built with build.js */
|
||||
/**
|
||||
* Socket.IO client
|
||||
*
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
this.io = {
|
||||
version: '0.6.1',
|
||||
version: '0.6.2',
|
||||
|
||||
setPath: function(path){
|
||||
if (window.console && console.error) console.error('io.setPath will be removed. Please set the variable WEB_SOCKET_SWF_LOCATION pointing to WebSocketMain.swf');
|
||||
@@ -577,7 +577,7 @@ if (typeof window != 'undefined'){
|
||||
var self = this;
|
||||
this._xhr = this._request('', 'GET', true);
|
||||
this._xhr.onreadystatechange = function(){
|
||||
if (self._xhr.readyState == 3) self._onData(self._xhr.responseText);
|
||||
if (self._xhr.readyState == 4) self._onData(self._xhr.responseText);
|
||||
};
|
||||
this._xhr.send(null);
|
||||
};
|
||||
@@ -831,6 +831,7 @@ JSONPPolling.xdomainCheck = function(){
|
||||
if (this.transport && !this.connected){
|
||||
if (this.connecting) this.disconnect();
|
||||
this.connecting = true;
|
||||
this.emit('connecting', [this.transport.type]);
|
||||
this.transport.connect();
|
||||
if (this.options.connectTimeout){
|
||||
var self = this;
|
||||
@@ -838,16 +839,17 @@ JSONPPolling.xdomainCheck = function(){
|
||||
if (!self.connected){
|
||||
self.disconnect();
|
||||
if (self.options.tryTransportsOnConnectTimeout && !self._rememberedTransport){
|
||||
var remainingTransports = [], transports = self.options.transports;
|
||||
for (var i = 0, transport; transport = transports[i]; i++){
|
||||
if (transport != self.transport.type) remainingTransports.push(transport);
|
||||
}
|
||||
if (remainingTransports.length){
|
||||
self.transport = self.getTransport(remainingTransports);
|
||||
if(!self._remainingTransports) self._remainingTransports = self.options.transports.slice(0);
|
||||
var transports = self._remainingTransports;
|
||||
while(transports.length > 0 && transports.splice(0,1)[0] != self.transport.type){}
|
||||
if(transports.length){
|
||||
self.transport = self.getTransport(transports);
|
||||
self.connect();
|
||||
}
|
||||
}
|
||||
if(!self._remainingTransports || self._remainingTransports.length == 0) self.emit('connect_failed');
|
||||
}
|
||||
if(self._remainingTransports && self._remainingTransports.length == 0) delete self._remainingTransports;
|
||||
}, this.options.connectTimeout);
|
||||
}
|
||||
}
|
||||
@@ -1551,8 +1553,10 @@ ASProxy.prototype =
|
||||
if (window.WebSocket) return;
|
||||
|
||||
var console = window.console;
|
||||
if (!console) console = {log: function(){ }, error: function(){ }};
|
||||
|
||||
if (!console || !console.log || !console.error) {
|
||||
console = {log: function(){ }, error: function(){ }};
|
||||
}
|
||||
|
||||
if (!swfobject.hasFlashPlayerVersion("9.0.0")) {
|
||||
console.error("Flash Player is not installed.");
|
||||
return;
|
||||
@@ -1574,73 +1578,22 @@ ASProxy.prototype =
|
||||
WebSocket.__addTask(function() {
|
||||
self.__createFlash(url, protocol, proxyHost, proxyPort, headers);
|
||||
});
|
||||
}, 1);
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
WebSocket.prototype.__createFlash = function(url, protocol, proxyHost, proxyPort, headers) {
|
||||
var self = this;
|
||||
self.__flash =
|
||||
WebSocket.__flash.create(url, protocol, proxyHost || null, proxyPort || 0, headers || null);
|
||||
|
||||
self.__flash.addEventListener("open", function(fe) {
|
||||
try {
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
if (self.__timer) clearInterval(self.__timer);
|
||||
if (window.opera) {
|
||||
// Workaround for weird behavior of Opera which sometimes drops events.
|
||||
self.__timer = setInterval(function () {
|
||||
self.__handleMessages();
|
||||
}, 500);
|
||||
}
|
||||
if (self.onopen) self.onopen();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
self.__flash.addEventListener("event", function(fe) {
|
||||
// Uses setTimeout() to workaround the error:
|
||||
// > You are trying to call recursively into the Flash Player which is not allowed.
|
||||
setTimeout(function() { self.__handleEvents(); }, 0);
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("close", function(fe) {
|
||||
try {
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
if (self.__timer) clearInterval(self.__timer);
|
||||
if (self.onclose) self.onclose();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("message", function() {
|
||||
try {
|
||||
self.__handleMessages();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("error", function(fe) {
|
||||
try {
|
||||
if (self.__timer) clearInterval(self.__timer);
|
||||
if (self.onerror) self.onerror();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
self.__flash.addEventListener("stateChange", function(fe) {
|
||||
try {
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
self.bufferedAmount = fe.getBufferedAmount();
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
});
|
||||
|
||||
//console.log("[WebSocket] Flash object is ready");
|
||||
};
|
||||
|
||||
WebSocket.prototype.send = function(data) {
|
||||
if (this.__flash) {
|
||||
this.readyState = this.__flash.getReadyState();
|
||||
}
|
||||
if (!this.__flash || this.readyState == WebSocket.CONNECTING) {
|
||||
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
|
||||
}
|
||||
@@ -1654,7 +1607,7 @@ ASProxy.prototype =
|
||||
if (result < 0) { // success
|
||||
return true;
|
||||
} else {
|
||||
this.bufferedAmount = result;
|
||||
this.bufferedAmount += result;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -1662,7 +1615,6 @@ ASProxy.prototype =
|
||||
WebSocket.prototype.close = function() {
|
||||
var self = this;
|
||||
if (!self.__flash) return;
|
||||
self.readyState = self.__flash.getReadyState();
|
||||
if (self.readyState == WebSocket.CLOSED || self.readyState == WebSocket.CLOSING) return;
|
||||
self.__flash.close();
|
||||
// Sets/calls them manually here because Flash WebSocketConnection.close cannot fire events
|
||||
@@ -1673,7 +1625,7 @@ ASProxy.prototype =
|
||||
if (self.onclose) {
|
||||
// Make it asynchronous so that it looks more like an actual
|
||||
// close event
|
||||
setTimeout(self.onclose, 1);
|
||||
setTimeout(self.onclose, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1742,30 +1694,62 @@ ASProxy.prototype =
|
||||
}
|
||||
};
|
||||
|
||||
WebSocket.prototype.__handleMessages = function() {
|
||||
// Gets data using readSocketData() instead of getting it from event object
|
||||
WebSocket.prototype.__handleEvents = function() {
|
||||
// Gets events using receiveEvents() instead of getting it from event object
|
||||
// of Flash event. This is to make sure to keep message order.
|
||||
// It seems sometimes Flash events don't arrive in the same order as they are sent.
|
||||
var arr = this.__flash.readSocketData();
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var data = decodeURIComponent(arr[i]);
|
||||
var events = this.__flash.receiveEvents();
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
try {
|
||||
if (this.onmessage) {
|
||||
var e;
|
||||
if (window.MessageEvent) {
|
||||
e = document.createEvent("MessageEvent");
|
||||
e.initMessageEvent("message", false, false, data, null, null, window, null);
|
||||
} else { // IE
|
||||
e = {data: data};
|
||||
var event = events[i];
|
||||
if ("readyState" in event) {
|
||||
this.readyState = event.readyState;
|
||||
}
|
||||
if (event.type == "open") {
|
||||
|
||||
if (this.__timer) clearInterval(this.__timer);
|
||||
if (window.opera) {
|
||||
// Workaround for weird behavior of Opera which sometimes drops events.
|
||||
this.__timer = setInterval(function () {
|
||||
this.__handleEvents();
|
||||
}, 500);
|
||||
}
|
||||
this.onmessage(e);
|
||||
if (this.onopen) this.onopen();
|
||||
|
||||
} else if (event.type == "close") {
|
||||
|
||||
if (this.__timer) clearInterval(this.__timer);
|
||||
if (this.onclose) this.onclose();
|
||||
|
||||
} else if (event.type == "message") {
|
||||
|
||||
if (this.onmessage) {
|
||||
var data = decodeURIComponent(event.data);
|
||||
var e;
|
||||
if (window.MessageEvent && !window.opera) {
|
||||
e = document.createEvent("MessageEvent");
|
||||
e.initMessageEvent("message", false, false, data, null, null, window, null);
|
||||
} else {
|
||||
// IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
|
||||
e = {data: data};
|
||||
}
|
||||
this.onmessage(e);
|
||||
}
|
||||
|
||||
} else if (event.type == "error") {
|
||||
|
||||
if (this.__timer) clearInterval(this.__timer);
|
||||
if (this.onerror) this.onerror();
|
||||
|
||||
} else {
|
||||
throw "unknown event type: " + event.type;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e.toString());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {object} object
|
||||
* @param {string} type
|
||||
@@ -1780,7 +1764,7 @@ ASProxy.prototype =
|
||||
}
|
||||
object.dispatchEvent(event, arguments);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-interface">DOM 2 EventInterface</a>}
|
||||
@@ -1841,6 +1825,12 @@ ASProxy.prototype =
|
||||
|
||||
WebSocket.__tasks = [];
|
||||
|
||||
WebSocket.loadFlashPolicyFile = function(url) {
|
||||
WebSocket.__addTask(function() {
|
||||
WebSocket.__flash.loadManualPolicyFile(url);
|
||||
});
|
||||
}
|
||||
|
||||
WebSocket.__initialize = function() {
|
||||
if (WebSocket.__swfLocation) {
|
||||
// For backword compatibility.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
var io = require('socket.io')
|
||||
, assert = require('assert')
|
||||
, Listener = io.Listener;
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test server initialization': function(assert){
|
||||
'test server initialization': function(){
|
||||
var _server = require('http').createServer(function(){})
|
||||
, _socket = io.listen(_server, { log: null });
|
||||
assert.ok(_socket instanceof Listener);
|
||||
@@ -14,4 +15,4 @@ module.exports = {
|
||||
})
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var http = require('http')
|
||||
, net = require('net')
|
||||
, io = require('socket.io')
|
||||
, assert = require('assert')
|
||||
, decode = require('socket.io/utils').decode
|
||||
, port = 7100
|
||||
, Listener = io.Listener
|
||||
@@ -30,7 +31,7 @@ function client(server, sessid){
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test serving static javascript client': function(assert){
|
||||
'test serving static javascript client': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
assert.response(_server
|
||||
@@ -50,7 +51,7 @@ module.exports = {
|
||||
, { headers: { 'Content-Type': 'application/x-shockwave-flash' }});
|
||||
},
|
||||
|
||||
'test serving non-socket.io requests': function(assert){
|
||||
'test serving non-socket.io requests': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
_server.on('request', function(req, res){
|
||||
@@ -64,8 +65,9 @@ module.exports = {
|
||||
, { body: 'Hello world' });
|
||||
},
|
||||
|
||||
'test destroying an upgrade connection that is not WebSocket': function(assert){
|
||||
'test destroying an upgrade connection that is not WebSocket': function(){
|
||||
var _server = server()
|
||||
|
||||
, _socket = socket(_server);
|
||||
listen(_server, function(){
|
||||
var client = http.createClient(_server._port)
|
||||
@@ -80,12 +82,15 @@ module.exports = {
|
||||
client.addListener('end', function(){
|
||||
assert.ok(! upgraded);
|
||||
_server.close();
|
||||
})
|
||||
});
|
||||
client.on('error', function (e) {
|
||||
// ignore errors
|
||||
});
|
||||
request.end();
|
||||
});
|
||||
},
|
||||
|
||||
'test broadcasting to clients': function(assert){
|
||||
'test broadcasting to clients': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
listen(_server, function(){
|
||||
@@ -123,7 +128,7 @@ module.exports = {
|
||||
})
|
||||
},
|
||||
|
||||
'test connecting with an invalid sessionid': function(assert){
|
||||
'test connecting with an invalid sessionid': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
listen(_server, function(){
|
||||
@@ -139,7 +144,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test connecting to an invalid transport': function(assert){
|
||||
'test connecting to an invalid transport': function(){
|
||||
var _server = server(function(req, res){
|
||||
res.writeHead(200);
|
||||
res.end(req.url == '/socket.io/inexistent' ? 'All cool' : '');
|
||||
@@ -149,4 +154,4 @@ module.exports = {
|
||||
assert.response(_server, { url: '/socket.io/inexistent' }, { body: 'All cool' });
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var io = require('socket.io')
|
||||
, net = require('net')
|
||||
, http = require('http')
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, port = 7700
|
||||
, encode = require('socket.io/utils').encode
|
||||
@@ -31,7 +32,7 @@ function listen(s, callback){
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test xml policy added to connection': function(assert){
|
||||
'test xml policy added to connection': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
listen(_server, function(){
|
||||
@@ -45,4 +46,4 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var io = require('socket.io')
|
||||
, net = require('net')
|
||||
, assert = require('assert')
|
||||
, http = require('http')
|
||||
, querystring = require('querystring')
|
||||
, port = 7600
|
||||
@@ -62,7 +63,10 @@ function get(server, url, assert, callback){
|
||||
});
|
||||
|
||||
client.end = function(){
|
||||
request.connection.destroy();
|
||||
if (request.abort)
|
||||
request.abort();
|
||||
else
|
||||
request.connection.destroy();
|
||||
};
|
||||
|
||||
return client;
|
||||
@@ -77,7 +81,7 @@ function post(client, url, data, callback){
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test connection and handshake': function(assert){
|
||||
'test connection and handshake': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server)
|
||||
, trips = 2;
|
||||
@@ -105,7 +109,6 @@ module.exports = {
|
||||
_socket.on('connection', function(client){
|
||||
assert.ok(client instanceof HTMLFile);
|
||||
client.on('message', function(msg){
|
||||
assert.ok(msg == 'from client');
|
||||
--trips || close();
|
||||
});
|
||||
});
|
||||
@@ -117,7 +120,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test clients tracking': function(assert){
|
||||
'test clients tracking': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
|
||||
@@ -142,7 +145,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test buffered messages': function(assert){
|
||||
'test buffered messages': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, { transportOptions: {
|
||||
'htmlfile': {
|
||||
@@ -181,7 +184,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test hearbeat timeout': function(assert){
|
||||
'test hearbeat timeout': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, {
|
||||
transportOptions: {
|
||||
@@ -211,4 +214,4 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var io = require('socket.io')
|
||||
, http = require('http')
|
||||
, querystring = require('querystring')
|
||||
, assert = require('assert')
|
||||
, port = 7500
|
||||
, encode = require('socket.io/utils').encode
|
||||
, _decode = require('socket.io/utils').decode
|
||||
@@ -66,7 +67,7 @@ function post(client, url, data, callback){
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test connection and handshake': function(assert){
|
||||
'test connection and handshake': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server)
|
||||
, trips = 2;
|
||||
@@ -98,7 +99,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test clients tracking': function(assert){
|
||||
'test clients tracking': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
|
||||
@@ -113,7 +114,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test buffered messages': function(assert){
|
||||
'test buffered messages': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, { transportOptions: {
|
||||
'jsonp-polling': {
|
||||
@@ -145,4 +146,4 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var io = require('socket.io')
|
||||
, assert = require('assert')
|
||||
, encode = require('socket.io/utils').encode
|
||||
, decode = require('socket.io/utils').decode
|
||||
, port = 7200
|
||||
@@ -30,7 +31,7 @@ function client(server, sessid){
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test connection and handshake': function(assert){
|
||||
'test connection and handshake': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server)
|
||||
, _client
|
||||
@@ -66,7 +67,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test clients tracking': function(assert){
|
||||
'test clients tracking': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
|
||||
@@ -87,7 +88,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test buffered messages': function(assert){
|
||||
'test buffered messages': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, {
|
||||
transportOptions: {
|
||||
@@ -128,7 +129,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test json encoding': function(assert){
|
||||
'test json encoding': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server)
|
||||
, _client
|
||||
@@ -162,7 +163,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test hearbeat timeout': function(assert){
|
||||
'test hearbeat timeout': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, {
|
||||
transportOptions: {
|
||||
@@ -191,7 +192,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test client broadcast': function(assert){
|
||||
'test client broadcast': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
|
||||
@@ -242,4 +243,4 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
var io = require('socket.io')
|
||||
, net = require('net')
|
||||
, http = require('http')
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, port = 7300
|
||||
, encode = require('socket.io/utils').encode
|
||||
@@ -78,7 +79,7 @@ function post(client, url, data, callback){
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test connection and handshake': function(assert){
|
||||
'test connection and handshake': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server)
|
||||
, trips = 2;
|
||||
@@ -118,7 +119,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test clients tracking': function(assert){
|
||||
'test clients tracking': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
|
||||
@@ -143,7 +144,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test buffered messages': function(assert){
|
||||
'test buffered messages': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, { transportOptions: {
|
||||
'xhr-multipart': {
|
||||
@@ -182,7 +183,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test hearbeat timeout': function(assert){
|
||||
'test hearbeat timeout': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, {
|
||||
transportOptions: {
|
||||
@@ -212,4 +213,4 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var io = require('socket.io')
|
||||
, http = require('http')
|
||||
, assert = require('assert')
|
||||
, querystring = require('querystring')
|
||||
, port = 7400
|
||||
, encode = require('socket.io/utils').encode
|
||||
@@ -56,7 +57,7 @@ function post(client, url, data, callback){
|
||||
|
||||
module.exports = {
|
||||
|
||||
'test connection and handshake': function(assert){
|
||||
'test connection and handshake': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server)
|
||||
, trips = 2;
|
||||
@@ -88,7 +89,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test clients tracking': function(assert){
|
||||
'test clients tracking': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server);
|
||||
|
||||
@@ -103,7 +104,7 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
'test buffered messages': function(assert){
|
||||
'test buffered messages': function(){
|
||||
var _server = server()
|
||||
, _socket = socket(_server, { transportOptions: {
|
||||
'xhr-polling': {
|
||||
@@ -135,4 +136,4 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
var encode = require('socket.io/utils').encode,
|
||||
var assert = require('assert')
|
||||
encode = require('socket.io/utils').encode,
|
||||
decode = require('socket.io/utils').decode;
|
||||
|
||||
module.exports = {
|
||||
'test decoding': function(assert){
|
||||
'test decoding': function(){
|
||||
var decoded = decode('~m~5~m~abcde' + '~m~9~m~123456789');
|
||||
assert.equal(decoded.length, 2);
|
||||
assert.equal(decoded[0], 'abcde');
|
||||
assert.equal(decoded[1], '123456789');
|
||||
},
|
||||
|
||||
'test decoding of bad framed messages': function(assert){
|
||||
'test decoding of bad framed messages': function(){
|
||||
var decoded = decode('~m~5~m~abcde' + '~m\uffsdaasdfd9~m~1aaa23456789');
|
||||
assert.equal(decoded.length, 1);
|
||||
assert.equal(decoded[0], 'abcde');
|
||||
assert.equal(decoded[1], undefined);
|
||||
},
|
||||
|
||||
'test encoding': function(assert){
|
||||
'test encoding': function(){
|
||||
assert.equal(encode(['abcde', '123456789']), '~m~5~m~abcde' + '~m~9~m~123456789');
|
||||
assert.equal(encode('asdasdsad'), '~m~9~m~asdasdsad');
|
||||
assert.equal(encode(''), '~m~0~m~');
|
||||
assert.equal(encode(null), '~m~0~m~');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user