diff --git a/docs/blockchain-development-tutorials/cadence/fork-testing/index.md b/docs/blockchain-development-tutorials/cadence/fork-testing/index.md index d84123336c..277f97855a 100644 --- a/docs/blockchain-development-tutorials/cadence/fork-testing/index.md +++ b/docs/blockchain-development-tutorials/cadence/fork-testing/index.md @@ -2,10 +2,11 @@ sidebar_position: 20 sidebar_label: Fork Testing title: Fork Testing with Cadence -description: Run your Cadence test suite against a forked mainnet or testnet using flow test --fork. Test against real contracts and production data without deploying to live networks. +description: Run your Cadence test suite against a forked mainnet or testnet using fork testing. Test against real contracts and production data without deploying to live networks. keywords: - fork testing - - flow test --fork + - test_fork pragma + - flow test - cadence tests - mainnet fork - testnet fork @@ -16,7 +17,6 @@ keywords: - real contracts - on-chain state - block height - - fork-height - historical debugging - reproducible tests - test deployment @@ -31,7 +31,7 @@ keywords: # Fork testing with Cadence -This tutorial teaches you how to run your Cadence tests against a snapshot of Flow mainnet using `flow test --fork`. You'll learn how to test your contracts against real deployed contracts and production data without needing to deploy anything to a live network or bootstrap test accounts. +This tutorial teaches you how to run your Cadence tests against a snapshot of Flow mainnet using `flow test` with the `#test_fork` pragma. You'll learn how to test your contracts against real deployed contracts and production data without needing to deploy anything to a live network or bootstrap test accounts. Fork testing bridges the gap between isolated local unit tests and testnet deployments. It allows you to validate your contracts work correctly with real on-chain state, test integrations with deployed contracts, and debug issues with historical blockchain data—all in a safe, local environment. @@ -39,7 +39,7 @@ Fork testing bridges the gap between isolated local unit tests and testnet deplo After you complete this tutorial, you'll be able to: -- **Run Cadence tests against forked networks** with `flow test --fork`. +- **Run Cadence tests against forked networks** with `#test_fork`. - **Test contracts that depend on real mainnet contracts** without manual setup. - **Use account impersonation** to execute transactions as any mainnet account. - **Read from production blockchain state** in your test suite. @@ -56,16 +56,6 @@ You'll create a complete fork testing setup that demonstrates: - Executing transactions using impersonated mainnet accounts. - A reusable pattern for integration testing your Flow applications. -### Reproducibility first - -Pin a specific block height when you need reproducible results: - -```zsh -flow test --fork mainnet --fork-height -``` - -Document the pin heights you rely on (for example, in CI variables or a simple file in the repo) and update them via a dedicated freshness PR. For best results, keep a per‑spork stable pin and also run a "latest" freshness job. - ## Prerequisites ### Flow CLI @@ -91,7 +81,7 @@ You'll need network access to Flow's public access nodes. The tutorial uses thes :::info -This tutorial covers `flow test --fork` (running tests against forked network state), which is different from `flow emulator --fork` (starting the emulator in fork mode for manual interaction). +This tutorial covers fork testing with `flow test` (running tests against forked network state), which is different from `flow emulator --fork` (starting the emulator in fork mode for manual interaction). ::: @@ -170,6 +160,8 @@ flow generate test FlowToken Open `cadence/tests/FlowToken_test.cdc` and replace its contents with: ```cadence cadence/tests/FlowToken_test.cdc +#test_fork(network: "mainnet", height: nil) + import Test access(all) fun testFlowTokenSupplyIsPositive() { @@ -187,29 +179,30 @@ access(all) fun testFlowTokenSupplyIsPositive() { :::info +- **The `#test_fork` pragma** at the top configures this test to run against mainnet - Use `Test.executeScript()` to read contract state -- The script imports `FlowToken` by name - the dependency manager handles address resolution. -- In fork mode, this automatically uses the mainnet FlowToken contract. -- Extract the return value with proper type casting and assert on it. -- File paths in `Test.readFile()` are relative to the test file location (use `../scripts/` from `cadence/tests/`). +- The script imports `FlowToken` by name - the dependency manager handles address resolution +- In fork mode, this automatically uses the mainnet FlowToken contract +- Extract the return value with proper type casting and assert on it +- File paths in `Test.readFile()` are relative to the test file location (use `../scripts/` from `cadence/tests/`) ::: #### Quick verify -Run just this test file against a fork to confirm your setup works: +Run just this test file to confirm your setup works: ```zsh -flow test cadence/tests/FlowToken_test.cdc --fork mainnet +flow test cadence/tests/FlowToken_test.cdc ``` -Target testnet instead: +The pragma handles the fork configuration automatically! You will see the test PASS. If not, verify your network host in `flow.json` and that dependencies are installed. -```zsh -flow test cadence/tests/FlowToken_test.cdc --fork testnet -``` +**To test against testnet instead**, simply change the pragma in the test file: -You will see the test PASS. If not, verify your network host in `flow.json` and that dependencies are installed. +```cadence +#test_fork(network: "testnet", height: nil) +``` ## Deploy and Test Your Contract @@ -224,6 +217,7 @@ flow accounts create ``` Follow the prompts: + - Select "mainnet" for the network. - Name your account as desired. @@ -292,9 +286,9 @@ Update your `flow.json` to include the contract with aliases, and use the addres :::info - No local private key is required for forked tests. The accounts entry above is included so you can copy and reference the address in your config. You can also omit keys for fork tests. Contracts deploy to the testing environment at `testing` alias, and transactions that interact with forked state can use impersonation. The `Test.deployContract` function will automatically deploy your contract to the testing environment during test execution. +No local private key is required for forked tests. The accounts entry above is included so you can copy and reference the address in your config. You can also omit keys for fork tests. Contracts deploy to the testing environment at `testing` alias, and transactions that interact with forked state can use impersonation. The `Test.deployContract` function will automatically deploy your contract to the testing environment during test execution. - ::: +::: ### Create scripts for testing @@ -336,6 +330,8 @@ flow generate test TokenChecker Open `cadence/tests/TokenChecker_test.cdc` and replace its contents with: ```cadence cadence/tests/TokenChecker_test.cdc +#test_fork(network: "mainnet", height: nil) + import Test access(all) fun setup() { @@ -377,10 +373,11 @@ access(all) fun testHasMinimumBalance() { ### What's happening here -1. **Your contract uses FlowToken**: `TokenChecker` imports and interacts with the real FlowToken contract. -2. **No bootstrapping needed**: When you run with `--fork`, real mainnet accounts (like `0x1654653399040a61`, the Flow service account) already have balances. -3. **Test against real state**: You can query actual accounts and verify your contract logic works with production data. -4. **Local deployment**: Your `TokenChecker` contract is deployed locally to the test environment, but it reads from forked mainnet state. +1. **The `#test_fork` pragma configures the test**: At the top of the file, the pragma tells the test framework to run against mainnet. +2. **Your contract uses FlowToken**: `TokenChecker` imports and interacts with the real FlowToken contract. +3. **No bootstrapping needed**: With the fork pragma, real mainnet accounts (like `0x1654653399040a61`, the Flow service account) already have balances. +4. **Test against real state**: You can query actual accounts and verify your contract logic works with production data. +5. **Local deployment**: Your `TokenChecker` contract is deployed locally to the test environment, but it reads from forked mainnet state. ## Execute transactions with account impersonation @@ -443,7 +440,7 @@ transaction(amount: UFix64, to: Address) { ### Test transaction execution with impersonation -Add this test function to the current `cadence/tests/TokenChecker_test.cdc` file: +Add this test function to the current `cadence/tests/TokenChecker_test.cdc` file (the pragma is already at the top of the file): ```cadence access(all) fun testTransactionAsMainnetAccount() { @@ -519,13 +516,13 @@ access(all) fun testTransactionAsMainnetAccount() { ## Run all tests together -Now that you have multiple test files, run them all against the forked network: +Now that you have multiple test files with the `#test_fork` pragma, simply run: ```zsh -flow test --fork mainnet +flow test ``` -This runs all `*_test.cdc` files in your project against mainnet. You will see: +That's it! The pragma handles all the fork configuration. This runs all `*_test.cdc` files in your project—both local tests and fork tests together. You will see: ``` Test results: "cadence/tests/FlowToken_test.cdc" @@ -537,40 +534,53 @@ Test results: "cadence/tests/TokenChecker_test.cdc" - PASS: testTransactionAsMainnetAccount ``` -### Additional options +### Best Practices: In-File Configuration vs CLI Flags + +**Recommended:** Configure fork tests in your test file with `#test_fork` + +```cadence +#test_fork(network: "mainnet", height: nil) +import Test +// Your tests... +``` + +Then run with: -You can also fork from testnet (`flow test --fork testnet`) or pin to a specific block height (`--fork-height`). See the [Fork Testing Flags] reference for all available options. +```bash +flow test +``` -See also: +**Not recommended:** CLI flags (legacy approach) -- Strategy: [Testing Strategy on Flow] -- Emulator (fork mode for interactive E2E): [Flow Emulator] -- Networks and access nodes: [Flow Networks] +```bash +flow test --fork mainnet # Requires typing flags every time +``` -:::info -External oracles and off-chain systems +Configuring fork tests in the file keeps the configuration with your test code, making tests self-documenting and easier to maintain. -Fork tests run against Flow chain state only: -- No live off-chain/API calls or cross-chain reads -- Price feeds, bridges, indexers, and similar must be mocked (stub contracts or fixtures) -- For end-to-end, combine with `flow emulator --fork` and a local stub service -::: +You can also run specific test files or change the network/block height in the pragma as needed. See the [Fork Testing Flags] reference for more options. -### Select tests quickly +## Pinning block heights for reproducibility -- Run specific files or directories: +For reproducible test results, pin your tests to a specific block height: -```zsh -flow test cadence/tests/FlowToken_test.cdc cadence/tests/TokenChecker_test.cdc --fork mainnet +```cadence +#test_fork(network: "mainnet", height: 85229104) ``` -- Optional: narrow by function name with `--name`: +This ensures your tests run against the same blockchain state every time, useful for: -```zsh -flow test cadence/tests/TokenChecker_test.cdc --name _smoke --fork mainnet +- Deterministic test results in CI/CD +- Reproducing historical bugs at a specific point in time +- Testing against known network state + +To use the latest state instead, use `height: nil`: + +```cadence +#test_fork(network: "mainnet", height: nil) ``` -- Optional: suffix a few functions with `_smoke` for quick PR runs; run the full suite nightly or on protected branches. +Note that block heights are only available within the current spork (network upgrade period). See [Testing Smart Contracts] for more on managing pinned heights over time. ## When to use fork testing @@ -589,9 +599,9 @@ For strategy, limitations, and best practices, see the guide: [Testing Smart Con In this tutorial, you learned how to use fork testing to validate your Cadence contracts against live Flow network state. You created tests that read from real mainnet contracts, deployed custom contracts that interact with production data, and executed transactions using account impersonation—all without deploying to a live network or bootstrapping test accounts. -Now that you have completed this tutorial, you will be able to: +Now that you have completed this tutorial, you can: -- **Run Cadence tests against forked networks** with `flow test --fork`. +- **Run Cadence tests against forked networks** with `#test_fork`. - **Test contracts that depend on real mainnet contracts** without manual setup. - **Use account impersonation** to execute transactions as any mainnet account. - **Read from production blockchain state** in your test suite. diff --git a/docs/build/cadence/smart-contracts/testing-strategy.md b/docs/build/cadence/smart-contracts/testing-strategy.md index 510f4552a0..420ca430d2 100644 --- a/docs/build/cadence/smart-contracts/testing-strategy.md +++ b/docs/build/cadence/smart-contracts/testing-strategy.md @@ -36,7 +36,7 @@ A single, pragmatic strategy for testing on Flow. Use layers that are determinis ## At a glance - **Unit & Property — Test Framework**: Hermetic correctness and invariants -- **Integration — `flow test --fork`**: Real contracts and data; mutations stay local +- **Integration — Fork Testing**: Real contracts and data; mutations stay local - **Local integration sandbox (interactive, `flow emulator --fork`)**: Drive apps/E2E against production-like state - **Staging (testnet)**: Final plumbing and config checks - **Post-deploy (read-only)**: Invariant dashboards and alerts @@ -49,17 +49,18 @@ A single, pragmatic strategy for testing on Flow. Use layers that are determinis - **Use when**: Validating Cadence logic, invariants, access control, error paths, footprint - **Why**: Fully deterministic and isolated; highest-regression signal - **Run**: Every commit/PR; wide parallelism - - **Notes**: Write clear success/failure tests, add simple “this should always hold” rules when helpful, and avoid external services +- **Notes**: Write clear success/failure tests, add simple “this should always hold” rules when helpful, and avoid external services See also: [Running Cadence Tests]. -### Integration — `flow test --fork` +### Integration — Fork Testing - **Use when**: Interacting with real on-chain contracts/data (FT/NFT standards, AMMs, wallets, oracles, bridges), upgrade checks, historical repro - **Why**: Real addresses, capability paths, and resource schemas; catches drift early - **Run**: On PRs, run the full forked suite if practical (pinned), or a small quick set; run more cases nightly or on main +- **How**: Configure with `#test_fork(network: "mainnet", height: nil)` in your test file, or use `flow test --fork` CLI flags - **Notes**: - - Pin with `--fork-height` where reproducibility matters + - Pin with `height: 85432100` in the pragma (or `--fork-height` CLI flag) where reproducibility matters - Prefer local deployment + impersonation over real mainnet accounts - Mutations are local to the forked runtime; the live network is never changed - Be mindful of access-node availability and rate limits @@ -72,10 +73,10 @@ See also: [Fork Testing with Cadence], [Fork Testing Flags]. - **Use when**: Driving dapps, wallets, bots, indexers, or exploratory debugging outside the test framework - **Why**: Production-like state with local, disposable control; great for E2E and migrations - **Run**: Dev machines and focused E2E CI jobs -- **Notes**: +- **Notes**: - Pin height; run on dedicated ports; impersonation is built-in; mutations are local; off-chain/oracle calls are not live—mock or run local stubs - What to run: Manual exploration and debugging of flows against a forked state; frontend connected to the emulator (e.g., `npm run dev` pointed at `http://localhost:8888`); automated E2E/FE suites (e.g., Cypress/Playwright) against the local fork; headless clients, wallets/bots/indexers, and migration scripts - - Not for the canonical Cadence test suite—prefer `flow test --fork` for scripted Cadence tests (see [Fork Testing Flags] and [Running Cadence Tests]) + - Not for the canonical Cadence test suite—prefer fork testing with `flow test` for scripted Cadence tests (see [Fork Testing Flags] and [Running Cadence Tests]) Quick start example: @@ -86,11 +87,11 @@ See also: [Fork Testing with Cadence], [Fork Testing Flags]. ```javascript // In your root component (e.g., App.tsx) - import { FlowProvider } from "@onflow/react-sdk"; + import { FlowProvider } from '@onflow/react-sdk'; function App() { return ( - + {/* Your app components */} ); @@ -112,20 +113,22 @@ See also: [Flow Emulator]. - **Use when**: Final network plumbing and configuration checks before release - **Why**: Validates infra differences you cannot fully simulate - **Run**: Pre-release and on infra changes -- **Notes**: +- **Notes**: - Keep canaries minimal and time-boxed; protocol/partner support may be limited on testnet (not all third-party contracts are deployed or up to date) - What to run: Minimal app smoke tests (login/auth, key flows, mint/transfer, event checks); frontend connected to Testnet with a small Cypress/Playwright smoke set; infra/config checks (endpoints, contract addresses/aliases, env vars, service/test accounts) - - Not for the canonical Cadence test suite — prefer `flow test --fork` for scripted tests (see [Fork Testing Flags] and [Running Cadence Tests]) + - Not for the canonical Cadence test suite — prefer fork testing with `flow test` for scripted tests (see [Fork Testing Flags] and [Running Cadence Tests]) Quick start example: ```javascript // In your root component (e.g., App.tsx) - import { FlowProvider } from "@onflow/react-sdk"; + import { FlowProvider } from '@onflow/react-sdk'; function App() { return ( - + {/* Your app components */} ); @@ -150,7 +153,7 @@ See also: [Flow Networks]. ## Reproducibility and data management - - **Pin where reproducibility matters**: Use `--fork-height ` for both `flow test --fork` and `flow emulator --fork`. Pins are per‑spork; historical data beyond spork boundaries is unavailable. For best results, keep a per‑spork stable pin and also run a "latest" freshness job. +- **Pin where reproducibility matters**: Use `--fork-height ` for both `flow test --fork` and `flow emulator --fork`. Pins are per‑spork; historical data beyond spork boundaries is unavailable. For best results, keep a per‑spork stable pin and also run a "latest" freshness job. - **Named snapshots**: Maintain documented pin heights (e.g., in CI vars or a simple file) with names per dependency/protocol - **Refresh policy**: Advance pins via a dedicated “freshness” PR; compare old vs. new pins - **Goldens**: Save a few canonical samples (e.g., event payloads, resource layouts, key script outputs) as JSON in your repo, and compare them in CI to catch accidental schema/shape changes. Update the samples intentionally as part of upgrades. @@ -163,9 +166,9 @@ See also: [Flow Networks]. ## Test selection and tagging - - **Optional naming helpers**: Use simple suffixes in test names like `_fork`, `_smoke`, `_e2e` if helpful - - Run the tests you care about by passing files/directories: `flow test FILE1 FILE2 DIR1 ...` (most common) - - Optionally, use `--name ` to match test functions when it’s convenient +- **Optional naming helpers**: Use simple suffixes in test names like `_fork`, `_smoke`, `_e2e` if helpful +- Run the tests you care about by passing files/directories: `flow test FILE1 FILE2 DIR1 ...` (most common) +- Optionally, use `--name ` to match test functions when it’s convenient - **Defaults**: PRs can run the full fork suite (pinned) or a small quick set; nightly runs broader coverage (+ optional E2E) ## Troubleshooting tips @@ -178,7 +181,7 @@ See also: [Flow Networks]. ## Do / Don’t - **Do**: Keep a fast, hermetic base; pin forks; tag tests; maintain tiny PR smoke sets; document pins and set a simple refresh schedule (e.g., after each spork or monthly) -- **Don’t**: Make “latest” your default in CI; create or rely on real mainnet accounts; conflate `flow test --fork` with `flow emulator --fork` +- **Don't**: Make "latest" your default in CI; create or rely on real mainnet accounts; conflate fork testing (`flow test`) with the emulator's fork mode (`flow emulator --fork`) ## Related docs @@ -186,9 +189,10 @@ See also: [Flow Networks]. - Guide → How-to: [Cadence Testing Framework] - Tutorial → Step-by-step: [Fork Testing with Cadence] - Tool → Emulator (including fork mode): [Flow Emulator] -- Flags → `flow test --fork`: [Fork Testing Flags] +- Reference → Fork testing flags: [Fork Testing Flags] + [Running Cadence Tests]: ../../tools/flow-cli/tests.md [Cadence Testing Framework]: ./testing.md [Fork Testing with Cadence]: ../../../blockchain-development-tutorials/cadence/fork-testing/index.md diff --git a/docs/build/tools/flow-cli/tests.md b/docs/build/tools/flow-cli/tests.md index 57af647155..25ca681b8a 100644 --- a/docs/build/tools/flow-cli/tests.md +++ b/docs/build/tools/flow-cli/tests.md @@ -255,6 +255,28 @@ To dive deeper into testing the functionality of your Cadence scripts and contra Run tests against forked mainnet or testnet state. For a step-by-step tutorial, see: [Fork Testing with Cadence](../../../blockchain-development-tutorials/cadence/fork-testing/index.md). For background and best practices, see the guide: [Testing Strategy on Flow](../../cadence/smart-contracts/testing-strategy.md). +#### Configuring Fork Tests + +**Recommended**: Use the `#test_fork` pragma in your test file: + +```cadence +#test_fork(network: "mainnet", height: nil) + +import Test + +access(all) fun testAgainstMainnet() { + // Test runs against mainnet state +} +``` + +Then run with: + +```shell +flow test +``` + +The pragma configures fork testing directly in your test files, making tests self-documenting. You can also use CLI flags (documented below) to override or configure fork tests without modifying test files. + #### --fork - Type: `string`