diff --git a/docs/blockchain-development-tutorials/cadence/fork-testing/index.md b/docs/blockchain-development-tutorials/cadence/fork-testing/index.md new file mode 100644 index 0000000000..3475e1e2ff --- /dev/null +++ b/docs/blockchain-development-tutorials/cadence/fork-testing/index.md @@ -0,0 +1,618 @@ +--- +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. +keywords: + - fork testing + - flow test --fork + - cadence tests + - mainnet fork + - testnet fork + - integration testing + - Flow CLI + - account impersonation + - production testing + - real contracts + - on-chain state + - block height + - fork-height + - historical debugging + - reproducible tests + - test deployment + - FlowToken + - FungibleToken + - test scripts + - test transactions + - local testing + - safe testing + - forked runtime +--- + +# 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. + +Fork testing bridges the gap between isolated local unit tests and testnet deployments. It enables you to validate your contracts work correctly with real on-chain state, test integrations with deployed contracts, and debug issues using historical blockchain data—all in a safe, local environment. + +## What You'll Learn + +After completing this tutorial, you'll be able to: + +- **Run Cadence tests against forked networks** using `flow 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 +- **Pin tests to specific block heights** for historical debugging +- **Integrate fork testing** into your development workflow + +## What You'll Build + +You'll create a complete fork testing setup that demonstrates: + +- Reading from the live FlowToken contract on mainnet +- Deploying your own contract that interacts with mainnet contracts +- Testing custom logic against real account balances and state +- Executing transactions using impersonated mainnet accounts +- A reusable pattern for integration testing your Flow applications + +**Time Commitment:** Approximately 30 minutes + +### 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 + +This tutorial requires [Flow CLI] v1.8.0 or later installed. If you haven't installed it yet and have [homebrew] installed, run: + +```bash +brew install flow-cli +``` + +For other operating systems, refer to the [installation guide]. + +### Basic Cadence Testing Knowledge + +You should be familiar with writing basic Cadence tests. If you're new to Cadence testing, start with [Testing Smart Contracts] first. + +### Network Access + +You'll need network access to Flow's public access nodes. The tutorial uses these endpoints, which are freely available: + +- Mainnet: `access.mainnet.nodes.onflow.org:9000` +- Testnet: `access.devnet.nodes.onflow.org:9000` + +:::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). + +::: + +## Create Your Project + +Navigate to your development directory and create a new Flow project: + +```zsh +mkdir fork-testing-demo +cd fork-testing-demo +flow init --yes +``` + +The `--yes` flag accepts defaults non-interactively. `flow init` is interactive by default and can scaffold various templates. + +Alternatively, create the directory and initialize in one command: + +```zsh +flow init fork-testing-demo --yes +cd fork-testing-demo +``` + +## Install Dependencies + +Use the [Dependency Manager] to install the `FlowToken` and `FungibleToken` contracts: + +```zsh +flow dependencies install FlowToken FungibleToken +``` + +This downloads the contracts and their dependencies into the `imports/` folder and updates your `flow.json` with the correct addresses and aliases across all networks (mainnet, testnet, emulator). + +Your `flow.json` will now include an entry like: + +```json +{ + "dependencies": { + "FlowToken": { + "source": "mainnet://1654653399040a61.FlowToken", + "aliases": { + "emulator": "0ae53cb6e3f42a79", + "mainnet": "1654653399040a61", + "testnet": "7e60df042a9c0868" + } + } + } +} +``` + +Your `flow.json` should now have the mainnet and testnet networks configured from `flow init`. In fork mode, contract imports automatically resolve to the correct network addresses. + +## Test Reading Live State + +Generate a script to read FlowToken supply: + +```zsh +flow generate script GetFlowTokenSupply +``` + +Open `cadence/scripts/GetFlowTokenSupply.cdc` and replace its contents with: + +```cadence cadence/scripts/GetFlowTokenSupply.cdc +import "FlowToken" + +access(all) fun main(): UFix64 { + return FlowToken.totalSupply +} +``` + +Generate the test file: + +```zsh +flow generate test FlowToken +``` + +Open `cadence/tests/FlowToken_test.cdc` and replace its contents with: + +```cadence cadence/tests/FlowToken_test.cdc +import Test + +access(all) fun testFlowTokenSupplyIsPositive() { + let scriptResult = Test.executeScript( + Test.readFile("../scripts/GetFlowTokenSupply.cdc"), + [] + ) + + Test.expect(scriptResult, Test.beSucceeded()) + + let supply = scriptResult.returnValue! as! UFix64 + Test.assert(supply > 0.0, message: "FlowToken supply should be positive") +} +``` + +Notes: +- 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/`) + +#### Quick verify + +Run just this test file against a fork to confirm your setup works: + +```zsh +flow test cadence/tests/FlowToken_test.cdc --fork mainnet +``` + +Target testnet instead: + +```zsh +flow test cadence/tests/FlowToken_test.cdc --fork testnet +``` + +You should see the test PASS. If not, verify your network host in `flow.json` and that dependencies are installed. + +## Deploy and Test Your Contract + +Now you'll create a contract that depends on FlowToken and test it against the forked mainnet state—no need to bootstrap tokens or set up test accounts. + +### Create a Test Account + +Create a new account for deploying your contract: + +```zsh +flow accounts create +``` + +Follow the prompts: +- Select "mainnet" for the network +- Name your account as desired + +This will output the new account address. Use this address as the mainnet alias for your contract in flow.json. + +:::note +This creates a local account with a mainnet-format address for fork testing. When you're ready to deploy to actual mainnet, you'll use this same account—see the [Deploying Contracts guide](pathname:///build/cadence/smart-contracts/deploying) for details. +::: + +### Create a Contract that Uses FlowToken + +Generate a new contract: + +```zsh +flow generate contract TokenChecker +``` + +This creates `cadence/contracts/TokenChecker.cdc` and adds it to `flow.json`. Now update the contract with your logic: + +```cadence cadence/contracts/TokenChecker.cdc +import "FlowToken" + +access(all) contract TokenChecker { + + access(all) fun checkBalance(address: Address): UFix64 { + let account = getAccount(address) + + let vaultRef = account.capabilities + .borrow<&FlowToken.Vault>(/public/flowTokenBalance) + ?? panic("Could not borrow FlowToken Vault reference") + + return vaultRef.balance + } + + access(all) fun hasMinimumBalance(address: Address, minimum: UFix64): Bool { + return self.checkBalance(address: address) >= minimum + } +} +``` + +### Configure Contract in flow.json + +Add the `TokenChecker` contract configuration to `flow.json`. The contract needs a **mainnet alias** so that imports can resolve properly during fork testing. + +Update your `flow.json` to include the contract with aliases, using the address you generated in the previous step: + +```json +{ + "contracts": { + "TokenChecker": { + "source": "cadence/contracts/TokenChecker.cdc", + "aliases": { + "testing": "0000000000000008", + "mainnet": "" + } + } + }, + "accounts": { + "mainnet-test": { + "address": "" + } + } +} +``` + +Note: No local private key is required for forked tests. The accounts entry above is included so you can copy/reference the address in your config; keys can be omitted 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 + +Generate the scripts: + +```zsh +flow generate script CheckBalance +flow generate script HasMinimumBalance +``` + +Open `cadence/scripts/CheckBalance.cdc` and replace its contents with: + +```cadence cadence/scripts/CheckBalance.cdc +import "TokenChecker" + +access(all) fun main(addr: Address): UFix64 { + return TokenChecker.checkBalance(address: addr) +} +``` + +Open `cadence/scripts/HasMinimumBalance.cdc` and replace its contents with: + +```cadence cadence/scripts/HasMinimumBalance.cdc +import "TokenChecker" + +access(all) fun main(addr: Address, min: UFix64): Bool { + return TokenChecker.hasMinimumBalance(address: addr, minimum: min) +} +``` + +### Test Your Contract with Forked State + +Generate the test file: + +```zsh +flow generate test TokenChecker +``` + +Open `cadence/tests/TokenChecker_test.cdc` and replace its contents with: + +```cadence cadence/tests/TokenChecker_test.cdc +import Test + +access(all) fun setup() { + // Deploy TokenChecker to the test account + let err = Test.deployContract( + name: "TokenChecker", + path: "../contracts/TokenChecker.cdc", + arguments: [] + ) + Test.expect(err, Test.beNil()) +} + +access(all) fun testCheckBalanceOnRealAccount() { + // Test against a real mainnet account (Flow service account) + let scriptResult = Test.executeScript( + Test.readFile("../scripts/CheckBalance.cdc"), + [Address(0x1654653399040a61)] // Flow service account on mainnet + ) + + Test.expect(scriptResult, Test.beSucceeded()) + + let balance = scriptResult.returnValue! as! UFix64 + // The Flow service account should have a balance + Test.assert(balance > 0.0, message: "Service account should have FLOW tokens") +} + +access(all) fun testHasMinimumBalance() { + let scriptResult = Test.executeScript( + Test.readFile("../scripts/HasMinimumBalance.cdc"), + [Address(0x1654653399040a61), 1.0] + ) + + Test.expect(scriptResult, Test.beSucceeded()) + + let hasMinimum = scriptResult.returnValue! as! Bool + Test.assert(hasMinimum == true, message: "Service account should have at least 1 FLOW") +} +``` + +### 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 + +## Execute Transactions with Account Impersonation + +Fork testing includes built-in account impersonation—you can execute transactions as **any mainnet account** without needing private keys. This lets you test interactions with real accounts and their existing state. + +### Create Transactions + +Generate the transactions: + +```zsh +flow generate transaction SetupFlowTokenVault +flow generate transaction TransferTokens +``` + +Open `cadence/transactions/SetupFlowTokenVault.cdc` and replace its contents with: + +```cadence cadence/transactions/SetupFlowTokenVault.cdc +import "FungibleToken" +import "FlowToken" + +transaction { + prepare(signer: auth(Storage, Capabilities) &Account) { + if signer.storage.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault) == nil { + signer.storage.save(<-FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()), to: /storage/flowTokenVault) + let cap = signer.capabilities.storage.issue<&FlowToken.Vault>(/storage/flowTokenVault) + signer.capabilities.publish(cap, at: /public/flowTokenReceiver) + signer.capabilities.publish(cap, at: /public/flowTokenBalance) + } + } +} +``` + +Open `cadence/transactions/TransferTokens.cdc` and replace its contents with: + +```cadence cadence/transactions/TransferTokens.cdc +import "FungibleToken" +import "FlowToken" + +transaction(amount: UFix64, to: Address) { + let sentVault: @{FungibleToken.Vault} + + prepare(signer: auth(Storage) &Account) { + let vaultRef = signer.storage.borrow( + from: /storage/flowTokenVault + ) ?? panic("Could not borrow reference to the owner's Vault") + + self.sentVault <- vaultRef.withdraw(amount: amount) + } + + execute { + let recipient = getAccount(to) + let receiverRef = recipient.capabilities + .borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver) + ?? panic("Could not borrow receiver reference") + + receiverRef.deposit(from: <-self.sentVault) + } +} +``` + +### Test Transaction Execution with Impersonation + +Add this test function to the existing `cadence/tests/TokenChecker_test.cdc` file: + +```cadence +access(all) fun testTransactionAsMainnetAccount() { + // Impersonate the Flow service account (or any mainnet account) + // No private keys needed - fork testing has built-in impersonation + let serviceAccount = Test.getAccount(0x1654653399040a61) + + // Check initial balance + let initialBalanceScript = Test.executeScript( + Test.readFile("../scripts/CheckBalance.cdc"), + [serviceAccount.address] + ) + Test.expect(initialBalanceScript, Test.beSucceeded()) + let initialBalance = initialBalanceScript.returnValue! as! UFix64 + + // Create a test recipient account and set up FlowToken vault + let recipient = Test.createAccount() + + // Set up the recipient's FlowToken vault + let setupResult = Test.executeTransaction( + Test.Transaction( + code: Test.readFile("../transactions/SetupFlowTokenVault.cdc"), + authorizers: [recipient.address], + signers: [recipient], + arguments: [] + ) + ) + Test.expect(setupResult, Test.beSucceeded()) + + // Execute transaction AS the mainnet service account + // This works because fork testing allows impersonating any account + let txResult = Test.executeTransaction( + Test.Transaction( + code: Test.readFile("../transactions/TransferTokens.cdc"), + authorizers: [serviceAccount.address], + signers: [serviceAccount], + arguments: [10.0, recipient.address] + ) + ) + + Test.expect(txResult, Test.beSucceeded()) + + // Verify the sender's balance decreased + let newBalanceScript = Test.executeScript( + Test.readFile("../scripts/CheckBalance.cdc"), + [serviceAccount.address] + ) + Test.expect(newBalanceScript, Test.beSucceeded()) + let newBalance = newBalanceScript.returnValue! as! UFix64 + + // Balance should have decreased by exactly the transfer amount + Test.assertEqual(initialBalance - 10.0, newBalance) + + // Verify the recipient received the tokens + let recipientBalanceScript = Test.executeScript( + Test.readFile("../scripts/CheckBalance.cdc"), + [recipient.address] + ) + Test.expect(recipientBalanceScript, Test.beSucceeded()) + let recipientBalance = recipientBalanceScript.returnValue! as! UFix64 + // Recipient should have at least 10.0 (may be slightly more due to storage refunds) + Test.assert(recipientBalance >= 10.0, message: "Recipient should have at least 10 FLOW") +} +``` + +### Key Points About Account Impersonation + +1. **Any account can be used**: Call `Test.getAccount(address)` with any mainnet address +2. **No private keys needed**: Fork testing has built-in impersonation—you can sign transactions as any account +3. **Real account state**: The account has its actual mainnet balance, storage, and capabilities +4. **Mutations are local**: Changes only affect your test environment, not the real network +5. **Test complex scenarios**: Impersonate whale accounts, protocol accounts, or any user to test edge cases + +## Run All Tests Together + +Now that you have multiple test files, run them all against the forked network: + +```zsh +flow test --fork mainnet +``` + +This runs all `*_test.cdc` files in your project against mainnet. You should see: + +``` +Test results: "cadence/tests/FlowToken_test.cdc" +- PASS: testFlowTokenSupplyIsPositive + +Test results: "cadence/tests/TokenChecker_test.cdc" +- PASS: testCheckBalanceOnRealAccount +- PASS: testHasMinimumBalance +- PASS: testTransactionAsMainnetAccount +``` + +### Additional Options + +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. + +See also: + +- Strategy: [Testing Strategy on Flow] +- Emulator (fork mode for interactive E2E): [Flow Emulator] +- Networks and access nodes: [Flow Networks] + +:::info +External oracles and off-chain systems + +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 +::: + +### Select tests quickly + +- Run specific files or directories: + +```zsh +flow test cadence/tests/FlowToken_test.cdc cadence/tests/TokenChecker_test.cdc --fork mainnet +``` + +- Optional: narrow by function name with `--name`: + +```zsh +flow test cadence/tests/TokenChecker_test.cdc --name _smoke --fork mainnet +``` + +- Optional: suffix a few functions with `_smoke` for quick PR runs; run the full suite nightly or on protected branches. + +## When to Use Fork Testing + +Fork testing is most valuable for: + +- Integration testing with real onchain contracts and data +- Pre-deployment validation before mainnet releases +- Upgrade testing against production state +- Reproducing issues at a specific block height +- Testing interactions with high-value or protocol accounts +- Validating contract behavior with real-world data patterns + +For strategy, limitations, and best practices, see the guide: [Testing Smart Contracts]. + +## Conclusion + +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 should be able to: + +- **Run Cadence tests against forked networks** using `flow 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 +- **Pin tests to specific block heights** for historical debugging +- **Integrate fork testing** into your development workflow + +Fork testing bridges the gap between local unit tests and testnet deployments, enabling you to catch integration issues early and test against real-world conditions. Use it as part of your pre-deployment validation process, alongside emulator unit tests for determinism and isolation, and testnet deployments for final verification. + +### Next Steps + +- Explore additional assertions and helpers in the [Cadence Testing Framework] +- Add more real-world tests that read from standard contracts like Flow NFT +- Keep unit tests on the emulator for determinism and isolation; run forked integration tests selectively in CI +- Review the [Fork Testing Flags] reference for advanced options +- Learn about [Flow Networks] and public access nodes + + + +[Flow CLI]: ../../../build/tools/flow-cli/index.md +[homebrew]: https://brew.sh +[installation guide]: ../../../build/tools/flow-cli/install.md +[Testing Smart Contracts]: ../../../build/cadence/smart-contracts/testing-strategy.md +[Dependency Manager]: ../../../build/tools/flow-cli/dependency-manager.md +[Fork Testing Flags]: ../../../build/tools/flow-cli/tests.md#fork-testing-flags +[Cadence Testing Framework]: https://cadence-lang.org/docs/testing-framework +[Flow Networks]: ../../../protocol/flow-networks/index.md +[Testing Strategy on Flow]: ../../../build/cadence/smart-contracts/testing-strategy.md +[Flow Emulator]: ../../../build/tools/emulator/index.md + + diff --git a/docs/build/cadence/smart-contracts/testing-strategy.md b/docs/build/cadence/smart-contracts/testing-strategy.md new file mode 100644 index 0000000000..510f4552a0 --- /dev/null +++ b/docs/build/cadence/smart-contracts/testing-strategy.md @@ -0,0 +1,201 @@ +--- +title: Testing Smart Contracts +sidebar_label: Testing Smart Contracts +sidebar_position: 3 +description: A layered testing strategy for Flow—unit tests, forked integration, and a forked emulator sandbox. Guidance for reproducibility and simple CI setup. +keywords: + - testing strategy + - unit testing + - integration testing + - fork testing + - flow test --fork + - flow emulator --fork + - emulator + - testnet + - CI pipeline + - continuous integration + - reproducibility + - fork-height + - block height pinning + - test selection + - smoke tests + - E2E testing + - account impersonation + - test troubleshooting + - golden files + - test automation + - Flow CLI + - Cadence tests + - spork boundaries +--- + +# Testing Smart Contracts + +A single, pragmatic strategy for testing on Flow. Use layers that are deterministic and isolated by default, add realism with forks when needed, and keep a minimal set of live network checks before release. + +## At a glance + +- **Unit & Property — Test Framework**: Hermetic correctness and invariants +- **Integration — `flow test --fork`**: 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 + +## Layers + +### Unit & Property — Test Framework + +- Use `flow test` +- **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 + +See also: [Running Cadence Tests]. + +### Integration — `flow test --fork` + +- **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 +- **Notes**: + - Pin with `--fork-height` 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 + - External oracles/protocols: forked tests do not call off-chain services or other chains; mock these or run a local stub + +See also: [Fork Testing with Cadence], [Fork Testing Flags]. + +### Local Integration Sandbox — `flow emulator --fork` + +- **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**: + - 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]) + + Quick start example: + + ```bash + # Start a fork (pinning height recommended for reproducibility) + flow emulator --fork mainnet --fork-height + ``` + + ```javascript + // In your root component (e.g., App.tsx) + import { FlowProvider } from "@onflow/react-sdk"; + + function App() { + return ( + + {/* Your app components */} + + ); + } + ``` + + ```bash + # Run app + npm run dev + + # Run E2E tests + npx cypress run + ``` + +See also: [Flow Emulator]. + +### Staging — Testnet + +- **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**: + - 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]) + + Quick start example: + + ```javascript + // In your root component (e.g., App.tsx) + import { FlowProvider } from "@onflow/react-sdk"; + + function App() { + return ( + + {/* Your app components */} + + ); + } + ``` + + ```bash + # Run app + npm run dev + + # Run smoke tests + npx cypress run --spec "cypress/e2e/smoke.*" + ``` + +See also: [Flow Networks]. + +### Post-deploy Monitoring (read-only) + +- **Use when**: After releases to confirm invariants and event rates +- **Why**: Detects real-world anomalies quickly +- **Run**: Continuous dashboards/alerts tied to invariants + +## 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. +- **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. + +## CI tips + +- PRs: Run emulator unit/property and forked integration (pinned). Full suite is fine if practical; otherwise a small quick set. +- Nightly/Main: Add a latest pin job and expand fork coverage as needed. +- E2E (optional): Use `flow emulator --fork` at a stable pin and run your browser tests. + +## 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 +- **Defaults**: PRs can run the full fork suite (pinned) or a small quick set; nightly runs broader coverage (+ optional E2E) + +## Troubleshooting tips + +- Re-run at the same `--fork-height`, then at latest +- Compare contract addresses/aliases in `flow.json` +- Diff event/resource shapes against your stored samples +- Check access-node health and CI parallelism/sharding + +## 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` + +## Related docs + +- Guide → Running tests: [Running Cadence Tests] +- 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] + + +[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 +[Flow Emulator]: ../../tools/emulator/index.md +[Fork Testing Flags]: ../../tools/flow-cli/tests.md#fork-testing-flags +[Flow Networks]: ../../../protocol/flow-networks/index.md +[Network Upgrade (Spork) Process]: ../../../protocol/node-ops/node-operation/network-upgrade.md +[Flow CLI Configuration (flow.json)]: ../../tools/flow-cli/flow.json/initialize-configuration.md +[Dependency Manager]: ../../tools/flow-cli/dependency-manager.md +[Cadence Testing Framework]: https://cadence-lang.org/docs/testing-framework diff --git a/docs/build/cadence/smart-contracts/testing.md b/docs/build/cadence/smart-contracts/testing.md index a5bc94b050..271d345879 100644 --- a/docs/build/cadence/smart-contracts/testing.md +++ b/docs/build/cadence/smart-contracts/testing.md @@ -1,41 +1,36 @@ --- -title: Testing Smart Contracts -sidebar_label: Testing Smart Contracts -description: Learn comprehensive testing strategies for Flow smart contracts. Master unit testing, integration testing, and code coverage using the Cadence Testing Framework and Flow CLI. +title: Cadence Testing Framework +sidebar_label: Cadence Testing Framework +description: Learn how to write and run tests for Cadence contracts, scripts, and transactions using the Cadence Testing Framework and Flow CLI. sidebar_position: 4 sidebar_custom_props: icon: 📝 keywords: - - smart contract testing - Cadence testing - - test coverage - unit tests - - integration tests - - Flow CLI - - test automation - - testing framework - - test suites - code coverage + - Flow CLI - test assertions - test helpers - - automated testing - - contract verification - - testing best practices --- # Testing Smart Contracts Testing is an essential part of smart contract development to ensure the correctness and reliability of your code. The Cadence Testing Framework provides a convenient way to write tests for your contracts, scripts and transactions which allows you to verify the functionality and correctness of your smart contracts. +:::info +Looking for high‑level guidance on when to use emulator, forks, or testnet? See [Testing Smart Contracts](./testing-strategy.md). +::: + ## Install Flow CLI -The [Flow CLI](../../../build/tools/flow-cli/index.md) is the primary tool for developing, testing, and deploying smart contracts to the Flow network. +The [Flow CLI] is the primary tool for developing, testing, and deploying smart contracts to the Flow network. -If you haven't installed the Flow CLI yet and have [homebrew](https://brew.sh/) installed, simply run `brew install flow-cli`. Alternatively, refer to the Flow CLI [installation instructions](../../../build/tools/flow-cli/install.md). +If you haven't installed the Flow CLI yet and have [homebrew](https://brew.sh/) installed, simply run `brew install flow-cli`. Alternatively, refer to the Flow CLI [installation instructions]. ## Create a new project -In your preferred code editor, create a new directory for your project and navigate to it in the terminal. Then initialize a new Flow project by running the command `flow init`. This will create a `flow.json` config file that contains the [project's configuration](../../../build/tools/flow-cli/flow.json/configuration.md). +In your preferred code editor, create a new directory for your project and navigate to it in the terminal. Then initialize a new Flow project by running the command `flow init`. This will create a `flow.json` config file that contains the [project's configuration]. ```bash mkdir test-cadence @@ -218,7 +213,7 @@ By leveraging these advanced testing techniques, you can write more robust and r This is a basic example, and there are many more advanced features and techniques you can explore when working with the Cadence Testing Framework. -For more in-depth tutorials and documentation, refer to the official [Cadence language documentation](https://cadence-lang.org/) and the [Flow CLI documentation](../../../build/tools/flow-cli/index.md). +For more in-depth tutorials and documentation, refer to the official [Cadence language documentation](https://cadence-lang.org/) and the [Flow CLI documentation]. ## Testing Requirements @@ -240,7 +235,7 @@ In all three cases, the test code will need to deploy the contracts, configure a ### Cadence tests Cadence comes with built-in support for code coverage, as well as a native testing framework which allows developers to write their tests using Cadence. -This framework is bundled with the [Flow CLI](../../../build/tools/flow-cli/index.md) tool, which includes a dedicated command for running tests (`flow test`). +This framework is bundled with the [Flow CLI] tool, which includes a dedicated command for running tests (`flow test`). You can find examples of Cadence tests in the following projects: [hybrid-custody](https://github.com/onflow/hybrid-custody/tree/main/test), [flow-nft](https://github.com/onflow/flow-nft/tree/master/tests), [flow-ft](https://github.com/onflow/flow-ft/tree/master/tests). Visit the [documentation](https://cadence-lang.org/docs/testing-framework) to view all the available features. @@ -259,31 +254,9 @@ There is also a [repository](https://github.com/m-Peter/flow-code-coverage#readm The Cadence testing framework utilizes the emulator under the hood. -### Go Tests - -Tests in Go can be written using [flow-go-sdk](https://github.com/onflow/flow-go-sdk) and the go test command. - -You can find examples of Go tests in the following projects: [flow-core-contracts](https://github.com/onflow/flow-core-contracts/tree/master/lib/go/test), [flow-nft](https://github.com/onflow/flow-nft/tree/master/lib/go/test), [flow-ft](https://github.com/onflow/flow-ft/tree/master/lib/go/test). - - -These tests are tied to the emulator but can be refactored to run on testnet - - -## Testing Your Application - -### Automated Testing of Contract Code - -All contracts should include test coverage for _all contract functions_. Make sure you've accounted for success and failure cases appropriately. - -Tests should also be runnable in automated environments (CI). You can use the [Cadence testing utils](https://cadence-lang.org/docs/testing-framework) to create tests for your smart contract code. +### Fork testing (overview) -### Stress Testing Live Applications Before Mainnet - -Once you deployed your application to the testnet, you should record how your application handles non-trivial amounts of traffic to ensure there are no issues. - - -Get familiar with the [Cadence anti-patterns](https://cadence-lang.org/docs/anti-patterns) to avoid avoid problematic or unintended behavior. - +For running tests against a fork of mainnet/testnet, see the dedicated tutorial: [Fork Testing with Cadence (Step-by-Step)]. For available flags, see [Fork Testing Flags]. To interactively explore a forked state outside the test framework, see [Flow Emulator]. For when to use forks vs emulator, see [Testing Strategy on Flow]. ## References @@ -293,3 +266,14 @@ Get familiar with the [Cadence anti-patterns](https://cadence-lang.org/docs/anti - [hybrid-custody](https://github.com/onflow/hybrid-custody/tree/main/test), - [flow-nft](https://github.com/onflow/flow-nft/tree/master/tests), - [flow-ft](https://github.com/onflow/flow-ft/tree/master/tests). + + +[Testing Strategy on Flow]: ./testing-strategy.md +[Flow CLI]: ../../../build/tools/flow-cli/index.md +[installation instructions]: ../../../build/tools/flow-cli/install.md +[project's configuration]: ../../../build/tools/flow-cli/flow.json/configuration.md +[Flow CLI documentation]: ../../../build/tools/flow-cli/index.md +[Network Upgrade (Spork) Process]: ../../../protocol/node-ops/node-operation/network-upgrade.md +[Fork Testing Flags]: ../../tools/flow-cli/tests.md#fork-testing-flags +[Flow Emulator]: ../../tools/emulator/index.md +[Fork Testing with Cadence (Step-by-Step)]: ../../../blockchain-development-tutorials/cadence/fork-testing/index.md \ No newline at end of file diff --git a/docs/build/tools/emulator/index.md b/docs/build/tools/emulator/index.md index d22893cc34..06e1a2017b 100644 --- a/docs/build/tools/emulator/index.md +++ b/docs/build/tools/emulator/index.md @@ -2,13 +2,36 @@ title: Flow Emulator description: Local Flow network for development and testing sidebar_position: 3 +keywords: + - Flow Emulator + - local development + - testing + - flow emulator --fork + - fork mode + - emulator flags + - mainnet fork + - testnet fork + - fork-height + - fork-host + - gRPC server + - REST API + - snapshots + - persistent storage + - block time + - code coverage + - debugging + - service account + - Flow CLI + - local blockchain + - E2E testing + - off-chain mocking --- The Flow Emulator is a lightweight tool that emulates the behavior of the real Flow network for local development and testing. ## Installation -The emulator is included with the [Flow CLI](../flow-cli/index.md). Follow the [installation guide](../flow-cli/install.md) to get started. +The emulator is included with the [Flow CLI]. Follow the [installation guide] to get started. ## Quick Start @@ -18,10 +41,10 @@ First, create a `flow.json` configuration file: flow init --config-only ``` -Then start the Flow Emulator: +Then start the Flow Emulator in fork mode (defaults to mainnet when value omitted): ```bash -flow emulator +flow emulator --fork ``` You'll see output similar to: @@ -39,17 +62,98 @@ This starts a local Flow network with: - REST API on `http://localhost:8888` - Admin API on port `8080` -## Common Options +## Available Commands + +- `snapshot`: Create/Load/List emulator snapshots. See: [Create Emulator Snapshot] + +## Key Flags + +- **Networking** + - `--host `: Host to listen on for gRPC/REST/Admin (default: all interfaces) + - `--port, -p `: gRPC port (default `3569`) + - `--rest-port `: REST API port (default `8888`) + - `--admin-port `: Admin API port (default `8080`) + - `--debugger-port `: Debug Adapter Protocol port (default `2345`) + - `--grpc-debug`: Enable gRPC server reflection + - `--rest-debug`: Enable REST API debug output + +- **State & Persistence** + - `--persist`: Enable persistent storage (default disabled) + - `--dbpath `: Directory for on-disk state (default `./flowdb`) + - `--sqlite-url `: Use SQLite storage backend + - `--redis-url `: Use Redis storage backend + - `--checkpoint-dir `: Load state from checkpoint directory + - `--state-hash `: Load state from checkpoint state hash + +- **Forking** + - `--fork `: Start the emulator in fork mode using a network from `flow.json`. If provided without a value, defaults to `mainnet`. + - `--fork-host `: Access node to query when forking Mainnet/Testnet + - `--fork-height `: Starting block height when forking + +- **Cadence & VM** + - `--block-time, -b `: Time between sealed blocks (e.g. `1s`, `300ms`) + - `--coverage-reporting`: Enable code coverage reporting + - `--computation-reporting`: Enable computation reporting + - `--legacy-upgrade`: Enable legacy contract upgrade behavior + - `--scheduled-transactions`: Enable scheduled transactions (default true) + - `--script-gas-limit `: Gas limit for scripts (default `100000`) + - `--transaction-max-gas-limit `: Max transaction gas limit (default `9999`) + - `--transaction-expiry `: Transaction expiry in blocks (default `10`) + - `--skip-tx-validation`: Skip tx signature and sequence number checks + - `--simple-addresses`: Use sequential addresses starting with `0x01` + - `--storage-limit`: Enforce account storage limit (default true) + - `--storage-per-flow `: MB of storage per 1 FLOW token + - `--token-supply `: Initial FLOW token supply (default `1000000000.0`) + - `--transaction-fees`: Enable transaction fees + - `--setup-evm`: Deploy EVM contracts (default true) + - `--setup-vm-bridge`: Deploy VM Bridge contracts (default true) + +- **Service Account & Identity** + - `--chain-id `: Address generation chain (default `emulator`) + - `--service-priv-key ` / `--service-pub-key `: Service account keys + - `--service-sig-algo `: Service key signature algo (default `ECDSA_P256`) + - `--service-hash-algo `: Service key hash algo (default `SHA3_256`) + - `--min-account-balance `: Minimum account balance / account creation cost + - `--contracts`: Deploy common contracts on start + - `--contract-removal`: Allow contract removal for development (default true) + - `--init`: Initialize a new account profile + +- **Logging & Output** + - `--verbose, -v`: Verbose logging + - `--log-format `: Logging output format (default `text`) + +- **Snapshots** + - `--snapshot`: Enable snapshots in the emulator + +## Examples ```bash -# Start with verbose logging +# Verbose logs flow emulator --verbose -# Set custom block time (e.g., 1 second between blocks) +# Custom ports +flow emulator --port 9000 --rest-port 9001 --admin-port 9002 + +# Custom block time (1 second between blocks) flow emulator --block-time 1s -# Persist state between restarts -flow emulator --persist +# Persist state on disk +flow emulator --persist --dbpath ./flowdb + +# Fork from Mainnet using flow.json +flow emulator --fork + +# Fork from Testnet using flow.json and pin to a height +flow emulator --fork testnet --fork-height 12345678 + +# Fork from Testnet at a specific height +flow emulator --fork-host access.devnet.nodes.onflow.org:9000 --fork-height 12345678 + +# Disable fees and use simple addresses for local testing +flow emulator --transaction-fees=false --simple-addresses + +# Enable code coverage reporting +flow emulator --coverage-reporting # Change the gRPC and REST API ports flow emulator --port 9000 --rest-port 9001 @@ -58,17 +162,37 @@ flow emulator --port 9000 --rest-port 9001 flow emulator --help ``` -For all available options, see the [CLI commands overview](../flow-cli/index.md). +For the complete and current list of flags, run: + +```bash +flow emulator --help +``` ## Debugging & Testing - **Code Coverage**: Add `--coverage-reporting` flag and visit `http://localhost:8080/emulator/codeCoverage` - **Debugging**: Use `#debugger()` pragma in Cadence code for breakpoints +- **Fork mode note**: When using `flow emulator --fork`, only Flow chain state is available. External oracles/APIs and cross-chain reads are not live; mock these or run local stub services for E2E. ## Snapshots The Flow CLI provides a command to create emulator snapshots, which are points in blockchain history you can later jump to and reset the state to that moment. This can be useful for testing where you establish a beginning state, run tests and after revert back to the initial state. +### Quick snapshot workflow + +```bash +# 1) Start the emulator with snapshots enabled (in a separate terminal) +flow emulator --snapshot + +# 2) Create a snapshot at the current state +flow emulator snapshot create baseline + +# 3) Make changes, run tests, etc. + +# 4) Reset the emulator back to the snapshot +flow emulator snapshot load baseline +``` + ### Create a new snapshot Create a new emulator snapshot at the current block with a name of `myInitialState`. @@ -93,8 +217,13 @@ To list all the existing snapshots we previously created and can load to run: flow emulator list ``` -To learn more about using the Emulator, have a look at the [README of the repository](https://github.com/onflow/flow-emulator). - ## Additional Resources -For advanced configuration options, see the [Flow Emulator repository](https://github.com/onflow/flow-emulator/). +To learn more about using the Emulator, please have a look at the [public GitHub repository]. + + + +[Flow CLI]: ../flow-cli/index.md +[installation guide]: ../flow-cli/install.md +[Create Emulator Snapshot]: ../flow-cli/utils/snapshot-save.md +[public GitHub repository]: https://github.com/onflow/flow-emulator \ No newline at end of file diff --git a/docs/build/tools/flow-cli/tests.md b/docs/build/tools/flow-cli/tests.md index 369d812cac..57af647155 100644 --- a/docs/build/tools/flow-cli/tests.md +++ b/docs/build/tools/flow-cli/tests.md @@ -3,6 +3,29 @@ title: Running Cadence Tests sidebar_label: Running Cadence Tests description: How to run Cadence tests from the CLI sidebar_position: 11 +keywords: + - flow test + - Cadence tests + - Flow CLI + - test command + - test flags + - code coverage + - fork testing + - flow test --fork + - fork-height + - fork-host + - mainnet fork + - testnet fork + - test discovery + - test aliases + - testing configuration + - test selection + - test by name + - random testing + - coverage reporting + - test automation + - integration testing + - spork boundaries --- The Flow CLI provides a straightforward command to execute Cadence tests, enabling developers to validate their scripts and smart contracts effectively. @@ -106,15 +129,15 @@ To learn more about writing tests in Cadence, visit the [Cadence Testing Framewo --- -### Running Specific Tests +### Running Specific Tests and Files -If you wish to run a specific test script rather than all tests, you can provide the path to the test file: +Run specific test scripts or directories by providing their paths: ```shell -flow test path/to/your/test_script_test.cdc +flow test path/to/your/test_script_test.cdc path/to/another_test.cdc tests/subsuite/ ``` -This will execute only the tests contained in the specified file. +This executes only the tests contained in the specified files and directories. --- @@ -225,3 +248,53 @@ flow test --name=testSumOfTwo This command will run only the test function named `testSumOfTwo` across all test scripts that contain it. To dive deeper into testing the functionality of your Cadence scripts and contracts, explore the [Cadence Testing Framework](https://cadence-lang.org/docs/testing-framework) documentation. + +--- + +### Fork Testing Flags + +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). + +#### --fork + +- Type: `string` +- Default: `""` (empty). If provided without a value, defaults to `mainnet`. + +Fork tests from a network defined in `flow.json`. The CLI resolves the GRPC access host and chain ID from the selected network configuration. + +```shell +flow test --fork # Uses mainnet by default +flow test --fork testnet # Uses testnet +flow test --fork mynet # Uses a custom network defined in flow.json +``` + +Requirements: + +- The network must exist in `flow.json` +- The network must have a valid `host` configured + +#### --fork-host + +- Type: `string` +- Default: `""` + +Directly specify a GRPC access node host. This bypasses the `flow.json` network lookup. + +```shell +flow test --fork-host access.mainnet.nodes.onflow.org:9000 +``` + +See public access node URLs in [Flow Networks](../../../protocol/flow-networks/index.md). + +#### --fork-height + +- Type: `uint64` +- Default: `0` + +Pin the fork to a specific block height for historical state testing. Only blocks from the current spork (since the most recent network upgrade) are available via public access nodes; earlier blocks are not accessible via public access nodes. + +```shell +flow test --fork mainnet --fork-height 85432100 +``` + +> Note: Historical data beyond spork boundaries is not available via standard access nodes. See the [Network Upgrade (Spork) Process](../../../protocol/node-ops/node-operation/network-upgrade.md). diff --git a/docs/protocol/flow-networks/index.md b/docs/protocol/flow-networks/index.md index 4c23c8420f..8ade53bf55 100644 --- a/docs/protocol/flow-networks/index.md +++ b/docs/protocol/flow-networks/index.md @@ -27,6 +27,7 @@ For more information on how to access these networks, refer to the following gui - [Flow Testnet](./accessing-testnet.md) - [Flow Mainnet](./accessing-mainnet.md) + ### Network There are two primary ways to access onchain data within the Flow network; Access Nodes and Light nodes. Access Nodes are the node type that are most useful for developers, as they provide access to the Flow network via the following API endpoints: