diff --git a/docs/blockchain-development-tutorials/cadence/emulator-fork-testing/index.md b/docs/blockchain-development-tutorials/cadence/emulator-fork-testing/index.md index d7a98e6732..bba40b4a3c 100644 --- a/docs/blockchain-development-tutorials/cadence/emulator-fork-testing/index.md +++ b/docs/blockchain-development-tutorials/cadence/emulator-fork-testing/index.md @@ -30,9 +30,9 @@ keywords: # Interactive Testing with Forked Emulator -This tutorial teaches you how to run your app, E2E tests, and manual explorations against a snapshot of Flow mainnet using `flow emulator --fork`. You'll learn how to connect your frontend to production-like state, test user flows with real contracts and data, and debug issues interactively—all without deploying to a live network. +Fork testing gives you a local copy of mainnet state that you can freely modify and reset instantly. Test your DeFi app against real DEX liquidity pools and lending protocols without risking funds, verify integrations with existing mainnet contracts before deploying, and debug production issues at specific block heights with exact mainnet state. -The forked emulator creates a local Flow network that mirrors mainnet or testnet state. It's perfect for manual testing, running E2E test suites, and exploring contract interactions in a production-like environment with full control. +This tutorial teaches you how to run your app and E2E tests against Flow mainnet using `flow emulator --fork`. You'll connect your frontend to production-like state, impersonate any mainnet account, and test with real balances and assets—all running locally. ## What You'll Learn @@ -40,9 +40,10 @@ After you complete this tutorial, you'll be able to: - **Start the emulator in fork mode** with `flow emulator --fork`. - **Connect your app frontend** to the forked emulator. +- **Test DeFi integrations** against real liquidity pools, DEXs, and protocols. - **Test against real mainnet contracts** and production data interactively. - **Run E2E tests** (Cypress, Playwright) against forked state. -- **Use account impersonation** to test as any mainnet account. +- **Use account impersonation** to test as any mainnet account with real balances and assets. - **Pin to specific block heights** for reproducible testing. - **Debug and explore** contract interactions manually. @@ -96,7 +97,7 @@ You'll need network access to Flow's public access nodes: :::info -This tutorial covers `flow emulator --fork` (interactive testing with a forked emulator), which is different from `flow test --fork` (running Cadence test files against forked state). For testing Cadence contracts with test files, see [Fork Testing with Cadence]. +This tutorial covers `flow emulator --fork` (interactive testing with a forked emulator), which is different from `flow test --fork` (running Cadence test files against forked state). For an overview of both modes, see [Fork Testing](../../../build/tools/flow-cli/fork-testing.md). For testing Cadence contracts with test files, see [Fork Testing with Cadence]. ::: @@ -118,6 +119,7 @@ The emulator's fork mode starts a local Flow blockchain that connects to a real Use `flow emulator --fork` for: +- **DeFi application testing**: Test against real liquidity pools, DEXs, and lending protocols with production state - **E2E and frontend testing**: Run Cypress/Playwright tests against production-like state - **Manual exploration**: Interact with your app connected to forked mainnet - **Debugging user issues**: Reproduce bugs at specific block heights @@ -169,7 +171,13 @@ access(all) fun main(): UFix64 { } ``` -In another terminal, run the script: +First, verify the script works against real mainnet: + +```bash +flow scripts execute cadence/scripts/getFlowSupply.cdc --network mainnet +``` + +Then, in another terminal, run the script against the fork: ```bash flow scripts execute cadence/scripts/getFlowSupply.cdc --network mainnet-fork @@ -187,150 +195,227 @@ cd emulator-fork-demo flow init --yes ``` -The `--yes` flag accepts defaults non-interactively. +This creates an empty Flow project with default configuration. + +## Start the Forked Emulator -## Configure Fork Network in flow.json +Start the emulator in fork mode, connected to mainnet: -Before starting the emulator, configure a fork network in your `flow.json`. This enables automatic contract alias inheritance from mainnet, so you don't need to manually duplicate aliases. +```bash +flow emulator --fork mainnet +``` -Open `flow.json` and add a `mainnet-fork` network: +You'll see output like: -```json -{ - "networks": { - "emulator": "127.0.0.1:3569", - "mainnet": "access.mainnet.nodes.onflow.org:9000", - "testnet": "access.devnet.nodes.onflow.org:9000", - "mainnet-fork": { - "host": "127.0.0.1:3569", - "fork": "mainnet" - } - } -} ``` +INFO[0000] ⚙️ Using service account 0xf8d6e0586b0a20c7 +INFO[0000] 🌱 Starting Flow Emulator in fork mode (mainnet) +INFO[0000] 🛠 GRPC server started on 127.0.0.1:3569 +INFO[0000] 📡 REST server started on 127.0.0.1:8888 +INFO[0000] 🌐 Forking from access.mainnet.nodes.onflow.org:9000 +``` + +**Leave this terminal running.** The emulator is now serving: + +- **REST API**: `http://localhost:8888` (for FCL/frontend) +- **gRPC API**: `localhost:3569` (for Flow CLI) + +:::info Fork Network Configuration -**What this does:** +When you run `flow init`, the CLI automatically configures a `mainnet-fork` network in your `flow.json` that inherits all contract aliases from mainnet. This means you don't need to manually configure fork networks—it just works! -- `host`: Points to your local emulator -- `fork`: Tells the CLI to automatically inherit contract aliases from mainnet +For details on fork network configuration, see the [Fork Testing Overview](../../../build/tools/flow-cli/fork-testing.md) and [flow.json Configuration Reference](../../../build/tools/flow-cli/flow.json/configuration.md#networks). -Now any contract with a `mainnet` alias will automatically work on `mainnet-fork` without manual configuration! +::: :::tip -**Why forking is powerful:** +Pin to a specific block height for reproducibility: + +```bash +flow emulator --fork mainnet --fork-height +``` + +This ensures the forked state is consistent across runs—essential for E2E tests in CI. + +::: + +## Deploy Your Contracts Against Mainnet State -The emulator fork mode gives you access to **real production state**: +The most common use case: deploy your NEW contracts to the forked emulator so they can interact with real mainnet contracts and data. This lets you test your DeFi protocol against live DEXs, lending protocols, liquidity pools, and other production DeFi infrastructure. -- ✅ Test against actual deployed contracts (FT, NFT, DEXs, marketplaces) -- ✅ Read real account balances, storage, and capabilities -- ✅ Query production data without setting up test fixtures -- ✅ Catch integration issues with real-world contract implementations -- ✅ Debug with historical state by pinning block heights +### Example: Deploy and Test Your Contract -**Plus, fork networks simplify configuration:** +**1. Create your contract:** -- ✅ No need to duplicate 30+ contract aliases -- ✅ Automatic inheritance from source network -- ✅ Can override specific contracts if needed +```bash +flow generate contract MyDeFiProtocol +``` -**Example of automatic inheritance:** +Edit `cadence/contracts/MyDeFiProtocol.cdc`: + +```cadence +import "FlowToken" + +access(all) contract MyDeFiProtocol { + // Your DeFi logic that reads real mainnet FlowToken data + access(all) fun getTotalSupply(): UFix64 { + return FlowToken.totalSupply + } +} +``` + +**2. Start the forked emulator:** + +```bash +flow emulator --fork mainnet +``` + +When the emulator starts, note the service account address in the logs: + +``` +⚙️ Using service account 0xe467b9dd11fa00df +``` + +**3. Configure the service account:** + +Add the forked emulator's service account (use the address from the startup logs and a dummy key). + +First, create a dummy key file: + +```bash +echo "0000000000000000000000000000000000000000000000000000000000000000" > blank-key.pkey +``` + +Then manually add to your `flow.json`: ```json { - "dependencies": { - "FlowToken": { - "aliases": { - "mainnet": "0x1654653399040a61" - // ✅ mainnet-fork automatically inherits this! - // No need for: "mainnet-fork": "0x1654653399040a61" + "accounts": { + "mainnet-fork-service": { + "address": "0xe467b9dd11fa00df", + "key": { + "type": "file", + "location": "blank-key.pkey" } } } } ``` -When you run commands with `--network mainnet-fork`, the CLI automatically resolves contract imports to their mainnet addresses. +Since signature validation is disabled in fork mode, the key value doesn't matter. -::: +**4. Configure deployment:** -## Start the Forked Emulator +```bash +flow config add deployment \ + --network mainnet-fork \ + --account mainnet-fork-service \ + --contract MyDeFiProtocol +``` -Start the emulator in fork mode, connected to mainnet: +**5. Deploy your contract:** ```bash -flow emulator --fork mainnet +flow project deploy --network mainnet-fork --update ``` -You'll see output like: +:::tip -``` -INFO[0000] ⚙️ Using service account 0xf8d6e0586b0a20c7 -INFO[0000] 🌱 Starting Flow Emulator in fork mode (mainnet) -INFO[0000] 🛠 GRPC server started on 127.0.0.1:3569 -INFO[0000] 📡 REST server started on 127.0.0.1:8888 -INFO[0000] 🌐 Forking from access.mainnet.nodes.onflow.org:9000 +Use `--update` if you're working on an existing project that's already deployed to mainnet. The forked emulator mirrors mainnet state, so if your contract already exists at that address on mainnet, it will exist in the fork too. The `--update` flag replaces the mainnet version with your local changes. + +::: + +**6. Test your contract:** + +Your contract can now interact with real mainnet contracts! Create a script to test it: + +```bash +flow generate script getTotalSupply ``` -**Leave this terminal running.** The emulator is now serving: +Add the following to `cadence/scripts/getTotalSupply.cdc`: -- **REST API**: `http://localhost:8888` (for FCL/frontend) -- **gRPC API**: `localhost:3569` (for Flow CLI) +```cadence +import "MyDeFiProtocol" -:::tip +access(all) fun main(): UFix64 { + return MyDeFiProtocol.getTotalSupply() +} +``` -Pin to a specific block height for reproducibility: +Run the script: ```bash -flow emulator --fork mainnet --fork-height +flow scripts execute cadence/scripts/getTotalSupply.cdc --network mainnet-fork ``` -This ensures the forked state is consistent across runs—essential for E2E tests in CI. +You'll see something like `Result: 1628083999.54686045` - the real mainnet FlowToken supply! Your contract runs locally but reads production data. Perfect for testing integrations before mainnet deployment. -::: +## Mock Existing Mainnet Contracts -## Mocking Mainnet Contracts +You can override existing mainnet contracts with your own versions for testing. This is useful for testing contract upgrades, fixing bugs, or adding test functionality to mainnet contracts. -Just like mocking dependencies in unit tests, you can **mock real mainnet contracts** by deploying modified versions—perfect for testing upgrades, bug fixes, or alternative implementations against real production state. +### Example: Mock a Mainnet Contract -Configure the mock in `flow.json`, then deploy to the forked emulator. Your mock takes precedence while other contracts use real mainnet versions. +Let's say you want to test how your DeFi protocol behaves with a modified version of an existing mainnet contract. -### Example +**1. Create your mock oracle contract:** -**1. Configure in `flow.json`:** +```bash +flow generate contract PriceOracle +``` + +Edit `cadence/contracts/PriceOracle.cdc` to match the interface of the mainnet oracle you want to mock: + +```cadence +// Mock implementation of mainnet PriceOracle with fixed test prices +access(all) contract PriceOracle { + access(all) fun getPrice(): UFix64 { + return 123.45 // Fixed test price for predictable testing + } +} +``` + +**2. Deploy to the SAME address as the mainnet oracle:** + +In your `flow.json`, configure deployment to use the mainnet oracle's address: ```json { - "accounts": { - "flow-token-mainnet": { - "address": "0x1654653399040a61", - "key": "0000000000000000000000000000000000000000000000000000000000000000" - } - }, "contracts": { - "FlowToken": { - "source": "./contracts/FlowTokenModified.cdc", - "aliases": { - "mainnet": "0x1654653399040a61" - } - } + "PriceOracle": "cadence/contracts/PriceOracle.cdc" }, "deployments": { "mainnet-fork": { - "flow-token-mainnet": ["FlowToken"] + "mainnet-oracle-account": ["PriceOracle"] + } + }, + "accounts": { + "mainnet-oracle-account": { + "address": "0x1654653399040a61", + "key": { + "type": "file", + "location": "blank-key.pkey" + } } } } ``` -**2. Deploy the mock:** +**3. Deploy with `--update` flag:** ```bash -flow emulator --fork mainnet flow project deploy --network mainnet-fork --update ``` -Your app now uses the mocked FlowToken while FungibleToken, USDC, and all other contracts use real mainnet versions. +Now your mock oracle replaces the mainnet oracle at that address. All imports and references to the original oracle will use your mocked version with fixed test prices instead! + +:::tip + +This is how you test contract upgrades or modifications against real mainnet state without affecting the live network. + +::: ## Install Dependencies @@ -414,15 +499,26 @@ Now let's connect a frontend. ## Create a React App -Create a React app with Flow integration: +Create a Next.js app with Flow integration: + +```bash +npx create-next-app@latest flow-fork-app +``` + +During setup, choose: + +- **Use TypeScript**: Yes +- **Use src directory**: Yes +- **Use App Router**: Yes + +Then install the Flow React SDK: ```bash -npx create-react-app flow-fork-app cd flow-fork-app npm install @onflow/react-sdk ``` -Copy your project's `flow.json` into the React app's `src` directory: +Copy your project's `flow.json` into the app's `src` directory: ```bash # From your flow-fork-app directory @@ -431,18 +527,28 @@ cp ../flow.json src/ This allows the `FlowProvider` to resolve contract imports. -Replace `src/index.js` with: +### Configure for Fork Testing + +Since Next.js uses the App Router with server components, create a client component wrapper. First, create the components directory: + +```bash +mkdir -p src/components +``` + +Then create `src/components/FlowProviderWrapper.tsx`: + +```typescript +'use client'; -```javascript -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import App from './App'; import { FlowProvider } from '@onflow/react-sdk'; -import flowJSON from './flow.json'; +import flowJSON from '../flow.json'; -const root = ReactDOM.createRoot(document.getElementById('root')); -root.render( - +export default function FlowProviderWrapper({ + children, +}: { + children: React.ReactNode; +}) { + return ( - + {children} - , -); + ); +} +``` + +Then update `src/app/layout.tsx` to use the wrapper: + +```typescript +import FlowProviderWrapper from '@/components/FlowProviderWrapper'; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {children} + + + ); +} ``` -Replace `src/App.js` with: +### Create a Demo Component + +Create a simple demo that queries FlowToken supply from the forked mainnet. Update `src/app/page.tsx`: + +```typescript +'use client'; -````javascript import { useState } from 'react'; import { useFlowCurrentUser, useFlowQuery, Connect } from '@onflow/react-sdk'; -function App() { +export default function Home() { const { user } = useFlowCurrentUser(); const [shouldFetch, setShouldFetch] = useState(false); @@ -499,7 +629,7 @@ function App() { - {error &&

Error: {error.message}

} + {error &&

Error: {(error as Error).message}

} {flowSupply && (

Total Supply: {Number(flowSupply).toLocaleString()} FLOW @@ -519,25 +649,27 @@ function App() { ); } +``` + +### Start the dev wallet (optional) + +For wallet authentication flows, start the FCL dev wallet in another terminal: + +```bash +flow dev-wallet +``` -export default App; -# 2. Configure fork network (add to flow.json) -# Add this in "networks": -# "mainnet-fork": { -# "host": "127.0.0.1:3569", -# "fork": "mainnet" -# } This starts the dev wallet at `http://localhost:8701`. ### Run your app -Start the React app: +Start the Next.js dev server: ```bash -npm start -```` +npm run dev +``` -Your browser will open to `http://localhost:3000`. Click "Get FlowToken Supply" to see real mainnet data! +Navigate to `http://localhost:3000`. Click "Get FlowToken Supply" to see real mainnet data! **What's happening:** @@ -646,14 +778,19 @@ Now let's test transferring tokens from a mainnet account using impersonation. ### CLI-Based Impersonation -To use impersonation with the CLI, you need to add the mainnet account to your `flow.json` (signature validation is disabled, so the key value doesn't matter): +To use impersonation with the CLI, you need to add the mainnet account to your `flow.json` (signature validation is disabled, so the key value doesn't matter). + +Manually add to your `flow.json` (using the same `blank-key.pkey` file): ```json { "accounts": { "mainnet-service": { "address": "0x1654653399040a61", - "key": "0000000000000000000000000000000000000000000000000000000000000000" + "key": { + "type": "file", + "location": "blank-key.pkey" + } } } } @@ -684,9 +821,9 @@ flow dev-wallet In your app (running against the forked emulator), click the wallet connect button. In the dev wallet UI: -1. **Enter any mainnet address** in the address field (e.g., a whale wallet, NFT collector, or protocol account) +1. **Enter any mainnet address** in the address field (e.g., a whale wallet, liquidity provider, or DeFi protocol account) 2. Click "Authenticate" -3. Your app is now authenticated as that mainnet account with all its real balances, NFTs, and storage! +3. Your app is now authenticated as that mainnet account with all its real balances, liquidity positions, and storage! **Additional dev wallet features in fork mode:** @@ -698,7 +835,7 @@ This lets you: - Test your app as a user with specific assets or permissions - Debug issues reported by specific mainnet accounts -- Verify flows work for accounts with large balances or many NFTs +- Verify flows work for accounts with large balances or complex liquidity positions - Test edge cases with real account states - Add test funds to accounts that need more FLOW for testing @@ -748,6 +885,29 @@ Use the same approach with Playwright, Puppeteer, or any browser automation tool ## Common Use Cases +### Testing DeFi Applications + +Test your DeFi application against real mainnet liquidity and protocols: + +1. Fork mainnet at a specific block height +2. Impersonate accounts with large token balances or LP positions +3. Test your swap, lending, or yield farming logic against real DEX state +4. Verify slippage calculations with actual liquidity pool reserves +5. Test edge cases like low liquidity scenarios using real market conditions + +**Example: Testing a swap integration** + +```bash +# Fork at a known block with specific liquidity conditions +flow emulator --fork mainnet --fork-height + +# In your test, impersonate a whale account +# Execute swaps against real DEX contracts (IncrementFi, etc.) +# Verify your price calculations match actual execution +``` + +This lets you test against production liquidity without spending real tokens or affecting live markets. + ### Testing Contract Upgrades Test a contract upgrade against real mainnet state by mocking the contract with your upgraded version: @@ -864,7 +1024,7 @@ flow transactions send my_transaction.cdc \ --network mainnet-fork ``` -This lets you test with real NFT collector accounts, whale wallets, or any address that has interesting state on mainnet. +This lets you test with real whale wallets, liquidity provider accounts, or any address that has interesting DeFi state on mainnet. ### 6. Document Your Fork Heights @@ -922,22 +1082,11 @@ flow emulator --fork-host access.mainnet.nodes.onflow.org:9000 **Error:** `import "FlowToken" could not be resolved` -**Solution:** Ensure your fork network is properly configured: - -````json -{ -# 2. Configure fork network (add to flow.json) -# Add this in "networks": -# "mainnet-fork": { -# "host": "127.0.0.1:3569", -# "fork": "mainnet" -# } - -And that you've installed dependencies with the mainnet alias: +**Solution:** Make sure you've installed dependencies with the mainnet alias: ```bash -flow dependencies install -```` +flow dependencies install FlowToken FungibleToken +``` Verify the contract has a mainnet alias that the fork can inherit. @@ -965,18 +1114,7 @@ Check the emulator is running and serving on port 8888. 1. **Wrong network:** Using `flowNetwork: 'emulator'` when forking mainnet will use emulator contract addresses (`0x0ae53cb6...`) instead of mainnet addresses. Use your fork network name (`'mainnet-fork'`). -2. **Missing fork network in flow.json:** Make sure your `flow.json` has the fork network configured: - - ```json - "networks": { - "mainnet-fork": { - "host": "127.0.0.1:3569", - "fork": "mainnet" - } - } - ``` - -3. **Missing flowJson prop:** The `flowJson` prop is required for contract import resolution. Make sure you're importing and passing your `flow.json` file. +2. **Missing flowJson prop:** The `flowJson` prop is required for contract import resolution. Make sure you're importing and passing your `flow.json` file. ### Script Returns Stale Data @@ -1036,8 +1174,9 @@ The forked emulator bridges the gap between local development and testnet/mainne - Add E2E tests to your CI/CD pipeline using pinned fork heights - Test your app's upgrade flows against forked mainnet -- Explore [Flow React SDK] hooks and components (events, mutations, Cross-VM features) +- Review the [Fork Testing Overview] for both emulator and test framework fork modes - For Cadence contract testing, see [Fork Testing with Cadence] +- Explore [Flow React SDK] hooks and components (events, mutations, Cross-VM features) - Review the [Testing Strategy] for the full testing approach - Check [Flow Emulator] docs for advanced emulator flags @@ -1046,6 +1185,7 @@ The forked emulator bridges the gap between local development and testnet/mainne [Flow CLI]: ../../../build/tools/flow-cli/index.md [homebrew]: https://brew.sh [installation guide]: ../../../build/tools/flow-cli/install.md +[Fork Testing Overview]: ../../../build/tools/flow-cli/fork-testing.md [Fork Testing with Cadence]: ../fork-testing/index.md [Testing Strategy]: ../../../build/cadence/smart-contracts/testing-strategy.md [Network Upgrade (Spork) Process]: ../../../protocol/node-ops/node-operation/network-upgrade.md diff --git a/docs/build/tools/flow-cli/flow.json/configuration.md b/docs/build/tools/flow-cli/flow.json/configuration.md index 4653c56175..0ab128714b 100644 --- a/docs/build/tools/flow-cli/flow.json/configuration.md +++ b/docs/build/tools/flow-cli/flow.json/configuration.md @@ -45,6 +45,7 @@ The `networks` section defines which Flow networks your project can connect to. ``` **Common Networks:** + - `emulator`: Your local development environment - `testnet`: Flow's test network for development and testing - `mainnet`: Flow's production network @@ -61,6 +62,22 @@ For enhanced security, you can specify network keys: } ``` +**Fork Networks:** +Fork networks allow you to test against a local emulator that mirrors mainnet or testnet state. When you run `flow emulator --fork mainnet`, the CLI automatically creates a `mainnet-fork` network configuration that inherits contract aliases from the parent network: + +```json +"networks": { + "mainnet-fork": { + "host": "127.0.0.1:3569", + "fork": "mainnet" + } +} +``` + +The `fork` property tells the CLI to inherit all contract aliases from the specified network (e.g., `mainnet`), so you don't need to manually duplicate aliases for forked networks. + +Learn more: [Fork Testing Overview](../fork-testing.md) + ### Accounts The `accounts` section defines the accounts you can use for transactions and deployments. @@ -96,6 +113,7 @@ For more control over key management: ``` **Key Types:** + - `hex`: Standard hex-encoded private key - `file`: Read key from a separate file - `bip44`: Derive from mnemonic phrase @@ -119,6 +137,7 @@ For better security, you can store private keys in separate files: The key file should contain only the hex-encoded private key (e.g., `ae1b44c0f5e8f6992ef2348898a35e50a8b0b9684000da8b1dade1b3bcd6ebee`). **Special Address Values:** + - `"service"`: Use the default service account (emulator only) ### Contracts @@ -151,6 +170,7 @@ Use aliases when contracts are already deployed on specific networks: ``` **When to Use Aliases:** + - For core contracts already deployed on mainnet/testnet - To avoid redeploying dependencies - To use the official versions of common contracts @@ -209,6 +229,7 @@ The `deployments` section defines which contracts get deployed to which accounts **Format:** `"NETWORK": { "ACCOUNT": ["CONTRACT1", "CONTRACT2"] }` **Important Notes:** + - Don't deploy contracts that have aliases defined for that network - Contracts are deployed in dependency order automatically - You can deploy the same contract to multiple accounts (but not in the same deploy command) diff --git a/docs/build/tools/flow-cli/fork-testing.md b/docs/build/tools/flow-cli/fork-testing.md new file mode 100644 index 0000000000..9d6a5507f5 --- /dev/null +++ b/docs/build/tools/flow-cli/fork-testing.md @@ -0,0 +1,220 @@ +--- +title: Fork Testing +description: Test your Flow applications against production state using mainnet or testnet forks +sidebar_position: 15 +--- + +# Fork Testing + +Fork testing allows you to run tests and development environments against a **local copy of mainnet or testnet state**. This gives you access to real contracts, accounts, and data without deploying to live networks or affecting production state. + +## What is Fork Testing? + +Fork testing creates a local Flow network that mirrors the state of a real network (mainnet or testnet). Your code runs locally, but can read from and interact with production contract implementations, real account balances, and actual on-chain data. + +**Key Benefits:** + +- ✅ **Test against real production contracts** - No need to mock complex dependencies +- ✅ **Access real account state** - Test with actual balances, NFTs, and storage +- ✅ **Reproduce production issues** - Debug problems at specific block heights +- ✅ **Test contract upgrades safely** - Verify changes work with real mainnet state +- ✅ **Safe testing environment** - All changes stay local, never affect the real network +- ✅ **Fast iteration** - No deployment costs or wait times + +Fork testing is an essential part of a comprehensive testing strategy. It complements unit tests and integration tests by letting you validate your contracts against real-world state and dependencies. Learn more about building a complete testing approach in the [Testing Strategy guide](../../../build/cadence/smart-contracts/testing-strategy.md). + +## Two Fork Testing Modes + +The Flow CLI provides two different fork testing modes for different use cases: + +### 1. Emulator Fork Mode (`flow emulator --fork`) + +**Best for:** + +- Frontend and app development +- E2E testing (Cypress, Playwright) +- Manual testing and exploration +- Wallet integration testing +- Bot and indexer development + +**How it works:** +Starts a full emulator with REST and gRPC APIs that you can connect to with FCL, dev wallet, or any Flow SDK. + +```bash +flow emulator --fork mainnet +``` + +**Learn more:** [Interactive Testing with Forked Emulator](../../../blockchain-development-tutorials/cadence/emulator-fork-testing/index.md) + +### 2. Test Framework Fork Mode (`flow test` + `#test_fork`) + +**Best for:** + +- Cadence integration tests +- Contract testing against real dependencies +- Testing contract logic with real mainnet state + +**How it works:** +Runs your `*_test.cdc` files against a forked network using the [Cadence Testing Framework](../../../build/cadence/smart-contracts/testing.md). Add the `#test_fork` pragma to your test file, then run: + +```bash +flow test +``` + +**Learn more:** [Fork Testing with Cadence](../../../blockchain-development-tutorials/cadence/fork-testing/index.md) + +## Quick Comparison + +| Feature | `flow emulator --fork` | `flow test` + `#test_fork` | +| --------------- | --------------------------------------- | -------------------------- | +| **Use for** | App E2E, manual testing, debugging | Cadence integration tests | +| **Connects to** | Frontend, wallets, bots, E2E tools | Cadence Testing Framework | +| **Run with** | FCL, Cypress, Playwright, manual clicks | `flow test` command | +| **Best for** | User flows, UI testing, exploration | Contract logic validation | +| **Examples** | React app, wallet flows, E2E suites | `*_test.cdc` files | + +## Common Use Cases + +### DeFi Protocol Testing + +Test your DeFi contracts against real mainnet state - real DEX liquidity, real oracle prices, real token supplies. + +### Contract Upgrade Testing + +Deploy your upgraded contract to a fork and verify it works with real mainnet state before deploying to production. + +### Bug Reproduction + +Fork to the exact block height where a bug occurred and debug with the actual state that caused the issue. + +### Integration Testing + +Test how your contracts interact with production versions of core contracts (FungibleToken, NFT standards, etc). + +## Getting Started + +### Prerequisites + +- [Flow CLI](./install.md) v2.12.0 or later +- Basic understanding of Flow development + +### Quick Start: Emulator Fork + +```bash +# 1. Initialize a Flow project +flow init + +# 2. Install dependencies (e.g., FlowToken) +flow dependencies install FlowToken FungibleToken + +# 3. Start the forked emulator +flow emulator --fork mainnet + +# 4. In another terminal, run scripts/transactions +flow scripts execute myScript.cdc --network mainnet-fork +``` + +**Next steps:** Follow the [complete emulator fork tutorial](../../../blockchain-development-tutorials/cadence/emulator-fork-testing/index.md) + +### Quick Start: Cadence Test Fork + +Add the fork pragma to your test file: + +```cadence +#test_fork(network: "mainnet", height: nil) + +import Test + +access(all) fun testExample() { + // Your test code here +} +``` + +Then run the test: + +```bash +flow test tests/MyContract_test.cdc +``` + +**Next steps:** Follow the [complete Cadence fork testing tutorial](../../../blockchain-development-tutorials/cadence/fork-testing/index.md) + +## Key Features + +### Pin to Block Heights + +Fork to specific block heights for reproducible testing: + +```bash +# Emulator fork with block height +flow emulator --fork mainnet --fork-height +``` + +```cadence +// Test with block height - add to your test file +#test_fork(network: "mainnet", height: ) +``` + +```bash +# Then run the test +flow test test_file.cdc +``` + +Replace `` with the specific block number you want to test against. Note that block heights are only available within the current spork. + +### Account Impersonation + +Fork mode disables signature verification, allowing you to execute transactions as any mainnet account for testing. + +### Dependency Mocking + +Override specific mainnet contracts with your own versions while keeping all other contracts unchanged - perfect for testing contract upgrades. + +### Automatic Configuration + +Fork networks are automatically configured when you run fork commands. Contract aliases from the parent network (mainnet/testnet) are automatically inherited. + +Learn more: [flow.json Configuration - Fork Networks](./flow.json/configuration.md#networks) + +## Best Practices + +1. **Pin block heights in CI/CD** - Ensures reproducible test results +2. **Test on testnet first** - Avoid mainnet rate limits during development +3. **Use the right mode** - Emulator fork for apps, test fork for Cadence contracts +4. **Mock external services** - Fork only mirrors Flow state, not external APIs +5. **Document your fork heights** - Keep track of which blocks work for testing + +## Network Requirements + +Fork testing requires network access to Flow's public access nodes: + +- **Mainnet:** `access.mainnet.nodes.onflow.org:9000` +- **Testnet:** `access.devnet.nodes.onflow.org:9000` + +Data is fetched on-demand and cached locally for performance. + +## Limitations + +- **Spork boundaries:** Historical data is only available within the current spork +- **Off-chain services:** Oracles, IPFS, and cross-chain bridges must be mocked +- **Network latency:** First access to accounts/contracts requires network fetch + +Learn more: [Network Upgrade (Spork) Process](../../../protocol/node-ops/node-operation/network-upgrade.md) + +## Tutorials + +- [Interactive Testing with Forked Emulator](../../../blockchain-development-tutorials/cadence/emulator-fork-testing/index.md) - Complete guide to `flow emulator --fork` +- [Fork Testing with Cadence](../../../blockchain-development-tutorials/cadence/fork-testing/index.md) - Complete guide to `flow test` with `#test_fork` + +## Related Documentation + +- [Flow Emulator](../emulator/index.md) - Learn more about the Flow emulator +- [Cadence Testing Framework](../../../build/cadence/smart-contracts/testing.md) - Write and run Cadence tests +- [flow.json Configuration](./flow.json/configuration.md) - Configure fork networks +- [Testing Strategy](../../../build/cadence/smart-contracts/testing-strategy.md) - Overall testing approach +- [Dependency Manager](./dependency-manager.md) - Install and manage contract dependencies + +## Need Help? + +- Review the [complete tutorials](../../../blockchain-development-tutorials/cadence/emulator-fork-testing/index.md) for step-by-step guidance +- Check the [troubleshooting sections](../../../blockchain-development-tutorials/cadence/emulator-fork-testing/index.md#troubleshooting) in the tutorials +- Ask questions in the [Flow Discord](https://discord.gg/flow) diff --git a/docs/build/tools/flow-cli/index.md b/docs/build/tools/flow-cli/index.md index e8c0fd8d05..de8056d7fc 100644 --- a/docs/build/tools/flow-cli/index.md +++ b/docs/build/tools/flow-cli/index.md @@ -15,6 +15,7 @@ With Flow CLI, developers can: - **Query Chain State**: Retrieve data from the Flow blockchain, including account balances, event logs, and the status of specific transactions. - **Deploy Smart Contracts**: Easily deploy and update Cadence smart contracts on any Flow environment (emulator, testnet, or mainnet). - **Use the Emulator:** Set up a local Flow blockchain instance with the Flow emulator to test and debug smart contracts in a development environment before deploying them on the network. +- **Test with Fork Mode**: Use [fork testing](fork-testing.md) to run tests and development environments against a local copy of mainnet or testnet state, giving you access to real contracts and data without affecting production. - **Interact with the [Flow Access API](/http-api)**: Automate complex workflows using configuration files and command-line scripting, which allows for greater flexibility in continuous integration (CI) or custom development tools. - **Access Flow’s Tooling Ecosystem**: Integrate Flow CLI with other developer tools like the [Cadence Extension for VSCode](https://marketplace.visualstudio.com/items?itemName=onflow.cadence) to enhance your development experience.