> ## Documentation Index
> Fetch the complete documentation index at: https://cofhe-docs.fhenix.zone/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing

> Common patterns for writing Hardhat tests with the CoFHE plugin

This page shows the common patterns for writing Hardhat tests with the CoFHE plugin.

## Test setup

Use `hre.cofhe.createClientWithBatteries` in a `before` hook. It creates and connects a fully configured `CofheClient` — including a self-permit — so the client is ready for every test in the suite:

```typescript theme={null}
import hre from 'hardhat';
import { CofheClient } from '@cofhe/sdk';
import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers';

let cofheClient: CofheClient;
let signer: HardhatEthersSigner;

before(async () => {
  [signer] = await hre.ethers.getSigners();
  cofheClient = await hre.cofhe.createClientWithBatteries(signer);
});
```

See [Client](/client-sdk/hardhat-plugin/client) for manual setup options.

## Encrypt → store → decrypt

The core test loop: encrypt a value, pass it to a contract, then decrypt the stored handle.

```typescript theme={null}
import { Encryptable, FheTypes } from '@cofhe/sdk';
import { expect } from 'chai';

// 1. Encrypt the input
const encrypted = await cofheClient
  .encryptInputs([Encryptable.uint32(100n)])
  .execute();

// 2. Send to contract
const tx = await testContract.setValue(encrypted[0]);
await tx.wait();

// 3. Read the stored handle
const ctHash = await testContract.storedValue();

// 4. Decrypt for display
const decrypted = await cofheClient
  .decryptForView(ctHash, FheTypes.Uint32)
  .execute();

expect(decrypted).to.equal(100n);
```

## Reading plaintext directly

In tests you can bypass the normal decrypt flow and read the raw plaintext stored by the mock contracts. This is useful for asserting contract state without needing a permit:

```typescript theme={null}
import hre from 'hardhat';

// Get raw plaintext value
const plaintext = await hre.cofhe.mocks.getPlaintext(ctHash);

// Or use the assertion shorthand
await hre.cofhe.mocks.expectPlaintext(ctHash, 100n);
```

See [Mock Contracts](/client-sdk/hardhat-plugin/mock-contracts) for details.

## Permits

`createClientWithBatteries` pre-generates a self-permit, so `decryptForView` and `decryptForTx().withPermit()` work immediately. For tests that need named permits or multiple signers, create them explicitly:

```typescript theme={null}
import { PermitUtils } from '@cofhe/sdk/permits';

const permit = await cofheClient.permits.createSelf({
  issuer: signer.address,
  name: 'My Test Permit',
});

// Select it as the active permit
const permitHash = PermitUtils.getHash(permit);
cofheClient.permits.selectActivePermit(permitHash);
```

Alternatively, create a separate client for each signer:

```typescript theme={null}
import hre from 'hardhat';

const [bob, alice] = await hre.ethers.getSigners();
const bobClient = await hre.cofhe.createClientWithBatteries(bob);
const aliceClient = await hre.cofhe.createClientWithBatteries(alice);
```

## `decryptForTx` patterns

[`decryptForTx`](/client-sdk/guides/decrypt-to-tx) returns a `{ ctHash, decryptedValue, signature }` tuple for on-chain submission. The permit mode must be selected explicitly.

### Globally allowed values (`.withoutPermit()`)

When a contract calls `FHE.allowPublic(handle)`, anyone can decrypt without a permit:

```typescript theme={null}
import { expect } from 'chai';

const result = await cofheClient
  .decryptForTx(publicCtHash)
  .withoutPermit()
  .execute();

expect(result.decryptedValue).to.equal(55n);
```

### Access-controlled values (`.withPermit()`)

For handles restricted by ACL policy, supply a permit:

<CodeGroup>
  ```typescript Explicit permit theme={null}
  const result = await cofheClient
    .decryptForTx(ctHash)
    .withPermit(permit)
    .execute();

  expect(result.decryptedValue).to.equal(99n);
  ```

  ```typescript Active permit theme={null}
  // resolves the active permit automatically
  const result = await cofheClient
    .decryptForTx(ctHash)
    .withPermit()
    .execute();

  expect(result.decryptedValue).to.equal(99n);
  ```
</CodeGroup>

### Submitting the result on-chain

Pass the result directly to your contract:

```typescript theme={null}
await myContract.revealValue(
  result.ctHash,
  result.decryptedValue,
  result.signature
);
```

For a full walkthrough of `decryptForTx`, see [Decrypt to Transact](/client-sdk/guides/decrypt-to-tx).
