# Migrate Mocha tests from Hardhat 2

Description: How to migrate Mocha tests from Hardhat 2 to Hardhat 3

Note: This document was authored using MDX

  Source: https://github.com/NomicFoundation/hardhat-website/tree/main/src/content/docs/docs/migrate-from-hardhat2/guides/mocha-tests.mdx

This guide walks you through the changes needed to migrate your Mocha tests from Hardhat 2 to Hardhat 3.

## ESM

Hardhat 3 is ESM-first, so JavaScript test files (`.js`) are treated as ES modules. See the [ESM migration guide](/docs/migrate-from-hardhat2/guides/migrate-to-esm) for the conversion steps, or for how to keep your tests as CommonJS with a `.cjs` extension.

If you keep your tests as CommonJS, you can't `require("hardhat")` at the top level. Use a dynamic `import` from a `before` hook instead:

```js
describe("suite", function () {
  let hre;
  before(async function () {
    ({ default: hre } = await import("hardhat"));
  });

  it("some test", async function () {
    // use the hre
  });
});
```

## Network connections

One of the biggest changes in Hardhat 3 is how network connections work. You don't have a single, global network connection anymore. Instead, you create and manage network connections explicitly. For example, if you have a test that uses the JSON-RPC provider:

```ts
describe("suite", function () {
  it("some test", async function () {
    const blockNumber = await hre.network.provider.send("eth_blockNumber");
  });
});
```

You now have to create a network connection first:

```ts
describe("suite", function () {
  it("some test", async function () {
    const { provider } = await hre.network.create();
    const blockNumber = await provider.send("eth_blockNumber");
  });
});
```

Most of the time, you'll want to use the same provider for multiple tests. If you're using ESM syntax, you can use top-level await and define it as a shared variable:

```ts
const { provider } = await hre.network.create();

describe("suite", function () {
  it("some test", async function () {
    const blockNumber = await provider.send("eth_blockNumber");
  });
});
```

If you're using CommonJS modules instead, you can define the provider in a `before` block:

```ts
let provider;

describe("suite", function () {
  before(async function () {
    ({ provider } = await hre.network.create());
  });

  it("some test", async function () {
    const blockNumber = await provider.send("eth_blockNumber");
  });
});
```

## The ethers.js object

In Hardhat 2, the `hardhat-ethers` plugin adds an `ethers` object to the Hardhat Runtime Environment, meaning you can do things like this in a test:

```ts
const hre = require("hardhat");

describe("suite", function () {
  it("some test", async function () {
    const contract = await hre.ethers.deployContract("MyContract");
  });
});
```

In Hardhat 3, this same `ethers` object is included as part of each created network connection:

```ts
import hre from "hardhat";

describe("suite", function () {
  let ethers;
  before(async function () {
    ({ ethers } = await hre.network.create());
  });

  it("some test", async function () {
    const contract = await ethers.deployContract("MyContract");
  });
});
```

## Chai matchers changes

Some of the Chai matchers have changed in Hardhat 3, to make them work with multiple network connections.

These changes are:

- Some matchers take an instance of `HardhatEthers` (i.e. the `ethers` object from the network connection), as shown in this list.
- `.reverted` is now `.revert(ethers)`
- `.revertedWithoutReason()` is now `.revertedWithoutReason(ethers)`
- `changeEtherBalance`, `changeEtherBalances`, `changeTokenBalance`, and `changeTokenBalances` now take an instance of `HardhatEthers` as the first argument.

## Hardhat network helper changes

The `@nomicfoundation/hardhat-network-helpers` package is now a plugin. Instead of importing its functions directly, now you get the helpers as part of the network connection:

```ts
import { network } from "hardhat";
const { networkHelpers } = await network.create();

await networkHelpers.mine(5);
```
