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

in #utopian-io8 years ago (edited)

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

Sort:  

Thank you for your contribution.


Need help? Write a ticket on https://support.utopian.io.
Chat with us on Discord.

[utopian-moderator]

Thank you moderator

Congratulations @superoo7! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of posts published

Click on any badge to view your own Board of Honor on SteemitBoard.

To support your work, I also upvoted your post!
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

Upvote this notification to help all Steemit users. Learn why here!

You've been upvoted by TeamMalaysia Community :-

To support the growth of TeamMalaysia Follow our upvotes by using steemauto.com and follow trail of @myach

Vote TeamMalaysia witness bitrocker2020 using this link vote for witness

Hey @superoo7 I am @utopian-io. I have just upvoted you!

Achievements

  • People loved what you did here. GREAT JOB!
  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Utopian Witness!

Participate on Discord. Lets GROW TOGETHER!

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Coin Marketplace

STEEM 0.05
TRX 0.33
JST 0.082
BTC 62530.03
ETH 1633.28
USDT 1.00
SBD 0.44