Adding StreamCompletion message (TS)

This commit is contained in:
Pawel Kadluczka 2017-10-17 13:12:09 -07:00 committed by Pawel Kadluczka
parent 8d1d6d0300
commit 6bddb258cd
6 changed files with 193 additions and 68 deletions

View File

@ -8,6 +8,7 @@ import { TransportType, ITransport, TransferMode } from "../Microsoft.AspNetCore
import { Observer } from "../Microsoft.AspNetCore.SignalR.Client.TS/Observable" import { Observer } from "../Microsoft.AspNetCore.SignalR.Client.TS/Observable"
import { TextMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters" import { TextMessageFormat } from "../Microsoft.AspNetCore.SignalR.Client.TS/Formatters"
import { ILogger, LogLevel } from "../Microsoft.AspNetCore.SignalR.Client.TS/ILogger" import { ILogger, LogLevel } from "../Microsoft.AspNetCore.SignalR.Client.TS/ILogger"
import { MessageType } from "../Microsoft.AspNetCore.SignalR.Client.TS/IHubProtocol"
import { asyncit as it, captureException } from './JasmineUtils'; import { asyncit as it, captureException } from './JasmineUtils';
@ -37,7 +38,7 @@ describe("HubConnection", () => {
// Verify the message is sent // Verify the message is sent
expect(connection.sentData.length).toBe(1); expect(connection.sentData.length).toBe(1);
expect(JSON.parse(connection.sentData[0])).toEqual({ expect(JSON.parse(connection.sentData[0])).toEqual({
type: 1, type: MessageType.Invocation,
invocationId: connection.lastInvocationId, invocationId: connection.lastInvocationId,
target: "testMethod", target: "testMethod",
nonblocking: true, nonblocking: true,
@ -63,7 +64,7 @@ describe("HubConnection", () => {
// Verify the message is sent // Verify the message is sent
expect(connection.sentData.length).toBe(1); expect(connection.sentData.length).toBe(1);
expect(JSON.parse(connection.sentData[0])).toEqual({ expect(JSON.parse(connection.sentData[0])).toEqual({
type: 1, type: MessageType.Invocation,
invocationId: connection.lastInvocationId, invocationId: connection.lastInvocationId,
target: "testMethod", target: "testMethod",
nonblocking: false, nonblocking: false,
@ -83,7 +84,7 @@ describe("HubConnection", () => {
let hubConnection = new HubConnection(connection); let hubConnection = new HubConnection(connection);
let invokePromise = hubConnection.invoke("testMethod", "arg", 42); let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
connection.receive({ type: 3, invocationId: connection.lastInvocationId, error: "foo" }); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, error: "foo" });
let ex = await captureException(async () => invokePromise); let ex = await captureException(async () => invokePromise);
expect(ex.message).toBe("foo"); expect(ex.message).toBe("foo");
@ -95,7 +96,7 @@ describe("HubConnection", () => {
let hubConnection = new HubConnection(connection); let hubConnection = new HubConnection(connection);
let invokePromise = hubConnection.invoke("testMethod", "arg", 42); let invokePromise = hubConnection.invoke("testMethod", "arg", 42);
connection.receive({ type: 3, invocationId: connection.lastInvocationId, result: "foo" }); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, result: "foo" });
expect(await invokePromise).toBe("foo"); expect(await invokePromise).toBe("foo");
}); });
@ -108,7 +109,7 @@ describe("HubConnection", () => {
hubConnection.stop(); hubConnection.stop();
let ex = await captureException(async () => await invokePromise); let ex = await captureException(async () => await invokePromise);
expect(ex.message).toBe("Invocation cancelled due to connection being closed."); expect(ex.message).toBe("Invocation canceled due to connection being closed.");
}); });
it("completes pending invocations when connection is lost", async () => { it("completes pending invocations when connection is lost", async () => {
@ -123,17 +124,30 @@ describe("HubConnection", () => {
expect(ex.message).toBe("Connection lost"); expect(ex.message).toBe("Connection lost");
}); });
it("rejects streaming responses made using 'invoke'", async () => { it("rejects streaming results made using 'invoke'", async () => {
let connection = new TestConnection(); let connection = new TestConnection();
let hubConnection = new HubConnection(connection); let hubConnection = new HubConnection(connection);
let invokePromise = hubConnection.invoke("testMethod"); let invokePromise = hubConnection.invoke("testMethod");
connection.receive({ type: 2, invocationId: connection.lastInvocationId, item: null }); connection.receive({ type: MessageType.Result, invocationId: connection.lastInvocationId, item: null });
connection.onclose(); connection.onclose();
let ex = await captureException(async () => await invokePromise); let ex = await captureException(async () => await invokePromise);
expect(ex.message).toBe("Streaming methods must be invoked using HubConnection.stream"); expect(ex.message).toBe("Streaming methods must be invoked using the 'HubConnection.stream()' method.");
});
it("rejects streaming completions made using 'invoke'", async () => {
let connection = new TestConnection();
let hubConnection = new HubConnection(connection);
let invokePromise = hubConnection.invoke("testMethod");
connection.receive({ type: MessageType.StreamCompletion, invocationId: connection.lastInvocationId });
connection.onclose();
let ex = await captureException(async () => await invokePromise);
expect(ex.message).toBe("Streaming methods must be invoked using the 'HubConnection.stream()' method.");
}); });
}); });
@ -151,7 +165,7 @@ describe("HubConnection", () => {
let hubConnection = new HubConnection(connection, { logging: logger }); let hubConnection = new HubConnection(connection, { logging: logger });
connection.receive({ connection.receive({
type: 1, type: MessageType.Invocation,
invocationId: 0, invocationId: 0,
target: "message", target: "message",
arguments: ["test"], arguments: ["test"],
@ -168,7 +182,7 @@ describe("HubConnection", () => {
hubConnection.on("message", v => value = v); hubConnection.on("message", v => value = v);
connection.receive({ connection.receive({
type: 1, type: MessageType.Invocation,
invocationId: 0, invocationId: 0,
target: "message", target: "message",
arguments: ["test"], arguments: ["test"],
@ -187,7 +201,7 @@ describe("HubConnection", () => {
hubConnection.on("message", () => numInvocations2++); hubConnection.on("message", () => numInvocations2++);
connection.receive({ connection.receive({
type: 1, type: MessageType.Invocation,
invocationId: 0, invocationId: 0,
target: "message", target: "message",
arguments: [], arguments: [],
@ -207,7 +221,7 @@ describe("HubConnection", () => {
hubConnection.on("message", callback); hubConnection.on("message", callback);
connection.receive({ connection.receive({
type: 1, type: MessageType.Invocation,
invocationId: 0, invocationId: 0,
target: "message", target: "message",
arguments: [], arguments: [],
@ -217,7 +231,7 @@ describe("HubConnection", () => {
hubConnection.off("message", callback); hubConnection.off("message", callback);
connection.receive({ connection.receive({
type: 1, type: MessageType.Invocation,
invocationId: 0, invocationId: 0,
target: "message", target: "message",
arguments: [], arguments: [],
@ -259,7 +273,7 @@ describe("HubConnection", () => {
// invoke a method to make sure we are not trying to use null/undefined // invoke a method to make sure we are not trying to use null/undefined
connection.receive({ connection.receive({
type: 1, type: MessageType.Invocation,
invocationId: 0, invocationId: 0,
target: "message", target: "message",
arguments: [], arguments: [],
@ -287,7 +301,7 @@ describe("HubConnection", () => {
// Verify the message is sent // Verify the message is sent
expect(connection.sentData.length).toBe(1); expect(connection.sentData.length).toBe(1);
expect(JSON.parse(connection.sentData[0])).toEqual({ expect(JSON.parse(connection.sentData[0])).toEqual({
type: 1, type: MessageType.Invocation,
invocationId: connection.lastInvocationId, invocationId: connection.lastInvocationId,
target: "testStream", target: "testStream",
nonblocking: false, nonblocking: false,
@ -309,7 +323,7 @@ describe("HubConnection", () => {
hubConnection.stream<any>("testMethod", "arg", 42) hubConnection.stream<any>("testMethod", "arg", 42)
.subscribe(observer); .subscribe(observer);
connection.receive({ type: 3, invocationId: connection.lastInvocationId, error: "foo" }); connection.receive({ type: MessageType.StreamCompletion, invocationId: connection.lastInvocationId, error: "foo" });
let ex = await captureException(async () => await observer.completed); let ex = await captureException(async () => await observer.completed);
expect(ex.message).toEqual("Error: foo"); expect(ex.message).toEqual("Error: foo");
@ -323,7 +337,7 @@ describe("HubConnection", () => {
hubConnection.stream<any>("testMethod", "arg", 42) hubConnection.stream<any>("testMethod", "arg", 42)
.subscribe(observer); .subscribe(observer);
connection.receive({ type: 3, invocationId: connection.lastInvocationId }); connection.receive({ type: MessageType.StreamCompletion, invocationId: connection.lastInvocationId });
expect(await observer.completed).toEqual([]); expect(await observer.completed).toEqual([]);
}); });
@ -338,7 +352,7 @@ describe("HubConnection", () => {
hubConnection.stop(); hubConnection.stop();
let ex = await captureException(async () => await observer.completed); let ex = await captureException(async () => await observer.completed);
expect(ex.message).toEqual("Error: Invocation cancelled due to connection being closed."); expect(ex.message).toEqual("Error: Invocation canceled due to connection being closed.");
}); });
it("completes pending streams when connection is lost", async () => { it("completes pending streams when connection is lost", async () => {
@ -364,10 +378,10 @@ describe("HubConnection", () => {
hubConnection.stream<any>("testMethod") hubConnection.stream<any>("testMethod")
.subscribe(observer); .subscribe(observer);
connection.receive({ type: 3, invocationId: connection.lastInvocationId, result: "foo" }); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId, result: "foo" });
let ex = await captureException(async () => await observer.completed); let ex = await captureException(async () => await observer.completed);
expect(ex.message).toEqual("Error: Server provided a result in a completion response to a streamed invocation."); expect(ex.message).toEqual("Error: Hub methods must be invoked using the 'HubConnection.invoke()' method.");
}); });
it("yields items as they arrive", async () => { it("yields items as they arrive", async () => {
@ -378,16 +392,16 @@ describe("HubConnection", () => {
hubConnection.stream<any>("testMethod") hubConnection.stream<any>("testMethod")
.subscribe(observer); .subscribe(observer);
connection.receive({ type: 2, invocationId: connection.lastInvocationId, item: 1 }); connection.receive({ type: MessageType.Result, invocationId: connection.lastInvocationId, item: 1 });
expect(observer.itemsReceived).toEqual([1]); expect(observer.itemsReceived).toEqual([1]);
connection.receive({ type: 2, invocationId: connection.lastInvocationId, item: 2 }); connection.receive({ type: MessageType.Result, invocationId: connection.lastInvocationId, item: 2 });
expect(observer.itemsReceived).toEqual([1, 2]); expect(observer.itemsReceived).toEqual([1, 2]);
connection.receive({ type: 2, invocationId: connection.lastInvocationId, item: 3 }); connection.receive({ type: MessageType.Result, invocationId: connection.lastInvocationId, item: 3 });
expect(observer.itemsReceived).toEqual([1, 2, 3]); expect(observer.itemsReceived).toEqual([1, 2, 3]);
connection.receive({ type: 3, invocationId: connection.lastInvocationId }); connection.receive({ type: MessageType.StreamCompletion, invocationId: connection.lastInvocationId });
expect(await observer.completed).toEqual([1, 2, 3]); expect(await observer.completed).toEqual([1, 2, 3]);
}); });
@ -414,7 +428,7 @@ describe("HubConnection", () => {
// Send completion to trigger observer.complete() // Send completion to trigger observer.complete()
// Expectation is connection.receive will not to throw // Expectation is connection.receive will not to throw
connection.receive({ type: 3, invocationId: connection.lastInvocationId }); connection.receive({ type: MessageType.Completion, invocationId: connection.lastInvocationId });
}); });
}); });

View File

@ -6,7 +6,7 @@ import { IConnection } from "./IConnection"
import { HttpConnection} from "./HttpConnection" import { HttpConnection} from "./HttpConnection"
import { TransportType, TransferMode } from "./Transports" import { TransportType, TransferMode } from "./Transports"
import { Subject, Observable } from "./Observable" import { Subject, Observable } from "./Observable"
import { IHubProtocol, ProtocolType, MessageType, HubMessage, CompletionMessage, ResultMessage, InvocationMessage, NegotiationMessage } from "./IHubProtocol"; import { IHubProtocol, ProtocolType, MessageType, HubMessage, CompletionMessage, StreamCompletionMessage, ResultMessage, InvocationMessage, NegotiationMessage } from "./IHubProtocol";
import { JsonHubProtocol } from "./JsonHubProtocol"; import { JsonHubProtocol } from "./JsonHubProtocol";
import { TextMessageFormat } from "./Formatters" import { TextMessageFormat } from "./Formatters"
import { Base64EncodedHubProtocol } from "./Base64EncodedHubProtocol" import { Base64EncodedHubProtocol } from "./Base64EncodedHubProtocol"
@ -24,7 +24,7 @@ export class HubConnection {
private readonly connection: IConnection; private readonly connection: IConnection;
private readonly logger: ILogger; private readonly logger: ILogger;
private protocol: IHubProtocol; private protocol: IHubProtocol;
private callbacks: Map<string, (invocationUpdate: CompletionMessage | ResultMessage) => void>; private callbacks: Map<string, (invocationEvent: HubMessage, error?: Error) => void>;
private methods: Map<string, ((...args: any[]) => void)[]>; private methods: Map<string, ((...args: any[]) => void)[]>;
private id: number; private id: number;
private closedCallbacks: ConnectionClosed[]; private closedCallbacks: ConnectionClosed[];
@ -44,7 +44,7 @@ export class HubConnection {
this.connection.onreceive = (data: any) => this.processIncomingData(data); this.connection.onreceive = (data: any) => this.processIncomingData(data);
this.connection.onclose = (error?: Error) => this.connectionClosed(error); this.connection.onclose = (error?: Error) => this.connectionClosed(error);
this.callbacks = new Map<string, (invocationEvent: CompletionMessage | ResultMessage) => void>(); this.callbacks = new Map<string, (invocationEvent: HubMessage, error?: Error) => void>();
this.methods = new Map<string, ((...args: any[]) => void)[]>(); this.methods = new Map<string, ((...args: any[]) => void)[]>();
this.closedCallbacks = []; this.closedCallbacks = [];
this.id = 0; this.id = 0;
@ -63,9 +63,10 @@ export class HubConnection {
break; break;
case MessageType.Result: case MessageType.Result:
case MessageType.Completion: case MessageType.Completion:
case MessageType.StreamCompletion:
let callback = this.callbacks.get(message.invocationId); let callback = this.callbacks.get(message.invocationId);
if (callback != null) { if (callback != null) {
if (message.type == MessageType.Completion) { if (message.type == MessageType.Completion || message.type == MessageType.StreamCompletion) {
this.callbacks.delete(message.invocationId); this.callbacks.delete(message.invocationId);
} }
callback(message); callback(message);
@ -92,14 +93,8 @@ export class HubConnection {
} }
private connectionClosed(error?: Error) { private connectionClosed(error?: Error) {
let errorCompletionMessage = <CompletionMessage>{
type: MessageType.Completion,
invocationId: "-1",
error: error ? error.message : "Invocation cancelled due to connection being closed.",
};
this.callbacks.forEach(callback => { this.callbacks.forEach(callback => {
callback(errorCompletionMessage); callback(undefined, error ? error : new Error("Invocation canceled due to connection being closed."));
}); });
this.callbacks.clear(); this.callbacks.clear();
@ -136,22 +131,28 @@ export class HubConnection {
let subject = new Subject<T>(); let subject = new Subject<T>();
this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: CompletionMessage | ResultMessage) => { this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: HubMessage, error?: Error) => {
if (invocationEvent.type === MessageType.Completion) { if (error) {
let completionMessage = <CompletionMessage>invocationEvent; subject.error(error);
if (completionMessage.error) { return;
subject.error(new Error(completionMessage.error));
}
else if (completionMessage.result) {
subject.error(new Error("Server provided a result in a completion response to a streamed invocation."));
}
else {
// TODO: Log a warning if there's a payload?
subject.complete();
}
} }
else {
subject.next(<T>(<ResultMessage>invocationEvent).item); switch (invocationEvent.type) {
case MessageType.StreamCompletion:
let completionMessage = <StreamCompletionMessage>invocationEvent;
if (completionMessage.error) {
subject.error(new Error(completionMessage.error));
}
else {
subject.complete();
}
break;
case MessageType.Result:
subject.next(<T>(<ResultMessage>invocationEvent).item);
break;
default:
subject.error(new Error("Hub methods must be invoked using the 'HubConnection.invoke()' method."));
break;
} }
}); });
@ -178,7 +179,11 @@ export class HubConnection {
let invocationDescriptor = this.createInvocation(methodName, args, false); let invocationDescriptor = this.createInvocation(methodName, args, false);
let p = new Promise<any>((resolve, reject) => { let p = new Promise<any>((resolve, reject) => {
this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: CompletionMessage | ResultMessage) => { this.callbacks.set(invocationDescriptor.invocationId, (invocationEvent: HubMessage, error?: Error) => {
if (error) {
reject(error);
return;
}
if (invocationEvent.type === MessageType.Completion) { if (invocationEvent.type === MessageType.Completion) {
let completionMessage = <CompletionMessage>invocationEvent; let completionMessage = <CompletionMessage>invocationEvent;
if (completionMessage.error) { if (completionMessage.error) {
@ -189,7 +194,7 @@ export class HubConnection {
} }
} }
else { else {
reject(new Error("Streaming methods must be invoked using HubConnection.stream")) reject(new Error("Streaming methods must be invoked using the 'HubConnection.stream()' method."));
} }
}); });

View File

@ -4,7 +4,8 @@
export const enum MessageType { export const enum MessageType {
Invocation = 1, Invocation = 1,
Result, Result,
Completion Completion,
StreamCompletion
} }
export interface HubMessage { export interface HubMessage {
@ -22,6 +23,10 @@ export interface ResultMessage extends HubMessage {
readonly item?: any; readonly item?: any;
} }
export interface StreamCompletionMessage extends HubMessage {
readonly error?: string;
}
export interface CompletionMessage extends HubMessage { export interface CompletionMessage extends HubMessage {
readonly error?: string; readonly error?: string;
readonly result?: any; readonly result?: any;

View File

@ -1,7 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
import { IHubProtocol, ProtocolType, MessageType, HubMessage, InvocationMessage, ResultMessage, CompletionMessage } from "./IHubProtocol"; import { IHubProtocol, ProtocolType, MessageType, HubMessage, InvocationMessage, ResultMessage, CompletionMessage, StreamCompletionMessage } from "./IHubProtocol";
import { BinaryMessageFormat } from "./Formatters" import { BinaryMessageFormat } from "./Formatters"
import * as msgpack5 from "msgpack5" import * as msgpack5 from "msgpack5"
@ -34,6 +34,8 @@ export class MessagePackHubProtocol implements IHubProtocol {
return this.createStreamItemMessage(properties); return this.createStreamItemMessage(properties);
case MessageType.Completion: case MessageType.Completion:
return this.createCompletionMessage(properties); return this.createCompletionMessage(properties);
case MessageType.StreamCompletion:
return this.createStreamCompletionMessage(properties);
default: default:
throw new Error("Invalid message type."); throw new Error("Invalid message type.");
} }
@ -97,7 +99,19 @@ export class MessagePackHubProtocol implements IHubProtocol {
break; break;
} }
return completionMessage as ResultMessage; return completionMessage as CompletionMessage;
}
private createStreamCompletionMessage(properties: any[]): StreamCompletionMessage {
if (properties.length < 2) {
throw new Error("Invalid payload for Completion message.");
}
return <StreamCompletionMessage>{
type: MessageType.StreamCompletion,
invocationId: properties[1],
error: properties.length == 3 ? properties[2] : null,
};
} }
writeMessage(message: HubMessage): ArrayBuffer { writeMessage(message: HubMessage): ArrayBuffer {

View File

@ -42,6 +42,16 @@ namespace Microsoft.AspNetCore.SignalR.Test.Server
return new string[] { "a", "b", "c" }.ToObservable(); return new string[] { "a", "b", "c" }.ToObservable();
} }
public IObservable<int> EmptyStream()
{
return Array.Empty<int>().ToObservable();
}
public IObservable<string> StreamThrowException(string message)
{
throw new InvalidOperationException(message);
}
public ComplexObject EchoComplexObject(ComplexObject complexObject) public ComplexObject EchoComplexObject(ComplexObject complexObject)
{ {
return complexObject; return complexObject;

View File

@ -10,7 +10,7 @@ describe('hubConnection', function () {
describe(protocol.name + ' over ' + signalR.TransportType[transportType] + ' transport', function () { describe(protocol.name + ' over ' + signalR.TransportType[transportType] + ' transport', function () {
it('can invoke server method and receive result', function (done) { it('can invoke server method and receive result', function (done) {
var message = "你好,世界!"; var message = '你好,世界!';
var options = { var options = {
transport: transportType, transport: transportType,
@ -57,7 +57,7 @@ describe('hubConnection', function () {
}); });
hubConnection.start().then(function () { hubConnection.start().then(function () {
hubConnection.send('SendCustomObject', { Name: "test", Value: 42}); hubConnection.send('SendCustomObject', { Name: 'test', Value: 42});
}).catch(function (e) { }).catch(function (e) {
fail(e); fail(e);
done(); done();
@ -89,7 +89,7 @@ describe('hubConnection', function () {
hubConnection.stop(); hubConnection.stop();
}, },
complete: function complete() { complete: function complete() {
expect(received).toEqual(["a", "b", "c"]); expect(received).toEqual(['a', 'b', 'c']);
hubConnection.stop(); hubConnection.stop();
} }
}); });
@ -100,7 +100,7 @@ describe('hubConnection', function () {
}); });
it('rethrows an exception from the server when invoking', function (done) { it('rethrows an exception from the server when invoking', function (done) {
var errorMessage = "An error occurred."; var errorMessage = 'An error occurred.';
var options = { var options = {
transport: transportType, transport: transportType,
protocol: protocol, protocol: protocol,
@ -125,8 +125,7 @@ describe('hubConnection', function () {
}); });
}); });
it('rethrows an exception from the server when streaming', function (done) { it('throws an exception when invoking streaming method with invoke', function (done) {
var errorMessage = "An error occurred.";
var options = { var options = {
transport: transportType, transport: transportType,
protocol: protocol, protocol: protocol,
@ -135,12 +134,90 @@ describe('hubConnection', function () {
var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options); var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.start().then(function () { hubConnection.start().then(function () {
hubConnection.stream('ThrowException', errorMessage).subscribe({ hubConnection.invoke('EmptyStream').then(function () {
// exception expected but none thrown
fail();
}).catch(function (e) {
expect(e.message).toBe('Streaming methods must be invoked using the \'HubConnection.stream()\' method.');
}).then(function () {
return hubConnection.stop();
}).then(function () {
done();
});
}).catch(function (e) {
fail(e);
done();
});
});
it('throws an exception when receiving a streaming result for method called with invoke', function (done) {
var options = {
transport: transportType,
protocol: protocol,
logging: signalR.LogLevel.Trace
};
var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.start().then(function () {
hubConnection.invoke('Stream').then(function () {
// exception expected but none thrown
fail();
}).catch(function (e) {
expect(e.message).toBe('Streaming methods must be invoked using the \'HubConnection.stream()\' method.');
}).then(function () {
return hubConnection.stop();
}).then(function () {
done();
});
}).catch(function (e) {
fail(e);
done();
});
});
it('rethrows an exception from the server when streaming', function (done) {
var errorMessage = 'An error occurred.';
var options = {
transport: transportType,
protocol: protocol,
logging: signalR.LogLevel.Trace
};
var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.start().then(function () {
hubConnection.stream('StreamThrowException', errorMessage).subscribe({
next: function next(item) { next: function next(item) {
fail(); fail();
}, },
error: function error(err) { error: function error(err) {
expect(err.message).toEqual("An error occurred."); expect(err.message).toEqual('An error occurred.');
done();
},
complete: function complete() {
fail();
}
});
}).catch(function (e) {
fail(e);
done();
});
});
it('throws an exception when invoking hub method with stream', function (done) {
var options = {
transport: transportType,
protocol: protocol,
logging: signalR.LogLevel.Trace
};
var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
hubConnection.start().then(function () {
hubConnection.stream('Echo', '42').subscribe({
next: function next(item) {
fail();
},
error: function error(err) {
expect(err.message).toEqual('Hub methods must be invoked using the \'HubConnection.invoke()\' method.');
done(); done();
}, },
complete: function complete() { complete: function complete() {
@ -161,7 +238,7 @@ describe('hubConnection', function () {
}; };
var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options); var hubConnection = new signalR.HubConnection(TESTHUBENDPOINT_URL, options);
var message = "你好 SignalR"; var message = '你好 SignalR';
// client side method names are case insensitive // client side method names are case insensitive
var methodName = 'message'; var methodName = 'message';
@ -187,9 +264,9 @@ describe('hubConnection', function () {
it('closed with error if hub cannot be created', function (done) { it('closed with error if hub cannot be created', function (done) {
var errorRegex = { 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 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", LongPolling: 'Internal Server Error',
ServerSentEvents: "Error occurred" ServerSentEvents: 'Error occurred'
}; };
var options = { var options = {