Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,4 @@ Released with 1.0.0-beta.37 code base.
### Fixed

- Fix intermittent CI build issues with `dtslint`. (#3479)
- Fix provider "error" / "end" events not fired when Websocket provider disconnects (#3485)
7 changes: 7 additions & 0 deletions packages/web3-core-requestmanager/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ RequestManager.prototype.setProvider = function (provider, net) {
subscription.callback(errors.ConnectionCloseError(event));
_this.subscriptions.delete(subscription.subscription.id);
});

if(_this.provider.emit){
_this.provider.emit('error', errors.ConnectionCloseError(event));
}
}
if(_this.provider.emit){
_this.provider.emit('end', event);
}
});

Expand Down
13 changes: 11 additions & 2 deletions test/eth.subscribe.ganache.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,27 @@ describe('subscription connect/reconnect', function () {
});

it('errors when the subscription got established (is running) and the connection does get closed', function () {
this.timeout(5000);
let counter = 0;

return new Promise(async function (resolve) {
web3.eth
.subscribe('newBlockHeaders')
.once('data', async function () {
await pify(server.close)();
})
.once('error', function (err) {
.on('error', function (err) {
counter++;
assert(err.message.includes('CONNECTION ERROR'));
assert(err.message.includes('close code `1006`'));
assert(err.message.includes('Connection dropped by remote peer.'));
resolve();
});

// Make sure error handler doesn't fire twice
await waitSeconds(2);
assert.equal(counter, 1);
web3.eth.currentProvider.removeAllListeners();
resolve();
});
});

Expand Down
105 changes: 105 additions & 0 deletions test/websocket.ganache.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,111 @@ describe('WebsocketProvider (ganache)', function () {
}
});

it('"error" handler fires if the client closes unilaterally', async function(){
this.timeout(5000);

server = ganache.server({port: port});
await pify(server.listen)(port);

// Open and verify connection
web3 = new Web3(new Web3.providers.WebsocketProvider(host + port));
await web3.eth.getBlockNumber();

await new Promise(async function(resolve){
web3.currentProvider.once('error', function(err){
assert(err.message.includes('Connection dropped by remote peer.'))
assert(err.message.includes('1006'));
resolve();
});

await pify(server.close)();
})
})

it('"error" handler fires if Web3 disconnects with error code', async function(){
this.timeout(5000);

server = ganache.server({port: port});
await pify(server.listen)(port);

// Open and verify connection
web3 = new Web3(new Web3.providers.WebsocketProvider(host + port));
await web3.eth.getBlockNumber();

await new Promise(async function(resolve){
web3.currentProvider.once('error', function(err){
assert(err.message.includes('1012'));
assert(err.message.includes('restart'));
resolve();
});

web3.currentProvider.disconnect(1012, 'restart');
})
})

it('"error" handler *DOES NOT* fire if disconnection is clean', async function(){
this.timeout(5000);

server = ganache.server({port: port});
await pify(server.listen)(port);

// Open and verify connection
web3 = new Web3(new Web3.providers.WebsocketProvider(host + port));
await web3.eth.getBlockNumber();

await new Promise(async function(resolve, reject){
web3.currentProvider.once('error', function(err){
reject('Should not fire error handler')
});

web3.currentProvider.disconnect(1000);
await utils.waitSeconds(2)
resolve();
})
})

it('"end" handler fires with close event object if client disconnect', async function(){
this.timeout(5000);

server = ganache.server({port: port});
await pify(server.listen)(port);

// Open and verify connection
web3 = new Web3(new Web3.providers.WebsocketProvider(host + port));
await web3.eth.getBlockNumber();

await new Promise(async function(resolve){
web3.currentProvider.once('end', function(event){
assert.equal(event.type, 'close');
assert.equal(event.wasClean, false);
resolve();
});

await pify(server.close)();
})
})

it('"end" handler fires with close event object if Web3 disconnects', async function(){
this.timeout(5000);

server = ganache.server({port: port});
await pify(server.listen)(port);

// Open and verify connection
web3 = new Web3(new Web3.providers.WebsocketProvider(host + port));
await web3.eth.getBlockNumber();

await new Promise(async function(resolve){
web3.currentProvider.once('end', function(event){
assert.equal(event.type, 'close');
assert.equal(event.wasClean, true);
resolve();
});

web3.currentProvider.disconnect(1000);
})
});

// Here, the first error (try/caught) is fired by the request queue checker in
// the onClose handler. The second error is fired by the readyState check in .send
it('errors when requests continue after socket closed', async function () {
Expand Down