Build on Flow: JS Testing - 2. Setup Emulator and Deploy Contracts
Tags: javascript, testing, flow, blockchain
Published: 2023-05-26 06:21:08

## Intro

[Last Time](https://dev.to/onflow/build-on-flow-js-testing-1-introduction-2g16) we've covered how you can get started with testing in your project. That article covers use of `init` and `make` commands in JS Testing Framework and how to use them to scaffold your testing enviroment.

We will assume you've gone through that process and have ready setup.

This time we will cover how you can deploy your newly developed contract to emulator to be able to run scripts and transactions against it.

## Prerequisites

You will need to install Flow CLI in order to be able to spin up Flow Emulator. Follow [instructions](https://developers.flow.com/tools/flow-cli/install) for your OS on Developer Portal.

If you haven't prepared your environment - follow instructions from [previous article](https://dev.to/onflow/build-on-flow-js-testing-1-introduction-2g16).

## Setup Cadence Folder

Most of the methods will allow you to use Cadence code straight from the `.cdc` files. The only requirement is to use specific folder structure in designated folder.

Let's create `cadence` folder in the root of your project. Then create 3 new folders inside of it:

- `contracts` - will hold all the contracts you would want to deploy
- `transactions` - for any transactions code
- `scripts` - same for scripts

> Please note that folders should be called exactly in the same manner or they won't work. We have planned the task, which would allow you to use custom names, but it's not implemented yet

In order for framework to know what location you want to use you will need to call `init` method:

```js
import path from "path";
import { emulator, init } from "@onflow/flow-js-testing";

describe("interactions - sendTransaction", () => {
  // Instantiate emulator and path to Cadence files
  beforeEach(async () => {
    const basePath = path.resolve(__dirname, "../cadence");
    await init(basePath);
    return emulator.start();
  });

  // Stop emulator, so it could be restarted
  afterEach(async () => {
    return emulator.stop();
  });
});
```

## Setup Emulator

In order to test any network interactions, we need instance of emulator running. Frameworks handle the process with `emulator` instance, which exposes two methods - `start` and `stop`. Those will handle running `flow emulator` process with necessary flags and extra steps after emulator will be stopped.

> You can reference code above to see how we use it in `beforeEach`/`afterEach` blocks.

## How to Deploy a contract?

Framework have two handy functions, which will help you deploy contracts:

- `deployContract` - allows you to pass contract code as a string (handy, when you are just playing around)
- `deployContractByName`- will allow you to deploy contract defined via file in your `cadence` folder (which you pass, when calling

They are quite similar in function, but `deployContractByName` provides you an easy way of deploying contracts located in your `cadence/contracts` folder. Let's create a file `HelloWorld.cdc` inside ouf our `contracts` folder and paste the following in:

```swift
pub contract HelloWorld{
    pub let greetings: String

    init(){
        self.greetings = "Hello, from Cadence"
    }
}
```

Our little contract only have single field, which we can read in the future. Let me show you how we can test it.

Create new test suit with `make` command:

```shell
npx @onflow/flow-js-testing make first
```

This command will run `make` tool provided by testing framework and create a `first.js` file, which will have a basic setup for you. Since deploying contract on Flow is just sending specifically designed transaction, we will use `shallPass` method to ensure everything works:

```js
import path from "path";
import { init, emulator, shallPass, deployContractByName } from "@onflow/flow-js-testing";

// Increase timeout if your tests failing due to timeout
jest.setTimeout(10000);

describe("deploy", () => {
  beforeEach(async () => {
    const basePath = path.resolve(__dirname, "../cadence");
    const logging = false;

    await init(basePath);
    return emulator.start({ logging });
  });

  // Stop emulator, so it could be restarted
  afterEach(async () => {
    return emulator.stop();
  });

  // We will put next block here
  // ========>
});
```

Our first test will be super simple. We will wrap `deployContractByName` with `shallPass` and await the result of that computation:

```js
test("deploy Hello", async () => {
  await shallPass(deployContractByName({ name: "Hello" }));
});
```

Well done! 👍 But scenarios like that is never the case. Contracts are usually much more complicated and accept multiple arguments to init it's field. Let's create another contract `Message.cdc` in our `contracts` folder and populate it with following Cadence code:

```swift
pub contract Message{
    pub let message: String

    init(message: String){
        self.message = message
    }
}
```

Now we need to pass arguments, when we deploy contract. We can do this by specifying `args` field on the object we pass into `deployContractByName`. It should be an array of values in the same order we defined them on `init` method of our contract.

```js
test("deploy Message", async () => {
  const message = "Cadence is great!";

  await shallPass(
    deployContractByName({
      name: "Message",
      args: [message],
    })
  );
});
```

> Note that framework will handle all the type conversions for you! 😎
>
> You can try to add another argument to ensure that test will fail, ensuring you are doing
> everything correctly.

Another function we have at our disposal is `deployContract`. It has pretty much the same API, except it expects `code` value for your Cadence instead of a file name. Let's make a simple test to
illustrate how you can use it.

```js
test("deploy Custom", async () => {
  await shallPass(
    deployContract({
      code: `
          pub contract Custom{
            pub let message: String
            
            init(){
              self.message = "This is custom contract! Neat, ha? :)"
            }
          }
        `,
    })
  );
});
```

You can pass arguments in the same fashion we did above for `deployContractByName` by specifying `args` field.

> Originally the purpose of this function was to process and consume arguments from
> `deployContractByName` and wasn't exported. After some consideration we've exported it to enable
> people who just learning Cadence to experiment quikly

You can find detailed explanation of both functions on [Flow Developer Portal - Contract Management (https://developers.flow.com/tooling/flow-js-testing/contracts)

## Too slow!

Sometimes scenario that you are trying to test takes more time than default Jest timeout - 5 seconds. You can control this by increasing the timeout to next reasonable value:

```js
// Place this after import lines
import path from "path";
import { deployContractByName, emulator, executeScript, init } from "@onflow/flow-js-testing";

jest.setTimeout(20000);

// the rest of the test setup below 👇
```

> Some CI environments might be slower than you local machine, so if you see randomly failing tests - try to increase this value.

That's all, folks! [Next time](https://dev.to/maxstalker/build-on-flow-js-testing-3-execute-scripts-and-send-transactions-5hac) we will take a look how we can execute scripts, sign and send
transactions.