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

New_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) and ended with the branch blockchain-4 (Github link)

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 - a testing framework created by Facebook team
  • @types/jest - types file for Jest (for TypeScript)
  • 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 and 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

DTube

Curriculum



Posted on Utopian.io - Rewarding Open Source Contributors

H2
H3
H4
Upload from PC
Video gallery
3 columns
2 columns
1 column
5 Comments