Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 84ac9b7

Browse files
jdevcsAyanami
and
Ayanami
authored
Fixed unit tests & removed dead code for web3-providers-http (#5228) (#5264)
* Fixed unit tests & removed dead code for web3-providers-http (#5228) * Fixed unit tests & removed dead code for web3-providers-http * Use chai-as-promised to resolve or reject promise * Fixed bug that timeout option doesn't work properly * change log update Co-authored-by: Ayanami <[email protected]>
1 parent fc7bfcd commit 84ac9b7

File tree

4 files changed

+134
-89
lines changed

4 files changed

+134
-89
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ Released with 1.0.0-beta.37 code base.
580580
- Add optional hex formatting parameter for getTransactionrReceipt (#5153)
581581
- Fix transactionRoot -> transactionsRoot in BlockHeader (#5083)
582582
- Fix Promise in Accounts.signTransaction() throwing errors that cannot be caught (#4724)
583+
- Fixed unit tests & removed dead code for web3-providers-http (#5228)
583584

584585
### Security
585586
- Updated `got` lib version and fixed other libs using npm audit fix (#5178) (#5254)

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,15 @@
109109
"buffer": "^4.9.2",
110110
"bundlesize": "^0.18.0",
111111
"chai": "^4.2.0",
112+
"chai-as-promised": "^7.1.1",
112113
"clean-webpack-plugin": "^3.0.0",
113114
"core-js": "^3.6.5",
114115
"crypto-js": "^3.3.0",
115116
"decache": "^4.6.0",
116117
"dependency-check": "^4.1.0",
117118
"ethereumjs-util": "^7.1.0",
118119
"ethers": "^5.4.4",
120+
"fetch-mock": "^9.11.0",
119121
"ganache-cli": "^6.12.0",
120122
"jshint": "^2.12.0",
121123
"karma": "^6.3.19",

packages/web3-providers-http/src/index.js

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
*/
2525

2626
var errors = require('web3-core-helpers').errors;
27-
var fetch = require('cross-fetch');
2827
var http = require('http');
2928
var https = require('https');
3029

3130
// Apply missing polyfill for IE
31+
require('cross-fetch/polyfill');
3232
require('es6-promise').polyfill();
3333
require('abortcontroller-polyfill/dist/polyfill-patch-fetch');
3434

@@ -65,21 +65,22 @@ var HttpProvider = function HttpProvider(host, options) {
6565
*/
6666
HttpProvider.prototype.send = function (payload, callback) {
6767
var options = {
68-
method: 'POST',
69-
body: JSON.stringify(payload)
68+
method: 'POST',
69+
body: JSON.stringify(payload)
7070
};
7171
var headers = {};
7272
var controller;
7373

7474
if (typeof AbortController !== 'undefined') {
7575
controller = new AbortController();
76-
} else if (typeof AbortController === 'undefined' && typeof window !== 'undefined' && typeof window.AbortController !== 'undefined') {
76+
} else if (typeof window !== 'undefined' && typeof window.AbortController !== 'undefined') {
7777
// Some chrome version doesn't recognize new AbortController(); so we are using it from window instead
7878
// https://stackoverflow.com/questions/55718778/why-abortcontroller-is-not-defined
7979
controller = new window.AbortController();
80-
} else {
81-
// Disable user defined timeout
82-
this.timeout = 0;
80+
}
81+
82+
if (typeof controller !== 'undefined') {
83+
options.signal = controller.signal;
8384
}
8485

8586
// the current runtime is node
@@ -99,8 +100,8 @@ HttpProvider.prototype.send = function (payload, callback) {
99100
}
100101
}
101102

102-
if(this.headers) {
103-
this.headers.forEach(function(header) {
103+
if (this.headers) {
104+
this.headers.forEach(function (header) {
104105
headers[header.name] = header.value;
105106
});
106107
}
@@ -112,55 +113,43 @@ HttpProvider.prototype.send = function (payload, callback) {
112113

113114
// As the Fetch API supports the credentials as following options 'include', 'omit', 'same-origin'
114115
// https://developer.mozilla.org/en-US/docs/Web/API/fetch#credentials
115-
// To avoid breaking change in 1.x we override this value based on boolean option.
116+
// To avoid breaking change in 1.x we override this value based on boolean option.
116117
if(this.withCredentials) {
117118
options.credentials = 'include';
118119
} else {
119120
options.credentials = 'omit';
120121
}
121-
122+
122123
options.headers = headers;
123124

124-
if (this.timeout > 0) {
125-
this.timeoutId = setTimeout(function() {
125+
if (this.timeout > 0 && typeof controller !== 'undefined') {
126+
this.timeoutId = setTimeout(function () {
126127
controller.abort();
127128
}, this.timeout);
128129
}
129130

130-
// Prevent global leak of connected
131-
var _this = this;
132-
133-
var success = function(response) {
131+
var success = function (response) {
134132
if (this.timeoutId !== undefined) {
135133
clearTimeout(this.timeoutId);
136134
}
137-
var result = response;
138-
var error = null;
139-
140-
try {
141-
// Response is a stream data so should be awaited for json response
142-
result.json().then(function(data) {
143-
result = data;
144-
_this.connected = true;
145-
callback(error, result);
146-
});
147-
} catch (e) {
148-
_this.connected = false;
149-
callback(errors.InvalidResponse(result));
150-
}
135+
136+
// Response is a stream data so should be awaited for json response
137+
response.json().then(function (data) {
138+
callback(null, data);
139+
}).catch(function (error) {
140+
callback(errors.InvalidResponse(response));
141+
});
151142
};
152143

153-
var failed = function(error) {
144+
var failed = function (error) {
154145
if (this.timeoutId !== undefined) {
155146
clearTimeout(this.timeoutId);
156147
}
157148

158149
if (error.name === 'AbortError') {
159-
_this.connected = false;
160150
callback(errors.ConnectionTimeout(this.timeout));
161151
}
162152

163-
_this.connected = false;
164153
callback(errors.InvalidConnection(this.host));
165154
}
166155

test/httpprovider.js

Lines changed: 108 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,52 @@
11
var chai = require('chai');
2+
var chaiAsPromised = require('chai-as-promised');
3+
chai.use(chaiAsPromised);
24
var assert = chai.assert;
5+
var expect = chai.expect;
36
var http = require('http');
47
var https = require('https');
5-
var SandboxedModule = require('sandboxed-module');
8+
var Web3 = require('../packages/web3');
9+
var HttpProvider = require('../packages/web3-providers-http');
10+
var fetchMock = require('fetch-mock');
611

7-
SandboxedModule.registerBuiltInSourceTransformer('istanbul');
12+
function isObject(object) {
13+
return object != null && typeof object === 'object';
14+
}
815

9-
class Response {
10-
constructor(url, headers) {
11-
this.url = url;
12-
var header = new Map();
13-
headers.map(function(h) {
14-
header.set(`${h[0].toLowerCase()}`, `${h[1]}`);
15-
});
16-
this.headers = header;
17-
this.ok = true;
18-
this.status = 200;
19-
this.statusText = 'OK';
20-
}
21-
};
22-
23-
function Mock(url, options) {
24-
const response = new Response(url, Object.entries(options.headers));
25-
return new Promise(function(resolve, reject) {
26-
resolve(response);
27-
});
28-
};
29-
30-
var HttpProvider = SandboxedModule.require('../packages/web3-providers-http', {
31-
requires: {
32-
'cross-fetch': Mock,
33-
},
34-
singleOnly: true
35-
});
16+
function deepEqual(object1, object2) {
17+
const keys1 = Object.keys(object1);
18+
const keys2 = Object.keys(object2);
19+
if (keys1.length !== keys2.length) {
20+
return false;
21+
}
22+
for (const key of keys1) {
23+
const val1 = object1[key];
24+
const val2 = object2[key];
25+
const areObjects = isObject(val1) && isObject(val2);
26+
if (areObjects && !deepEqual(val1, val2) || !areObjects && val1 !== val2) {
27+
return false;
28+
}
29+
}
30+
return true;
31+
}
3632

3733
describe('web3-providers-http', function () {
3834
describe('prepareRequest', function () {
39-
it('should set request header', async function () {
35+
it('should set request header', function () {
4036
var options = {headers: [{name: 'Access-Control-Allow-Origin', value: '*'}]}
4137
var provider = new HttpProvider('http://localhost:8545', options);
4238

43-
var origin = 'Access-Control-Allow-Origin';
4439
assert.equal(provider.headers, options.headers);
40+
assert.equal(provider.httpAgent instanceof http.Agent, true);
41+
});
42+
43+
it('should have https agent', function () {
44+
var provider = new HttpProvider('https://localhost');
45+
46+
assert.equal(provider.httpsAgent instanceof https.Agent, true);
4547
});
4648

47-
it('should use the passed custom http agent', async function () {
49+
it('should use the passed custom http agent', function () {
4850
var agent = new http.Agent();
4951
var options = {agent: {http: agent}};
5052
var provider = new HttpProvider('http://localhost:8545', options);
@@ -55,7 +57,7 @@ describe('web3-providers-http', function () {
5557
assert.equal(provider.agent, options.agent);
5658
});
5759

58-
it('should use the passed custom https agent', async function () {
60+
it('should use the passed custom https agent', function () {
5961
var agent = new https.Agent();
6062
var options = {agent: {https: agent}};
6163
var provider = new HttpProvider('http://localhost:8545', options);
@@ -65,34 +67,85 @@ describe('web3-providers-http', function () {
6567
assert.equal(provider.httpsAgent, undefined);
6668
assert.equal(provider.agent, options.agent);
6769
});
70+
});
6871

69-
/**
70-
Deprecated with xhr2-cookies since this is non-standard
72+
describe('send', function () {
73+
it('should fail with invalid remote node connection', async function () {
74+
var provider = new HttpProvider('http://localhost:8545');
75+
var web3 = new Web3(provider);
7176

72-
it('should use the passed baseUrl', function () {
73-
agent = new https.Agent();
74-
options = {agent: {https: agent, baseUrl: 'base'}};
75-
provider = new HttpProvider('http://localhost:8545', options);
76-
result = provider._prepareRequest();
77+
await expect(web3.eth.getChainId()).to.be.rejectedWith(Error, "CONNECTION ERROR: Couldn't connect to node http://localhost:8545.");
78+
});
7779

78-
assert.equal(typeof result, 'object');
79-
assert.equal(result.agents.httpsAgent, agent);
80-
assert.equal(result.agents.baseUrl, 'base');
81-
assert.equal(provider.httpAgent, undefined);
82-
assert.equal(provider.httpsAgent, undefined);
83-
assert.equal(provider.agent, options.agent);
80+
it('should fail for non-json format response', async function () {
81+
var provider = new HttpProvider('/fetchMock');
82+
var web3 = new Web3(provider);
83+
84+
fetchMock.mock('/fetchMock', 'Testing non-json format response');
85+
86+
await expect(web3.eth.getChainId()).to.be.rejectedWith(Error, /Invalid JSON RPC response/);
87+
fetchMock.restore();
8488
});
85-
**/
86-
});
8789

88-
describe('send', function () {
89-
it('should send basic async request', function (done) {
90-
var provider = new HttpProvider();
90+
it('should timeout by delayed response', async function () {
91+
var provider = new HttpProvider('/fetchMock', { timeout: 500 });
92+
var web3 = new Web3(provider);
93+
94+
fetchMock.mock('/fetchMock', 'Testing non-json format response', { delay: 1000 });
95+
96+
await expect(web3.eth.getChainId()).to.be.rejectedWith(Error, 'CONNECTION TIMEOUT: timeout of 500 ms achived');
97+
fetchMock.restore();
98+
});
99+
100+
it('should send basic async request', async function () {
101+
var provider = new HttpProvider('/fetchMock');
102+
103+
var reqObject = {
104+
'jsonrpc': '2.0',
105+
'id': 0,
106+
'method': 'eth_chainId',
107+
'params': []
108+
};
109+
110+
var resObject = {
111+
'jsonrpc': '2.0',
112+
'id': 0,
113+
'result': '0x1'
114+
};
115+
116+
fetchMock.mock((url, opts) => {
117+
const reqCount = JSON.parse(opts.body).id;
118+
reqObject = JSON.stringify((() => {
119+
const obj = reqObject;
120+
obj.id = reqCount;
121+
return obj;
122+
})());
123+
resObject = (() => {
124+
const obj = resObject;
125+
obj.id = reqCount;
126+
return obj;
127+
})();
128+
const matcher = {
129+
url: '/fetchMock',
130+
method: 'POST',
131+
credentials: 'omit',
132+
headers: {
133+
'Content-Type': 'application/json'
134+
},
135+
body: reqObject
136+
};
137+
return url === matcher.url
138+
&& opts.method === matcher.method
139+
&& opts.credentials === matcher.credentials
140+
&& deepEqual(opts.headers, matcher.headers)
141+
&& opts.body === matcher.body;
142+
}, resObject);
143+
144+
var web3 = new Web3(provider);
91145

92-
provider.send({}, function (err, result) {
93-
assert.equal(typeof result, 'undefined');
94-
done();
95-
});
146+
var chainId = await web3.eth.getChainId();
147+
assert.equal(chainId, 1);
148+
fetchMock.restore();
96149
});
97150
});
98151
});

0 commit comments

Comments
 (0)