Skip to content

Commit 3b1655e

Browse files
committed
fix(WebSocketSubject): ensure error codes passed to WebSocket close method
1 parent 861a0c1 commit 3b1655e

File tree

2 files changed

+57
-7
lines changed

2 files changed

+57
-7
lines changed

spec/observables/dom/webSocket-spec.js

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ describe('Observable.webSocket', function () {
1515
teardownMockWebSocket();
1616
});
1717

18-
it ('should send a message', function () {
18+
it('should send and receive messages', function () {
1919
var messageReceived = false;
2020
var subject = Observable.webSocket('ws://mysocket');
2121

@@ -27,6 +27,7 @@ describe('Observable.webSocket', function () {
2727
});
2828

2929
var socket = MockWebSocket.lastSocket();
30+
expect(socket.url).toBe('ws://mysocket');
3031

3132
socket.open();
3233
expect(socket.lastMessageSent()).toBe('ping');
@@ -35,7 +36,7 @@ describe('Observable.webSocket', function () {
3536
expect(messageReceived).toBe(true);
3637
});
3738

38-
it ('receive multiple messages', function () {
39+
it('receive multiple messages', function () {
3940
var expected = ['what', 'do', 'you', 'do', 'with', 'a', 'drunken', 'sailor?'];
4041
var results = [];
4142
var subject = Observable.webSocket('ws://mysocket');
@@ -55,7 +56,7 @@ describe('Observable.webSocket', function () {
5556
expect(results).toEqual(expected);
5657
});
5758

58-
it ('should queue messages prior to subscription', function () {
59+
it('should queue messages prior to subscription', function () {
5960
var expected = ['make', 'him', 'walk', 'the', 'plank'];
6061
var subject = Observable.webSocket('ws://mysocket');
6162

@@ -75,7 +76,7 @@ describe('Observable.webSocket', function () {
7576
expect(socket.sent.length).toBe(expected.length);
7677
});
7778

78-
it('should send messages immediately if alreayd open', function () {
79+
it('should send messages immediately if already open', function () {
7980
var subject = Observable.webSocket('ws://mysocket');
8081
subject.subscribe();
8182
var socket = MockWebSocket.lastSocket();
@@ -103,7 +104,20 @@ describe('Observable.webSocket', function () {
103104
expect(socket.readyState).toBe(3); // closed
104105
});
105106

106-
it('should allow resubscription after closure', function () {
107+
it('should close the socket with a code and a reason when errored', function () {
108+
var subject = Observable.webSocket('ws://mysocket');
109+
subject.subscribe();
110+
var socket = MockWebSocket.lastSocket();
111+
socket.open();
112+
113+
spyOn(socket, 'close').and.callThrough();
114+
expect(socket.close).not.toHaveBeenCalled();
115+
116+
subject.error({ code: 1337, reason: 'Too bad, so sad :('});
117+
expect(socket.close).toHaveBeenCalledWith(1337, 'Too bad, so sad :(');
118+
});
119+
120+
it('should allow resubscription after closure via complete', function () {
107121
var subject = Observable.webSocket('ws://mysocket');
108122
subject.subscribe();
109123
var socket1 = MockWebSocket.lastSocket();
@@ -118,6 +132,22 @@ describe('Observable.webSocket', function () {
118132
expect(socket2).not.toBe(socket1);
119133
expect(socket2.lastMessageSent()).toBe('a mariner yer not. yarrr.');
120134
});
135+
136+
it('should allow resubscription after closure via error', function () {
137+
var subject = Observable.webSocket('ws://mysocket');
138+
subject.subscribe();
139+
var socket1 = MockWebSocket.lastSocket();
140+
socket1.open();
141+
subject.error({ code: 1337 });
142+
143+
subject.next('yo-ho! yo-ho!');
144+
subject.subscribe();
145+
var socket2 = MockWebSocket.lastSocket();
146+
socket2.open();
147+
148+
expect(socket2).not.toBe(socket1);
149+
expect(socket2.lastMessageSent()).toBe('yo-ho! yo-ho!');
150+
});
121151
});
122152

123153
var sockets = [];
@@ -145,6 +175,15 @@ MockWebSocket.prototype = {
145175
return sent.length > 0 ? sent[sent.length - 1] : undefined;
146176
},
147177

178+
closeDirty: function (code, reason) {
179+
if (this.readyState < 2) {
180+
this.readyState = 2;
181+
this.closeCode = code;
182+
this.closeReason = reason;
183+
this.triggerClose({ wasClean: false });
184+
}
185+
},
186+
148187
triggerClose: function (e) {
149188
this.readyState = 3;
150189
this.trigger('close', e);
@@ -176,7 +215,7 @@ MockWebSocket.prototype = {
176215
this.readyState = 2;
177216
this.closeCode = code;
178217
this.closeReason = reason;
179-
this.triggerClose({ wasClean: (!code || code === 1000) });
218+
this.triggerClose({ wasClean: true });
180219
}
181220
},
182221

src/observable/dom/webSocket.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,18 @@ export class WebSocketSubject<T> extends Subject<T> {
109109

110110
self.destination = Subscriber.create(
111111
(x) => socket.readyState === 1 && socket.send(x),
112-
(e) => socket.close(e),
112+
(e) => {
113+
const closingObserver = self.closingObserver;
114+
if (closingObserver) {
115+
closingObserver.next(undefined);
116+
}
117+
if (e && e.code) {
118+
socket.close(e.code, e.reason);
119+
} else {
120+
self._finalError(new TypeError('WebSocketSubject.error must be called with an object with an error code, ' +
121+
'and an optional reason: { code: number, reason: string }'));
122+
}
123+
},
113124
( ) => {
114125
const closingObserver = self.closingObserver;
115126
if (closingObserver) {

0 commit comments

Comments
 (0)