Skip to content
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(script): Assert state changes for script tests #79

Merged
merged 45 commits into from
Mar 11, 2025

Conversation

benceharomi
Copy link
Contributor

Summary

I focused on improving the tests, but also cleaned up and organised some of the scripts to make them easier to follow.
This PR resolves #65

Approach

Not all scripts store their deployed contract addresses in public variables, so I assumed those addresses weren’t accessible. To handle address checks, I added two functions:

  1. A function to calculate the expected address of a contract using the deployer, salt, bytecode, and constructor arguments.
  2. A function to check if a contract is deployed at a specific address.

For each test, I followed these steps:

  1. Calculate the expected address of the contract to be deployed.
  2. Check that no contract exists at this address.
  3. Run the deployment script.
  4. Check the same address again to confirm the contract was deployed.

Each test goes through all possible branches in the script and each test case covers the deployment of one contract. I also changed the scripts so they start by loading the required env vars, if an env var is missing, the script will fail right away, before starting deployments.

The test process for each script includes:

  • Testing all the scenarios where the script should revert (e.g., missing env vars).
  • Testing all possible branches of execution, one test case for each.

For the calldata computation scripts, the success tests basically replicate the implementation logic, but they’re useful to confirm everything works as expected, especially if the code is refactored in the future.

To reduce repeated code, I moved common test cases into the base file so they can be reused. This makes the test files cleaner and easier to read.

This approach helped me achieve 100% code and branch coverage for all tested scripts.
image

ENV issues

I ran into some strange behaviour with how Foundry handles environment variables. I found a closed GitHub issue explaining this problem. The issue is that if env vars are set in both setUp and the test cases, Foundry doesn’t reload them before every test, even though setUp runs before each test. For example, if one test clears an env var set in setUp, the next test might see it as empty. Since Foundry runs tests in non-deterministic order, this causes unexpected results.

To fix this, I created a separate function that can be used to set env vars at the start of each test case. This ensures that the right env vars are always set before the tests run.

Findings

There is a lot of repeated code in the scripts, as shown by the number of reused test cases. This duplication could be reduced by either:

  • Merging similar scripts and using branching logic with params (e.g., the AccountHiding scripts, which are 99% identical to the non-hiding versions).
  • Moving shared functions into a helper contract or library.

I also noticed that some deployment scripts use a hardcoded salt value of 0. If this wasn’t intentional, it might need to be addressed. (DeployEmailRecoveryModule, DeploySafeRecoveryWithAccountHiding, DeployUniversalEmailRecoveryModule)

Copy link

test(script): Assert state changes for script tests

Generated at commit: affc9dedff40f71927f866b456db860c2ce134d8

🚨 Report Summary

Severity Level Results
Contracts Critical
High
Medium
Low
Note
Total
0
0
0
4
17
21
Dependencies Critical
High
Medium
Low
Note
Total
0
0
0
0
0
0

For more details view the full report in OpenZeppelin Code Inspector

Copy link
Collaborator

@JohnGuilding JohnGuilding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good few additional points:

  1. Some of my script tests are failing locally with a mix of errors related to env vars. The errors vary each time (occasionally they all pass). I wonder if my env vars are not getting set up correctly somehow. Are your tests passing locally?
  2. Could you implement this point you raised:

Merging similar scripts and using branching logic with params (e.g., the AccountHiding scripts, which are 99% identical to the non-hiding versions).

  1. Could you also replace any hardcoded salts with env values as well?

@JohnGuilding
Copy link
Collaborator

@benceharomi solved on my end I was accidently running forge test instead of pnpm test:script

@JohnGuilding
Copy link
Collaborator

Latest changes look good. Only task left is regarding "Merging similar scripts and using branching logic with params". let me know if any issues

@benceharomi
Copy link
Contributor Author

@JohnGuilding it's ready for review

@JohnGuilding JohnGuilding merged commit d0f0fd6 into zkemail:main Mar 11, 2025
3 checks passed
@benceharomi benceharomi deleted the script-tests branch March 20, 2025 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Assert state changes for script tests
2 participants