Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 42 additions & 65 deletions src/SignalR/clients/ts/FunctionalTests/ts/HubConnectionTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,25 +413,27 @@ describe("hubConnection", () => {
});
});

it("closed with error or start fails if hub cannot be created", async (done) => {
it("closed with error or start fails if hub cannot be created", async () => {
const hubConnection = getConnectionBuilder(transportType, ENDPOINT_BASE_URL + "/uncreatable")
.withHubProtocol(protocol)
.build();

const expectedErrorMessage = "Server returned an error on close: Connection closed with an error. InvalidOperationException: Unable to resolve service for type 'System.Object' while attempting to activate 'FunctionalTests.UncreatableHub'.";

const closePromise = new PromiseSource();
// Either start will fail or onclose will be called. Never both.
hubConnection.onclose((error) => {
expect(error!.message).toEqual(expectedErrorMessage);
done();
closePromise.resolve();
});

try {
await hubConnection.start();
} catch (error) {
expect(error!.message).toEqual(expectedErrorMessage);
done();
closePromise.resolve();
}
await closePromise;
});

it("can handle different types", (done) => {
Expand Down Expand Up @@ -565,7 +567,7 @@ describe("hubConnection", () => {
});
});

it("can stream from client to server with rxjs", async (done) => {
it("can stream from client to server with rxjs", async () => {
const hubConnection = getConnectionBuilder(transportType)
.withHubProtocol(protocol)
.build();
Expand All @@ -579,10 +581,9 @@ describe("hubConnection", () => {
subject.complete();
expect(await resultPromise).toBe("Hello world!");
await hubConnection.stop();
done();
});

it("can stream from client to server and close with error with rxjs", async (done) => {
it("can stream from client to server and close with error with rxjs", async () => {
const hubConnection = getConnectionBuilder(transportType)
.withHubProtocol(protocol)
.build();
Expand All @@ -602,15 +603,14 @@ describe("hubConnection", () => {
} finally {
await hubConnection.stop();
}
done();
});
});
});

eachTransport((transportType) => {
describe("over " + HttpTransportType[transportType] + " transport", () => {

it("can connect to hub with authorization", async (done) => {
it("can connect to hub with authorization", async () => {
const message = "你好,世界!";

try {
Expand All @@ -620,9 +620,10 @@ describe("hubConnection", () => {
accessTokenFactory: () => jwtToken,
}).build();

const closePromise = new PromiseSource();
hubConnection.onclose((error) => {
expect(error).toBe(undefined);
done();
closePromise.resolve();
});
await hubConnection.start();
const response = await hubConnection.invoke("Echo", message);
Expand All @@ -631,24 +632,24 @@ describe("hubConnection", () => {

await hubConnection.stop();

done();
await closePromise;
} catch (err) {
fail(err);
done();
}
});

it("can connect to hub with authorization using async token factory", async (done) => {
it("can connect to hub with authorization using async token factory", async () => {
const message = "你好,世界!";

try {
const hubConnection = getConnectionBuilder(transportType, ENDPOINT_BASE_URL + "/authorizedhub", {
accessTokenFactory: () => getJwtToken(ENDPOINT_BASE_URL + "/generateJwtToken"),
}).build();

const closePromise = new PromiseSource();
hubConnection.onclose((error) => {
expect(error).toBe(undefined);
done();
closePromise.resolve();
});
await hubConnection.start();
const response = await hubConnection.invoke("Echo", message);
Expand All @@ -657,48 +658,49 @@ describe("hubConnection", () => {

await hubConnection.stop();

done();
await closePromise;
} catch (err) {
fail(err);
done();
}
});

if (transportType !== HttpTransportType.LongPolling) {
it("terminates if no messages received within timeout interval", async (done) => {
it("terminates if no messages received within timeout interval", async () => {
const hubConnection = getConnectionBuilder(transportType).build();
hubConnection.serverTimeoutInMilliseconds = 100;

const closePromise = new PromiseSource();
hubConnection.onclose((error) => {
expect(error).toEqual(new Error("Server timeout elapsed without receiving a message from the server."));
done();
closePromise.resolve();
});

await hubConnection.start();
await closePromise;
});
}

it("preserves cookies between requests", async (done) => {
const hubConnection = getConnectionBuilder(transportType, HTTPORHTTPS_TESTHUBENDPOINT_URL).build();
await hubConnection.start();
const cookieValue = await hubConnection.invoke<string>("GetCookie", "testCookie");
const cookieValue2 = await hubConnection.invoke<string>("GetCookie", "testCookie2");
expect(cookieValue).toEqual("testValue");
expect(cookieValue2).toEqual("testValue2");
await hubConnection.stop();
done();
});
if (shouldRunHttpsTests) {
it("preserves cookies between requests", async () => {
const hubConnection = getConnectionBuilder(transportType, HTTPORHTTPS_TESTHUBENDPOINT_URL).build();
await hubConnection.start();
const cookieValue = await hubConnection.invoke<string>("GetCookie", "testCookie");
const cookieValue2 = await hubConnection.invoke<string>("GetCookie", "testCookie2");
expect(cookieValue).toEqual("testValue");
expect(cookieValue2).toEqual("testValue2");
await hubConnection.stop();
});
}

it("expired cookies are not preserved", async (done) => {
it("expired cookies are not preserved", async () => {
const hubConnection = getConnectionBuilder(transportType, HTTPORHTTPS_TESTHUBENDPOINT_URL).build();
await hubConnection.start();
const cookieValue = await hubConnection.invoke<string>("GetCookie", "expiredCookie");
expect(cookieValue).toBeNull();
await hubConnection.stop();
done();
});

it("can reconnect", async (done) => {
it("can reconnect", async () => {
try {
const reconnectingPromise = new PromiseSource();
const reconnectedPromise = new PromiseSource<string | undefined>();
Expand Down Expand Up @@ -731,16 +733,13 @@ describe("hubConnection", () => {
expect(response).toEqual("test");

await hubConnection.stop();

done();
} catch (err) {
fail(err);
done();
}
});
});

it("can change url in reconnecting state", async (done) => {
it("can change url in reconnecting state", async () => {
try {
const reconnectingPromise = new PromiseSource();
const hubConnection = getConnectionBuilder(transportType)
Expand All @@ -762,16 +761,13 @@ describe("hubConnection", () => {
expect(hubConnection.baseUrl).toBe("http://example123.com");

await hubConnection.stop();

done();
} catch (err) {
fail(err);
done();
}
});
});

it("can reconnect after negotiate redirect", async (done) => {
it("can reconnect after negotiate redirect", async () => {
try {
const reconnectingPromise = new PromiseSource();
const reconnectedPromise = new PromiseSource<string | undefined>();
Expand Down Expand Up @@ -809,15 +805,12 @@ describe("hubConnection", () => {
expect(postReconnectRedirects).toBeGreaterThan(preReconnectRedirects);

await hubConnection.stop();

done();
} catch (err) {
fail(err);
done();
}
});

it("can reconnect after skipping negotiation", async (done) => {
it("can reconnect after skipping negotiation", async () => {
try {
const reconnectingPromise = new PromiseSource();
const reconnectedPromise = new PromiseSource<string | undefined>();
Expand Down Expand Up @@ -852,15 +845,12 @@ describe("hubConnection", () => {
expect(response).toEqual("test");

await hubConnection.stop();

done();
} catch (err) {
fail(err);
done();
}
});

it("connection id matches server side connection id", async (done) => {
it("connection id matches server side connection id", async () => {
try {
const reconnectingPromise = new PromiseSource();
const reconnectedPromise = new PromiseSource<string | undefined>();
Expand Down Expand Up @@ -899,15 +889,12 @@ describe("hubConnection", () => {

await hubConnection.stop();
expect(hubConnection.connectionId).toBeNull();

done();
} catch (err) {
fail(err);
done();
}
});

it("connection id is alwys null is negotiation is skipped", async (done) => {
it("connection id is alwys null is negotiation is skipped", async () => {
try {
const hubConnection = getConnectionBuilder(
HttpTransportType.WebSockets,
Expand All @@ -925,16 +912,13 @@ describe("hubConnection", () => {
await hubConnection.stop();

expect(hubConnection.connectionId).toBeNull();

done();
} catch (err) {
fail(err);
done();
}
});

if (typeof EventSource !== "undefined") {
it("allows Server-Sent Events when negotiating for JSON protocol", async (done) => {
it("allows Server-Sent Events when negotiating for JSON protocol", async () => {
const hubConnection = getConnectionBuilder(undefined, TESTHUB_NOWEBSOCKETS_ENDPOINT_URL)
.withHubProtocol(new JsonHubProtocol())
.build();
Expand All @@ -946,14 +930,13 @@ describe("hubConnection", () => {
expect(await hubConnection.invoke("GetActiveTransportName")).toEqual("ServerSentEvents");

await hubConnection.stop();
done();
} catch (e) {
fail(e);
}
});
}

it("skips Server-Sent Events when negotiating for MessagePack protocol", async (done) => {
it("skips Server-Sent Events when negotiating for MessagePack protocol", async () => {
const hubConnection = getConnectionBuilder(undefined, TESTHUB_NOWEBSOCKETS_ENDPOINT_URL)
.withHubProtocol(new MessagePackHubProtocol())
.build();
Expand All @@ -965,16 +948,14 @@ describe("hubConnection", () => {
expect(await hubConnection.invoke("GetActiveTransportName")).toEqual("LongPolling");

await hubConnection.stop();
done();
} catch (e) {
fail(e);
}
});

it("transport falls back from WebSockets to SSE or LongPolling", async (done) => {
it("transport falls back from WebSockets to SSE or LongPolling", async () => {
// Skip test on Node as there will always be a WebSockets implementation on Node
if (typeof window === "undefined") {
done();
return;
}

Expand All @@ -1000,11 +981,10 @@ describe("hubConnection", () => {
fail(e);
} finally {
(window as any).WebSocket = oldWebSocket;
done();
}
});

it("over LongPolling it sends DELETE request and waits for poll to terminate", async (done) => {
it("over LongPolling it sends DELETE request and waits for poll to terminate", async () => {
// Create an HTTP client to capture the poll
const defaultClient = new DefaultHttpClient(TestLogger.instance);

Expand Down Expand Up @@ -1052,14 +1032,12 @@ describe("hubConnection", () => {
} catch (e) {
fail(e);
} finally {
done();
}
});

it("populates the Content-Type header when sending XMLHttpRequest", async (done) => {
it("populates the Content-Type header when sending XMLHttpRequest", async () => {
// Skip test on Node as this header isn't set (it was added for React-Native)
if (typeof window === "undefined") {
done();
return;
}
const hubConnection = getConnectionBuilder(HttpTransportType.LongPolling, TESTHUB_NOWEBSOCKETS_ENDPOINT_URL)
Expand All @@ -1075,7 +1053,6 @@ describe("hubConnection", () => {
expect(await hubConnection.invoke("GetContentTypeHeader")).toEqual("text/plain;charset=UTF-8");

await hubConnection.stop();
done();
} catch (e) {
fail(e);
}
Expand Down