-
-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🧪 Test: Add more test coverage to actions #1466
Changes from 5 commits
ea1a139
fa87a5e
efb8b71
b14c990
bb288ba
cb6cad5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { createAddress } from '@tevm/address' | ||
import { createTevmNode } from '@tevm/node' | ||
import { numberToHex, parseEther } from '@tevm/utils' | ||
import { describe, expect, it } from 'vitest' | ||
import { debugTraceCallJsonRpcProcedure } from './debugTraceCallProcedure.js' | ||
|
||
// TODO this test kinda sucks because it isn't tracing anything but since the logic is mostly in callHandler which is tested it's fine for now | ||
|
||
describe('debugTraceCallJsonRpcProcedure', () => { | ||
it('should trace a call and return the expected result', async () => { | ||
const client = createTevmNode() | ||
const procedure = debugTraceCallJsonRpcProcedure(client) | ||
|
||
const result = await procedure({ | ||
jsonrpc: '2.0', | ||
method: 'debug_traceCall', | ||
params: [ | ||
{ | ||
to: createAddress('0x1234567890123456789012345678901234567890').toString(), | ||
data: '0x60806040', | ||
value: numberToHex(parseEther('1')), | ||
tracer: 'callTracer', | ||
}, | ||
], | ||
id: 1, | ||
}) | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
{ | ||
"id": 1, | ||
"jsonrpc": "2.0", | ||
"method": "debug_traceCall", | ||
"result": { | ||
"failed": false, | ||
"gas": "0x0", | ||
"returnValue": "0x", | ||
"structLogs": [], | ||
}, | ||
} | ||
`) | ||
}) | ||
Comment on lines
+28
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding explicit assertions alongside the snapshot. While the inline snapshot is useful for capturing the overall structure of the response, it might be beneficial to add explicit assertions for critical values. This would make the test's intentions clearer and easier to maintain. Consider adding explicit assertions before the snapshot, like this: expect(result.result.failed).toBe(false)
expect(result.result.gas).toBe('0x0')
expect(result.result.returnValue).toBe('0x')
expect(result.result.structLogs).toEqual([])
// Keep the existing snapshot for overall structure
expect(result).toMatchInlineSnapshot(/* ... */) This approach combines the benefits of snapshot testing with clear, specific assertions. |
||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { createAddress } from '@tevm/address' | ||
import { SimpleContract } from '@tevm/contract' | ||
import { createTevmNode } from '@tevm/node' | ||
import { describe, expect, it } from 'vitest' | ||
import { callHandler } from '../Call/callHandler.js' | ||
import { deployHandler } from '../Deploy/deployHandler.js' | ||
import { debugTraceTransactionJsonRpcProcedure } from './debugTraceTransactionProcedure.js' | ||
|
||
describe('debugTraceTransactionJsonRpcProcedure', () => { | ||
it('should trace a transaction and return the expected result', async () => { | ||
const client = createTevmNode({ miningConfig: { type: 'auto' } }) | ||
const procedure = debugTraceTransactionJsonRpcProcedure(client) | ||
|
||
const contract = SimpleContract.withAddress(createAddress(420).toString()) | ||
|
||
await deployHandler(client)(contract.deploy(1n)) | ||
|
||
const sendTxResult = await callHandler(client)({ | ||
createTransaction: true, | ||
...contract.write.set(69n), | ||
}) | ||
|
||
if (!sendTxResult.txHash) { | ||
throw new Error('Transaction failed') | ||
} | ||
|
||
const result = await procedure({ | ||
jsonrpc: '2.0', | ||
method: 'debug_traceTransaction', | ||
params: [ | ||
{ | ||
transactionHash: sendTxResult.txHash, | ||
tracer: 'callTracer', | ||
}, | ||
], | ||
id: 1, | ||
}) | ||
|
||
expect(result).toMatchInlineSnapshot(` | ||
{ | ||
"id": 1, | ||
"jsonrpc": "2.0", | ||
"method": "debug_traceTransaction", | ||
"result": { | ||
"failed": false, | ||
"gas": "0x0", | ||
"returnValue": "0x", | ||
"structLogs": [], | ||
}, | ||
} | ||
`) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
import { createAddress } from '@tevm/address' | ||
import { createTevmNode } from '@tevm/node' | ||
import { SimpleContract } from '@tevm/test-utils' | ||
import { SimpleContract, transports } from '@tevm/test-utils' | ||
import { | ||
type Address, | ||
type Hex, | ||
PREFUNDED_ACCOUNTS, | ||
encodeDeployData, | ||
encodeFunctionData, | ||
hexToBytes, | ||
hexToNumber, | ||
keccak256, | ||
stringToHex, | ||
} from '@tevm/utils' | ||
|
@@ -33,7 +34,7 @@ describe(ethGetLogsHandler.name, () => { | |
}) | ||
} | ||
|
||
it.todo('should return logs for a given block range', async () => { | ||
it('should return logs for a given block range', async () => { | ||
const client = createTevmNode() | ||
const from = createAddress(PREFUNDED_ACCOUNTS[0].address) | ||
|
||
|
@@ -49,19 +50,26 @@ describe(ethGetLogsHandler.name, () => { | |
}) | ||
|
||
const contractAddress = deployResult.createdAddress as Address | ||
expect(deployResult.createdAddresses?.size).toBe(1) | ||
await mineHandler(client)() | ||
|
||
// Emit some events | ||
for (let i = 0; i < 3; i++) { | ||
await callHandler(client)({ | ||
const res = await callHandler(client)({ | ||
to: contractAddress, | ||
from: from.toString(), | ||
data: encodeFunctionData(SimpleContract.write.set(BigInt(i))), | ||
createTransaction: true, | ||
}) | ||
expect(res.logs).toHaveLength(1) | ||
await mineHandler(client)() | ||
const { rawData: newValue } = await callHandler(client)({ | ||
to: contractAddress, | ||
data: encodeFunctionData(SimpleContract.read.get()), | ||
}) | ||
expect(hexToNumber(newValue)).toBe(i) | ||
} | ||
|
||
await mineHandler(client)() | ||
|
||
const filterParams: FilterParams = { | ||
address: contractAddress, | ||
fromBlock: 0n, | ||
|
@@ -75,13 +83,14 @@ describe(ethGetLogsHandler.name, () => { | |
|
||
expect(logs).toHaveLength(3) | ||
expect(logs[0]).toMatchObject({ | ||
address: contractAddress, | ||
// this is actually a bug | ||
address: createAddress(contractAddress).toString().toLowerCase(), | ||
Comment on lines
+84
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Address Normalization Issue The comment on line 86 indicates there's a bug related to address formatting. In the assertion on line 87, the address is converted to lowercase using Recommendation: Ethereum addresses are case-insensitive but can be checksummed for error detection. Instead of converting to lowercase, consider using a standard method for address normalization or validation, such as EIP-55 checksumming. expect(logs[0]).toMatchObject({
- address: createAddress(contractAddress).toString().toLowerCase(),
+ address: createAddress(contractAddress).toString(),
blockNumber: expect.any(BigInt),
transactionHash: expect.any(String),
}) If the logged address is in lowercase, ensure that the comparison accounts for the address format used by the logging system.
|
||
blockNumber: expect.any(BigInt), | ||
transactionHash: expect.any(String), | ||
}) | ||
}) | ||
|
||
it.todo('should filter logs by topics', async () => { | ||
it('should filter logs by topics', async () => { | ||
const client = createTevmNode() | ||
const from = createAddress(PREFUNDED_ACCOUNTS[0].address) | ||
|
||
|
@@ -96,6 +105,9 @@ describe(ethGetLogsHandler.name, () => { | |
|
||
const contractAddress = deployResult.createdAddress as Address | ||
|
||
// Mine the deployment transaction | ||
await mineHandler(client)() | ||
|
||
// Set values to emit events | ||
await callHandler(client)({ | ||
to: contractAddress, | ||
|
@@ -129,7 +141,7 @@ describe(ethGetLogsHandler.name, () => { | |
expect(logs[1]).toBeTruthy() | ||
}) | ||
|
||
it.todo('should handle pending blocks', async () => { | ||
it('should handle pending blocks', async () => { | ||
const client = createTevmNode() | ||
const from = createAddress(PREFUNDED_ACCOUNTS[0].address) | ||
|
||
|
@@ -144,6 +156,9 @@ describe(ethGetLogsHandler.name, () => { | |
|
||
const contractAddress = deployResult.createdAddress as Address | ||
|
||
// Mine the deployment transaction | ||
await mineHandler(client)() | ||
|
||
// Emit an event without mining | ||
await callHandler(client)({ | ||
to: contractAddress, | ||
|
@@ -164,10 +179,10 @@ describe(ethGetLogsHandler.name, () => { | |
}) | ||
|
||
expect(logs).toHaveLength(1) | ||
expect(logs[0]?.blockNumber).toBe('pending') | ||
expect(logs[0]?.blockNumber).toBe(2n) | ||
}) | ||
|
||
it.todo('should return all logs when no topics are specified', async () => { | ||
it('should return all logs when no topics are specified', async () => { | ||
const client = createTevmNode() | ||
const from = createAddress('0x1234567890123456789012345678901234567890') | ||
|
||
|
@@ -184,6 +199,9 @@ describe(ethGetLogsHandler.name, () => { | |
|
||
const contractAddress = deployResult.createdAddress as Address | ||
|
||
// Mine the deployment transaction | ||
await mineHandler(client)() | ||
|
||
// Emit some events | ||
for (let i = 0; i < 3; i++) { | ||
await callHandler(client)({ | ||
|
@@ -194,23 +212,15 @@ describe(ethGetLogsHandler.name, () => { | |
}) | ||
} | ||
|
||
const res = await mineHandler(client)() | ||
|
||
const block = await client.getVm().then((vm) => vm.blockchain.getBlock(hexToBytes(res.blockHashes?.[0] as Hex))) | ||
|
||
const receiptManager = await client.getReceiptsManager() | ||
block.transactions.forEach(async (tx) => { | ||
const [receipt] = (await receiptManager.getReceiptByTxHash(tx.hash())) ?? [] | ||
console.log(receipt?.logs) | ||
}) | ||
await mineHandler(client)() | ||
|
||
const logs = await ethGetLogsHandler(client)({ | ||
filterParams: {}, | ||
}) | ||
|
||
expect(logs).toHaveLength(3) | ||
expect(logs[0]).toMatchObject({ | ||
address: contractAddress, | ||
address: contractAddress.toLowerCase(), | ||
blockNumber: expect.any(BigInt), | ||
transactionHash: expect.any(String), | ||
}) | ||
|
@@ -220,5 +230,44 @@ describe(ethGetLogsHandler.name, () => { | |
}) | ||
}) | ||
|
||
it.todo('should work fetching logs that were created by tevm after forking') | ||
it('should work for past blocks in forked mode', async () => { | ||
const client = createTevmNode({ | ||
fork: { | ||
transport: transports.optimism, | ||
blockTag: 125985200n, | ||
}, | ||
}) | ||
const logs = await ethGetLogsHandler(client)({ | ||
filterParams: { | ||
address: '0xdC6fF44d5d932Cbd77B52E5612Ba0529DC6226F1', | ||
fromBlock: 125985142n, | ||
toBlock: 125985142n, | ||
topics: [ | ||
'0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925', | ||
'0x0000000000000000000000007f26A7572E8B877654eeDcBc4E573657619FA3CE', | ||
'0x0000000000000000000000007B46fFbC976db2F94C3B3CDD9EbBe4ab50E3d77d', | ||
], | ||
}, | ||
}) | ||
expect(logs).toHaveLength(1) | ||
expect(logs).toMatchInlineSnapshot(` | ||
[ | ||
{ | ||
"address": "0xdc6ff44d5d932cbd77b52e5612ba0529dc6226f1", | ||
"blockHash": "0x6c9355482a6937e44fbfbd1c0c9cc95882e47e80c9b48772699c6a49bad1e392", | ||
"blockNumber": 125985142n, | ||
"data": "0x0000000000000000000000000000000000000000000b2f1069a1f95dc7180000", | ||
"logIndex": 23n, | ||
"removed": false, | ||
"topics": [ | ||
"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", | ||
"0x0000000000000000000000007f26a7572e8b877654eedcbc4e573657619fa3ce", | ||
"0x0000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d", | ||
], | ||
"transactionHash": "0x4f0781ec417fecaf44b248fd0b0485dca9fbe78ad836598b65c12bb13ab9ddd4", | ||
"transactionIndex": 11n, | ||
}, | ||
] | ||
`) | ||
Comment on lines
+231
to
+269
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance Test Robustness for Forked Mode The test uses hardcoded block numbers and addresses specific to the forked network. Suggestion: To improve the test's robustness and maintainability:
const FORK_BLOCK_NUMBER = 125985200n
const TEST_BLOCK_NUMBER = 125985142n
const TEST_ADDRESS = '0xdC6fF44d5d932Cbd77B52E5612Ba0529DC6226F1'
const client = createTevmNode({
fork: {
transport: transports.optimism,
blockTag: FORK_BLOCK_NUMBER,
},
})
const logs = await ethGetLogsHandler(client)({
filterParams: {
address: TEST_ADDRESS,
fromBlock: TEST_BLOCK_NUMBER,
toBlock: TEST_BLOCK_NUMBER,
topics: [...],
},
})
expect(logs).not.toHaveLength(0)
expect(logs[0]?.blockNumber).toBe(TEST_BLOCK_NUMBER) This approach enhances clarity and eases future updates. |
||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Address the TODO comment to improve test quality.
The TODO comment indicates that the current test might not be comprehensive enough. Consider enhancing the test to cover more scenarios or to trace actual operations.
As a follow-up, could you provide more context on why the current test "kinda sucks"? This information would be helpful in determining how to improve the test coverage.