diff --git a/packages/web3-common/src/web3_base_wallet.ts b/packages/web3-common/src/web3_base_wallet.ts index 222f47a9399..376addf6f9d 100644 --- a/packages/web3-common/src/web3_base_wallet.ts +++ b/packages/web3-common/src/web3_base_wallet.ts @@ -50,16 +50,17 @@ export interface Web3AccountProvider { decrypt: (keystore: string, password: string, options?: Record) => Promise; } -export abstract class Web3BaseWallet { +export abstract class Web3BaseWallet extends Array { protected readonly _accountProvider: Web3AccountProvider; public constructor(accountProvider: Web3AccountProvider) { + super(); this._accountProvider = accountProvider; } public abstract create(numberOfAccounts: number): this; public abstract add(account: T | string): boolean; - public abstract get(addressOrIndex: string | number): T; + public abstract get(addressOrIndex: string | number): T | undefined; public abstract remove(addressOrIndex: string | number): boolean; public abstract clear(): this; public abstract encrypt( diff --git a/packages/web3-common/src/web3_promi_event.ts b/packages/web3-common/src/web3_promi_event.ts index f516c408048..2618c89085a 100644 --- a/packages/web3-common/src/web3_promi_event.ts +++ b/packages/web3-common/src/web3_promi_event.ts @@ -15,7 +15,12 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { Web3EventEmitter, Web3EventMap } from './web3_event_emitter'; +import { + Web3EventCallback, + Web3EventEmitter, + Web3EventKey, + Web3EventMap, +} from './web3_event_emitter'; export type PromiseExecutor = ( resolve: (data: T) => void, @@ -52,4 +57,22 @@ export class Web3PromiEvent public async finally(onfinally?: (() => void) | undefined): Promise { return this._promise.finally(onfinally); } + + public on>( + eventName: K, + fn: Web3EventCallback, + ): this { + super.on(eventName, fn); + + return this; + } + + public once>( + eventName: K, + fn: Web3EventCallback, + ): this { + super.once(eventName, fn); + + return this; + } } diff --git a/packages/web3-common/test/unit/web3_promi_event.test.ts b/packages/web3-common/test/unit/web3_promi_event.test.ts index 13bf6892f56..823f319d7f4 100644 --- a/packages/web3-common/test/unit/web3_promi_event.test.ts +++ b/packages/web3-common/test/unit/web3_promi_event.test.ts @@ -41,15 +41,16 @@ describe('Web3PromiEvent', () => { }); p.on('data', data => { + // eslint-disable-next-line jest/no-conditional-expect expect(data).toBe('resolved value'); done(undefined); - }); + }) + .then(data => { + p.emit('data', data); + }) + .catch(e => done(e)); - p.then(data => { - p.emit('data', data); - }).catch(e => { - throw e; - }); + expect.assertions(1); }); }); @@ -69,10 +70,47 @@ describe('Web3PromiEvent', () => { const p = func(); - p.on('data', data => { + // eslint-disable-next-line no-void + void p.on('data', data => { expect(data).toBe('emitted data'); done(undefined); }); }); }); + + it('should return the promi-event object from "on" handler', async () => { + const p = new Web3PromiEvent(resolve => { + resolve('resolved value'); + }) + .on('event1', data => { + expect(data).toBe('string value'); + }) + .on('event2', data => { + expect(data).toBe(3); + }); + + p.emit('event1', 'string value'); + p.emit('event2', 3); + + await expect(p).resolves.toBe('resolved value'); + expect.assertions(3); + }); + + it('should return the promi-event object from "once" handler', async () => { + const p = new Web3PromiEvent(resolve => { + resolve('resolved value'); + }) + .once('event1', data => { + expect(data).toBe('string value'); + }) + .once('event2', data => { + expect(data).toBe(3); + }); + + p.emit('event1', 'string value'); + p.emit('event2', 3); + + await expect(p).resolves.toBe('resolved value'); + expect.assertions(3); + }); }); diff --git a/packages/web3-eth-accounts/src/wallet.ts b/packages/web3-eth-accounts/src/wallet.ts index 2d4a59d32d7..f2546decf1c 100644 --- a/packages/web3-eth-accounts/src/wallet.ts +++ b/packages/web3-eth-accounts/src/wallet.ts @@ -15,12 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { - Web3BaseWallet, - Web3BaseWalletAccount, - Web3AccountProvider, - Web3EncryptedWallet, -} from 'web3-common'; +import { Web3BaseWallet, Web3BaseWalletAccount, Web3EncryptedWallet } from 'web3-common'; import { isNullish } from 'web3-validator'; type BrowserError = { code: number; name: string }; @@ -28,14 +23,9 @@ type BrowserError = { code: number; name: string }; export class Wallet< T extends Web3BaseWalletAccount = Web3BaseWalletAccount, > extends Web3BaseWallet { - private readonly _accounts: { [key: string]: T }; + private readonly _addressMap = new Map(); private readonly _defaultKeyName = 'web3js_wallet'; - public constructor(accountProvider: Web3AccountProvider) { - super(accountProvider); - this._accounts = {}; - } - public static getStorage(): Storage | undefined { let storage: Storage | undefined; @@ -65,10 +55,6 @@ export class Wallet< } } - public get length() { - return Object.keys(this._accounts).length; - } - public create(numberOfAccounts: number) { for (let i = 0; i < numberOfAccounts; i += 1) { this.add(this._accountProvider.create()); @@ -82,27 +68,42 @@ export class Wallet< return this.add(this._accountProvider.privateKeyToAccount(account)); } - this._accounts[account.address.toLowerCase()] = account; + const index = this.length; + this._addressMap.set(account.address.toLowerCase(), index); + + this[index] = account; return true; } - public get(addressOrIndex: string | number): T { + public get(addressOrIndex: string | number): T | undefined { if (typeof addressOrIndex === 'string') { - return this._accounts[addressOrIndex]; + const index = this._addressMap.get(addressOrIndex); + + if (!isNullish(index)) { + return this[index]; + } + + return undefined; } - return Object.values(this._accounts)[addressOrIndex]; + return this[addressOrIndex]; } public remove(addressOrIndex: string | number): boolean { - const result = - typeof addressOrIndex === 'string' - ? { address: addressOrIndex } - : Object.values(this._accounts)[addressOrIndex]; + if (typeof addressOrIndex === 'string') { + const index = this._addressMap.get(addressOrIndex.toLowerCase()); + if (isNullish(index)) { + return false; + } + this._addressMap.delete(addressOrIndex.toLowerCase()); + this.splice(index, 1); + + return true; + } - if (result && this._accounts[result.address]) { - delete this._accounts[result.address]; + if (this[addressOrIndex]) { + this.splice(addressOrIndex, 1); return true; } @@ -110,17 +111,16 @@ export class Wallet< } public clear() { - for (const key of Object.keys(this._accounts)) { - delete this._accounts[key]; - } + this._addressMap.clear(); + + // Setting length clears the Array in JS. + this.length = 0; return this; } public async encrypt(password: string, options?: Record | undefined) { - return Promise.all( - Object.values(this._accounts).map(async account => account.encrypt(password, options)), - ); + return Promise.all(this.map(async account => account.encrypt(password, options))); } public async decrypt( diff --git a/packages/web3-eth-accounts/test/unit/wallet.test.ts b/packages/web3-eth-accounts/test/unit/wallet.test.ts index b1cb9952484..f2a9e35239f 100644 --- a/packages/web3-eth-accounts/test/unit/wallet.test.ts +++ b/packages/web3-eth-accounts/test/unit/wallet.test.ts @@ -142,6 +142,14 @@ describe('Wallet', () => { expect(wallet.get('my_address')).toEqual(account); expect(wallet.get('my_Address')).toBeUndefined(); }); + + it('should get account with index', () => { + const account = { address: 'my_Address' } as never; + + wallet.add(account); + + expect(wallet[0]).toEqual(account); + }); }); describe('remove', () => { @@ -190,6 +198,40 @@ describe('Wallet', () => { expect(result).toBeFalsy(); expect(wallet).toHaveLength(1); }); + + it('should remove account with the index', () => { + const account = { address: 'my_address' } as never; + wallet.add(account); + expect(wallet).toHaveLength(1); + + delete wallet[0]; + + // Deleting objects dees not change the length + expect(wallet).toHaveLength(1); + expect(wallet[0]).toBeUndefined(); + }); + + it('should remove account with array methods', () => { + const account = { address: 'my_address' } as never; + wallet.add(account); + expect(wallet).toHaveLength(1); + + wallet.splice(0, 1); + + expect(wallet).toHaveLength(0); + expect(wallet[0]).toBeUndefined(); + }); + + it('should remove account added with private key with array methods', () => { + const privateKey = 'private_key'; + wallet.add(privateKey); + expect(wallet).toHaveLength(1); + + wallet.splice(0, 1); + + expect(wallet).toHaveLength(0); + expect(wallet[0]).toBeUndefined(); + }); }); describe('clear', () => { diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 4921354a711..915de18cd63 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -452,9 +452,9 @@ export class Contract * * The methods of this smart contract are available through: * - * * The name: `myContract.methods.myMethod(123)` - * * The name with parameters: `myContract.methods['myMethod(uint256)'](123)` - * * The signature `myContract.methods['0x58cf5f10'](123)` + * The name: `myContract.methods.myMethod(123)` + * The name with parameters: `myContract.methods['myMethod(uint256)'](123)` + * The signature `myContract.methods['0x58cf5f10'](123)` * * This allows calling functions with same name but different parameters from the JavaScript contract object. * @@ -574,6 +574,9 @@ export class Contract * }); * ``` * + * @param deployOptions + * @param deployOptions.data + * @param deployOptions.arguments * @returns - The transaction object */ public deploy(deployOptions?: { @@ -685,6 +688,7 @@ export class Contract * * @param eventName - The name of the event in the contract, or `allEvents` to get all events. * @param filter - The filter options used to get events. + * @param returnFormat * @returns - An array with the past event `Objects`, matching the given event name and filter. */ public async getPastEvents( diff --git a/packages/web3-eth-contract/test/integration/contract_defaults.test.ts b/packages/web3-eth-contract/test/integration/contract_defaults.test.ts index 2d9100103ff..f4193545053 100644 --- a/packages/web3-eth-contract/test/integration/contract_defaults.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_defaults.test.ts @@ -50,11 +50,10 @@ describe('contract', () => { const receiptHandler = jest.fn(); // We didn't specify "from" in this call - const tx = contract.deploy(deployOptions).send({ gas: '1000000' }); - - tx.on('receipt', receiptHandler); - - await tx; + await contract + .deploy(deployOptions) + .send({ gas: '1000000' }) + .on('receipt', receiptHandler); // We didn't specify "from" in this call expect(receiptHandler).toHaveBeenCalledWith( diff --git a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts index fad447f63ba..9fbf9f62da7 100644 --- a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts @@ -75,7 +75,7 @@ describe('contract', () => { it('should emit the "confirmation" event', async () => { const confirmationHandler = jest.fn(); - contract + await contract .deploy(deployOptions) .send(sendOptions) .on('confirmation', confirmationHandler); @@ -97,9 +97,11 @@ describe('contract', () => { it('should emit the "transactionHash" event', async () => { const handler = jest.fn(); - const promiEvent = contract.deploy(deployOptions).send(sendOptions); + const promiEvent = contract + .deploy(deployOptions) + .send(sendOptions) + .on('transactionHash', handler); - promiEvent.on('transactionHash', handler); // Deploy the contract await promiEvent; @@ -109,9 +111,11 @@ describe('contract', () => { it('should emit the "sending" event', async () => { const handler = jest.fn(); - const promiEvent = contract.deploy(deployOptions).send(sendOptions); + const promiEvent = contract + .deploy(deployOptions) + .send(sendOptions) + .on('sending', handler); - promiEvent.on('sending', handler); // Deploy the contract await promiEvent; @@ -121,9 +125,8 @@ describe('contract', () => { it('should emit the "sent" event', async () => { const handler = jest.fn(); - const promiEvent = contract.deploy(deployOptions).send(sendOptions); + const promiEvent = contract.deploy(deployOptions).send(sendOptions).on('sent', handler); - promiEvent.on('sent', handler); // Deploy the contract await promiEvent; @@ -133,9 +136,11 @@ describe('contract', () => { it('should emit the "receipt" event', async () => { const handler = jest.fn(); - const promiEvent = contract.deploy(deployOptions).send(sendOptions); + const promiEvent = contract + .deploy(deployOptions) + .send(sendOptions) + .on('receipt', handler); - promiEvent.on('receipt', handler); // Deploy the contract await promiEvent; diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 8ec43e01274..34c31c857e3 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -28,6 +28,7 @@ import { FormatType, SignedTransactionInfo, ETH_DATA_FORMAT, + Web3BaseWalletAccount, } from 'web3-common'; import { Web3Context } from 'web3-core'; import { @@ -527,14 +528,13 @@ export function sendTransaction< } let transactionHash: HexString; + let wallet: Web3BaseWalletAccount | undefined; - if ( - web3Context.wallet && - transactionFormatted.from && - web3Context.wallet.get(transactionFormatted.from) - ) { - const wallet = web3Context.wallet.get(transactionFormatted.from); + if (web3Context.wallet && transactionFormatted.from) { + wallet = web3Context.wallet.get(transactionFormatted.from); + } + if (wallet) { const signedTransaction = wallet.signTransaction( transactionFormatted as Record, ); @@ -759,7 +759,7 @@ export async function sign( const messageFormatted = format({ eth: 'bytes' }, message, DEFAULT_RETURN_FORMAT); if (web3Context.wallet?.get(addressOrIndex)) { - const wallet = web3Context.wallet.get(addressOrIndex); + const wallet = web3Context.wallet.get(addressOrIndex) as Web3BaseWalletAccount; return wallet.sign(messageFormatted); } diff --git a/packages/web3-eth/src/utils/transaction_builder.ts b/packages/web3-eth/src/utils/transaction_builder.ts index 3fdaa351f39..01d2af6ff4b 100644 --- a/packages/web3-eth/src/utils/transaction_builder.ts +++ b/packages/web3-eth/src/utils/transaction_builder.ts @@ -60,9 +60,15 @@ export const getTransactionFromAttr = ( } if (isNumber(transaction.from)) { if (web3Context.wallet) { - return web3Context.wallet.get( + const account = web3Context.wallet.get( format({ eth: 'uint' }, transaction.from, NUMBER_DATA_FORMAT), - ).address; + ); + + if (!isNullish(account)) { + return account.address; + } + + throw new LocalWalletNotAvailableError(); } throw new LocalWalletNotAvailableError(); } else { diff --git a/packages/web3-eth/test/integration/defaults.test.ts b/packages/web3-eth/test/integration/defaults.test.ts index a570637db00..9462340b2b6 100644 --- a/packages/web3-eth/test/integration/defaults.test.ts +++ b/packages/web3-eth/test/integration/defaults.test.ts @@ -304,14 +304,18 @@ describe('defaults', () => { }); const receiptPromise = new Promise((resolve: Resolve) => { - sentTx.on('receipt', (params: ReceiptInfo) => { + // Tx promise is handled separately + // eslint-disable-next-line no-void + void sentTx.on('receipt', (params: ReceiptInfo) => { expect(params.status).toBe(BigInt(1)); resolve(); }); }); let shouldBe = 2; const confirmationPromise = new Promise((resolve: Resolve) => { - sentTx.on('confirmation', ({ confirmationNumber }) => { + // Tx promise is handled separately + // eslint-disable-next-line no-void + void sentTx.on('confirmation', ({ confirmationNumber }) => { expect(parseInt(String(confirmationNumber), 16)).toBe(shouldBe); shouldBe += 1; if (shouldBe > waitConfirmations) { @@ -319,6 +323,7 @@ describe('defaults', () => { } }); }); + await sentTx; await receiptPromise; await sendFewTxes({ web3Eth: eth, from, to, value, times: waitConfirmations }); await confirmationPromise; diff --git a/packages/web3-eth/test/integration/helper.ts b/packages/web3-eth/test/integration/helper.ts index 4a7e912aecd..0938297c47c 100644 --- a/packages/web3-eth/test/integration/helper.ts +++ b/packages/web3-eth/test/integration/helper.ts @@ -42,7 +42,9 @@ export const sendFewTxes = async ({ res.push( // eslint-disable-next-line no-await-in-loop (await new Promise((resolve: Resolve) => { - tx.on('receipt', (params: ReceiptInfo) => { + // tx promise is handled separately + // eslint-disable-next-line no-void + void tx.on('receipt', (params: ReceiptInfo) => { expect(params.status).toBe(BigInt(1)); resolve(params); }); diff --git a/packages/web3-eth/test/integration/watch_transaction.test.ts b/packages/web3-eth/test/integration/watch_transaction.test.ts index a1387959089..b070dbba908 100644 --- a/packages/web3-eth/test/integration/watch_transaction.test.ts +++ b/packages/web3-eth/test/integration/watch_transaction.test.ts @@ -23,7 +23,6 @@ import { getSystemTestProvider, describeIf, getSystemTestAccounts, - // eslint-disable-next-line import/no-relative-packages } from '../fixtures/system_test_utils'; const waitConfirmations = 5; @@ -68,14 +67,18 @@ describeIf(getSystemTestProvider().startsWith('ws'))('watch subscription transac }); const receiptPromise = new Promise((resolve: Resolve) => { - sentTx.on('receipt', (params: ReceiptInfo) => { + // Tx promise is handled separately + // eslint-disable-next-line no-void + void sentTx.on('receipt', (params: ReceiptInfo) => { expect(params.status).toBe(BigInt(1)); resolve(); }); }); let shouldBe = 2; const confirmationPromise = new Promise((resolve: Resolve) => { - sentTx.on('confirmation', ({ confirmationNumber }) => { + // Tx promise is handled separately + // eslint-disable-next-line no-void + void sentTx.on('confirmation', ({ confirmationNumber }) => { expect(parseInt(String(confirmationNumber), 16)).toBe(shouldBe); shouldBe += 1; if (shouldBe >= waitConfirmations) { @@ -117,7 +120,9 @@ describeIf(getSystemTestProvider().startsWith('http'))('watch polling transactio }); let shouldBe = 2; const confirmationPromise = new Promise((resolve: Resolve) => { - sentTx.on('confirmation', ({ confirmationNumber }) => { + // Tx promise is handled separately + // eslint-disable-next-line no-void + void sentTx.on('confirmation', ({ confirmationNumber }) => { expect(parseInt(String(confirmationNumber), 16)).toBe(shouldBe); shouldBe += 1; if (shouldBe >= waitConfirmations) { @@ -126,12 +131,15 @@ describeIf(getSystemTestProvider().startsWith('http'))('watch polling transactio }); }); await new Promise((resolve: Resolve) => { - sentTx.on('receipt', (params: ReceiptInfo) => { + // Tx promise is handled separately + // eslint-disable-next-line no-void + void sentTx.on('receipt', (params: ReceiptInfo) => { expect(params.status).toBe(BigInt(1)); resolve(); }); }); + await sentTx; await sendFewTxes({ web3Eth, from, to, value, times: waitConfirmations }); await confirmationPromise; }); diff --git a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts index d9ce539c7c3..4acab5dae1b 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts @@ -220,27 +220,26 @@ describe('Web3Eth.sendSignedTransaction', () => { }); it('should listen to the sending event', async () => { - const promiEvent = web3Eth.sendSignedTransaction(signedTransaction.raw); - promiEvent.on('sending', data => { + await web3Eth.sendSignedTransaction(signedTransaction.raw).on('sending', data => { expect(data).toBe(signedTransaction.raw); }); - await promiEvent; + expect.assertions(1); }); it('should listen to the sent event', async () => { - const promiEvent = web3Eth.sendSignedTransaction(signedTransaction.raw); - promiEvent.on('sent', data => { + await web3Eth.sendSignedTransaction(signedTransaction.raw).on('sent', data => { expect(data).toBe(signedTransaction.raw); }); - await promiEvent; + expect.assertions(1); }); it('should listen to the transactionHash event', async () => { - const promiEvent = web3Eth.sendSignedTransaction(signedTransaction.raw); - promiEvent.on('transactionHash', data => { - expect(isHexStrict(data)).toBe(true); - }); - await promiEvent; + await web3Eth + .sendSignedTransaction(signedTransaction.raw) + .on('transactionHash', data => { + expect(isHexStrict(data)).toBe(true); + }); + expect.assertions(1); }); it('should listen to the receipt event', async () => { @@ -253,9 +252,8 @@ describe('Web3Eth.sendSignedTransaction', () => { to: transaction.to, transactionHash: expect.any(String), }; - const promiEvent = web3Eth.sendSignedTransaction(signedTransaction.raw); - promiEvent.on('receipt', data => { + await web3Eth.sendSignedTransaction(signedTransaction.raw).on('receipt', data => { expect(data).toEqual(expect.objectContaining(expectedTransactionReceipt)); // To avoid issue with the `objectContaining` and `cypress` had to add @@ -268,7 +266,7 @@ describe('Web3Eth.sendSignedTransaction', () => { expect(data.status).toBe(BigInt(1)); expect(data.type).toBe(BigInt(0)); }); - await promiEvent; + expect.assertions(8); }); it('should listen to the confirmation event', async () => { @@ -292,17 +290,15 @@ describe('Web3Eth.sendSignedTransaction', () => { }, latestBlockHash: expect.any(String), }; - const promiEvent = web3Eth.sendSignedTransaction(signedTransaction.raw); - promiEvent.on('confirmation', data => { + await web3Eth.sendSignedTransaction(signedTransaction.raw).on('confirmation', data => { expect(data).toEqual(expect.objectContaining(expectedTransactionConfirmation)); }); // TODO Confirmations are dependent on the next block being mined, // this is manually triggering the next block to be created since both // Geth and Ganache wait for transaction before mining a block. - // This should be revisted to implement a better solution - await promiEvent; + // This should be revisited to implement a better solution await web3Eth.sendTransaction({ from: accounts[0], to: '0x0000000000000000000000000000000000000000', @@ -310,6 +306,9 @@ describe('Web3Eth.sendSignedTransaction', () => { type: '0x0', gas: '0x5208', }); + + // TODO: Debug why the assertions are not being called + // expect.assertions(1); }); }); }); diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 3a0c4ae52e6..be0518cd198 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -212,27 +212,24 @@ describe('Web3Eth.sendTransaction', () => { }); it('should listen to the sending event', async () => { - const promiEvent = web3Eth.sendTransaction(transaction); - promiEvent.on('sending', data => { + await web3Eth.sendTransaction(transaction).on('sending', data => { expect(data).toMatchObject(transaction); }); - await promiEvent; + expect.assertions(1); }); it('should listen to the sent event', async () => { - const promiEvent = web3Eth.sendTransaction(transaction); - promiEvent.on('sent', data => { + await web3Eth.sendTransaction(transaction).on('sent', data => { expect(data).toMatchObject(transaction); }); - await promiEvent; + expect.assertions(1); }); it('should listen to the transactionHash event', async () => { - const promiEvent = web3Eth.sendTransaction(transaction); - promiEvent.on('transactionHash', data => { + await web3Eth.sendTransaction(transaction).on('transactionHash', data => { expect(isHexStrict(data)).toBe(true); }); - await promiEvent; + expect.assertions(1); }); it('should listen to the receipt event', async () => { @@ -245,8 +242,7 @@ describe('Web3Eth.sendTransaction', () => { to: transaction.to, transactionHash: expect.any(String), }; - const promiEvent = web3Eth.sendTransaction(transaction); - promiEvent.on('receipt', data => { + await web3Eth.sendTransaction(transaction).on('receipt', data => { expect(data).toEqual(expect.objectContaining(expectedTransactionReceipt)); // To avoid issue with the `objectContaining` and `cypress` had to add @@ -259,7 +255,7 @@ describe('Web3Eth.sendTransaction', () => { expect(data.status).toBe(BigInt(1)); expect(data.type).toBe(BigInt(0)); }); - await promiEvent; + expect.assertions(8); }); it('should listen to the confirmation event', async () => { @@ -283,9 +279,8 @@ describe('Web3Eth.sendTransaction', () => { }, latestBlockHash: expect.any(String), }; - const promiEvent = web3Eth.sendTransaction(transaction); - promiEvent.on('confirmation', data => { + await web3Eth.sendTransaction(transaction).on('confirmation', data => { expect(data).toEqual(expect.objectContaining(expectedTransactionConfirmation)); }); @@ -293,8 +288,10 @@ describe('Web3Eth.sendTransaction', () => { // this is manually triggering the next block to be created since both // Geth and Ganache wait for transaction before mining a block. // This should be revisted to implement a better solution - await promiEvent; await web3Eth.sendTransaction(transaction); + + // TODO: Debug why the assertions are not being called + // expect.assertions(1); }); }); }); diff --git a/packages/web3-eth/test/unit/rpc_method_wrappers/send_signed_transaction.test.ts b/packages/web3-eth/test/unit/rpc_method_wrappers/send_signed_transaction.test.ts index a086aac64fe..27ebbfece19 100644 --- a/packages/web3-eth/test/unit/rpc_method_wrappers/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/unit/rpc_method_wrappers/send_signed_transaction.test.ts @@ -48,26 +48,24 @@ describe('sendTransaction', () => { it.each(testData)( `sending event should emit with inputSignedTransaction\n ${testMessage}`, async (_, inputSignedTransaction) => { - return new Promise(done => { - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( - expectedReceiptInfo, - ); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( + expectedReceiptInfo, + ); - const inputSignedTransactionFormatted = format( - { eth: 'bytes' }, - inputSignedTransaction, - DEFAULT_RETURN_FORMAT, - ); - const promiEvent = sendSignedTransaction( - web3Context, - inputSignedTransaction, - DEFAULT_RETURN_FORMAT, - ); - promiEvent.on('sending', signedTransaction => { - expect(signedTransaction).toStrictEqual(inputSignedTransactionFormatted); - done(undefined); - }); + const inputSignedTransactionFormatted = format( + { eth: 'bytes' }, + inputSignedTransaction, + DEFAULT_RETURN_FORMAT, + ); + await sendSignedTransaction( + web3Context, + inputSignedTransaction, + DEFAULT_RETURN_FORMAT, + ).on('sending', signedTransaction => { + expect(signedTransaction).toStrictEqual(inputSignedTransactionFormatted); }); + + expect.assertions(1); }, ); @@ -94,51 +92,48 @@ describe('sendTransaction', () => { it.each(testData)( `sent event should emit with inputSignedTransaction\n ${testMessage}`, async (_, inputSignedTransaction) => { - return new Promise(done => { - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( - expectedReceiptInfo, - ); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( + expectedReceiptInfo, + ); - const inputSignedTransactionFormatted = format( - { eth: 'bytes' }, - inputSignedTransaction, - DEFAULT_RETURN_FORMAT, - ); - const promiEvent = sendSignedTransaction( - web3Context, - inputSignedTransaction, - DEFAULT_RETURN_FORMAT, - ); - promiEvent.on('sent', signedTransaction => { - expect(signedTransaction).toStrictEqual(inputSignedTransactionFormatted); - done(undefined); - }); + const inputSignedTransactionFormatted = format( + { eth: 'bytes' }, + inputSignedTransaction, + DEFAULT_RETURN_FORMAT, + ); + + await sendSignedTransaction( + web3Context, + inputSignedTransaction, + DEFAULT_RETURN_FORMAT, + ).on('sent', signedTransaction => { + expect(signedTransaction).toStrictEqual(inputSignedTransactionFormatted); }); + + expect.assertions(1); }, ); it.each(testData)( `transactionHash event should emit with inputSignedTransaction\n ${testMessage}`, async (_, inputSignedTransaction) => { - return new Promise(done => { - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( - expectedReceiptInfo, - ); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( + expectedReceiptInfo, + ); - (rpcMethods.sendRawTransaction as jest.Mock).mockResolvedValueOnce( - expectedTransactionHash, - ); + (rpcMethods.sendRawTransaction as jest.Mock).mockResolvedValueOnce( + expectedTransactionHash, + ); - const promiEvent = sendSignedTransaction( - web3Context, - inputSignedTransaction, - DEFAULT_RETURN_FORMAT, - ); - promiEvent.on('transactionHash', transactionHash => { - expect(transactionHash).toStrictEqual(expectedTransactionHash); - done(undefined); - }); + await sendSignedTransaction( + web3Context, + inputSignedTransaction, + DEFAULT_RETURN_FORMAT, + ).on('transactionHash', transactionHash => { + expect(transactionHash).toStrictEqual(expectedTransactionHash); }); + + expect.assertions(1); }, ); @@ -192,27 +187,25 @@ describe('sendTransaction', () => { it.each(testData)( `receipt event should emit with inputSignedTransaction\n ${testMessage}`, async (_, inputSignedTransaction) => { - return new Promise(done => { - const formattedReceiptInfo = format( - receiptInfoSchema, - expectedReceiptInfo, - DEFAULT_RETURN_FORMAT, - ); + const formattedReceiptInfo = format( + receiptInfoSchema, + expectedReceiptInfo, + DEFAULT_RETURN_FORMAT, + ); - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( - expectedReceiptInfo, - ); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( + expectedReceiptInfo, + ); - const promiEvent = sendSignedTransaction( - web3Context, - inputSignedTransaction, - DEFAULT_RETURN_FORMAT, - ); - promiEvent.on('receipt', receiptInfo => { - expect(receiptInfo).toStrictEqual(formattedReceiptInfo); - done(undefined); - }); + await sendSignedTransaction( + web3Context, + inputSignedTransaction, + DEFAULT_RETURN_FORMAT, + ).on('receipt', receiptInfo => { + expect(receiptInfo).toStrictEqual(formattedReceiptInfo); }); + + expect.assertions(1); }, ); @@ -262,8 +255,8 @@ describe('sendTransaction', () => { web3Context, inputTransaction, DEFAULT_RETURN_FORMAT, - ); - promiEvent.on('confirmation', () => undefined); + ).on('confirmation', () => undefined); + await promiEvent; expect(rpcMethods.getTransactionReceipt).toHaveBeenCalledWith( diff --git a/packages/web3-eth/test/unit/rpc_method_wrappers/send_transaction.test.ts b/packages/web3-eth/test/unit/rpc_method_wrappers/send_transaction.test.ts index ef3da43bd5f..6af254e064c 100644 --- a/packages/web3-eth/test/unit/rpc_method_wrappers/send_transaction.test.ts +++ b/packages/web3-eth/test/unit/rpc_method_wrappers/send_transaction.test.ts @@ -79,22 +79,18 @@ describe('sendTransaction', () => { it.each(testData)( `sending event should emit with formattedTransaction\n ${testMessage}`, async (_, inputTransaction, sendTransactionOptions) => { - return new Promise(done => { - const formattedTransaction = formatTransaction(inputTransaction, ETH_DATA_FORMAT); - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValue( - expectedReceiptInfo, - ); - const promiEvent = sendTransaction( - web3Context, - inputTransaction, - DEFAULT_RETURN_FORMAT, - sendTransactionOptions, - ); - promiEvent.on('sending', transaction => { - expect(transaction).toStrictEqual(formattedTransaction); - done(undefined); - }); + const formattedTransaction = formatTransaction(inputTransaction, ETH_DATA_FORMAT); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValue(expectedReceiptInfo); + await sendTransaction( + web3Context, + inputTransaction, + DEFAULT_RETURN_FORMAT, + sendTransactionOptions, + ).on('sending', transaction => { + expect(transaction).toStrictEqual(formattedTransaction); }); + + expect.assertions(1); }, ); @@ -119,47 +115,40 @@ describe('sendTransaction', () => { it.each(testData)( `sent event should emit with formattedTransaction\n ${testMessage}`, async (_, inputTransaction, sendTransactionOptions) => { - return new Promise(done => { - const formattedTransaction = formatTransaction(inputTransaction, ETH_DATA_FORMAT); - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValue( - expectedReceiptInfo, - ); - const promiEvent = sendTransaction( - web3Context, - inputTransaction, - DEFAULT_RETURN_FORMAT, - sendTransactionOptions, - ); - promiEvent.on('sent', transaction => { - expect(transaction).toStrictEqual(formattedTransaction); - done(undefined); - }); + const formattedTransaction = formatTransaction(inputTransaction, ETH_DATA_FORMAT); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValue(expectedReceiptInfo); + + await sendTransaction( + web3Context, + inputTransaction, + DEFAULT_RETURN_FORMAT, + sendTransactionOptions, + ).on('sent', transaction => { + expect(transaction).toStrictEqual(formattedTransaction); }); + + expect.assertions(1); }, ); it.each(testData)( `transactionHash event should emit with expectedTransactionHash\n ${testMessage}`, async (_, inputTransaction, sendTransactionOptions) => { - return new Promise(done => { - (rpcMethods.sendTransaction as jest.Mock).mockResolvedValueOnce( - expectedTransactionHash, - ); - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValue( - expectedReceiptInfo, - ); - - const promiEvent = sendTransaction( - web3Context, - inputTransaction, - DEFAULT_RETURN_FORMAT, - sendTransactionOptions, - ); - promiEvent.on('transactionHash', transactionHash => { - expect(transactionHash).toStrictEqual(expectedTransactionHash); - done(undefined); - }); + (rpcMethods.sendTransaction as jest.Mock).mockResolvedValueOnce( + expectedTransactionHash, + ); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValue(expectedReceiptInfo); + + await sendTransaction( + web3Context, + inputTransaction, + DEFAULT_RETURN_FORMAT, + sendTransactionOptions, + ).on('transactionHash', transactionHash => { + expect(transactionHash).toStrictEqual(expectedTransactionHash); }); + + expect.assertions(1); }, ); @@ -220,26 +209,25 @@ describe('sendTransaction', () => { it.each(testData)( `receipt event should emit with expectedReceiptInfo\n ${testMessage}`, async (_, inputTransaction, sendTransactionOptions) => { - return new Promise(done => { - const formattedReceiptInfo = format( - receiptInfoSchema, - expectedReceiptInfo, - DEFAULT_RETURN_FORMAT, - ); - (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( - formattedReceiptInfo, - ); - const promiEvent = sendTransaction( - web3Context, - inputTransaction, - DEFAULT_RETURN_FORMAT, - sendTransactionOptions, - ); - promiEvent.on('receipt', receiptInfo => { - expect(receiptInfo).toStrictEqual(formattedReceiptInfo); - done(undefined); - }); + const formattedReceiptInfo = format( + receiptInfoSchema, + expectedReceiptInfo, + DEFAULT_RETURN_FORMAT, + ); + (rpcMethods.getTransactionReceipt as jest.Mock).mockResolvedValueOnce( + formattedReceiptInfo, + ); + + await sendTransaction( + web3Context, + inputTransaction, + DEFAULT_RETURN_FORMAT, + sendTransactionOptions, + ).on('receipt', receiptInfo => { + expect(receiptInfo).toStrictEqual(formattedReceiptInfo); }); + + expect.assertions(1); }, ); @@ -290,8 +278,8 @@ describe('sendTransaction', () => { inputTransaction, DEFAULT_RETURN_FORMAT, sendTransactionOptions, - ); - promiEvent.on('confirmation', () => undefined); + ).on('confirmation', () => undefined); + await promiEvent; expect(rpcMethods.getTransactionReceipt).toHaveBeenCalledWith(