Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

Commit

Permalink
Merge pull request #139 from mistic/connection-events
Browse files Browse the repository at this point in the history
feat(NA): add new connection events.
  • Loading branch information
Urigo authored May 23, 2017
2 parents 00becb5 + 5a40830 commit 3b091ce
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 7 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- Added built-in support for `subscribe` from `graphql-js` [PR #133](https://github.com/apollographql/subscriptions-transport-ws/pull/133)
- Fixed infinity reconnects when server accepts connections but its in an error state. [PR #135](https://github.com/apollographql/subscriptions-transport-ws/pull/135)
- Force close client-side socket when using `close()`, and ignore reconnect logic. [PR #137](https://github.com/apollographql/subscriptions-transport-ws/pull/137)

- Added new connection events to give a more accurate control over the connection state [PR #139]. Fixes [Issue #136].

### 0.6.0

Expand Down
55 changes: 50 additions & 5 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,54 @@ export class SubscriptionClient {
};
}

/**
* @deprecated This method will become deprecated in the next release.
* You can use onConnecting and onConnected instead.
*/
public onConnect(callback: ListenerFn, context?: any): Function {
return this.on('connect', callback, context);
this.logWarningOnNonProductionEnv('This method will become deprecated in the next release. ' +
'You can use onConnecting and onConnected instead.');
return this.onConnecting(callback, context);
}

/**
* @deprecated This method will become deprecated in the next release.
* You can use onDisconnected instead.
*/
public onDisconnect(callback: ListenerFn, context?: any): Function {
return this.on('disconnect', callback, context);
this.logWarningOnNonProductionEnv('This method will become deprecated in the next release. ' +
'You can use onDisconnected instead.');
return this.onDisconnected(callback, context);
}

/**
* @deprecated This method will become deprecated in the next release.
* You can use onReconnecting and onReconnected instead.
*/
public onReconnect(callback: ListenerFn, context?: any): Function {
return this.on('reconnect', callback, context);
this.logWarningOnNonProductionEnv('This method will become deprecated in the next release. ' +
'You can use onReconnecting and onReconnected instead.');
return this.onReconnecting(callback, context);
}

public onConnected(callback: ListenerFn, context?: any): Function {
return this.on('connected', callback, context);
}

public onConnecting(callback: ListenerFn, context?: any): Function {
return this.on('connecting', callback, context);
}

public onDisconnected(callback: ListenerFn, context?: any): Function {
return this.on('disconnected', callback, context);
}

public onReconnected(callback: ListenerFn, context?: any): Function {
return this.on('reconnected', callback, context);
}

public onReconnecting(callback: ListenerFn, context?: any): Function {
return this.on('reconnecting', callback, context);
}

public unsubscribe(opId: number) {
Expand Down Expand Up @@ -238,6 +276,12 @@ export class SubscriptionClient {
return this;
}

private logWarningOnNonProductionEnv(warning: string) {
if (process && process.env && process.env.NODE_ENV !== 'production') {
console.warn(warning);
}
}

private checkOperationOptions(options: OperationOptions, handler: (error: Error[], result?: any) => void) {
const { query, variables, operationName } = options;

Expand Down Expand Up @@ -386,7 +430,7 @@ export class SubscriptionClient {
this.client = new this.wsImpl(this.url, GRAPHQL_WS);

this.client.onopen = () => {
this.eventEmitter.emit(this.reconnecting ? 'reconnect' : 'connect');
this.eventEmitter.emit(this.reconnecting ? 'reconnecting' : 'connecting');

const payload: ConnectionParams = typeof this.connectionParams === 'function' ? this.connectionParams() : this.connectionParams;

Expand All @@ -396,7 +440,7 @@ export class SubscriptionClient {
};

this.client.onclose = () => {
this.eventEmitter.emit('disconnect');
this.eventEmitter.emit('disconnected');

if (this.forceClose) {
this.forceClose = false;
Expand Down Expand Up @@ -444,6 +488,7 @@ export class SubscriptionClient {
break;

case MessageTypes.GQL_CONNECTION_ACK:
this.eventEmitter.emit(this.reconnecting ? 'reconnected' : 'connected');
this.reconnecting = false;
this.backoff.reset();

Expand Down
77 changes: 76 additions & 1 deletion src/test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,81 @@ describe('Client', function () {
});
});

it('should emit connected event for client side when socket closed', (done) => {
const client = new SubscriptionClient(`ws://localhost:${TEST_PORT}/`);
const onConnectingSpy = sinon.spy();
const unregisterOnConnecting = client.onConnecting(onConnectingSpy);

const unregister = client.onConnected(() => {
unregisterOnConnecting();
unregister();
expect(onConnectingSpy.called).to.equal(true);
done();
});
});

it('should emit connecting event for client side when socket closed', (done) => {
const subscriptionsClient = new SubscriptionClient(`ws://localhost:${TEST_PORT}/`);
const onConnectedSpy = sinon.spy();
const unregisterOnConnected = subscriptionsClient.onConnected(onConnectedSpy);
const unregisterOnConnecting = subscriptionsClient.onConnecting(() => {
unregisterOnConnecting();
unregisterOnConnected();
expect(onConnectedSpy.called).to.equal(false);
done();
});
});

it('should emit disconnected event for client side when socket closed', (done) => {
const client = new SubscriptionClient(`ws://localhost:${TEST_PORT}/`, {
connectionCallback: () => {
client.client.close();
},
});

const unregister = client.onDisconnected(() => {
unregister();
done();
});
});

it('should emit reconnected event for client side when socket closed', (done) => {
const client = new SubscriptionClient(`ws://localhost:${TEST_PORT}/`, {
reconnect: true,
reconnectionAttempts: 1,
connectionCallback: () => {
client.client.close();
},
});
const onReconnectingSpy = sinon.spy();
const unregisterOnReconnecting = client.onReconnecting(onReconnectingSpy);

const unregister = client.onReconnected(() => {
unregisterOnReconnecting();
unregister();
expect(onReconnectingSpy.called).to.equal(true);
done();
});
});

it('should emit reconnecting event for client side when socket closed', (done) => {
const subscriptionsClient = new SubscriptionClient(`ws://localhost:${TEST_PORT}/`, {
reconnect: true,
reconnectionAttempts: 1,
connectionCallback: () => {
subscriptionsClient.client.close();
},
});
const onReconnectedSpy = sinon.spy();
const unregisterOnReconnected = subscriptionsClient.onReconnected(onReconnectedSpy);
const unregisterOnReconnecting = subscriptionsClient.onReconnecting(() => {
unregisterOnReconnecting();
unregisterOnReconnected();
expect(onReconnectedSpy.called).to.equal(false);
done();
});
});

it('should throw an exception when query is not provided', (done) => {
const client = new SubscriptionClient(`ws://localhost:${TEST_PORT}/`);

Expand Down Expand Up @@ -481,7 +556,7 @@ describe('Client', function () {
});
});

it('should handle init_fail message and handle server that closes connection', (done) => {
it('should handle connection_error message and handle server that closes connection', (done) => {
let client: any = null;

wsServer.on('connection', (connection: any) => {
Expand Down

0 comments on commit 3b091ce

Please sign in to comment.