Making the client and tests work on IE

This commit is contained in:
Pawel Kadluczka 2017-08-28 14:56:56 -07:00
parent ff2bf5ad75
commit 2a36aa141d
9 changed files with 180 additions and 218 deletions

View File

@ -15,7 +15,7 @@ export class Base64EncodedHubProtocol implements IHubProtocol {
parseMessages(input: any): HubMessage[] {
// The format of the message is `size:message;`
let pos = input.indexOf(":");
if (pos == -1 || !input.endsWith(";")) {
if (pos == -1 || input[input.length - 1] != ';') {
throw new Error("Invalid payload.");
}

View File

@ -8,7 +8,7 @@ export namespace TextMessageFormat {
}
export function parse(input: string): string[] {
if (!input.endsWith(RecordSeparator)) {
if (input[input.length - 1] != RecordSeparator) {
throw new Error("Message is incomplete.");
}
@ -57,7 +57,10 @@ export namespace BinaryMessageFormat {
}
if (uint8Array.byteLength >= (offset + 8 + size)) {
result.push(uint8Array.slice(offset + 8, offset + 8 + size))
// IE does not support .slice() so use subarray
result.push(uint8Array.slice
? uint8Array.slice(offset + 8, offset + 8 + size)
: uint8Array.subarray(offset + 8, offset + 8 + size));
}
else {
throw new Error("Incomplete message");

View File

@ -55,11 +55,10 @@ export class HubConnection {
case MessageType.Completion:
let callback = this.callbacks.get(message.invocationId);
if (callback != null) {
callback(message);
if (message.type == MessageType.Completion) {
this.callbacks.delete(message.invocationId);
}
callback(message);
}
break;
default:

View File

@ -195,9 +195,6 @@ export class LongPollingTransport implements ITransport {
}
let pollXhr = new XMLHttpRequest();
if (transferMode === TransferMode.Binary) {
pollXhr.responseType = "arraybuffer";
}
pollXhr.onload = () => {
if (pollXhr.status == 200) {
@ -248,6 +245,11 @@ export class LongPollingTransport implements ITransport {
this.pollXhr = pollXhr;
this.pollXhr.open("GET", url, true);
if (transferMode === TransferMode.Binary) {
this.pollXhr.responseType = "arraybuffer";
}
// IE caches xhr requests
this.pollXhr.setRequestHeader("Cache-Control", "no-cache");
// TODO: consider making timeout configurable
this.pollXhr.timeout = 120000;
this.pollXhr.send();

View File

@ -8,8 +8,8 @@
<script type="text/javascript" src="lib/jasmine/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine/jasmine-html.js"></script>
<script type="text/javascript" src="lib/jasmine/boot.js"></script>
<script type="text/javascript" src="lib/signalr/signalr-client.min.js"></script>
<script type="text/javascript" src="lib/signalr/signalr-msgpackprotocol.min.js"></script>
<script type="text/javascript" src="lib/signalr/signalr-clientES5.min.js"></script>
<script type="text/javascript" src="lib/signalr/signalr-msgpackprotocolES5.min.js"></script>
<script src="js/common.js"></script>
<script src="js/webSocketTests.js"></script>
<script src="js/connectionTests.js"></script>

View File

@ -1,8 +1,10 @@
const ECHOENDPOINT_URL = `http://${document.location.host}/echo`;
"use strict";
var ECHOENDPOINT_URL = "http://" + document.location.host + "/echo";
function getTransportTypes() {
let transportTypes = [ signalR.TransportType.WebSockets ];
if (typeof (EventSource) !== "undefined") {
var transportTypes = [signalR.TransportType.WebSockets];
if (typeof EventSource !== "undefined") {
transportTypes.push(signalR.TransportType.ServerSentEvents);
}
transportTypes.push(signalR.TransportType.LongPolling);
@ -11,14 +13,16 @@ function getTransportTypes() {
}
function eachTransport(action) {
getTransportTypes().forEach(t => action(t));
getTransportTypes().forEach(function (t) {
return action(t);
});
}
function eachTransportAndProtocol(action) {
let protocols = [
new signalR.JsonHubProtocol(),
new signalRMsgPack.MessagePackHubProtocol()
];
getTransportTypes().forEach(t =>
protocols.forEach(p => action(t, p)));
}
var protocols = [new signalR.JsonHubProtocol(), new signalRMsgPack.MessagePackHubProtocol()];
getTransportTypes().forEach(function (t) {
return protocols.forEach(function (p) {
return action(t, p);
});
});
}

View File

@ -1,61 +1,58 @@
describe('connection', () => {
it(`can connect to the server without specifying transport explicitly`, done => {
const message = "Hello World!";
let connection = new signalR.HttpConnection(ECHOENDPOINT_URL);
"use strict";
let received = "";
connection.onDataReceived = data => {
describe('connection', function () {
it("can connect to the server without specifying transport explicitly", function (done) {
var message = "Hello World!";
var connection = new signalR.HttpConnection(ECHOENDPOINT_URL);
var received = "";
connection.onDataReceived = function (data) {
received += data;
if (data == message) {
connection.stop();
}
}
};
connection.onClosed = error => {
connection.onClosed = function (error) {
expect(error).toBeUndefined();
done();
}
};
connection.start()
.then(() => {
connection.send(message);
})
.catch(e => {
fail();
done();
});
connection.start().then(function () {
connection.send(message);
}).catch(function (e) {
fail();
done();
});
});
eachTransport(transportType => {
it(`over ${signalR.TransportType[transportType]} can send and receive messages`, done => {
const message = "Hello World!";
let connection = new signalR.HttpConnection(ECHOENDPOINT_URL,
{
transport: transportType,
logger: new signalR.ConsoleLogger(signalR.LogLevel.Information)
});
eachTransport(function (transportType) {
it("over " + signalR.TransportType[transportType] + " can send and receive messages", function (done) {
var message = "Hello World!";
var connection = new signalR.HttpConnection(ECHOENDPOINT_URL, {
transport: transportType,
logger: new signalR.ConsoleLogger(signalR.LogLevel.Information)
});
let received = "";
connection.onDataReceived = data => {
var received = "";
connection.onDataReceived = function (data) {
received += data;
if (data == message) {
connection.stop();
}
}
};
connection.onClosed = error => {
connection.onClosed = function (error) {
expect(error).toBeUndefined();
done();
}
};
connection.start()
.then(() => {
connection.send(message);
})
.catch(e => {
fail();
done();
});
connection.start().then(function () {
connection.send(message);
}).catch(function (e) {
fail();
done();
});
});
});
});
});

View File

@ -1,194 +1,149 @@
const TESTHUBENDPOINT_URL = `http://${document.location.host}/testhub`;
'use strict';
describe('hubConnection', () => {
eachTransportAndProtocol((transportType, protocol) => {
describe(`${protocol.name} over ${signalR.TransportType[transportType]} transport`, () => {
it(`can invoke server method and receive result`, done => {
const message = "你好,世界!";
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
hubConnection.onClosed = error => {
var TESTHUBENDPOINT_URL = 'http://' + document.location.host + '/testhub';
describe('hubConnection', function () {
eachTransportAndProtocol(function (transportType, protocol) {
describe(protocol.name + ' over ' + signalR.TransportType[transportType] + ' transport', function () {
it('can invoke server method and receive result', function (done) {
var message = "你好,世界!";
var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType, logger: logger }), logger, protocol);
hubConnection.onClosed = function (error) {
expect(error).toBe(undefined);
done();
}
};
hubConnection.start()
.then(() => {
hubConnection.invoke('Echo', message)
.then(result => {
expect(result).toBe(message);
})
.catch(e => {
fail(e);
})
.then(() => {
hubConnection.stop();
})
})
.catch(e => {
hubConnection.start().then(function () {
hubConnection.invoke('Echo', message).then(function (result) {
expect(result).toBe(message);
}).catch(function (e) {
fail(e);
done();
}).then(function () {
hubConnection.stop();
});
}).catch(function (e) {
fail(e);
done();
});
});
it(`can stream server method and receive result`, done => {
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
it('can stream server method and receive result', function (done) {
var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType, logger: logger }), logger, protocol);
hubConnection.onClosed = error => {
hubConnection.onClosed = function (error) {
expect(error).toBe(undefined);
done();
}
};
let received = [];
hubConnection.start()
.then(() => {
hubConnection.stream('Stream')
.subscribe({
next: (item) => {
received.push(item);
},
error: (err) => {
fail(err);
hubConnection.stop();
},
complete: () => {
expect(received).toEqual(["a", "b", "c"]);
hubConnection.stop();
}
});
})
.catch(e => {
fail(e);
done();
var received = [];
hubConnection.start().then(function () {
hubConnection.stream('Stream').subscribe({
next: function next(item) {
received.push(item);
},
error: function error(err) {
fail(err);
hubConnection.stop();
},
complete: function complete() {
expect(received).toEqual(["a", "b", "c"]);
hubConnection.stop();
}
});
}).catch(function (e) {
fail(e);
done();
});
});
it(`rethrows an exception from the server when invoking`, done => {
const errorMessage = "An error occurred.";
it('rethrows an exception from the server when invoking', function (done) {
var errorMessage = "An error occurred.";
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType, logger: logger }), logger, protocol);
hubConnection.start()
.then(() => {
hubConnection.invoke('ThrowException', errorMessage)
.then(() => {
// exception expected but none thrown
fail();
})
.catch(e => {
expect(e.message).toBe(errorMessage);
})
.then(() => {
return hubConnection.stop();
})
.then(() => {
done();
});
})
.catch(e => {
fail(e);
hubConnection.start().then(function () {
hubConnection.invoke('ThrowException', errorMessage).then(function () {
// exception expected but none thrown
fail();
}).catch(function (e) {
expect(e.message).toBe(errorMessage);
}).then(function () {
return hubConnection.stop();
}).then(function () {
done();
});
}).catch(function (e) {
fail(e);
done();
});
});
it(`rethrows an exception from the server when streaming`, done => {
const errorMessage = "An error occurred.";
it('rethrows an exception from the server when streaming', function (done) {
var errorMessage = "An error occurred.";
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType, logger: logger }), logger, protocol);
hubConnection.start()
.then(() => {
hubConnection.stream('ThrowException', errorMessage)
.subscribe({
next: (item) => {
fail();
},
error: (err) => {
expect(err.message).toEqual("An error occurred.");
done();
},
complete: () => {
fail();
}
});
})
.catch(e => {
fail(e);
done();
hubConnection.start().then(function () {
hubConnection.stream('ThrowException', errorMessage).subscribe({
next: function next(item) {
fail();
},
error: function error(err) {
expect(err.message).toEqual("An error occurred.");
done();
},
complete: function complete() {
fail();
}
});
}).catch(function (e) {
fail(e);
done();
});
});
it(`can receive server calls`, done => {
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
it('can receive server calls', function (done) {
var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType, logger: logger }), logger, protocol);
const message = "你好 SignalR";
var message = "你好 SignalR";
let callbackPromise = new Promise((resolve, reject) => {
hubConnection.on("Message", msg => {
expect(msg).toBe(message);
resolve();
});
hubConnection.on("Message", function (msg) {
expect(msg).toBe(message);
done();
});
hubConnection.start()
.then(() => {
return Promise.all([hubConnection.invoke('InvokeWithString', message), callbackPromise]);
})
.then(() => {
return stop();
})
.then(() => {
done();
})
.catch(e => {
fail(e);
done();
});
hubConnection.start().then(function () {
return hubConnection.invoke('InvokeWithString', message);
})
.then(function() {
return hubConnection.stop();
})
.catch(function (e) {
fail(e);
done();
});
});
it(`closed with error if hub cannot be created`, done => {
let errorRegex = {
WebSockets: "1011", // Message is browser specific (e.g. 'Websocket closed with status code: 1011')
it('closed with error if hub cannot be created', function (done) {
var errorRegex = {
WebSockets: "1011|1005", // Message is browser specific (e.g. 'Websocket closed with status code: 1011'), Edge and IE report 1005 even though the server sent 1011
LongPolling: "Internal Server Error",
ServerSentEvents: "Error occurred"
};
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
`http://${document.location.host}/uncreatable`,
{ transport: transportType, logger: logger }),
logger,
protocol);
var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
var hubConnection = new signalR.HubConnection(new signalR.HttpConnection('http://' + document.location.host + '/uncreatable', { transport: transportType, logger: logger }), logger, protocol);
hubConnection.onClosed = error => {
hubConnection.onClosed = function (error) {
expect(error.message).toMatch(errorRegex[signalR.TransportType[transportType]]);
done();
}
};
hubConnection.start();
});
});

View File

@ -1,22 +1,24 @@
'use strict';
describe('WebSockets', function () {
it('can be used to connect to SignalR', done => {
const message = "message";
it('can be used to connect to SignalR', function (done) {
var message = "message";
let webSocket = new WebSocket(ECHOENDPOINT_URL.replace(/^http/, "ws"));
var webSocket = new WebSocket(ECHOENDPOINT_URL.replace(/^http/, "ws"));
webSocket.onopen = () => {
webSocket.onopen = function () {
webSocket.send(message);
};
var received = "";
webSocket.onmessage = event => {
webSocket.onmessage = function (event) {
received += event.data;
if (received === message) {
webSocket.close();
}
};
webSocket.onclose = event => {
webSocket.onclose = function (event) {
if (!event.wasClean) {
fail("connection closed with unexpected status code: " + event.code + " " + event.reason);
}