# Collecting test coverage with Blueprint (https://docs-dmpho5eos-ton-core-docs.vercel.app/llms/contract-dev/blueprint/coverage/content.md)



<Callout type="note">
  [Acton](/llms/contract-dev/acton/content.md) is the recommended tool for new smart contract projects. Blueprint remains supported for existing projects.
</Callout>

<Callout>
  This page covers coverage calculated on TVM assembly instructions. Path- and source-line coverage is not implemented.
</Callout>

There are two main ways to calculate coverage of your `@ton/sandbox` tests.

## Easy way [#easy-way]

<Callout type="caution" title="Library compatibility">
  For this way to work correctly, a version of `@ton/sandbox >= 0.37.2` and `@ton/blueprint >= 0.41.0` is needed.
</Callout>

When using Blueprint, the only thing you need to collect coverage is to run the following command:

```bash
blueprint test --coverage
```

Results will appear in the `coverage/` directory as HTML files with reports for each of your contracts.

## Customizable way [#customizable-way]

There might be some reasons why you don't want to simply use `--coverage`.

* You don't want to collect coverage for all contracts.
* You use `@ton/sandbox` but don't use `@ton/blueprint`.
* Not all contracts have source code. (For example, for each transaction, you deploy a new contract, and you don't have wrappers for it.)
* You want to get the raw data and customize the output.

<div className="fd-steps">
  <div className="fd-step">
    ### Enable coverage collection [#1-enable-coverage-collection]

    Before running tests, add `blockchain.enableCoverage()` to collect coverage data:

    ```typescript
    import {Blockchain} from '@ton/sandbox';

    describe('Contract Tests', () => {
        let blockchain: Blockchain;
        let contract: SandboxContract<MyContract>;

        beforeEach(async () => {
            blockchain = await Blockchain.create();

            blockchain.enableCoverage();
            // or for COVERAGE=true mode only
            // blockchain.enableCoverage(process.env["COVERAGE"] === "true");

            // Deploy your contract
            contract = blockchain.openContract(MyContract.fromInit());
            // ... deployment logic
        });

        // Your tests here...
    });
    ```
  </div>

  <div className="fd-step">
    ### Collect coverage after tests [#2-collect-coverage-after-tests]

    ```typescript
    afterAll(() => {
        const coverage = blockchain.coverage(contract);
        console.log(coverage?.summary());
    })
    ```
  </div>

  <div className="fd-step">
    ### Generate reports [#3-generate-reports]

    ```typescript
    import {writeFileSync} from 'fs';

    afterAll(() => {
        const coverage = blockchain.coverage(contract);
        if (!coverage) return;

        // Generate HTML report for detailed analysis
        const htmlReport = coverage.report("html");
        writeFileSync("coverage.html", htmlReport);

        // Print text report to console
        const textReport = coverage.report("text");
        console.log(textReport);
    });
    ```
  </div>
</div>

## Understanding coverage data [#understanding-coverage-data]

### Coverage summary [#coverage-summary]

The coverage summary provides key metrics about your test coverage:

```typescript
const summary = coverage.summary();

console.log(`Total lines: ${summary.totalLines}`);
console.log(`Covered lines: ${summary.coveredLines}`);
console.log(`Coverage percentage: ${summary.coveragePercentage.toFixed(2)}%`);
console.log(`Total gas consumed: ${summary.totalGas}`);
console.log(`Total hits: ${summary.totalHits}`);

// Instruction-level statistics
summary.instructionStats.forEach(stat => {
    console.log(`${stat.name}: ${stat.totalHits} hits, ${stat.totalGas} gas, avg ${stat.avgGas}`);
});
```

### Coverage reports [#coverage-reports]

* **HTML Report**: Interactive report with highlighting and line-by-line coverage details
* **Text Report**: Console-friendly report with coverage information and marked code

## Advanced usage patterns [#advanced-usage-patterns]

### Multiple test suites [#multiple-test-suites]

When running multiple test files, you might want to merge coverage data:

```typescript
// In first test file
const coverage1 = blockchain.coverage(contract);
if (!coverage1) return;
const coverage1Json = coverage1.toJson();
writeFileSync("coverage1.json", coverage1Json);

// In second test file
const coverage2 = blockchain.coverage(contract);
if (!coverage2) return;
const coverage2Json = coverage2.toJson();
writeFileSync("coverage2.json", coverage2Json);

// Merge coverage data in separate script after tests
const savedCoverage1 = Coverage.fromJson(readFileSync("coverage1.json", "utf-8"));
const savedCoverage2 = Coverage.fromJson(readFileSync("coverage2.json", "utf-8"));
const totalCoverage = savedCoverage1.mergeWith(savedCoverage2);

console.log(`Combined coverage: ${totalCoverage.summary().coveragePercentage}%`);
```

## Coverage for multiple contracts [#coverage-for-multiple-contracts]

When testing systems with multiple contracts:

```typescript title="Not runnable"
describe('Multi-Contract System', () => {
    let blockchain: Blockchain;
    let contract1: SandboxContract<Contract1>;
    let contract2: SandboxContract<Contract2>;

    beforeEach(async () => {
        blockchain = await Blockchain.create();
        blockchain.enableCoverage();

        // Deploy multiple contracts
        contract1 = blockchain.openContract(Contract1.fromInit());
        contract2 = blockchain.openContract(Contract2.fromInit());
    });

    afterAll(() => {
        // Get coverage for each contract separately
        const coverage1 = blockchain.coverage(contract1);
        const coverage2 = blockchain.coverage(contract2);

        if (!coverage1 || !coverage2) return;

        console.log('Contract 1 Coverage:', coverage1.summary().coveragePercentage);
        console.log('Contract 2 Coverage:', coverage2.summary().coveragePercentage);

        // Generate separate reports
        writeFileSync("contract1-coverage.html", coverage1.report("html"));
        writeFileSync("contract2-coverage.html", coverage2.report("html"));
    });
});
```

## Interpret results [#interpret-results]

The usual report looks like this:

<Image src="/images/coverage-report.png" />

Apart from the header statistics, the line-by-line coverage report is the most informative. Most fields are self-explanatory; the code section shows per-instruction hit counts (blue) and gas cost (red). This helps you analyze both coverage and gas efficiency.

<Callout>
  To understand the TVM assembly output, read [TVM](/llms/foundations/whitepapers/tvm/content.md).
</Callout>
