From ebba894fb33a1832392085ecf448b424b7de7c4b Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Wed, 15 May 2024 13:41:06 +0200
Subject: [PATCH 01/17] increase unit tests for SocketProvider
---
.gitignore | 2 +
packages/web3-utils/src/socket_provider.ts | 2 +-
.../test/unit/socket_provider.test.ts | 390 +++++++++++++++++-
3 files changed, 386 insertions(+), 8 deletions(-)
diff --git a/.gitignore b/.gitignore
index c22337c0c9a..72f88324900 100644
--- a/.gitignore
+++ b/.gitignore
@@ -47,3 +47,5 @@ packages/web3/.in3/
benchmark-data.txt
.eslintcache
+
+.history
\ No newline at end of file
diff --git a/packages/web3-utils/src/socket_provider.ts b/packages/web3-utils/src/socket_provider.ts
index d847dcbccc9..046fc69d0ad 100644
--- a/packages/web3-utils/src/socket_provider.ts
+++ b/packages/web3-utils/src/socket_provider.ts
@@ -360,7 +360,7 @@ export abstract class SocketProvider<
const checkQueue = async () =>
new Promise(resolve => {
const interval = setInterval(() => {
- if (forceDisconnect && retryAttempt === 5) {
+ if (forceDisconnect && retryAttempt >= 5) {
this.clearQueues();
}
if (this.getPendingRequestQueueSize() === 0 && this.getSentRequestsQueueSize() === 0) {
diff --git a/packages/web3-utils/test/unit/socket_provider.test.ts b/packages/web3-utils/test/unit/socket_provider.test.ts
index a09f1467ce0..9878879e3ba 100644
--- a/packages/web3-utils/test/unit/socket_provider.test.ts
+++ b/packages/web3-utils/test/unit/socket_provider.test.ts
@@ -15,7 +15,14 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
-import { Web3APIPayload, EthExecutionAPI, JsonRpcResponse, Web3ProviderStatus } from 'web3-types';
+import {
+ Web3APIPayload,
+ EthExecutionAPI,
+ JsonRpcResponse,
+ Web3ProviderStatus,
+ JsonRpcIdentifier,
+} from 'web3-types';
+import { MaxAttemptsReachedOnReconnectingError } from 'web3-errors';
import { EventEmitter } from '../../src/event_emitter';
// eslint-disable-next-line import/no-relative-packages
import { sleep } from '../../../../fixtures/utils';
@@ -40,8 +47,27 @@ class TestProvider extends SocketProvider {
// eslint-disable-next-line
protected _sendToSocket(_payload: Web3APIPayload): void {}
// eslint-disable-next-line
- protected _parseResponses(_event: any): JsonRpcResponse[] {
- return [] as JsonRpcResponse[];
+ protected _parseResponses(_event: { data: string } | undefined): JsonRpcResponse[] {
+ if (!_event || !_event.data) {
+ return [];
+ }
+ const returnValues: JsonRpcResponse[] = [];
+
+ // DE-CHUNKER
+ const dechunkedData = _event.data
+ .replace(/\}[\n\r]?\{/g, '}|--|{') // }{
+ .replace(/\}\][\n\r]?\[\{/g, '}]|--|[{') // }][{
+ .replace(/\}[\n\r]?\[\{/g, '}|--|[{') // }[{
+ .replace(/\}\][\n\r]?\{/g, '}]|--|{') // }]{
+ .split('|--|');
+
+ dechunkedData.forEach((chunkData: string) => {
+ const result = JSON.parse(chunkData) as unknown as JsonRpcResponse;
+
+ if (result) returnValues.push(result);
+ });
+
+ return returnValues;
}
public message(_event: any): void {
this._onMessage(_event);
@@ -74,6 +100,26 @@ describe('SocketProvider', () => {
expect(provider).toBeInstanceOf(SocketProvider);
expect(provider.SocketConnection).toEqual(dummySocketConnection);
});
+ it('should call _clearQueues when chunkResponseParser emits an error', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ const clearQueuesSpy = jest.spyOn(provider as any, '_clearQueues');
+
+ try {
+ // @ts-expect-error access readonly method
+ provider['chunkResponseParser']['autoReconnect'] = false;
+ // @ts-expect-error access readonly method
+ provider['chunkResponseParser']['chunkTimeout'] = 0;
+
+ provider['chunkResponseParser'].parseResponse('invalid-json');
+ } catch (error) {
+ // nothing
+ }
+
+ // wait 1 second for the timeout to trigger
+ await sleep(100);
+
+ expect(clearQueuesSpy).toHaveBeenCalled();
+ });
});
describe('testing _reconnect() method', () => {
it('should not be called when { autoReconnect: false }', () => {
@@ -94,6 +140,111 @@ describe('SocketProvider', () => {
// @ts-expect-error run protected method
expect(provider._reconnect).not.toHaveBeenCalled();
});
+ it('should call _reconnect when isReconnecting is true and an error happens', () => {
+ const provider = new TestProvider(socketPath, socketOption);
+ provider['_reconnect'] = jest.fn();
+ provider['isReconnecting'] = true;
+
+ provider['_onError']({});
+
+ expect(provider['_reconnect']).toHaveBeenCalled();
+ });
+
+ it('should call _reconnect when isReconnecting is false and an error happens', () => {
+ const provider = new TestProvider(socketPath, socketOption);
+ provider['_reconnect'] = jest.fn();
+ provider['isReconnecting'] = false;
+
+ provider['_onError']({});
+ expect(provider['_reconnect']).not.toHaveBeenCalled();
+ });
+
+ it('should return if the provider is already isReconnecting', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ // just to run the test faster moke `connect`
+ jest.spyOn(provider, 'connect');
+
+ // @ts-expect-error access protected method
+ expect(provider._reconnectAttempts).toBe(0);
+ provider['_reconnect']();
+ // @ts-expect-error access protected method
+ expect(provider._reconnectAttempts).toBe(1);
+
+ // after the first call provider.isReconnecting will set to true and so the `_reconnectAttempts` will not be incremented
+ provider['_reconnect']();
+
+ // @ts-expect-error access protected method
+ expect(provider._reconnectAttempts).toBe(1);
+ });
+
+ it('should reconnect the socket when the number of reconnect attempts is less than the maximum attempts', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ // @ts-expect-error access protected method
+ const openSocketConnectionSpy = jest.spyOn(provider, '_openSocketConnection');
+ // @ts-expect-error access protected method
+ const removeSocketListenersSpy = jest.spyOn(provider, '_removeSocketListeners');
+ const connectSpy = jest.spyOn(provider, 'connect');
+
+ // Set the reconnect attempts to less than the maximum attempts
+ provider['_reconnectAttempts'] = 2;
+
+ provider['_reconnect']();
+
+ // wait for the timeout to trigger
+ await sleep(100);
+
+ expect(openSocketConnectionSpy).toHaveBeenCalled();
+ expect(removeSocketListenersSpy).toHaveBeenCalled();
+ expect(connectSpy).toHaveBeenCalled();
+ });
+
+ it('should clear the queues and emit an error event when the number of reconnect attempts reaches the maximum attempts', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ const clearQueuesSpy = jest.spyOn(provider as any, '_clearQueues');
+ // @ts-expect-error access protected method
+ const removeSocketListenersSpy = jest.spyOn(provider, '_removeSocketListeners');
+ const errorEventSpy = jest.spyOn(provider['_eventEmitter'], 'emit');
+
+ // Set the reconnect attempts to the maximum attempts
+ provider['_reconnectAttempts'] = 5;
+
+ provider['_reconnect']();
+
+ // wait for the timeout to trigger
+ await sleep(100);
+
+ expect(clearQueuesSpy).toHaveBeenCalled();
+ expect(removeSocketListenersSpy).toHaveBeenCalled();
+ expect(errorEventSpy).toHaveBeenCalledWith(
+ 'error',
+ expect.any(MaxAttemptsReachedOnReconnectingError),
+ );
+ });
+
+ it('should keep pending requests but clear the sent requests queue when reconnecting', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+
+ provider.setStatus('connected');
+ // Add a sent request
+ provider.request({ id: 2, method: 'some_rpc_method' }).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ // @ts-expect-error run protected method
+ expect(provider._sentRequestsQueue.size).toBe(1);
+
+ // @ts-expect-error access protected method
+ const rejectSpy = jest.spyOn(provider['_pendingRequestsQueue'], 'delete');
+ const deleteSpy = jest.spyOn(provider['_sentRequestsQueue'], 'delete');
+
+ const pendingRequestsQueueSize = provider['_pendingRequestsQueue'].size;
+ const sentRequestsQueueSize = provider['_sentRequestsQueue'].size;
+
+ provider['_reconnect']();
+
+ expect(provider['_pendingRequestsQueue'].size).toEqual(pendingRequestsQueueSize);
+
+ expect(deleteSpy).toHaveBeenCalledTimes(sentRequestsQueueSize);
+ });
});
describe('testing connect() method', () => {
@@ -213,9 +364,7 @@ describe('SocketProvider', () => {
const funcBSpy = jest
// spy on provider.super._onDisconnect
.spyOn(
- Object.getPrototypeOf(
- Object.getPrototypeOf(Object.getPrototypeOf(provider)),
- ),
+ Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(provider))),
'_onDisconnect',
)
.mockReturnValue(new EventEmitter());
@@ -298,6 +447,30 @@ describe('SocketProvider', () => {
// @ts-expect-error run protected method
expect(provider._sentRequestsQueue.get(payload.id).payload).toBe(payload);
});
+ it('should clear _sentRequestsQueue in case `_sendToSocket` had an error', async () => {
+ // Create a mock SocketProvider instance
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+
+ const deleteSpy = jest.spyOn(provider['_sentRequestsQueue'], 'delete');
+
+ provider.setStatus('connected');
+ // Assert that the _sendToSocket method was called with the correct payload
+ // @ts-expect-error access protected method
+ provider._sendToSocket = () => {
+ throw new Error('any error');
+ };
+ // Call the request method
+ provider
+ .request({ id: 1, method: 'some_rpc_method' })
+ .then(() => {
+ // nothing
+ })
+ .catch(() => {
+ // nothing
+ });
+
+ expect(deleteSpy).toHaveBeenCalled();
+ });
});
describe('testing _clearQueues() method', () => {
@@ -339,4 +512,207 @@ describe('SocketProvider', () => {
});
});
});
-});
+
+ describe('safeDisconnect', () => {
+ it('should disconnect the socket when there are no pending or sent requests', async () => {
+ const provider = new TestProvider(socketPath, socketOption);
+ const disconnectSpy = jest.spyOn(provider, 'disconnect');
+ await provider.safeDisconnect();
+ expect(disconnectSpy).toHaveBeenCalled();
+ });
+
+ it('should disconnect the socket after waiting for pending and sent requests to be empty', async () => {
+ const provider = new TestProvider(socketPath, socketOption);
+ const disconnectSpy = jest.spyOn(provider, 'disconnect');
+
+ // Add a pending request
+ provider.request({ id: 1, method: 'some_rpc_method' }).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ // Add a sent request
+ provider.request({ id: 2, method: 'some_rpc_method' }).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ expect(provider.getPendingRequestQueueSize()).toBe(2);
+
+ provider.clearQueues();
+ // Call safeDisconnect and wait for the queues to be empty
+ await provider.safeDisconnect(undefined, undefined, false, 100);
+
+ expect(disconnectSpy).toHaveBeenCalled();
+ expect(provider.getPendingRequestQueueSize()).toBe(0);
+ expect(provider.getSentRequestsQueueSize()).toBe(0);
+ });
+
+ it('should force disconnect the socket after waiting for 5 attempts', async () => {
+ const provider = new TestProvider(socketPath, socketOption);
+ const disconnectSpy = jest.spyOn(provider, 'disconnect');
+ const clearQueuesSpy = jest.spyOn(provider as any, 'clearQueues');
+
+ // Add a pending request
+ provider.request({ id: 1, method: 'some_rpc_method' }).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ expect(provider.getPendingRequestQueueSize()).toBe(1);
+
+ // Add a sent request
+ provider.request({ id: 2, method: 'some_rpc_method' }).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ // expect(provider.getSentRequestsQueueSize()).toBe(1);
+
+ // Call safeDisconnect with forceDisconnect set to true and a small interval
+ await provider.safeDisconnect(undefined, undefined, true, 100);
+
+ expect(disconnectSpy).toHaveBeenCalled();
+ expect(clearQueuesSpy).toHaveBeenCalled();
+ });
+ });
+ describe('removeAllListeners', () => {
+ it('should remove all listeners for the specified event type', () => {
+ const provider = new TestProvider(socketPath, socketOption);
+ const listener1 = jest.fn();
+ const listener2 = jest.fn();
+ const listener3 = jest.fn();
+ provider.on('event', listener1);
+ provider.on('event', listener2);
+ provider.on('otherEvent', listener3);
+
+ provider.removeAllListeners('event');
+
+ provider['_eventEmitter'].emit('event');
+ provider['_eventEmitter'].emit('otherEvent');
+
+ expect(listener1).not.toHaveBeenCalled();
+ expect(listener2).not.toHaveBeenCalled();
+ expect(listener3).toHaveBeenCalled();
+ });
+ });
+
+ describe('_sendPendingRequests', () => {
+ it('should send pending requests to the socket', () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+
+ const payload1 = { id: 1, method: 'method1', params: [] };
+ const payload2 = { id: 2, method: 'method2', params: [] };
+ // Add a pending request
+ provider.request(payload1).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ // Add a sent request
+ provider.request(payload2).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ expect(provider.getPendingRequestQueueSize()).toBe(2);
+
+ provider['_sendToSocket'] = jest.fn();
+
+ provider['_sendPendingRequests']();
+
+ expect(provider['_sendToSocket']).toHaveBeenCalledTimes(2);
+ expect(provider['_sendToSocket']).toHaveBeenCalledWith(payload1);
+ expect(provider['_sendToSocket']).toHaveBeenCalledWith(payload2);
+ expect(provider['_pendingRequestsQueue'].size).toBe(0);
+ expect(provider['_sentRequestsQueue'].size).toBe(2);
+ });
+
+ it('should not send any requests if the pending requests queue is empty', () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ provider['_sendToSocket'] = jest.fn();
+
+ provider['_sendPendingRequests']();
+
+ expect(provider['_sendToSocket']).not.toHaveBeenCalled();
+ expect(provider['_pendingRequestsQueue'].size).toBe(0);
+ expect(provider['_sentRequestsQueue'].size).toBe(0);
+ });
+ });
+
+ describe('_onConnect', () => {
+ it('should set the connection status to "connected"', () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+
+ // Act
+ provider['_onConnect']();
+
+ expect(provider['_connectionStatus']).toBe('connected');
+ });
+ });
+
+ describe('_onMessage', () => {
+ it('should resolve the deferred promise for valid responses with errors', () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+
+ const payload1 = {
+ id: 1,
+ method: 'method1',
+ params: [],
+ jsonrpc: '2.0' as JsonRpcIdentifier,
+ error: { code: -32601, message: 'Method not found' },
+ };
+ const event = {
+ data: JSON.stringify(payload1),
+ };
+ // Add a pending request
+ provider.request(payload1).catch(() => {
+ // it will throw with "Connection not open" because no actual connection is used in the test. So ignore the error
+ });
+ expect(provider.getPendingRequestQueueSize()).toBe(1);
+
+ // @ts-expect-error access protected method
+ provider['_sentRequestsQueue'] = provider['_pendingRequestsQueue'];
+
+ const deferredPromiseResolveSpy = jest.spyOn(
+ provider['_sentRequestsQueue'].get(1)!.deferredPromise,
+ 'resolve',
+ );
+ provider['_onMessage']({
+ ...event,
+ });
+
+ expect(deferredPromiseResolveSpy).toHaveBeenCalledWith(payload1);
+ });
+
+ it('should not emit "message" event for invalid responses', () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ const event = {
+ data: JSON.stringify([
+ { id: 1, jsonrpc: '2.0', error: { code: -32601, message: 'Method not found' } },
+ { id: 2, jsonrpc: '2.0', error: { code: -32601, message: 'Method not found' } },
+ ]),
+ };
+
+ const eventEmitterSpy = jest.spyOn(provider['_eventEmitter'], 'emit');
+
+ provider['_onMessage'](event);
+
+ expect(eventEmitterSpy).not.toHaveBeenCalledWith('message', {
+ id: 1,
+ jsonrpc: '2.0',
+ error: { code: -32601, message: 'Method not found' },
+ });
+ expect(eventEmitterSpy).not.toHaveBeenCalledWith('message', {
+ id: 2,
+ jsonrpc: '2.0',
+ error: { code: -32601, message: 'Method not found' },
+ });
+ });
+
+ it('should emit "message" event for notifications', () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ const event = {
+ data: JSON.stringify({ jsonrpc: '2.0', method: 'notification_1_subscription', params: {} }),
+ };
+
+ const eventEmitterSpy = jest.spyOn(provider['_eventEmitter'], 'emit');
+
+ provider['_onMessage'](event);
+
+ expect(eventEmitterSpy).toHaveBeenCalledWith('message', {
+ jsonrpc: '2.0',
+ method: 'notification_1_subscription',
+ params: {},
+ });
+ });
+ });
+});
\ No newline at end of file
From 5dc439067f49fc5a17e0b2a0bfadf58bb1edf695 Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Thu, 16 May 2024 15:15:54 +0200
Subject: [PATCH 02/17] add a test for SocketProvider
---
.../web3-utils/test/unit/socket_provider.test.ts | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/packages/web3-utils/test/unit/socket_provider.test.ts b/packages/web3-utils/test/unit/socket_provider.test.ts
index 9878879e3ba..9dd9ed69170 100644
--- a/packages/web3-utils/test/unit/socket_provider.test.ts
+++ b/packages/web3-utils/test/unit/socket_provider.test.ts
@@ -447,6 +447,22 @@ describe('SocketProvider', () => {
// @ts-expect-error run protected method
expect(provider._sentRequestsQueue.get(payload.id).payload).toBe(payload);
});
+
+ it('should add request to the `_sentRequestsQueue` when the status is `connected` for batch requests', () => {
+ const provider = new TestProvider(socketPath, socketOption);
+ const payload = [
+ { id: 1, method: 'some_rpc_method', jsonrpc: '2.0' as JsonRpcIdentifier },
+ { id: 2, method: 'some_rpc_method', jsonrpc: '2.0' as JsonRpcIdentifier },
+ ];
+ provider.setStatus('connected');
+ const reqPromise = provider.request(payload as any);
+ expect(reqPromise).toBeInstanceOf(Promise);
+
+ // the id of the first request in the batch is the one used to identify the batch request
+ // @ts-expect-error run protected method
+ expect(provider._sentRequestsQueue.get(payload[0].id).payload).toBe(payload);
+ });
+
it('should clear _sentRequestsQueue in case `_sendToSocket` had an error', async () => {
// Create a mock SocketProvider instance
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
From 9f9d6df55a8b8bdd63c5dc66ab70811ac542aca7 Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Thu, 16 May 2024 15:34:59 +0200
Subject: [PATCH 03/17] add a test for PromiseHelper
---
packages/web3-utils/src/promise_helpers.ts | 2 +-
.../test/unit/promise_helpers.test.ts | 18 ++++++++++++++----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/packages/web3-utils/src/promise_helpers.ts b/packages/web3-utils/src/promise_helpers.ts
index c8e211fbbb7..1b9c37ffc3a 100644
--- a/packages/web3-utils/src/promise_helpers.ts
+++ b/packages/web3-utils/src/promise_helpers.ts
@@ -146,7 +146,7 @@ export function rejectIfTimeout(timeout: number, error: Error): [Timer, Promise<
/**
* Sets an interval that repeatedly executes the given cond function with the specified interval between each call.
* If the condition is met, the interval is cleared and a Promise that rejects with the returned value is returned.
- * @param cond - The function/confition to call.
+ * @param cond - The function/condition to call.
* @param interval - The interval in milliseconds.
* @returns - an array with the interval ID and the Promise.
*/
diff --git a/packages/web3-utils/test/unit/promise_helpers.test.ts b/packages/web3-utils/test/unit/promise_helpers.test.ts
index b18f4f1a5b0..f5df1dc1f25 100644
--- a/packages/web3-utils/test/unit/promise_helpers.test.ts
+++ b/packages/web3-utils/test/unit/promise_helpers.test.ts
@@ -60,6 +60,14 @@ describe('promise helpers', () => {
new Error('time out'),
);
});
+ it('throws if result is an instance of Error', async () => {
+ const dummyError = new Error('dummy error');
+ const asyncHelper = async () => {
+ return dummyError;
+ };
+
+ await expect(waitWithTimeout(asyncHelper(), 1000)).rejects.toThrow(dummyError);
+ });
});
describe('rejectIfTimeout', () => {
it('%s', async () => {
@@ -147,20 +155,22 @@ describe('promise helpers', () => {
});
it('should return interval id if not resolved in specific time', async () => {
-
let counter = 0;
const asyncHelper = async () => {
if (counter <= 3000000) {
counter += 1;
return undefined;
}
- return "result";
+ return 'result';
};
const testError = new Error('Test P2 Error');
- const [neverResolvePromise, intervalId] = pollTillDefinedAndReturnIntervalId(asyncHelper, 100);
- const promiCheck = Promise.race([neverResolvePromise, rejectIfTimeout(500,testError)[1]]);
+ const [neverResolvePromise, intervalId] = pollTillDefinedAndReturnIntervalId(
+ asyncHelper,
+ 100,
+ );
+ const promiCheck = Promise.race([neverResolvePromise, rejectIfTimeout(500, testError)[1]]);
await expect(promiCheck).rejects.toThrow(testError);
expect(intervalId).toBeDefined();
From 82a16b365e2f8558f53e300bf44ae4e6c5036ef1 Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Mon, 20 May 2024 02:29:32 +0200
Subject: [PATCH 04/17] add unit tests for utils
---
.../web3-utils/test/fixtures/converters.ts | 1 +
.../web3-utils/test/unit/converters.test.ts | 46 +++++++++++--
packages/web3-utils/test/unit/index.test.ts | 64 +++++++++++++++++++
packages/web3-utils/test/unit/objects.test.ts | 9 +++
.../test/unit/web3_deferred_promise.test.ts | 15 ++++-
5 files changed, 130 insertions(+), 5 deletions(-)
create mode 100644 packages/web3-utils/test/unit/index.test.ts
diff --git a/packages/web3-utils/test/fixtures/converters.ts b/packages/web3-utils/test/fixtures/converters.ts
index 91f3a76f738..3a443ad4079 100644
--- a/packages/web3-utils/test/fixtures/converters.ts
+++ b/packages/web3-utils/test/fixtures/converters.ts
@@ -359,6 +359,7 @@ export const bytesToUint8ArrayValidData: [Bytes, Uint8Array][] = [
['0x1234', new Uint8Array([18, 52])],
['0x1234', new Uint8Array([18, 52])],
[new Uint8Array(hexToBytes('0c12')), new Uint8Array(hexToBytes('0c12'))],
+ [[72, 12] as any, new Uint8Array([72, 12])],
];
export const toBigIntValidData: [any, bigint][] = [
diff --git a/packages/web3-utils/test/unit/converters.test.ts b/packages/web3-utils/test/unit/converters.test.ts
index 940590f06e7..8710eaee2e9 100644
--- a/packages/web3-utils/test/unit/converters.test.ts
+++ b/packages/web3-utils/test/unit/converters.test.ts
@@ -15,6 +15,9 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
+import { InvalidBytesError } from 'web3-errors';
+import { validator, utils } from 'web3-validator';
+
import {
asciiToHex,
bytesToHex,
@@ -76,7 +79,6 @@ import {
toBoolValidData,
toBoolInvalidData,
} from '../fixtures/converters';
-
describe('converters', () => {
describe('bytesToHex', () => {
describe('valid cases', () => {
@@ -375,10 +377,9 @@ describe('converters', () => {
it.each(toWeiValidDataWarnings)('%s', (input, output) => {
toWei(input[0], input[1]);
// expect(() => toWei(input[0], input[1])).toThrow(output);
- expect(console.warn).toHaveBeenCalledWith(output)
+ expect(console.warn).toHaveBeenCalledWith(output);
});
-
- })
+ });
});
describe('toChecksumAddress', () => {
describe('valid cases', () => {
@@ -391,6 +392,31 @@ describe('converters', () => {
expect(() => toChecksumAddress(input)).toThrow(output);
});
});
+ it('should return an empty string if hash is nullish', () => {
+ const address = '0xc1912fee45d61c87cc5ea59dae31190fffff232d';
+
+ // mock utils.uint8ArrayToHexString to return an empty string
+ jest.mock('web3-validator');
+ jest.spyOn(utils, 'uint8ArrayToHexString').mockReturnValue(undefined as unknown as string);
+
+ const result = toChecksumAddress(address);
+ expect(result).toEqual('');
+
+ jest.mock('web3-validator').restoreAllMocks();
+ });
+
+ it('should return an empty string if hash is equal to "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"', () => {
+ const address = '0xc1912fee45d61c87cc5ea59dae31190fffff232d';
+
+ // mock utils.uint8ArrayToHexString to return '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'
+ jest.mock('web3-validator');
+ const hash = '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
+ jest.spyOn(utils, 'uint8ArrayToHexString').mockReturnValue(hash);
+ const result = toChecksumAddress(address);
+ expect(result).toEqual('');
+
+ jest.mock('web3-validator').restoreAllMocks();
+ });
});
describe('bytesToUint8Array', () => {
describe('bytesToUint8Array', () => {
@@ -404,6 +430,18 @@ describe('converters', () => {
it.each(bytesToUint8ArrayInvalidData)('%s', (input, output) => {
expect(() => bytesToUint8Array(input)).toThrow(output);
});
+
+ it('should throw InvalidBytesError for invalid input even if it passed the validator', () => {
+ const invalidData = 8;
+ // the package 'web3-validator' contains `validator`.
+ // Mock mock the `validator.validate(...)` to not throw an error, but return `false` instead.
+ jest.mock('web3-validator');
+
+ jest.spyOn(validator, 'validate').mockReturnValue(undefined);
+
+ expect(() => bytesToUint8Array(invalidData as any)).toThrow(InvalidBytesError);
+ jest.mock('web3-validator').restoreAllMocks();
+ });
});
});
});
diff --git a/packages/web3-utils/test/unit/index.test.ts b/packages/web3-utils/test/unit/index.test.ts
new file mode 100644
index 00000000000..8682408801a
--- /dev/null
+++ b/packages/web3-utils/test/unit/index.test.ts
@@ -0,0 +1,64 @@
+/*
+This file is part of web3.js.
+
+web3.js is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+web3.js is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with web3.js. If not, see .
+*/
+
+import * as web3Utils from '../../src';
+
+import * as converters from '../../src/converters.js';
+import * as eventEmitter from '../../src/event_emitter.js';
+import * as validation from '../../src/validation.js';
+import * as formatter from '../../src/formatter.js';
+import * as hash from '../../src/hash.js';
+import * as random from '../../src/random.js';
+import * as stringManipulation from '../../src/string_manipulation.js';
+import * as objects from '../../src/objects.js';
+import * as promiseHelpers from '../../src/promise_helpers.js';
+import * as jsonRpc from '../../src/json_rpc.js';
+import * as web3DeferredPromise from '../../src/web3_deferred_promise.js';
+import * as ChunkResponseParser from '../../src/chunk_response_parser.js';
+import * as uuid from '../../src/uuid.js';
+import * as web3Eip1193Provider from '../../src/web3_eip1193_provider.js';
+import * as socketProvider from '../../src/socket_provider.js';
+import * as uint8array from '../../src/uint8array.js';
+
+describe('web3-utils exports', () => {
+ it('should export all modules', () => {
+ const modules = [
+ converters,
+ eventEmitter,
+ validation,
+ formatter,
+ hash,
+ random,
+ stringManipulation,
+ objects,
+ promiseHelpers,
+ jsonRpc,
+ web3DeferredPromise,
+ ChunkResponseParser,
+ uuid,
+ web3Eip1193Provider,
+ socketProvider,
+ uint8array,
+ ];
+
+ modules.forEach(module => {
+ Object.keys(module).forEach((property: string | any[]) => {
+ expect(web3Utils).toHaveProperty(property);
+ });
+ });
+ });
+});
diff --git a/packages/web3-utils/test/unit/objects.test.ts b/packages/web3-utils/test/unit/objects.test.ts
index 1201b3b7345..cca9d46cba9 100644
--- a/packages/web3-utils/test/unit/objects.test.ts
+++ b/packages/web3-utils/test/unit/objects.test.ts
@@ -79,5 +79,14 @@ describe('objects', () => {
expect(result.a).toStrictEqual(new Uint8Array([1, 2]));
});
+
+ it('should return the destination object if it is not iterable', () => {
+ const destination = 123; // Replace with your desired destination object
+ const sources: Record[] = []; // Replace with your desired sources array
+
+ const result = mergeDeep(destination as unknown as Record, ...sources);
+
+ expect(result).toBe(destination);
+ });
});
});
diff --git a/packages/web3-utils/test/unit/web3_deferred_promise.test.ts b/packages/web3-utils/test/unit/web3_deferred_promise.test.ts
index b8180705969..044f558fb10 100644
--- a/packages/web3-utils/test/unit/web3_deferred_promise.test.ts
+++ b/packages/web3-utils/test/unit/web3_deferred_promise.test.ts
@@ -53,4 +53,17 @@ describe('Web3DeferredPromise', () => {
expect(promise.state).toBe('rejected');
});
});
-});
+
+ describe('Web3DeferredPromise finally', () => {
+ it('should execute the callback when the promise is settled', async () => {
+ const promise = new Web3DeferredPromise();
+ let callbackExecuted = false;
+ promise.resolve(1);
+ await promise.finally(() => {
+ callbackExecuted = true;
+ });
+
+ expect(callbackExecuted).toBe(true);
+ });
+ });
+});
\ No newline at end of file
From ad73c898aa671ae3df66e3a3454a1c5335297d18 Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Mon, 20 May 2024 02:29:47 +0200
Subject: [PATCH 05/17] remove un visited code branch
---
packages/web3-utils/src/converters.ts | 3 ---
1 file changed, 3 deletions(-)
diff --git a/packages/web3-utils/src/converters.ts b/packages/web3-utils/src/converters.ts
index 55143a4277c..8e34e17bb49 100644
--- a/packages/web3-utils/src/converters.ts
+++ b/packages/web3-utils/src/converters.ts
@@ -383,9 +383,6 @@ export const toHex = (
if (isHex(value) && !isInt(value) && !isUInt(value)) {
return returnType ? 'bytes' : `0x${value}`;
}
- if (isHex(value) && !isInt(value) && isUInt(value)) {
- return returnType ? 'uint' : numberToHex(value);
- }
if (!Number.isFinite(value)) {
return returnType ? 'string' : utf8ToHex(value);
From 0d09e92024785eb7368db520a1b80665a5512434 Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Mon, 20 May 2024 02:35:11 +0200
Subject: [PATCH 06/17] fix linting issue
---
packages/web3-utils/test/unit/converters.test.ts | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/packages/web3-utils/test/unit/converters.test.ts b/packages/web3-utils/test/unit/converters.test.ts
index 8710eaee2e9..7c566aaa2a1 100644
--- a/packages/web3-utils/test/unit/converters.test.ts
+++ b/packages/web3-utils/test/unit/converters.test.ts
@@ -79,6 +79,7 @@ import {
toBoolValidData,
toBoolInvalidData,
} from '../fixtures/converters';
+
describe('converters', () => {
describe('bytesToHex', () => {
describe('valid cases', () => {
@@ -400,7 +401,7 @@ describe('converters', () => {
jest.spyOn(utils, 'uint8ArrayToHexString').mockReturnValue(undefined as unknown as string);
const result = toChecksumAddress(address);
- expect(result).toEqual('');
+ expect(result).toBe('');
jest.mock('web3-validator').restoreAllMocks();
});
@@ -413,7 +414,7 @@ describe('converters', () => {
const hash = '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470';
jest.spyOn(utils, 'uint8ArrayToHexString').mockReturnValue(hash);
const result = toChecksumAddress(address);
- expect(result).toEqual('');
+ expect(result).toBe('');
jest.mock('web3-validator').restoreAllMocks();
});
From b0e0bb40793b93ee14e2f30736d7034b65e0e14a Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Mon, 20 May 2024 03:49:37 +0200
Subject: [PATCH 07/17] point to a pice of code to investigate
---
packages/web3-utils/src/converters.ts | 12 ++++++++++++
packages/web3-utils/test/unit/converters.test.ts | 10 ++++++++++
2 files changed, 22 insertions(+)
diff --git a/packages/web3-utils/src/converters.ts b/packages/web3-utils/src/converters.ts
index 8e34e17bb49..bce8e635044 100644
--- a/packages/web3-utils/src/converters.ts
+++ b/packages/web3-utils/src/converters.ts
@@ -383,6 +383,18 @@ export const toHex = (
if (isHex(value) && !isInt(value) && !isUInt(value)) {
return returnType ? 'bytes' : `0x${value}`;
}
+ if (isHex(value) && !isInt(value) && isUInt(value)) {
+ // This condition seems problematic because meeting
+ // both conditions `!isInt(value) && isUInt(value)` should be impossible.
+ // But a value pass for those conditions: "101611154195520776335741463917853444671577865378275924493376429267637792638729"
+ // Note that according to the docs: it is supposed to be treated as a string (https://docs.web3js.org/guides/web3_upgrade_guide/x/web3_utils_migration_guide#conversion-to-hex)
+ // In short, the strange is that isInt(value) is false but isUInt(value) is true for the value above.
+ // So, isUInt(value) should be investigated.
+
+ // However, if `toHex('101611154195520776335741463917853444671577865378275924493376429267637792638729', true)` is called, it will return `true`.
+ // But, if `toHex('101611154195520776335741463917853444671577865378275924493376429267637792638729')` is called, it will throw inside `numberToHex`.
+ return returnType ? 'uint' : numberToHex(value);
+ }
if (!Number.isFinite(value)) {
return returnType ? 'string' : utf8ToHex(value);
diff --git a/packages/web3-utils/test/unit/converters.test.ts b/packages/web3-utils/test/unit/converters.test.ts
index 7c566aaa2a1..2ad49619652 100644
--- a/packages/web3-utils/test/unit/converters.test.ts
+++ b/packages/web3-utils/test/unit/converters.test.ts
@@ -328,6 +328,16 @@ describe('converters', () => {
it.each(toHexValidData)('%s', (input, output) => {
expect(toHex(input, true)).toEqual(output[1]);
});
+
+ it('an interesting case that needs investigation', () => {
+ // This case is to be investigated further
+ expect(
+ toHex(
+ '101611154195520776335741463917853444671577865378275924493376429267637792638729',
+ true,
+ ),
+ ).toEqual('uint');
+ });
});
describe('invalid cases', () => {
From 5b9bb46fc06f38d25b792967cd8a86d0deab3fc0 Mon Sep 17 00:00:00 2001
From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Mon, 20 May 2024 03:52:53 +0200
Subject: [PATCH 08/17] fix linting issue
---
packages/web3-utils/test/unit/converters.test.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/web3-utils/test/unit/converters.test.ts b/packages/web3-utils/test/unit/converters.test.ts
index 2ad49619652..ae4a461ac08 100644
--- a/packages/web3-utils/test/unit/converters.test.ts
+++ b/packages/web3-utils/test/unit/converters.test.ts
@@ -336,7 +336,7 @@ describe('converters', () => {
'101611154195520776335741463917853444671577865378275924493376429267637792638729',
true,
),
- ).toEqual('uint');
+ ).toBe('uint');
});
});
From 1392b05e9a328e47c90870ed4e7b18c2706aec2b Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Thu, 23 May 2024 14:55:33 -0400
Subject: [PATCH 09/17] add coverage to hash
---
packages/web3-utils/src/hash.ts | 3 ---
packages/web3-utils/test/fixtures/converters.ts | 3 ++-
packages/web3-utils/test/fixtures/hash.ts | 6 ++++++
packages/web3-utils/test/unit/hash.test.ts | 8 ++++++++
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/packages/web3-utils/src/hash.ts b/packages/web3-utils/src/hash.ts
index 6e498138c29..f7acc4f4fb9 100644
--- a/packages/web3-utils/src/hash.ts
+++ b/packages/web3-utils/src/hash.ts
@@ -169,9 +169,6 @@ export { keccak256Wrapper as keccak256 };
* @returns - the type and value of the input
*/
const getType = (arg: Sha3Input): [string, EncodingTypes] => {
- if (Array.isArray(arg)) {
- throw new Error('Autodetection of array types is not supported.');
- }
let type;
let value;
diff --git a/packages/web3-utils/test/fixtures/converters.ts b/packages/web3-utils/test/fixtures/converters.ts
index 2c20b823380..faa9f8bfe04 100644
--- a/packages/web3-utils/test/fixtures/converters.ts
+++ b/packages/web3-utils/test/fixtures/converters.ts
@@ -328,7 +328,7 @@ export const fromWeiValidData: [[Numbers, EtherUnits | number], Numbers][] = [
[['1123456789123456789', 'ether'], '1.123456789123456789'],
[['1123', 'kwei'], '1.123'],
[['1234100' ,'kwei'], '1234.1'],
- [['3308685546611893', 'ether'], '0.003308685546611893']
+ [['3308685546611893', 'ether'], '0.003308685546611893'],
];
export const toWeiValidData: [[Numbers, EtherUnits | number], Numbers][] = [
@@ -374,6 +374,7 @@ export const toWeiInvalidData: [[any, any], string][] = [
[[{}, 'kwei'], 'value "{}" at "/0" must pass "number" validation'],
[['data', 'kwei'], 'value "data" at "/0" must pass "number" validation'],
[['1234', 'uwei'], 'Invalid value given "uwei". Error: invalid unit.'],
+ [['123', -1], 'Invalid value given "-1". Error: not a valid unit. Must be a positive integer.'],
];
export const toCheckSumValidData: [string, string][] = [
['0x0089d53f703f7e0843953d48133f74ce247184c2', '0x0089d53F703f7E0843953D48133f74cE247184c2'],
diff --git a/packages/web3-utils/test/fixtures/hash.ts b/packages/web3-utils/test/fixtures/hash.ts
index 6bfe9f63f33..4f337c191ae 100644
--- a/packages/web3-utils/test/fixtures/hash.ts
+++ b/packages/web3-utils/test/fixtures/hash.ts
@@ -256,6 +256,7 @@ export const encodePackData: [TypedObject[] | TypedObjectAbbreviated[], any][] =
'0x12480000000000000000000000000000000000000000000000000000000000003c69a194aaf415ba5d6afca734660d0a3d45acdc05d54cd1ca89a8988e7625b4',
],
[[{ type: 'bytes4[]', value: ['0x11223344', '0x22334455'] }], '0x1122334422334455'],
+ [[{ type: '', value: '31323334' }], '0x'],
];
export const encodePackedInvalidData: [any, string][] = [
@@ -349,3 +350,8 @@ export const soliditySha3BigIntValidData: [Sha3Input[], string][] = [
return keccak256(abi.encodePacked(int(90071992547409))) ;}
*/
];
+
+export const getStorageSlotNumForLongStringValidData: [string|number, string | undefined][]
+ = [
+ [0, "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"]
+ ];
\ No newline at end of file
diff --git a/packages/web3-utils/test/unit/hash.test.ts b/packages/web3-utils/test/unit/hash.test.ts
index d381e3c4240..13b4c6aa1df 100644
--- a/packages/web3-utils/test/unit/hash.test.ts
+++ b/packages/web3-utils/test/unit/hash.test.ts
@@ -23,6 +23,7 @@ import {
soliditySha3Raw,
encodePacked,
keccak256 as web3keccak256,
+ getStorageSlotNumForLongString,
} from '../../src/hash';
import {
sha3Data,
@@ -37,6 +38,7 @@ import {
encodePackedInvalidData,
keccak256ValidData,
soliditySha3BigIntValidData,
+ getStorageSlotNumForLongStringValidData,
} from '../fixtures/hash';
describe('hash', () => {
@@ -149,4 +151,10 @@ describe('hash', () => {
});
});
});
+
+ describe('getStorageSlotNumForLongString', () => {
+ it.each(getStorageSlotNumForLongStringValidData)('%s', (input, output) => {
+ expect(getStorageSlotNumForLongString(input)).toEqual(output);
+ });
+ })
});
From f9559f334502ab4a3a81a3c24e02993680627ef2 Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Thu, 23 May 2024 17:17:09 -0400
Subject: [PATCH 10/17] cover json-rpc tests
---
packages/web3-utils/src/json_rpc.ts | 2 +-
packages/web3-utils/test/fixtures/json_rpc.ts | 17 ++++++++
.../web3-utils/test/unit/json_rpc.test.ts | 42 +++++++++++++++++--
3 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/packages/web3-utils/src/json_rpc.ts b/packages/web3-utils/src/json_rpc.ts
index 573d39197e3..495a425611f 100644
--- a/packages/web3-utils/src/json_rpc.ts
+++ b/packages/web3-utils/src/json_rpc.ts
@@ -99,7 +99,7 @@ let requestIdSeed: number | undefined;
/**
* Optionally use to make the jsonrpc `id` start from a specific number.
* Without calling this function, the `id` will be filled with a Uuid.
- * But after this being called with a number, the `id` will be a number staring from the provided `start` variable.
+ * But after this being called with a number, the `id` will be a number starting from the provided `start` variable.
* However, if `undefined` was passed to this function, the `id` will be a Uuid again.
* @param start - a number to start incrementing from.
* Or `undefined` to use a new Uuid (this is the default behavior)
diff --git a/packages/web3-utils/test/fixtures/json_rpc.ts b/packages/web3-utils/test/fixtures/json_rpc.ts
index 516711abceb..2be0f19b435 100644
--- a/packages/web3-utils/test/fixtures/json_rpc.ts
+++ b/packages/web3-utils/test/fixtures/json_rpc.ts
@@ -18,6 +18,7 @@ import { JsonRpcNotification, SubscriptionParams } from 'web3-types';
const responseWithResult = { jsonrpc: '2.0', id: 1, result: '' };
const responseWithError = { jsonrpc: '2.0', id: 1, error: { code: 1, message: 'string' } };
+const responseWithRpcError = { jsonrpc: '2.0', id: 1, error: { code: -32000, message: 'string' } };
const responseWithSubscription = { id: 1, jsonrpc: '2.0', result: '' };
const responseWithNotfication = {
jsonrpc: '2.0',
@@ -27,11 +28,13 @@ const responseWithNotfication = {
export const isResponseWithResultValidTest: [any, boolean][] = [
[responseWithResult, true],
[responseWithError, false],
+ [{...responseWithResult, id: '1'}, true],
];
export const isResponseWithErrorValidTest: [any, boolean][] = [
[responseWithResult, false],
[responseWithError, true],
+ [{...responseWithError, id: '1'}, true],
];
export const isResponseWithNotificationValidTest: [JsonRpcNotification, boolean][] = [
@@ -63,4 +66,18 @@ export const toPayloadValidTest: [any, any][] = [
params: undefined,
},
],
+ [
+ { method: 'add', jsonrpc: '1.0', id: 1},
+ {
+ method: 'add',
+ id: 1,
+ jsonrpc: '1.0',
+ params: undefined
+ },
+ ]
];
+
+export const isResponseRpcErrorValidData: [any, boolean][] = [
+ [responseWithRpcError, true],
+ [responseWithError, false],
+]
\ No newline at end of file
diff --git a/packages/web3-utils/test/unit/json_rpc.test.ts b/packages/web3-utils/test/unit/json_rpc.test.ts
index 89261009916..2cb958aad59 100644
--- a/packages/web3-utils/test/unit/json_rpc.test.ts
+++ b/packages/web3-utils/test/unit/json_rpc.test.ts
@@ -16,17 +16,21 @@ along with web3.js. If not, see .
*/
import {
+ isResponseRpcError,
isResponseWithResult,
isResponseWithError,
isResponseWithNotification,
isSubscriptionResult,
isValidResponse,
isBatchResponse,
+ setRequestIdStart,
+ toBatchPayload,
toPayload,
} from '../../src/json_rpc';
import {
isResponseWithResultValidTest,
isResponseWithErrorValidTest,
+ isResponseRpcErrorValidData,
isResponseWithNotificationValidTest,
isSubscriptionResultValidTest,
toPayloadValidTest,
@@ -51,6 +55,14 @@ describe('json rpc tests', () => {
});
});
});
+ describe('isResponseRpcError', () => {
+ describe('valid cases', () => {
+ it.each(isResponseRpcErrorValidData)('%s', (input, output) => {
+ const result = isResponseRpcError(input);
+ expect(result).toBe(output);
+ });
+ });
+ });
describe('isResponseWithNotification', () => {
describe('valid cases', () => {
it.each(isResponseWithNotificationValidTest)('should have notify', (input, output) => {
@@ -85,10 +97,34 @@ describe('json rpc tests', () => {
});
describe('toPayloadValid', () => {
describe('valid cases', () => {
- it.each(toPayloadValidTest)('isValidresponse valid test', (input, output) => {
- const result = toPayload(input);
+ beforeEach (() => {
+ setRequestIdStart(undefined)
+ });
+ it.each(toPayloadValidTest)('toPayload valid test', async (input, output) => {
+ const result = await new Promise((resolve) => {
+ resolve(toPayload(input))
+ })
expect(result).toStrictEqual(output);
});
+ it('should give payload that has requestid set', async () => {
+ setRequestIdStart(1)
+ const result = await new Promise((resolve) => {
+ resolve(toPayload({ method: 'delete' }))
+ })
+ expect(result).toStrictEqual({method: 'delete', id:2, params: undefined, jsonrpc: '2.0'});
+ });
});
});
-});
+ describe('toBatchPayload', () => {
+ it('should batch payload', async () => {
+ setRequestIdStart(0)
+ const result = await new Promise((resolve) => {
+ resolve(toBatchPayload([{ method: 'delete' }, {method: 'add'}]))
+ })
+ expect(result).toStrictEqual([
+ {method: 'delete', id:1, params: undefined, jsonrpc: '2.0'},
+ {method: 'add', id:2, params: undefined, jsonrpc: '2.0'}
+ ]);
+ });
+ })
+});
\ No newline at end of file
From d61bd1dc8b55a2f9e96cd50b436bd631a3c4e60f Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Thu, 23 May 2024 17:45:11 -0400
Subject: [PATCH 11/17] cover socket provider file
---
packages/web3-utils/test/fixtures/json_rpc.ts | 15 +++++++++++++++
packages/web3-utils/test/unit/json_rpc.test.ts | 11 ++++++++++-
.../web3-utils/test/unit/socket_provider.test.ts | 8 +++++++-
3 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/packages/web3-utils/test/fixtures/json_rpc.ts b/packages/web3-utils/test/fixtures/json_rpc.ts
index 2be0f19b435..0b87a35ec59 100644
--- a/packages/web3-utils/test/fixtures/json_rpc.ts
+++ b/packages/web3-utils/test/fixtures/json_rpc.ts
@@ -80,4 +80,19 @@ export const toPayloadValidTest: [any, any][] = [
export const isResponseRpcErrorValidData: [any, boolean][] = [
[responseWithRpcError, true],
[responseWithError, false],
+]
+
+export const isBatchRequestValidData: [any, boolean][] = [
+ [[{
+ method: 'add',
+ id: 1,
+ jsonrpc: '1.0',
+ params: undefined
+ }], true],
+ [{
+ method: 'add',
+ id: 1,
+ jsonrpc: '1.0',
+ params: undefined
+ }, false]
]
\ No newline at end of file
diff --git a/packages/web3-utils/test/unit/json_rpc.test.ts b/packages/web3-utils/test/unit/json_rpc.test.ts
index 2cb958aad59..27dee1a0354 100644
--- a/packages/web3-utils/test/unit/json_rpc.test.ts
+++ b/packages/web3-utils/test/unit/json_rpc.test.ts
@@ -25,6 +25,7 @@ import {
isBatchResponse,
setRequestIdStart,
toBatchPayload,
+ isBatchRequest,
toPayload,
} from '../../src/json_rpc';
import {
@@ -36,6 +37,7 @@ import {
toPayloadValidTest,
isValidResponseValidTest,
isBatchResponseValidTest,
+ isBatchRequestValidData,
} from '../fixtures/json_rpc';
describe('json rpc tests', () => {
@@ -89,12 +91,19 @@ describe('json rpc tests', () => {
});
describe('isBatchResponseValid', () => {
describe('valid cases', () => {
- it.each(isBatchResponseValidTest)('isValidresponse valid test', (input, output) => {
+ it.each(isBatchResponseValidTest)('isBatchResponseValid valid test', (input, output) => {
const result = isBatchResponse(input);
expect(result).toBe(output);
});
});
});
+ describe('isBatchRequest', () => {
+ describe('valid cases', () => {
+ it.each(isBatchRequestValidData)('isBatchRqeuest valid data', (input, output) => {
+ expect(isBatchRequest(input)).toBe(output);
+ })
+ })
+ })
describe('toPayloadValid', () => {
describe('valid cases', () => {
beforeEach (() => {
diff --git a/packages/web3-utils/test/unit/socket_provider.test.ts b/packages/web3-utils/test/unit/socket_provider.test.ts
index 9dd9ed69170..b116111e3aa 100644
--- a/packages/web3-utils/test/unit/socket_provider.test.ts
+++ b/packages/web3-utils/test/unit/socket_provider.test.ts
@@ -22,7 +22,7 @@ import {
Web3ProviderStatus,
JsonRpcIdentifier,
} from 'web3-types';
-import { MaxAttemptsReachedOnReconnectingError } from 'web3-errors';
+import { MaxAttemptsReachedOnReconnectingError, InvalidClientError } from 'web3-errors';
import { EventEmitter } from '../../src/event_emitter';
// eslint-disable-next-line import/no-relative-packages
import { sleep } from '../../../../fixtures/utils';
@@ -120,6 +120,12 @@ describe('SocketProvider', () => {
expect(clearQueuesSpy).toHaveBeenCalled();
});
+ it('should error when failing to _validateProviderPath', () => {
+ expect(() => {
+ // eslint-disable-next-line no-new
+ new TestProvider("", socketOption, { delay: 0 });
+ }).toThrow(InvalidClientError)
+ })
});
describe('testing _reconnect() method', () => {
it('should not be called when { autoReconnect: false }', () => {
From e8ccfffcc0889943aafc8529fb5385357283642c Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Thu, 23 May 2024 17:53:49 -0400
Subject: [PATCH 12/17] add coverage string manipulation
---
packages/web3-utils/test/fixtures/string_manipulation.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/packages/web3-utils/test/fixtures/string_manipulation.ts b/packages/web3-utils/test/fixtures/string_manipulation.ts
index be5b298c803..86be918051d 100644
--- a/packages/web3-utils/test/fixtures/string_manipulation.ts
+++ b/packages/web3-utils/test/fixtures/string_manipulation.ts
@@ -58,7 +58,7 @@ export const padRightData: [[Numbers, number, string], HexString][] = [
[['15.5', 8, '0'], '15.50000'],
];
-export const toTwosComplementData: [[Numbers, number], HexString][] = [
+export const toTwosComplementData: [[Numbers, number | undefined], HexString][] = [
[[13, 32], '0x0000000000000000000000000000000d'],
[[256, 30], '0x000000000000000000000000000100'],
[[0, 32], '0x00000000000000000000000000000000'],
@@ -69,9 +69,10 @@ export const toTwosComplementData: [[Numbers, number], HexString][] = [
[['13', 32], '0x0000000000000000000000000000000d'],
[['-13', 32], '0xfffffffffffffffffffffffffffffff3'],
[[-16, 2], '0xf0'],
+ [['0x1', undefined], '0x0000000000000000000000000000000000000000000000000000000000000001']
];
-export const fromTwosComplementData: [[Numbers, number], number | bigint][] = [
+export const fromTwosComplementData: [[Numbers, number | undefined], number | bigint][] = [
[['0x0000000000000000000000000000000d', 32], 13],
[['0x000000000000000000000000000100', 30], 256],
[['0x00000000000000000020000000000000', 32], BigInt('9007199254740992')],
@@ -81,6 +82,7 @@ export const fromTwosComplementData: [[Numbers, number], number | bigint][] = [
[[1000, 64], 1000],
[[-1000, 64], -1000],
[[BigInt(9), 1], -7],
+ [['0x0000000000000000000000000000000000000000000000000000000000000001', undefined], 1]
];
export const toTwosComplementInvalidData: [[Numbers, number], string][] = [
From 4ad228a992fa7237d977494aec2ae31144018382 Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Wed, 29 May 2024 17:05:33 -0400
Subject: [PATCH 13/17] add coverage to formatters.ts
---
packages/web3-utils/src/formatter.ts | 14 +-
.../web3-utils/src/web3_eip1193_provider.ts | 3 +-
.../web3-utils/test/fixtures/formatter.ts | 3 +-
.../test/unit/chunk_response_parser.test.ts | 14 ++
.../web3-utils/test/unit/converters.test.ts | 1 -
.../web3-utils/test/unit/formatter.test.ts | 159 +++++++++++++++++-
packages/web3-utils/test/unit/hash.test.ts | 14 ++
.../test/unit/socket_provider.test.ts | 123 ++++++++++++++
8 files changed, 317 insertions(+), 14 deletions(-)
diff --git a/packages/web3-utils/src/formatter.ts b/packages/web3-utils/src/formatter.ts
index 42062add5c6..102d0dead4f 100644
--- a/packages/web3-utils/src/formatter.ts
+++ b/packages/web3-utils/src/formatter.ts
@@ -57,10 +57,8 @@ const findSchemaByDataPath = (
for (const dataPart of dataPath) {
if (result.oneOf && previousDataPath) {
- const path = oneOfPath.find(function (element: [string, number]) {
- return (this as unknown as string) === element[0];
- }, previousDataPath ?? '');
-
+ const currentDataPath = previousDataPath;
+ const path = oneOfPath.find(([key]) => key === currentDataPath);
if (path && path[0] === previousDataPath) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
result = result.oneOf[path[1]];
@@ -74,11 +72,7 @@ const findSchemaByDataPath = (
result = (result.properties as Record)[dataPart];
} else if (result.items && (result.items as JsonSchema).properties) {
const node = (result.items as JsonSchema).properties as Record;
-
- if (!node) {
- return undefined;
- }
-
+
result = node[dataPart];
} else if (result.items && isObject(result.items)) {
result = result.items;
@@ -307,7 +301,7 @@ export const convert = (
// If value is an object, recurse into it
if (isObject(value)) {
- convert(value, schema, dataPath, format);
+ convert(value, schema, dataPath, format, oneOfPath);
dataPath.pop();
continue;
}
diff --git a/packages/web3-utils/src/web3_eip1193_provider.ts b/packages/web3-utils/src/web3_eip1193_provider.ts
index f0e2d4d30bf..036ab03adc3 100644
--- a/packages/web3-utils/src/web3_eip1193_provider.ts
+++ b/packages/web3-utils/src/web3_eip1193_provider.ts
@@ -68,7 +68,7 @@ export abstract class Eip1193Provider<
this._chainId = chainId;
this._eventEmitter.emit('chainChanged', this._chainId);
}
- })
+ })
.catch(err => {
// todo: add error handler
console.error(err);
@@ -98,6 +98,7 @@ export abstract class Eip1193Provider<
} as ProviderConnectInfo),
)
.catch(err => {
+ console.log("enters")
// todo: add error handler
// eslint-disable-next-line no-console
console.error(err);
diff --git a/packages/web3-utils/test/fixtures/formatter.ts b/packages/web3-utils/test/fixtures/formatter.ts
index 7437373d708..cc4c08c28ca 100644
--- a/packages/web3-utils/test/fixtures/formatter.ts
+++ b/packages/web3-utils/test/fixtures/formatter.ts
@@ -55,4 +55,5 @@ export const convertScalarValueValid: [[any, any, any], any][] = [
hexToBytes('0x00000000000000000000000000000000000000000000000000000000000000ff'),
),
],
-];
+ [[new Uint8Array(hexToBytes('FF')), 'bytes32', { bytes: "invalidFormat" }], [255]] // return original value when erroring
+];
\ No newline at end of file
diff --git a/packages/web3-utils/test/unit/chunk_response_parser.test.ts b/packages/web3-utils/test/unit/chunk_response_parser.test.ts
index 22100a3e6a8..707197e2889 100644
--- a/packages/web3-utils/test/unit/chunk_response_parser.test.ts
+++ b/packages/web3-utils/test/unit/chunk_response_parser.test.ts
@@ -71,4 +71,18 @@ describe('chunk_response_parser', () => {
}),
);
});
+
+ it('lastChunkTimeout return empty when auto reconnect true', async () => {
+ const p = new ChunkResponseParser(eventEmiter, true);
+ // @ts-expect-error set private property
+ p.chunkTimeout = 10;
+ const result = p.parseResponse(
+ '{"jsonrpc":"2.0","id":"96aa3f13-077c-4c82-a64a-64b8626f8192","result":"0x141414141',
+ );
+ const onError = jest.fn();
+ eventEmiter.on('error', onError);
+ // eslint-disable-next-line no-promise-executor-return
+ await new Promise(resolve => setTimeout(resolve, 1000));
+ expect(result).toEqual([])
+ });
});
diff --git a/packages/web3-utils/test/unit/converters.test.ts b/packages/web3-utils/test/unit/converters.test.ts
index ae4a461ac08..7481d5008ce 100644
--- a/packages/web3-utils/test/unit/converters.test.ts
+++ b/packages/web3-utils/test/unit/converters.test.ts
@@ -387,7 +387,6 @@ describe('converters', () => {
});
it.each(toWeiValidDataWarnings)('%s', (input, output) => {
toWei(input[0], input[1]);
- // expect(() => toWei(input[0], input[1])).toThrow(output);
expect(console.warn).toHaveBeenCalledWith(output);
});
});
diff --git a/packages/web3-utils/test/unit/formatter.test.ts b/packages/web3-utils/test/unit/formatter.test.ts
index bed8b55de8e..4e235081ddb 100644
--- a/packages/web3-utils/test/unit/formatter.test.ts
+++ b/packages/web3-utils/test/unit/formatter.test.ts
@@ -24,9 +24,10 @@ import {
HexString,
Numbers,
} from 'web3-types';
+import {FormatterError} from 'web3-errors';
import { expectTypeOf, typecheck } from '@humeris/espresso-shot';
import { isDataFormatValid, convertScalarValueValid } from '../fixtures/formatter';
-import { format, isDataFormat, convertScalarValue } from '../../src/formatter';
+import { format, isDataFormat, convertScalarValue, convert } from '../../src/formatter';
import { hexToBytes } from '../../src/converters';
type TestTransactionInfoType = {
@@ -584,6 +585,40 @@ describe('formatter', () => {
).toEqual(result);
});
+ it('should format array of objects with', () => {
+ const schema = {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ prop1: {
+ oneOf: [{ format: 'address' }, { type: 'string' }],
+ },
+ prop2: {
+ format: 'bytes',
+ },
+ },
+ },
+ };
+
+ const data = [
+ {
+ prop1: '0x7ed0e85b8e1e925600b4373e6d108f34ab38a401',
+ prop2: new Uint8Array(hexToBytes('FF')),
+ },
+ { prop1: 'some string', prop2: new Uint8Array(hexToBytes('FF')) },
+ ];
+
+ const result = [
+ { prop1: '0x7ed0e85b8e1e925600b4373e6d108f34ab38a401', prop2: '0xff' },
+ { prop1: 'some string', prop2: '0xff' },
+ ];
+
+ expect(
+ format(schema, data, { number: FMT_NUMBER.HEX, bytes: FMT_BYTES.HEX }),
+ ).toEqual(result);
+ });
+
it('should format array of different objects', () => {
const schema = {
type: 'array',
@@ -740,6 +775,77 @@ describe('formatter', () => {
});
describe('object values', () => {
+
+ describe('convert', () => {
+ it('should convert array values correctly when schema is an array and items are objects', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ transactions: {
+ type: 'array',
+ oneOf: [
+ {
+ items: {
+ type: 'object',
+ properties: {
+ type: { enum: ['A'] },
+ value: { type: 'string' }
+ }
+ }
+ },
+ {
+ items: {
+ type: 'object',
+ properties: {
+ type: { enum: ['B'] },
+ value: { type: 'number' }
+ }
+ }
+ }
+ ]
+ }
+ }
+ };
+ const data = {
+ transactions: [
+ { type: 'B', value: 42 },
+ { type: 'B', value: 43 }
+ ]
+ };
+ expect(convert(data, schema, [], {
+ number: FMT_NUMBER.HEX,
+ bytes: FMT_BYTES.HEX,
+ })).toEqual(data)
+ });
+ });
+
+ it('should delete the array property if schema for array items is nullish', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ transactions: {
+ type: 'array',
+ items: undefined // Simulate a missing or null schema for items
+ }
+ }
+ };
+
+ const data = {
+ transactions: [
+ { type: 'A', value: 'some string' },
+ { type: 'B', value: 42 }
+ ]
+ };
+
+ const result = convert(data, schema, [], {
+ number: FMT_NUMBER.HEX,
+ bytes: FMT_BYTES.HEX,
+ });
+
+ expect(result).toEqual({});
+ });
+
+
it('should format simple object', () => {
const schema = {
type: 'object',
@@ -776,6 +882,13 @@ describe('formatter', () => {
expect(result).toEqual(expected);
});
+ it('should throw FormatterError when jsonSchema is invalid', () => {
+ const invalidSchema1 = {};
+ const data = { key: 'value' };
+
+ expect(() => format(invalidSchema1, data)).toThrow(FormatterError);
+ });
+
it('should format nested objects', () => {
const schema = {
type: 'object',
@@ -820,7 +933,51 @@ describe('formatter', () => {
expect(result).toEqual(expected);
});
+
+ it('should return empty when no proerties or items', () => {
+ const data = { key: 'value' };
+ const schema = {
+ type: 'object',
+ };
+ const f = { number: FMT_NUMBER.NUMBER, bytes: FMT_BYTES.HEX };
+ const result = convert(data, schema, [], f, []);
+ expect(result).toEqual({});
});
+ it('should format nested objects with oneOf', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ details: {
+ type: 'object',
+ oneOf: [
+ { properties: { type: { enum: ['A'] }, value: { type: 'string' } } },
+ { properties: { type: { enum: ['B'] }, value: { type: 'number' } } }
+ ]
+ }
+ }
+ }
+
+ const data =
+ {
+ details: {
+ type: 'B',
+ value: 42
+ }
+ }
+ const result = convert(data, schema, [], {
+ number: FMT_NUMBER.BIGINT,
+ bytes: FMT_BYTES.UINT8ARRAY,
+ }, [['details', 1]]);
+
+ expect(result).toEqual({
+ details: {
+ type: 'B',
+ value: 42
+ }
+ });
+
+ })
+ });
describe('isDataFormat', () => {
describe('valid cases', () => {
it.each(isDataFormatValid)('%s', (input, output) => {
diff --git a/packages/web3-utils/test/unit/hash.test.ts b/packages/web3-utils/test/unit/hash.test.ts
index 13b4c6aa1df..9cff77de5a3 100644
--- a/packages/web3-utils/test/unit/hash.test.ts
+++ b/packages/web3-utils/test/unit/hash.test.ts
@@ -60,6 +60,20 @@ describe('hash', () => {
expect(sha3(input)).toBe(`0x${keccak256(output)}`);
});
});
+
+ describe('handle when array', () => {
+ it('should handle array input and convert it to Uint8Array for hashing', () => {
+ // Arrange
+ const input = [0x61, 0x62, 0x63]; // ['a', 'b', 'c']
+ const expectedHash = '0x7f83b165f6e8dd98bfa2727c7e4d949b';
+
+ // Act
+ const result = keccak256(input);
+
+ // Assert
+ expect(result).toEqual(expectedHash);
+ });
+ })
});
describe('sha3Raw', () => {
diff --git a/packages/web3-utils/test/unit/socket_provider.test.ts b/packages/web3-utils/test/unit/socket_provider.test.ts
index b116111e3aa..9d178464e6a 100644
--- a/packages/web3-utils/test/unit/socket_provider.test.ts
+++ b/packages/web3-utils/test/unit/socket_provider.test.ts
@@ -31,6 +31,7 @@ import { SocketProvider } from '../../src/socket_provider';
const dummySocketConnection = { dummy: 'dummy' };
class TestProvider extends SocketProvider {
+
protected _socketConnection?: typeof dummySocketConnection;
protected _openSocketConnection() {
@@ -651,6 +652,17 @@ describe('SocketProvider', () => {
});
describe('_onConnect', () => {
+
+ beforeEach(() => {
+ jest.spyOn(console, 'error').mockImplementation(() => {
+ // do nothing
+ }); // Spy on console.error to suppress and check calls
+ })
+
+ afterEach(() => {
+ jest.restoreAllMocks(); // Restore all mocks after each test
+ });
+
it('should set the connection status to "connected"', () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
@@ -659,8 +671,119 @@ describe('SocketProvider', () => {
expect(provider['_connectionStatus']).toBe('connected');
});
+ it('should set _accounts and _chainId when _getAccounts and _getChainId resolve', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([123]);
+ jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce("1");
+
+ await new Promise ((resolve) => {
+ provider['_onConnect']();
+ resolve("");
+ })
+ expect((provider as any)._chainId).toBe('1');
+ expect((provider as any)._accounts).toEqual([123]);
+ });
+ it('chainID should change when connecting twice', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+
+ await new Promise ((resolve) => {
+ jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([123]);
+ jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce("1");
+ provider['_onConnect']();
+ resolve("");
+ })
+ expect((provider as any)._chainId).toBe('1');
+ expect((provider as any)._accounts).toEqual([123]);
+
+ await new Promise ((resolve) => {
+ jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([123]);
+ jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce("2");
+ provider['_onConnect']();
+ resolve("");
+ })
+ expect((provider as any)._chainId).toBe('2');
+ expect((provider as any)._accounts).toEqual([123]);
+ });
+ it('should catch errors when _getAccounts and _getChainId throws', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ jest.spyOn(provider as any, '_getChainId').mockRejectedValueOnce(new Error(""));
+ jest.spyOn(provider as any, '_getAccounts').mockRejectedValueOnce(new Error(""));
+ jest.spyOn(provider, 'request').mockReturnValue(new Error() as unknown as Promise);
+
+ await new Promise ((resolve) => {
+ provider['_onConnect']();
+ resolve("");
+ })
+ expect((provider as any)._chainId).toBe('');
+ expect((provider as any)._accounts).toEqual([]);
+ });
+ it('should catch when connect emit fails', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce(1);
+ jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([]);
+ (provider as any)._eventEmitter.emit = jest.fn(() => {
+ throw new Error('event emitter failed');
+ })
+
+
+ await new Promise ((resolve) => {
+ provider['_onConnect']();
+ resolve("");
+ })
+ // I would check if console.error is called, but facing a race condition
+ expect((provider as any)._eventEmitter.emit).toHaveBeenCalledTimes(1);
+
+ });
});
+ describe('_getChainId', () => {
+ it('should return data from the chainId method', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ const chainId = 1;
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: chainId});
+ const result = await provider['_getChainId']();
+ expect(result).toBe(chainId);
+ })
+
+ it('should be returning undefined from the chainId method', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: undefined});
+ const result = await provider['_getChainId']();
+ expect(result).toBe("");
+ })
+
+ it('should return empty from the chainId method', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce(undefined);
+ const result = await provider['_getChainId']();
+ expect(result).toBe("");
+ })
+ })
+
+ describe('_getAccounts', () => {
+ it('should return data from the _getAccounts method', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ const accounts = [1];
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: accounts});
+ const result = await provider['_getAccounts']();
+ expect(result).toBe(accounts);
+ })
+
+ it('should returning undefined from the _getAccounts method', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: undefined});
+ const result = await provider['_getAccounts']();
+ expect(result).toEqual([]);
+ })
+
+ it('should return empty from the _getAccounts method', async () => {
+ const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce(undefined);
+ const result = await provider['_getAccounts']();
+ expect(result).toEqual([]);
+ })
+ })
+
describe('_onMessage', () => {
it('should resolve the deferred promise for valid responses with errors', () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
From 369776777d197789a82af88d1b21287edf2d7336 Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Wed, 29 May 2024 17:57:23 -0400
Subject: [PATCH 14/17] fix failing tests
---
packages/web3-utils/src/web3_eip1193_provider.ts | 1 -
packages/web3-utils/test/fixtures/formatter.ts | 2 +-
packages/web3-utils/test/unit/hash.test.ts | 14 --------------
3 files changed, 1 insertion(+), 16 deletions(-)
diff --git a/packages/web3-utils/src/web3_eip1193_provider.ts b/packages/web3-utils/src/web3_eip1193_provider.ts
index 036ab03adc3..fbedb19ab22 100644
--- a/packages/web3-utils/src/web3_eip1193_provider.ts
+++ b/packages/web3-utils/src/web3_eip1193_provider.ts
@@ -98,7 +98,6 @@ export abstract class Eip1193Provider<
} as ProviderConnectInfo),
)
.catch(err => {
- console.log("enters")
// todo: add error handler
// eslint-disable-next-line no-console
console.error(err);
diff --git a/packages/web3-utils/test/fixtures/formatter.ts b/packages/web3-utils/test/fixtures/formatter.ts
index cc4c08c28ca..32c5d167536 100644
--- a/packages/web3-utils/test/fixtures/formatter.ts
+++ b/packages/web3-utils/test/fixtures/formatter.ts
@@ -55,5 +55,5 @@ export const convertScalarValueValid: [[any, any, any], any][] = [
hexToBytes('0x00000000000000000000000000000000000000000000000000000000000000ff'),
),
],
- [[new Uint8Array(hexToBytes('FF')), 'bytes32', { bytes: "invalidFormat" }], [255]] // return original value when erroring
+ [[255, 'bytes32', { bytes: "invalidFormat" }], 255] // return original value when erroring
];
\ No newline at end of file
diff --git a/packages/web3-utils/test/unit/hash.test.ts b/packages/web3-utils/test/unit/hash.test.ts
index 9cff77de5a3..13b4c6aa1df 100644
--- a/packages/web3-utils/test/unit/hash.test.ts
+++ b/packages/web3-utils/test/unit/hash.test.ts
@@ -60,20 +60,6 @@ describe('hash', () => {
expect(sha3(input)).toBe(`0x${keccak256(output)}`);
});
});
-
- describe('handle when array', () => {
- it('should handle array input and convert it to Uint8Array for hashing', () => {
- // Arrange
- const input = [0x61, 0x62, 0x63]; // ['a', 'b', 'c']
- const expectedHash = '0x7f83b165f6e8dd98bfa2727c7e4d949b';
-
- // Act
- const result = keccak256(input);
-
- // Assert
- expect(result).toEqual(expectedHash);
- });
- })
});
describe('sha3Raw', () => {
From c24c7984ebf0cccb604312b7cc6cccb89b4f9fea Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Thu, 30 May 2024 10:38:45 -0400
Subject: [PATCH 15/17] update hash
---
packages/web3-utils/src/hash.ts | 2 --
packages/web3-utils/test/unit/formatter.test.ts | 1 +
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/packages/web3-utils/src/hash.ts b/packages/web3-utils/src/hash.ts
index f7acc4f4fb9..f828447b2c1 100644
--- a/packages/web3-utils/src/hash.ts
+++ b/packages/web3-utils/src/hash.ts
@@ -151,8 +151,6 @@ export const keccak256Wrapper = (
let processedData;
if (typeof data === 'bigint' || typeof data === 'number') {
processedData = utf8ToBytes(data.toString());
- } else if (Array.isArray(data)) {
- processedData = new Uint8Array(data);
} else if (typeof data === 'string' && !isHexStrict(data)) {
processedData = utf8ToBytes(data);
} else {
diff --git a/packages/web3-utils/test/unit/formatter.test.ts b/packages/web3-utils/test/unit/formatter.test.ts
index 4e235081ddb..8b18a901ef5 100644
--- a/packages/web3-utils/test/unit/formatter.test.ts
+++ b/packages/web3-utils/test/unit/formatter.test.ts
@@ -943,6 +943,7 @@ describe('formatter', () => {
const result = convert(data, schema, [], f, []);
expect(result).toEqual({});
});
+
it('should format nested objects with oneOf', () => {
const schema = {
type: 'object',
From 72e70950780025cbd265d345e9297cdea99971b6 Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Thu, 30 May 2024 12:48:47 -0400
Subject: [PATCH 16/17] run prettier
---
packages/web3-utils/src/converters.ts | 30 +-
packages/web3-utils/src/formatter.ts | 4 +-
packages/web3-utils/src/hash.ts | 22 +-
packages/web3-utils/src/promise_helpers.ts | 37 ++-
packages/web3-utils/src/socket_provider.ts | 28 +-
.../web3-utils/src/web3_eip1193_provider.ts | 2 +-
.../web3-utils/test/fixtures/converters.ts | 68 +++--
.../web3-utils/test/fixtures/formatter.ts | 4 +-
packages/web3-utils/test/fixtures/hash.ts | 16 +-
packages/web3-utils/test/fixtures/json_rpc.ts | 46 +--
.../test/fixtures/string_manipulation.ts | 4 +-
.../test/unit/chunk_response_parser.test.ts | 2 +-
.../web3-utils/test/unit/converters.test.ts | 17 +-
.../web3-utils/test/unit/formatter.test.ts | 277 ++++++++----------
packages/web3-utils/test/unit/hash.test.ts | 2 +-
.../web3-utils/test/unit/json_rpc.test.ts | 58 ++--
.../test/unit/socket_provider.test.ts | 104 +++----
.../test/unit/web3_deferred_promise.test.ts | 2 +-
18 files changed, 373 insertions(+), 350 deletions(-)
diff --git a/packages/web3-utils/src/converters.ts b/packages/web3-utils/src/converters.ts
index 5280a54551b..9c94a4332b0 100644
--- a/packages/web3-utils/src/converters.ts
+++ b/packages/web3-utils/src/converters.ts
@@ -79,7 +79,8 @@ export const ethUnitMap = {
tether: BigInt('1000000000000000000000000000000'),
};
-const PrecisionLossWarning = 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods';
+const PrecisionLossWarning =
+ 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods';
export type EtherUnits = keyof typeof ethUnitMap;
/**
@@ -366,7 +367,7 @@ export const toHex = (
return returnType ? 'bigint' : numberToHex(value);
}
- if(isUint8Array(value)) {
+ if (isUint8Array(value)) {
return returnType ? 'bytes' : bytesToHex(value);
}
@@ -391,7 +392,7 @@ export const toHex = (
// But a value pass for those conditions: "101611154195520776335741463917853444671577865378275924493376429267637792638729"
// Note that according to the docs: it is supposed to be treated as a string (https://docs.web3js.org/guides/web3_upgrade_guide/x/web3_utils_migration_guide#conversion-to-hex)
// In short, the strange is that isInt(value) is false but isUInt(value) is true for the value above.
- // So, isUInt(value) should be investigated.
+ // TODO: isUInt(value) should be investigated.
// However, if `toHex('101611154195520776335741463917853444671577865378275924493376429267637792638729', true)` is called, it will return `true`.
// But, if `toHex('101611154195520776335741463917853444671577865378275924493376429267637792638729')` is called, it will throw inside `numberToHex`.
@@ -428,14 +429,14 @@ export const toHex = (
*/
export const toNumber = (value: Numbers): number | bigint => {
if (typeof value === 'number') {
- if (value > 1e+20) {
- console.warn(PrecisionLossWarning)
- // JavaScript converts numbers >= 10^21 to scientific notation when coerced to strings,
- // leading to potential parsing errors and incorrect representations.
- // For instance, String(10000000000000000000000) yields '1e+22'.
- // Using BigInt prevents this
- return BigInt(value);
- }
+ if (value > 1e20) {
+ console.warn(PrecisionLossWarning);
+ // JavaScript converts numbers >= 10^21 to scientific notation when coerced to strings,
+ // leading to potential parsing errors and incorrect representations.
+ // For instance, String(10000000000000000000000) yields '1e+22'.
+ // Using BigInt prevents this
+ return BigInt(value);
+ }
return value;
}
@@ -515,10 +516,9 @@ export const fromWei = (number: Numbers, unit: EtherUnits | number): string => {
if (unit < 0 || !Number.isInteger(unit)) {
throw new InvalidIntegerError(unit);
}
- denomination = bigintPower(BigInt(10),BigInt(unit));
+ denomination = bigintPower(BigInt(10), BigInt(unit));
}
-
// value in wei would always be integer
// 13456789, 1234
const value = String(toNumber(number));
@@ -584,8 +584,8 @@ export const toWei = (number: Numbers, unit: EtherUnits | number): string => {
if (unit < 0 || !Number.isInteger(unit)) {
throw new InvalidIntegerError(unit);
}
-
- denomination = bigintPower(BigInt(10),BigInt(unit));
+
+ denomination = bigintPower(BigInt(10), BigInt(unit));
}
let parsedNumber = number;
diff --git a/packages/web3-utils/src/formatter.ts b/packages/web3-utils/src/formatter.ts
index 102d0dead4f..665965a8eed 100644
--- a/packages/web3-utils/src/formatter.ts
+++ b/packages/web3-utils/src/formatter.ts
@@ -58,7 +58,7 @@ const findSchemaByDataPath = (
for (const dataPart of dataPath) {
if (result.oneOf && previousDataPath) {
const currentDataPath = previousDataPath;
- const path = oneOfPath.find(([key]) => key === currentDataPath);
+ const path = oneOfPath.find(([key]) => key === currentDataPath);
if (path && path[0] === previousDataPath) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
result = result.oneOf[path[1]];
@@ -72,7 +72,7 @@ const findSchemaByDataPath = (
result = (result.properties as Record)[dataPart];
} else if (result.items && (result.items as JsonSchema).properties) {
const node = (result.items as JsonSchema).properties as Record;
-
+
result = node[dataPart];
} else if (result.items && isObject(result.items)) {
result = result.items;
diff --git a/packages/web3-utils/src/hash.ts b/packages/web3-utils/src/hash.ts
index f828447b2c1..0289a429a52 100644
--- a/packages/web3-utils/src/hash.ts
+++ b/packages/web3-utils/src/hash.ts
@@ -17,25 +17,25 @@ along with web3.js. If not, see .
/**
* This package provides utility functions for Ethereum dapps and other web3.js packages.
- *
+ *
* For using Utils functions, first install Web3 package using `npm i web3` or `yarn add web3`.
- * After that, Web3 Utils functions will be available as mentioned below.
+ * After that, Web3 Utils functions will be available as mentioned below.
* ```ts
* import { Web3 } from 'web3';
* const web3 = new Web3();
- *
+ *
* const value = web3.utils.fromWei("1", "ether")
- *
+ *
* ```
- *
+ *
* For using individual package install `web3-utils` package using `npm i web3-utils` or `yarn add web3-utils` and only import required functions.
- * This is more efficient approach for building lightweight applications.
+ * This is more efficient approach for building lightweight applications.
* ```ts
* import { fromWei, soliditySha3Raw } from 'web3-utils';
- *
+ *
* console.log(fromWei("1", "ether"));
* console.log(soliditySha3Raw({ type: "string", value: "helloworld" }))
- *
+ *
* ```
* @module Utils
*/
@@ -151,6 +151,8 @@ export const keccak256Wrapper = (
let processedData;
if (typeof data === 'bigint' || typeof data === 'number') {
processedData = utf8ToBytes(data.toString());
+ } else if (Array.isArray(data)) {
+ processedData = new Uint8Array(data);
} else if (typeof data === 'string' && !isHexStrict(data)) {
processedData = utf8ToBytes(data);
} else {
@@ -167,7 +169,9 @@ export { keccak256Wrapper as keccak256 };
* @returns - the type and value of the input
*/
const getType = (arg: Sha3Input): [string, EncodingTypes] => {
-
+ if (Array.isArray(arg)) {
+ throw new Error('Autodetection of array types is not supported.');
+ }
let type;
let value;
// if type is given
diff --git a/packages/web3-utils/src/promise_helpers.ts b/packages/web3-utils/src/promise_helpers.ts
index 1b9c37ffc3a..a2140a2d1c5 100644
--- a/packages/web3-utils/src/promise_helpers.ts
+++ b/packages/web3-utils/src/promise_helpers.ts
@@ -20,7 +20,6 @@ import { isNullish } from 'web3-validator';
export type Timer = ReturnType;
export type Timeout = ReturnType;
-
/**
* An alternative to the node function `isPromise` that exists in `util/types` because it is not available on the browser.
* @param object - to check if it is a `Promise`
@@ -74,7 +73,6 @@ export async function waitWithTimeout(
return result;
}
-
/**
* Repeatedly calls an async function with a given interval until the result of the function is defined (not undefined or null),
* or until a timeout is reached. It returns promise and intervalId.
@@ -85,25 +83,27 @@ export function pollTillDefinedAndReturnIntervalId(
func: AsyncFunction,
interval: number,
): [Promise>, Timer] {
-
let intervalId: Timer | undefined;
const polledRes = new Promise>((resolve, reject) => {
- intervalId = setInterval(function intervalCallbackFunc(){
- (async () => {
- try {
- const res = await waitWithTimeout(func, interval);
-
- if (!isNullish(res)) {
+ intervalId = setInterval(
+ (function intervalCallbackFunc() {
+ (async () => {
+ try {
+ const res = await waitWithTimeout(func, interval);
+
+ if (!isNullish(res)) {
+ clearInterval(intervalId);
+ resolve(res as unknown as Exclude);
+ }
+ } catch (error) {
clearInterval(intervalId);
- resolve(res as unknown as Exclude);
+ reject(error);
}
- } catch (error) {
- clearInterval(intervalId);
- reject(error);
- }
- })() as unknown;
- return intervalCallbackFunc;}() // this will immediate invoke first call
- , interval);
+ })() as unknown;
+ return intervalCallbackFunc;
+ })(), // this will immediate invoke first call
+ interval,
+ );
});
return [polledRes as unknown as Promise>, intervalId!];
@@ -113,7 +113,7 @@ export function pollTillDefinedAndReturnIntervalId(
* Repeatedly calls an async function with a given interval until the result of the function is defined (not undefined or null),
* or until a timeout is reached.
* pollTillDefinedAndReturnIntervalId() function should be used instead of pollTillDefined if you need IntervalId in result.
- * This function will be deprecated in next major release so use pollTillDefinedAndReturnIntervalId().
+ * This function will be deprecated in next major release so use pollTillDefinedAndReturnIntervalId().
* @param func - The function to call.
* @param interval - The interval in milliseconds.
*/
@@ -168,4 +168,3 @@ export function rejectIfConditionAtInterval(
});
return [intervalId!, rejectIfCondition];
}
-
diff --git a/packages/web3-utils/src/socket_provider.ts b/packages/web3-utils/src/socket_provider.ts
index 046fc69d0ad..0a73fb8378f 100644
--- a/packages/web3-utils/src/socket_provider.ts
+++ b/packages/web3-utils/src/socket_provider.ts
@@ -187,13 +187,13 @@ export abstract class SocketProvider<
protected _validateProviderPath(path: string): boolean {
return !!path;
}
-
+
/**
*
* @returns the pendingRequestQueue size
*/
// eslint-disable-next-line class-methods-use-this
- public getPendingRequestQueueSize() {
+ public getPendingRequestQueueSize() {
return this._pendingRequestsQueue.size;
}
@@ -350,32 +350,34 @@ export abstract class SocketProvider<
/**
* Safely disconnects the socket, async and waits for request size to be 0 before disconnecting
- * @param forceDisconnect - If true, will clear queue after 5 attempts of waiting for both pending and sent queue to be 0
+ * @param forceDisconnect - If true, will clear queue after 5 attempts of waiting for both pending and sent queue to be 0
* @param ms - Determines the ms of setInterval
* @param code - The code to be sent to the server
* @param data - The data to be sent to the server
*/
- public async safeDisconnect(code?: number, data?: string, forceDisconnect = false,ms = 1000) {
+ public async safeDisconnect(code?: number, data?: string, forceDisconnect = false, ms = 1000) {
let retryAttempt = 0;
- const checkQueue = async () =>
+ const checkQueue = async () =>
new Promise(resolve => {
const interval = setInterval(() => {
if (forceDisconnect && retryAttempt >= 5) {
this.clearQueues();
}
- if (this.getPendingRequestQueueSize() === 0 && this.getSentRequestsQueueSize() === 0) {
+ if (
+ this.getPendingRequestQueueSize() === 0 &&
+ this.getSentRequestsQueueSize() === 0
+ ) {
clearInterval(interval);
resolve(true);
}
- retryAttempt+=1;
- }, ms)
- })
-
+ retryAttempt += 1;
+ }, ms);
+ });
+
await checkQueue();
this.disconnect(code, data);
}
-
/**
* Removes all listeners for the specified event type.
* @param type - The event type to remove the listeners for
@@ -512,7 +514,7 @@ export abstract class SocketProvider<
if (isNullish(responses) || responses.length === 0) {
return;
}
-
+
for (const response of responses) {
if (
jsonRpc.isResponseWithNotification(response as JsonRpcNotification) &&
@@ -544,7 +546,7 @@ export abstract class SocketProvider<
this._sentRequestsQueue.delete(requestId);
}
}
-
+
public clearQueues(event?: ConnectionEvent) {
this._clearQueues(event);
}
diff --git a/packages/web3-utils/src/web3_eip1193_provider.ts b/packages/web3-utils/src/web3_eip1193_provider.ts
index fbedb19ab22..f0e2d4d30bf 100644
--- a/packages/web3-utils/src/web3_eip1193_provider.ts
+++ b/packages/web3-utils/src/web3_eip1193_provider.ts
@@ -68,7 +68,7 @@ export abstract class Eip1193Provider<
this._chainId = chainId;
this._eventEmitter.emit('chainChanged', this._chainId);
}
- })
+ })
.catch(err => {
// todo: add error handler
console.error(err);
diff --git a/packages/web3-utils/test/fixtures/converters.ts b/packages/web3-utils/test/fixtures/converters.ts
index faa9f8bfe04..cecb0b3fafb 100644
--- a/packages/web3-utils/test/fixtures/converters.ts
+++ b/packages/web3-utils/test/fixtures/converters.ts
@@ -235,21 +235,20 @@ export const toHexValidData: [Numbers | Bytes | Address | boolean, [HexString, V
],
['-0x01', ['-0x1', 'int256']],
['123c', ['0x123c', 'bytes']],
- [new Uint8Array([
- 221, 128, 128, 128, 148, 186, 248,
- 242, 159, 130, 231, 84, 254, 199,
- 252, 69, 21, 58, 104, 102, 201,
- 137, 255, 3, 196, 10, 128, 128,
- 128, 128
- ]), ['0xdd80808094baf8f29f82e754fec7fc45153a6866c989ff03c40a80808080', 'bytes']],
- [Buffer.from([
- 221, 128, 128, 128, 148, 186, 248,
- 242, 159, 130, 231, 84, 254, 199,
- 252, 69, 21, 58, 104, 102, 201,
- 137, 255, 3, 196, 10, 128, 128,
- 128, 128
- ]), ['0xdd80808094baf8f29f82e754fec7fc45153a6866c989ff03c40a80808080', 'bytes']]
-
+ [
+ new Uint8Array([
+ 221, 128, 128, 128, 148, 186, 248, 242, 159, 130, 231, 84, 254, 199, 252, 69, 21, 58,
+ 104, 102, 201, 137, 255, 3, 196, 10, 128, 128, 128, 128,
+ ]),
+ ['0xdd80808094baf8f29f82e754fec7fc45153a6866c989ff03c40a80808080', 'bytes'],
+ ],
+ [
+ Buffer.from([
+ 221, 128, 128, 128, 148, 186, 248, 242, 159, 130, 231, 84, 254, 199, 252, 69, 21, 58,
+ 104, 102, 201, 137, 255, 3, 196, 10, 128, 128, 128, 128,
+ ]),
+ ['0xdd80808094baf8f29f82e754fec7fc45153a6866c989ff03c40a80808080', 'bytes'],
+ ],
];
export const toHexInvalidData: [any, string][] = [
@@ -320,14 +319,14 @@ const conversionBaseData: [[Numbers, EtherUnits | number], string][] = [
export const fromWeiValidData: [[Numbers, EtherUnits | number], Numbers][] = [
...conversionBaseData,
- [['0xff', 'wei'], '255'],
- [[1e+22, 'ether'], '10000'],
- [[19999999999999991611392, 'ether'], '19999.999999999991611392'],
- [[1.9999999999999991611392e+22, 'ether'], '19999.999999999991611392'],
+ [['0xff', 'wei'], '255'],
+ [[1e22, 'ether'], '10000'],
+ [[19999999999999991611392, 'ether'], '19999.999999999991611392'],
+ [[1.9999999999999991611392e22, 'ether'], '19999.999999999991611392'],
[['1000000', 'ether'], '0.000000000001'],
[['1123456789123456789', 'ether'], '1.123456789123456789'],
[['1123', 'kwei'], '1.123'],
- [['1234100' ,'kwei'], '1234.1'],
+ [['1234100', 'kwei'], '1234.1'],
[['3308685546611893', 'ether'], '0.003308685546611893'],
];
@@ -339,17 +338,24 @@ export const toWeiValidData: [[Numbers, EtherUnits | number], Numbers][] = [
[['1000000', 'ether'], 0.000000000001],
[['1123456789123456789', 'ether'], '1.123456789123456789123'],
[['1123', 'kwei'], '1.12345'],
- [['1234100' ,'kwei'], '1234.1'],
+ [['1234100', 'kwei'], '1234.1'],
[['3308685546611893', 'ether'], '0.0033086855466118933'],
[['1123', 'kwei'], 1.12345],
-
];
export const toWeiValidDataWarnings: [[Numbers, EtherUnits], string][] = [
- [[0.0000000000000000000001, 'ether'], 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods'],
- [[0.0000000000000000000001, 'ether'], 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods'],
- [[1999999000000009900000, 'kwei'], 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods'],
-
+ [
+ [0.0000000000000000000001, 'ether'],
+ 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods',
+ ],
+ [
+ [0.0000000000000000000001, 'ether'],
+ 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods',
+ ],
+ [
+ [1999999000000009900000, 'kwei'],
+ 'Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods',
+ ],
];
export const fromWeiInvalidData: [[any, any], string][] = [
@@ -362,8 +368,14 @@ export const fromWeiInvalidData: [[any, any], string][] = [
[[{}, 'kwei'], 'Invalid value given "{}". Error: can not parse as number data'],
[['data', 'kwei'], 'Invalid value given "data". Error: can not parse as number data.'],
[['1234', 'uwei'], 'Invalid value given "uwei". Error: invalid unit.'],
- [['1234', -1], 'Invalid value given "-1". Error: not a valid unit. Must be a positive integer.'],
- [['1234', 3.3], 'Invalid value given "3.3". Error: not a valid unit. Must be a positive integer.']
+ [
+ ['1234', -1],
+ 'Invalid value given "-1". Error: not a valid unit. Must be a positive integer.',
+ ],
+ [
+ ['1234', 3.3],
+ 'Invalid value given "3.3". Error: not a valid unit. Must be a positive integer.',
+ ],
];
export const toWeiInvalidData: [[any, any], string][] = [
diff --git a/packages/web3-utils/test/fixtures/formatter.ts b/packages/web3-utils/test/fixtures/formatter.ts
index 32c5d167536..5d44b05df2d 100644
--- a/packages/web3-utils/test/fixtures/formatter.ts
+++ b/packages/web3-utils/test/fixtures/formatter.ts
@@ -55,5 +55,5 @@ export const convertScalarValueValid: [[any, any, any], any][] = [
hexToBytes('0x00000000000000000000000000000000000000000000000000000000000000ff'),
),
],
- [[255, 'bytes32', { bytes: "invalidFormat" }], 255] // return original value when erroring
-];
\ No newline at end of file
+ [[255, 'bytes32', { bytes: 'invalidFormat' }], 255], // return original value when erroring
+];
diff --git a/packages/web3-utils/test/fixtures/hash.ts b/packages/web3-utils/test/fixtures/hash.ts
index 4f337c191ae..1869dd10fec 100644
--- a/packages/web3-utils/test/fixtures/hash.ts
+++ b/packages/web3-utils/test/fixtures/hash.ts
@@ -286,9 +286,13 @@ export const encodePackedInvalidData: [any, string][] = [
{ type: 'bytes32', value: '0x1' },
'Invalid value given "0x1". Error: can not parse as byte data.',
],
+ [
+ [[{ type: 'string', value: '31323334' }], [{ type: '', value: '31323334' }]],
+ 'Autodetection of array types is not supported.',
+ ],
];
-export const keccak256ValidData: [string | Uint8Array | bigint, string][] = [
+export const keccak256ValidData: [string | Uint8Array | bigint | number[], string][] = [
['my data', '0x8e0c48154711500d6fa119cc31df4dec339091e8b426cf4109a769fe89baad31'],
[
new Uint8Array(Buffer.from('my data')),
@@ -299,6 +303,8 @@ export const keccak256ValidData: [string | Uint8Array | bigint, string][] = [
'0x2d19cd91fbcc44e6412f92c11da7907cdedb1ace04c47447b42a61f1cd63b85a',
],
[BigInt(3), '0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de'],
+ [[0x3], '0x69c322e3248a5dfc29d73c5b0553b0185a35cd5bb6386747517ef7e53b15e287'],
+ [new Uint8Array([0x3]), '0x69c322e3248a5dfc29d73c5b0553b0185a35cd5bb6386747517ef7e53b15e287'],
];
export const elementaryNameValidData: [any, string][] = [
@@ -351,7 +357,7 @@ export const soliditySha3BigIntValidData: [Sha3Input[], string][] = [
*/
];
-export const getStorageSlotNumForLongStringValidData: [string|number, string | undefined][]
- = [
- [0, "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"]
- ];
\ No newline at end of file
+export const getStorageSlotNumForLongStringValidData: [string | number, string | undefined][] = [
+ [0, '0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563'],
+ ['0', '0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563'],
+];
diff --git a/packages/web3-utils/test/fixtures/json_rpc.ts b/packages/web3-utils/test/fixtures/json_rpc.ts
index 0b87a35ec59..d801fa91587 100644
--- a/packages/web3-utils/test/fixtures/json_rpc.ts
+++ b/packages/web3-utils/test/fixtures/json_rpc.ts
@@ -28,13 +28,13 @@ const responseWithNotfication = {
export const isResponseWithResultValidTest: [any, boolean][] = [
[responseWithResult, true],
[responseWithError, false],
- [{...responseWithResult, id: '1'}, true],
+ [{ ...responseWithResult, id: '1' }, true],
];
export const isResponseWithErrorValidTest: [any, boolean][] = [
[responseWithResult, false],
[responseWithError, true],
- [{...responseWithError, id: '1'}, true],
+ [{ ...responseWithError, id: '1' }, true],
];
export const isResponseWithNotificationValidTest: [JsonRpcNotification, boolean][] = [
@@ -67,32 +67,40 @@ export const toPayloadValidTest: [any, any][] = [
},
],
[
- { method: 'add', jsonrpc: '1.0', id: 1},
+ { method: 'add', jsonrpc: '1.0', id: 1 },
{
method: 'add',
id: 1,
jsonrpc: '1.0',
- params: undefined
+ params: undefined,
},
- ]
+ ],
];
export const isResponseRpcErrorValidData: [any, boolean][] = [
[responseWithRpcError, true],
[responseWithError, false],
-]
+];
export const isBatchRequestValidData: [any, boolean][] = [
- [[{
- method: 'add',
- id: 1,
- jsonrpc: '1.0',
- params: undefined
- }], true],
- [{
- method: 'add',
- id: 1,
- jsonrpc: '1.0',
- params: undefined
- }, false]
-]
\ No newline at end of file
+ [
+ [
+ {
+ method: 'add',
+ id: 1,
+ jsonrpc: '1.0',
+ params: undefined,
+ },
+ ],
+ true,
+ ],
+ [
+ {
+ method: 'add',
+ id: 1,
+ jsonrpc: '1.0',
+ params: undefined,
+ },
+ false,
+ ],
+];
diff --git a/packages/web3-utils/test/fixtures/string_manipulation.ts b/packages/web3-utils/test/fixtures/string_manipulation.ts
index 86be918051d..dde49247677 100644
--- a/packages/web3-utils/test/fixtures/string_manipulation.ts
+++ b/packages/web3-utils/test/fixtures/string_manipulation.ts
@@ -69,7 +69,7 @@ export const toTwosComplementData: [[Numbers, number | undefined], HexString][]
[['13', 32], '0x0000000000000000000000000000000d'],
[['-13', 32], '0xfffffffffffffffffffffffffffffff3'],
[[-16, 2], '0xf0'],
- [['0x1', undefined], '0x0000000000000000000000000000000000000000000000000000000000000001']
+ [['0x1', undefined], '0x0000000000000000000000000000000000000000000000000000000000000001'],
];
export const fromTwosComplementData: [[Numbers, number | undefined], number | bigint][] = [
@@ -82,7 +82,7 @@ export const fromTwosComplementData: [[Numbers, number | undefined], number | bi
[[1000, 64], 1000],
[[-1000, 64], -1000],
[[BigInt(9), 1], -7],
- [['0x0000000000000000000000000000000000000000000000000000000000000001', undefined], 1]
+ [['0x0000000000000000000000000000000000000000000000000000000000000001', undefined], 1],
];
export const toTwosComplementInvalidData: [[Numbers, number], string][] = [
diff --git a/packages/web3-utils/test/unit/chunk_response_parser.test.ts b/packages/web3-utils/test/unit/chunk_response_parser.test.ts
index 707197e2889..bb4c70e8f1b 100644
--- a/packages/web3-utils/test/unit/chunk_response_parser.test.ts
+++ b/packages/web3-utils/test/unit/chunk_response_parser.test.ts
@@ -83,6 +83,6 @@ describe('chunk_response_parser', () => {
eventEmiter.on('error', onError);
// eslint-disable-next-line no-promise-executor-return
await new Promise(resolve => setTimeout(resolve, 1000));
- expect(result).toEqual([])
+ expect(result).toEqual([]);
});
});
diff --git a/packages/web3-utils/test/unit/converters.test.ts b/packages/web3-utils/test/unit/converters.test.ts
index 7481d5008ce..84073f4a4d7 100644
--- a/packages/web3-utils/test/unit/converters.test.ts
+++ b/packages/web3-utils/test/unit/converters.test.ts
@@ -330,7 +330,7 @@ describe('converters', () => {
});
it('an interesting case that needs investigation', () => {
- // This case is to be investigated further
+ // TODO: This case is to be investigated further
expect(
toHex(
'101611154195520776335741463917853444671577865378275924493376429267637792638729',
@@ -354,6 +354,14 @@ describe('converters', () => {
});
describe('fromWei', () => {
+ beforeEach(() => {
+ jest.spyOn(console, 'warn').mockImplementation(() => {
+ // do nothing
+ });
+ });
+ afterAll(() => {
+ jest.restoreAllMocks();
+ });
describe('valid cases', () => {
it.each(fromWeiValidData)('%s', (input, output) => {
expect(fromWei(input[0], input[1])).toEqual(output);
@@ -385,6 +393,9 @@ describe('converters', () => {
// do nothing
});
});
+ afterAll(() => {
+ jest.restoreAllMocks();
+ });
it.each(toWeiValidDataWarnings)('%s', (input, output) => {
toWei(input[0], input[1]);
expect(console.warn).toHaveBeenCalledWith(output);
@@ -407,7 +418,9 @@ describe('converters', () => {
// mock utils.uint8ArrayToHexString to return an empty string
jest.mock('web3-validator');
- jest.spyOn(utils, 'uint8ArrayToHexString').mockReturnValue(undefined as unknown as string);
+ jest.spyOn(utils, 'uint8ArrayToHexString').mockReturnValue(
+ undefined as unknown as string,
+ );
const result = toChecksumAddress(address);
expect(result).toBe('');
diff --git a/packages/web3-utils/test/unit/formatter.test.ts b/packages/web3-utils/test/unit/formatter.test.ts
index 8b18a901ef5..add9095596b 100644
--- a/packages/web3-utils/test/unit/formatter.test.ts
+++ b/packages/web3-utils/test/unit/formatter.test.ts
@@ -24,7 +24,7 @@ import {
HexString,
Numbers,
} from 'web3-types';
-import {FormatterError} from 'web3-errors';
+import { FormatterError } from 'web3-errors';
import { expectTypeOf, typecheck } from '@humeris/espresso-shot';
import { isDataFormatValid, convertScalarValueValid } from '../fixtures/formatter';
import { format, isDataFormat, convertScalarValue, convert } from '../../src/formatter';
@@ -585,40 +585,6 @@ describe('formatter', () => {
).toEqual(result);
});
- it('should format array of objects with', () => {
- const schema = {
- type: 'array',
- items: {
- type: 'object',
- properties: {
- prop1: {
- oneOf: [{ format: 'address' }, { type: 'string' }],
- },
- prop2: {
- format: 'bytes',
- },
- },
- },
- };
-
- const data = [
- {
- prop1: '0x7ed0e85b8e1e925600b4373e6d108f34ab38a401',
- prop2: new Uint8Array(hexToBytes('FF')),
- },
- { prop1: 'some string', prop2: new Uint8Array(hexToBytes('FF')) },
- ];
-
- const result = [
- { prop1: '0x7ed0e85b8e1e925600b4373e6d108f34ab38a401', prop2: '0xff' },
- { prop1: 'some string', prop2: '0xff' },
- ];
-
- expect(
- format(schema, data, { number: FMT_NUMBER.HEX, bytes: FMT_BYTES.HEX }),
- ).toEqual(result);
- });
-
it('should format array of different objects', () => {
const schema = {
type: 'array',
@@ -773,79 +739,7 @@ describe('formatter', () => {
).toEqual(result);
});
});
-
describe('object values', () => {
-
- describe('convert', () => {
- it('should convert array values correctly when schema is an array and items are objects', () => {
- const schema = {
- type: 'object',
- properties: {
- transactions: {
- type: 'array',
- oneOf: [
- {
- items: {
- type: 'object',
- properties: {
- type: { enum: ['A'] },
- value: { type: 'string' }
- }
- }
- },
- {
- items: {
- type: 'object',
- properties: {
- type: { enum: ['B'] },
- value: { type: 'number' }
- }
- }
- }
- ]
- }
- }
- };
- const data = {
- transactions: [
- { type: 'B', value: 42 },
- { type: 'B', value: 43 }
- ]
- };
- expect(convert(data, schema, [], {
- number: FMT_NUMBER.HEX,
- bytes: FMT_BYTES.HEX,
- })).toEqual(data)
- });
- });
-
- it('should delete the array property if schema for array items is nullish', () => {
- const schema = {
- type: 'object',
- properties: {
- transactions: {
- type: 'array',
- items: undefined // Simulate a missing or null schema for items
- }
- }
- };
-
- const data = {
- transactions: [
- { type: 'A', value: 'some string' },
- { type: 'B', value: 42 }
- ]
- };
-
- const result = convert(data, schema, [], {
- number: FMT_NUMBER.HEX,
- bytes: FMT_BYTES.HEX,
- });
-
- expect(result).toEqual({});
- });
-
-
it('should format simple object', () => {
const schema = {
type: 'object',
@@ -885,9 +779,9 @@ describe('formatter', () => {
it('should throw FormatterError when jsonSchema is invalid', () => {
const invalidSchema1 = {};
const data = { key: 'value' };
-
+
expect(() => format(invalidSchema1, data)).toThrow(FormatterError);
- });
+ });
it('should format nested objects', () => {
const schema = {
@@ -933,52 +827,7 @@ describe('formatter', () => {
expect(result).toEqual(expected);
});
-
- it('should return empty when no proerties or items', () => {
- const data = { key: 'value' };
- const schema = {
- type: 'object',
- };
- const f = { number: FMT_NUMBER.NUMBER, bytes: FMT_BYTES.HEX };
- const result = convert(data, schema, [], f, []);
- expect(result).toEqual({});
});
-
- it('should format nested objects with oneOf', () => {
- const schema = {
- type: 'object',
- properties: {
- details: {
- type: 'object',
- oneOf: [
- { properties: { type: { enum: ['A'] }, value: { type: 'string' } } },
- { properties: { type: { enum: ['B'] }, value: { type: 'number' } } }
- ]
- }
- }
- }
-
- const data =
- {
- details: {
- type: 'B',
- value: 42
- }
- }
- const result = convert(data, schema, [], {
- number: FMT_NUMBER.BIGINT,
- bytes: FMT_BYTES.UINT8ARRAY,
- }, [['details', 1]]);
-
- expect(result).toEqual({
- details: {
- type: 'B',
- value: 42
- }
- });
-
- })
- });
describe('isDataFormat', () => {
describe('valid cases', () => {
it.each(isDataFormatValid)('%s', (input, output) => {
@@ -1004,4 +853,124 @@ describe('formatter', () => {
});
});
});
+
+ describe('convert', () => {
+ it('should convert array values correctly when schema is an array and items are objects', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ transactions: {
+ type: 'array',
+ oneOf: [
+ {
+ items: {
+ type: 'object',
+ properties: {
+ address: { format: 'string' },
+ value: { type: 'string' },
+ },
+ },
+ },
+ {
+ items: {
+ type: 'object',
+ properties: {
+ address: { format: 'string' },
+ value: { type: 'number' },
+ },
+ },
+ },
+ ],
+ },
+ },
+ };
+ const data = {
+ transactions: [
+ { address: 'B', value: '42' },
+ { address: 'B', value: 43 },
+ ],
+ };
+ expect(
+ convert(data, schema, [], {
+ number: FMT_NUMBER.HEX,
+ bytes: FMT_BYTES.HEX,
+ }),
+ ).toEqual(data);
+ });
+
+ it('should delete the array property if schema for array items is nullish', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ transactions: {
+ type: 'array',
+ items: undefined, // Simulate a missing or null schema for items
+ },
+ },
+ };
+
+ const data = {
+ transactions: [
+ { type: 'A', value: 'some string' },
+ { type: 'B', value: 42 },
+ ],
+ };
+
+ const result = convert(data, schema, [], {
+ number: FMT_NUMBER.HEX,
+ bytes: FMT_BYTES.HEX,
+ });
+
+ expect(result).toEqual({});
+ });
+
+ it('should return empty when no proerties or items', () => {
+ const data = { key: 'value' };
+ const schema = {
+ type: 'object',
+ };
+ const f = { number: FMT_NUMBER.NUMBER, bytes: FMT_BYTES.HEX };
+ const result = convert(data, schema, [], f, []);
+ expect(result).toEqual({});
+ });
+
+ it('should format nested objects with oneOf', () => {
+ const schema = {
+ type: 'object',
+ properties: {
+ details: {
+ type: 'object',
+ oneOf: [
+ { properties: { type: { enum: ['A'] }, value: { type: 'string' } } },
+ { properties: { type: { enum: ['B'] }, value: { type: 'number' } } },
+ ],
+ },
+ },
+ };
+
+ const data = {
+ details: {
+ type: 'B',
+ value: 42,
+ },
+ };
+ const result = convert(
+ data,
+ schema,
+ [],
+ {
+ number: FMT_NUMBER.BIGINT,
+ bytes: FMT_BYTES.UINT8ARRAY,
+ },
+ [['details', 1]],
+ );
+
+ expect(result).toEqual({
+ details: {
+ type: 'B',
+ value: 42,
+ },
+ });
+ });
+ });
});
diff --git a/packages/web3-utils/test/unit/hash.test.ts b/packages/web3-utils/test/unit/hash.test.ts
index 13b4c6aa1df..814dacd45f2 100644
--- a/packages/web3-utils/test/unit/hash.test.ts
+++ b/packages/web3-utils/test/unit/hash.test.ts
@@ -156,5 +156,5 @@ describe('hash', () => {
it.each(getStorageSlotNumForLongStringValidData)('%s', (input, output) => {
expect(getStorageSlotNumForLongString(input)).toEqual(output);
});
- })
+ });
});
diff --git a/packages/web3-utils/test/unit/json_rpc.test.ts b/packages/web3-utils/test/unit/json_rpc.test.ts
index 27dee1a0354..ea16cd646d1 100644
--- a/packages/web3-utils/test/unit/json_rpc.test.ts
+++ b/packages/web3-utils/test/unit/json_rpc.test.ts
@@ -91,49 +91,57 @@ describe('json rpc tests', () => {
});
describe('isBatchResponseValid', () => {
describe('valid cases', () => {
- it.each(isBatchResponseValidTest)('isBatchResponseValid valid test', (input, output) => {
- const result = isBatchResponse(input);
- expect(result).toBe(output);
- });
+ it.each(isBatchResponseValidTest)(
+ 'isBatchResponseValid valid test',
+ (input, output) => {
+ const result = isBatchResponse(input);
+ expect(result).toBe(output);
+ },
+ );
});
});
describe('isBatchRequest', () => {
describe('valid cases', () => {
it.each(isBatchRequestValidData)('isBatchRqeuest valid data', (input, output) => {
expect(isBatchRequest(input)).toBe(output);
- })
- })
- })
+ });
+ });
+ });
describe('toPayloadValid', () => {
describe('valid cases', () => {
- beforeEach (() => {
- setRequestIdStart(undefined)
+ beforeEach(() => {
+ setRequestIdStart(undefined);
});
it.each(toPayloadValidTest)('toPayload valid test', async (input, output) => {
- const result = await new Promise((resolve) => {
- resolve(toPayload(input))
- })
+ const result = await new Promise(resolve => {
+ resolve(toPayload(input));
+ });
expect(result).toStrictEqual(output);
});
it('should give payload that has requestid set', async () => {
- setRequestIdStart(1)
- const result = await new Promise((resolve) => {
- resolve(toPayload({ method: 'delete' }))
- })
- expect(result).toStrictEqual({method: 'delete', id:2, params: undefined, jsonrpc: '2.0'});
+ setRequestIdStart(1);
+ const result = await new Promise(resolve => {
+ resolve(toPayload({ method: 'delete' }));
+ });
+ expect(result).toStrictEqual({
+ method: 'delete',
+ id: 2,
+ params: undefined,
+ jsonrpc: '2.0',
+ });
});
});
});
describe('toBatchPayload', () => {
it('should batch payload', async () => {
- setRequestIdStart(0)
- const result = await new Promise((resolve) => {
- resolve(toBatchPayload([{ method: 'delete' }, {method: 'add'}]))
- })
+ setRequestIdStart(0);
+ const result = await new Promise(resolve => {
+ resolve(toBatchPayload([{ method: 'delete' }, { method: 'add' }]));
+ });
expect(result).toStrictEqual([
- {method: 'delete', id:1, params: undefined, jsonrpc: '2.0'},
- {method: 'add', id:2, params: undefined, jsonrpc: '2.0'}
+ { method: 'delete', id: 1, params: undefined, jsonrpc: '2.0' },
+ { method: 'add', id: 2, params: undefined, jsonrpc: '2.0' },
]);
});
- })
-});
\ No newline at end of file
+ });
+});
diff --git a/packages/web3-utils/test/unit/socket_provider.test.ts b/packages/web3-utils/test/unit/socket_provider.test.ts
index 9d178464e6a..c2c3756c755 100644
--- a/packages/web3-utils/test/unit/socket_provider.test.ts
+++ b/packages/web3-utils/test/unit/socket_provider.test.ts
@@ -31,7 +31,6 @@ import { SocketProvider } from '../../src/socket_provider';
const dummySocketConnection = { dummy: 'dummy' };
class TestProvider extends SocketProvider {
-
protected _socketConnection?: typeof dummySocketConnection;
protected _openSocketConnection() {
@@ -124,9 +123,9 @@ describe('SocketProvider', () => {
it('should error when failing to _validateProviderPath', () => {
expect(() => {
// eslint-disable-next-line no-new
- new TestProvider("", socketOption, { delay: 0 });
- }).toThrow(InvalidClientError)
- })
+ new TestProvider('', socketOption, { delay: 0 });
+ }).toThrow(InvalidClientError);
+ });
});
describe('testing _reconnect() method', () => {
it('should not be called when { autoReconnect: false }', () => {
@@ -371,7 +370,9 @@ describe('SocketProvider', () => {
const funcBSpy = jest
// spy on provider.super._onDisconnect
.spyOn(
- Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(provider))),
+ Object.getPrototypeOf(
+ Object.getPrototypeOf(Object.getPrototypeOf(provider)),
+ ),
'_onDisconnect',
)
.mockReturnValue(new EventEmitter());
@@ -652,16 +653,15 @@ describe('SocketProvider', () => {
});
describe('_onConnect', () => {
-
beforeEach(() => {
- jest.spyOn(console, 'error').mockImplementation(() => {
+ jest.spyOn(console, 'error').mockImplementation(() => {
// do nothing
}); // Spy on console.error to suppress and check calls
- })
+ });
afterEach(() => {
jest.restoreAllMocks(); // Restore all mocks after each test
- });
+ });
it('should set the connection status to "connected"', () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
@@ -674,46 +674,46 @@ describe('SocketProvider', () => {
it('should set _accounts and _chainId when _getAccounts and _getChainId resolve', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([123]);
- jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce("1");
-
- await new Promise ((resolve) => {
+ jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce('1');
+
+ await new Promise(resolve => {
provider['_onConnect']();
- resolve("");
- })
+ resolve('');
+ });
expect((provider as any)._chainId).toBe('1');
expect((provider as any)._accounts).toEqual([123]);
});
it('chainID should change when connecting twice', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
-
- await new Promise ((resolve) => {
+
+ await new Promise(resolve => {
jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([123]);
- jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce("1");
+ jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce('1');
provider['_onConnect']();
- resolve("");
- })
+ resolve('');
+ });
expect((provider as any)._chainId).toBe('1');
expect((provider as any)._accounts).toEqual([123]);
- await new Promise ((resolve) => {
+ await new Promise(resolve => {
jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([123]);
- jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce("2");
+ jest.spyOn(provider as any, '_getChainId').mockResolvedValueOnce('2');
provider['_onConnect']();
- resolve("");
- })
+ resolve('');
+ });
expect((provider as any)._chainId).toBe('2');
expect((provider as any)._accounts).toEqual([123]);
});
it('should catch errors when _getAccounts and _getChainId throws', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
- jest.spyOn(provider as any, '_getChainId').mockRejectedValueOnce(new Error(""));
- jest.spyOn(provider as any, '_getAccounts').mockRejectedValueOnce(new Error(""));
+ jest.spyOn(provider as any, '_getChainId').mockRejectedValueOnce(new Error(''));
+ jest.spyOn(provider as any, '_getAccounts').mockRejectedValueOnce(new Error(''));
jest.spyOn(provider, 'request').mockReturnValue(new Error() as unknown as Promise);
-
- await new Promise ((resolve) => {
+
+ await new Promise(resolve => {
provider['_onConnect']();
- resolve("");
- })
+ resolve('');
+ });
expect((provider as any)._chainId).toBe('');
expect((provider as any)._accounts).toEqual([]);
});
@@ -723,16 +723,14 @@ describe('SocketProvider', () => {
jest.spyOn(provider as any, '_getAccounts').mockResolvedValueOnce([]);
(provider as any)._eventEmitter.emit = jest.fn(() => {
throw new Error('event emitter failed');
- })
-
+ });
- await new Promise ((resolve) => {
+ await new Promise(resolve => {
provider['_onConnect']();
- resolve("");
- })
+ resolve('');
+ });
// I would check if console.error is called, but facing a race condition
expect((provider as any)._eventEmitter.emit).toHaveBeenCalledTimes(1);
-
});
});
@@ -740,49 +738,49 @@ describe('SocketProvider', () => {
it('should return data from the chainId method', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
const chainId = 1;
- jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: chainId});
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({ result: chainId });
const result = await provider['_getChainId']();
expect(result).toBe(chainId);
- })
+ });
it('should be returning undefined from the chainId method', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
- jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: undefined});
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({ result: undefined });
const result = await provider['_getChainId']();
- expect(result).toBe("");
- })
+ expect(result).toBe('');
+ });
it('should return empty from the chainId method', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
jest.spyOn(provider as any, 'request').mockResolvedValueOnce(undefined);
const result = await provider['_getChainId']();
- expect(result).toBe("");
- })
- })
+ expect(result).toBe('');
+ });
+ });
describe('_getAccounts', () => {
it('should return data from the _getAccounts method', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
const accounts = [1];
- jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: accounts});
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({ result: accounts });
const result = await provider['_getAccounts']();
expect(result).toBe(accounts);
- })
+ });
it('should returning undefined from the _getAccounts method', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
- jest.spyOn(provider as any, 'request').mockResolvedValueOnce({result: undefined});
+ jest.spyOn(provider as any, 'request').mockResolvedValueOnce({ result: undefined });
const result = await provider['_getAccounts']();
expect(result).toEqual([]);
- })
+ });
it('should return empty from the _getAccounts method', async () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
jest.spyOn(provider as any, 'request').mockResolvedValueOnce(undefined);
const result = await provider['_getAccounts']();
expect(result).toEqual([]);
- })
- })
+ });
+ });
describe('_onMessage', () => {
it('should resolve the deferred promise for valid responses with errors', () => {
@@ -846,7 +844,11 @@ describe('SocketProvider', () => {
it('should emit "message" event for notifications', () => {
const provider = new TestProvider(socketPath, socketOption, { delay: 0 });
const event = {
- data: JSON.stringify({ jsonrpc: '2.0', method: 'notification_1_subscription', params: {} }),
+ data: JSON.stringify({
+ jsonrpc: '2.0',
+ method: 'notification_1_subscription',
+ params: {},
+ }),
};
const eventEmitterSpy = jest.spyOn(provider['_eventEmitter'], 'emit');
@@ -860,4 +862,4 @@ describe('SocketProvider', () => {
});
});
});
-});
\ No newline at end of file
+});
diff --git a/packages/web3-utils/test/unit/web3_deferred_promise.test.ts b/packages/web3-utils/test/unit/web3_deferred_promise.test.ts
index 044f558fb10..6fe87129e73 100644
--- a/packages/web3-utils/test/unit/web3_deferred_promise.test.ts
+++ b/packages/web3-utils/test/unit/web3_deferred_promise.test.ts
@@ -66,4 +66,4 @@ describe('Web3DeferredPromise', () => {
expect(callbackExecuted).toBe(true);
});
});
-});
\ No newline at end of file
+});
From b9617eebb77c1905ff40337ad115d9872629d356 Mon Sep 17 00:00:00 2001
From: Alex Luu
Date: Sun, 2 Jun 2024 22:38:45 -0400
Subject: [PATCH 17/17] remove unintended cases for formatter and convert
---
.../web3-utils/test/unit/formatter.test.ts | 110 +-----------------
1 file changed, 1 insertion(+), 109 deletions(-)
diff --git a/packages/web3-utils/test/unit/formatter.test.ts b/packages/web3-utils/test/unit/formatter.test.ts
index add9095596b..aa1a14fb6c9 100644
--- a/packages/web3-utils/test/unit/formatter.test.ts
+++ b/packages/web3-utils/test/unit/formatter.test.ts
@@ -855,76 +855,7 @@ describe('formatter', () => {
});
describe('convert', () => {
- it('should convert array values correctly when schema is an array and items are objects', () => {
- const schema = {
- type: 'object',
- properties: {
- transactions: {
- type: 'array',
- oneOf: [
- {
- items: {
- type: 'object',
- properties: {
- address: { format: 'string' },
- value: { type: 'string' },
- },
- },
- },
- {
- items: {
- type: 'object',
- properties: {
- address: { format: 'string' },
- value: { type: 'number' },
- },
- },
- },
- ],
- },
- },
- };
- const data = {
- transactions: [
- { address: 'B', value: '42' },
- { address: 'B', value: 43 },
- ],
- };
- expect(
- convert(data, schema, [], {
- number: FMT_NUMBER.HEX,
- bytes: FMT_BYTES.HEX,
- }),
- ).toEqual(data);
- });
-
- it('should delete the array property if schema for array items is nullish', () => {
- const schema = {
- type: 'object',
- properties: {
- transactions: {
- type: 'array',
- items: undefined, // Simulate a missing or null schema for items
- },
- },
- };
-
- const data = {
- transactions: [
- { type: 'A', value: 'some string' },
- { type: 'B', value: 42 },
- ],
- };
-
- const result = convert(data, schema, [], {
- number: FMT_NUMBER.HEX,
- bytes: FMT_BYTES.HEX,
- });
-
- expect(result).toEqual({});
- });
-
- it('should return empty when no proerties or items', () => {
+ it('should return empty when no properties or items', () => {
const data = { key: 'value' };
const schema = {
type: 'object',
@@ -933,44 +864,5 @@ describe('formatter', () => {
const result = convert(data, schema, [], f, []);
expect(result).toEqual({});
});
-
- it('should format nested objects with oneOf', () => {
- const schema = {
- type: 'object',
- properties: {
- details: {
- type: 'object',
- oneOf: [
- { properties: { type: { enum: ['A'] }, value: { type: 'string' } } },
- { properties: { type: { enum: ['B'] }, value: { type: 'number' } } },
- ],
- },
- },
- };
-
- const data = {
- details: {
- type: 'B',
- value: 42,
- },
- };
- const result = convert(
- data,
- schema,
- [],
- {
- number: FMT_NUMBER.BIGINT,
- bytes: FMT_BYTES.UINT8ARRAY,
- },
- [['details', 1]],
- );
-
- expect(result).toEqual({
- details: {
- type: 'B',
- value: 42,
- },
- });
- });
});
});