Blockchain Development from Scratch with Typescript #4: Added Jest for Node.js testing

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@superoo7·
0.000 HBD
Blockchain Development from Scratch with Typescript #4: Added Jest for Node.js testing
![New_Mockup_2_copy.png](https://cdn.utopian.io/posts/6fb2b4467fe19273e77633132318fd365700New_Mockup_2_copy.png)

#### What Will I Learn?

- Setup Jest workflow with TypeScript
- Basic testing with Jest

#### Requirements

- Understanding of Typescript
- Understanding basic of Object Oriented Programming and Data Structure
- Understand basic of Test Driven Development (Describe, It)

#### Difficulty

Advanced

#### Description

In this video, we will add basic testing to our existing blockchain app.

# Why testing?

To make our app more scalable and source code easier to be understand by others, we will add in testing to our project. This will ensure that when the blockchain being update, it does not break the existing features.

In this video tutorial, I will be using Jest, since it is the easiest to be setup and used for JavaScript project.

# Before starting the project

The project started with the branch `blockchain-3` ([Github link](https://github.com/superoo7/blockchain-tutorial/tree/blockchain-3)) and ended with the branch `blockchain-4` ([Github link](https://github.com/superoo7/blockchain-tutorial/tree/blockchain-4))

I added some adjustment in the source code. First, I added prettier in the setting. This is my prettier setup: (`.vscode/settings.json`)

```
{
    "tslint.enable": true,
    "typescript.tsdk": "./node_modules/typescript/lib",
    "files.exclude": {
      "**/.git": true,
      "**/.svn": true,
      "**/.hg": true,
      "**/.DS_Store": true,
      "**/node_modules": false,
      "**/*.map": {
        "when": "$(basename)"
      },
      "**/*.js": {
        "when": "$(basename).ts"
      },
      "**/*?.js": {
        "when": "$(basename).tsx"
      },
      "**/*.sqlite": true
    },
    "search.exclude": {
      "**/node_modules": true,
      "**/bower_components": true,
      "**/*.map": true,
      "**/dist": true,
      "**/dist-test": true
    },
    "editor.tabSize": 2,
    "editor.insertSpaces": true,
    "files.eol": "\n",
    "files.trimTrailingWhitespace": true,
    "prettier.printWidth": 100,
    "prettier.semi": false,
    "prettier.tabWidth": 2,
    "prettier.useTabs": false,
    "prettier.singleQuote": true,
    "prettier.trailingComma": "none",
    "prettier.disableLanguages": ["markdown", "json"],
    "editor.formatOnSave": true
  }
```

In addition to that, you need to initialize the project with `npm init -y`. (I didn't do that in the previous series)

# Install dependencies

There are 3 dependencies we need to install in this tutorial

- [jest](https://www.npmjs.com/package/jest) - a testing framework created by Facebook team
- [@types/jest](https://www.npmjs.com/package/@types/jest) - types file for Jest (for TypeScript)
- [concurrently](https://www.npmjs.com/package/concurrently) - this library allows you to execute 2 codes concurrently.

`yarn add --dev jest @types/jest concurrently`

Then, setup the command in `package.json` in the `script` key.

```
  "scripts": {
    "test": "concurrently \"tsc -w\" \"jest --watchAll\""
  },
```

When you run `yarn test`, it will execute typescript watch (`tsc -w`) alongside with jest watch (`jest --watchAll`)

# Code the testing file

After all the setup, we carry on to the testing file. The way jest finds test file is with `test.js` at the end. Therefore, we are going to name our test file as `block.test.ts` and `blockchain.test.ts` which will then being compiled into `.test.js`

First, setup a `blockchain.test.ts` file, and import necessary files to test.

```
import Blockchain from './blockchain'
import Block from './block'
import Transaction from './transaction'
import { BlockData, BlockChainData, TransactionData } from './types/class'
```

The test going to start with 'describe', where you describe your scope of testing. In this case, we are testing BlockChain Class, so we called it as 'Blockchain'.

```
describe('Blockchain', () => {
// insert code here
})
```

Then, inside the call back of describe, it where our test cases located. A simple sample test is as follow:

```
it('adds one to one correctly', () => {
  expect(1+1).toBe(2)
})
```

This 'it' will check for '1+1' to be 2, if it is, the test pass; if it isn't, the test fail.

In our blockchain class, we are testing the following 2:
- checks previous block's hash to be Equal to current block previousHash
- checks addBlock function

Since both of them are using same classes, and we need not to redeclare the same thing (apply DRY concept), I used `beforeEach()` function to run the repeated function before the test.

```
  let gb: BlockData, bc: BlockChainData, t: TransactionData
  let newB: BlockData

  beforeEach(() => {
    // create a genesis block
    gb = new Block()

    // initialize blockchain with genesis block
    bc = new Blockchain(gb)

    // create a transaction
    t = new Transaction('me', 'you', 7)
  })
```

The first test: "checks previous block's hash to be Equal to current block previousHash"

```
  it("checks previous block's hash to be Equal to current block previousHash", () => {
    newB = bc.getNextBlock([t])
    expect(newB.previousHash).toEqual(gb.hash)
  })
```

The second test: "checks addBlock function"

```
  it('checks addBlock function', () => {
    let beforeBC = bc.blocks.length // 1
    bc.addBlock(newB)
    let afterBC = bc.blocks.length // 2
    expect(beforeBC).toBe(afterBC - 1)
  })
```

Then, create another test file call `block.test.ts` to test Block class. The file starts with 'describe' it as 'Block', and create a block and transactions before the test.

```
import Block from './block'
import Transaction from './transaction'
import { TransactionData, BlockData } from './types/class'

describe('Block', () => {
  let t: TransactionData, b: BlockData

  beforeAll(() => {
    t = new Transaction('you', 'me', 4)
    b = new Block(1, '777', '666', 0, [t])
  })
// Insert code here
})
```

There is 2 cases we are testing on Block class:
- gets the key correctly
- adds transactions successfully

```
  it('get the key correctly', () => {
    // [{"from":"you","to":"me","amount":4}]
    // JSON.stringify(this.transactions) + this.index + this.previousHash + this.nonce
    expect(b.key).toBe('[{"from":"you","to":"me","amount":4}]16660')
  })

  it('adds transactions successfully', () => {
    let pT = b.transactions.length
    b.addTransaction(t)
    let aT = b.transactions.length
    expect(aT).toBe(pT + 1)
  })
```

You can find both files at [blockchain.test.ts](https://github.com/superoo7/blockchain-tutorial/blob/blockchain-4/src/blockchain.test.ts) and [block.test.ts](https://github.com/superoo7/blockchain-tutorial/blob/blockchain-4/src/block.test.ts)

# Next video

In the next video, I will be setting up web socket to allow the blockchain to "talk" to each other (also known as peer to peer network).

#### Video Tutorial

<iframe width="560" height="315" src="https://www.youtube.com/embed/yBAWIMUzHtM" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

[DTube](https://d.tube/#!/v/superoo7/ytpnfafz)

#### Curriculum

- [Introduction to Block, Transaction and Blockchain](https://utopian.io/utopian-io/@superoo7/blockchain-development-from-scratch-with-typescript-1-introduction-to-block-transaction-and-blockchain)
- [Setup Mining](https://utopian.io/utopian-io/@superoo7/blockchain-development-from-scratch-with-typescript-2-setup-mining)
- [Resolve Type error and Setup Express API Server](https://utopian.io/utopian-io/@superoo7/blockchain-development-from-scratch-with-typescript-3-resolve-type-error-and-setup-express-api-server)

<br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@superoo7/blockchain-development-from-scratch-with-typescript-4">Utopian.io -  Rewarding Open Source Contributors</a></em><hr/>
👍 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,