Wednesday, May 19, 2021

Custom decorator in typescript & how to mock them using Jest

 Let's see the basic decorator pattern in Javascript using the Typescript based library called kaop-ts.

Here are the sections for current article:

  1. What is Decorator
  2. Types of Decorator
  3. Creating the function with our custom made function decorator
1. What is Decorator?
    Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members. And these decorators wrap the context and gives you a way to process the context, add something extra in the context and even change the context. The word context means, that in case of a function decorator you can have the access to the Class to which the function belongs,  the passed parameters of the actual function call and many more.

2. Types of Decorators?
 
We have many different type of decorators. Some of them are:
  • Class Decorators
  • Function Decorators
  • Property Decorator
  • Accessor Decorator
And we have some others too but the above ones are most useful as well as popular. For further details on the above mentioned types please have a look at  TypeScript Decorators.

In a nutshell, decorators are special kind of functions that return another special kind of functions which is called as a wrapped up contextual function to the actual context on which the decorator function is applied.

Sounds a bit over complex but is pretty simple to understand. Lets look at the below code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function first() {
  console.log("first(): factory evaluated");
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("first(): called");
  };
}

function second() {
  console.log("second(): factory evaluated");
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("second(): called");
  };
}

class ExampleClass {
  @first()
  @second()
  method() {
    console.log("Original Method");
  }
}

const exampleClass = new ExampleClass();
exampleClass.method() 

If you check out the function first & second are the decorator factories who are returning a special function and this returned function is called as a contextual wrapped function for the specific context on which first and second is applied, so in our case the console will look like:

1
2
3
4
5
first(): factory evaluated
second(): factory evaluated
first(): called
second(): called
Original Method

So, if we see the logs, we get the understanding that the factories are called and the actual function (returns of factories) of these factories gets attached to the contextual block which in our case is a method of ExampleClass.

Now lets prepare a basic log based function decorator which will log the arguments before entering the function call as well as after completing the function execution. Here is main code of the LogMe decorator and we will then see the executional part.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import { applyDecorators, Logger } from '@nestjs/common';
import { afterMethod, beforeMethod } from 'kaop-ts';
import { from } from 'rxjs';
import to from 'await-to-js';

const logger = new Logger('LogMe', true);

const tc = async <T>(p: Promise<T>, errorExt?: any): Promise<[Error, T]> =>
  to(p, errorExt);

class LogMeRequestDTO {
  logArgumentsBefore?: boolean = false;
  logResult?: boolean = false;
  logArgumentsAfter?: boolean = false;
}

export const LogMe = (options: LogMeRequestDTO = {}) => {
  const before = beforeMethod((meta) => {
    /**
     * 
     */
    const printArray: string[] = [
      'ENTER LOGME',
      meta.target.constructor.name,
      meta.method.name,
    ];

    if (options?.logArgumentsBefore && meta?.args?.length > 0)
      printArray.push(JSON.stringify(meta.args));
    logger.debug(printArray.join(' -> '));
  });

  const after = afterMethod(async (meta) => {
    /**
     * 
     */

    const printArray: string[] = [
      'EXIT LOGME',
      meta.target.constructor.name,
      meta.method.name,
    ];
    let err;
    let finalResult;

    if (options?.logArgumentsAfter && meta?.args?.length > 0)
      printArray.push(JSON.stringify(meta.args));
    if (options?.logResult) {
      [err, finalResult] = await tc(from(meta.result).toPromise());
      if (err) printArray.push(JSON.stringify(err.message));
      else printArray.push(JSON.stringify(finalResult));
    }
    if (err) logger.error(printArray.join(' -> '));
    else logger.debug(printArray.join(' -> '));
  });

  return applyDecorators(before, after);
};

For now just concentrate on line 18, 33, and 57. 

Line 18: The function that will be called before the actual contextual block on which LogMe is applied
Line 33: The function that will be called after the actual contextual block on which LogMe is applied
Line 57: This is a utility function from nestjs that clubs all the decorator factories and lets you apply all of them with 1 clubbed name in our case its LogMe.

Line 11: is basically a DTO of passing the arguments for the behavior of out Logger, like whether to log anything before the execution of the contextual block or not and all. This DTO has 3 options where we can have logArgumentsBefore, logArgumentsAfter and logResult. All 3 have the exact functionality as their name suggests like:

logArgumentsBefore: Whether to log the passed arguments to contextual block, before the execution of the contextual block, 
logArgumentsAfter: Whether to log the passed arguments to contextual block, after the completion of the execution of the contextual block, 
logResult: Whether to log the result being returned from the function or not.

Now lets see how we will use the above Decorator. Since its a function decorator we will use above the functions, and as expected you will get the callback in the before function and after function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
export class AppService {

  @LogMe({
    logArgumentsAfter: true,
    logArgumentsBefore: true,
    logResult: true
  })
  getHello(name: string): Promise<string> | string {
    return Promise.resolve(`Hello ${name}`);
  }
}


Line 2: shows us how to use the LogMe decorator with the DTO we defined.

When we call the function getHello of the AppService Class we will get the call in LogMe definition first (in before and after one by one) then the call is transferred to the actual call.

1
2
3
4
...
const appService = new AppService();
appService.getHello('CODEPOOL');
...

Output:

1
2
3
4
[Nest] 11020   - 05/19/2021, 9:42:55 PM   [NestFactory] Starting Nest application...
[Nest] 11020   - 05/19/2021, 9:42:55 PM   [InstanceLoader] AppModule dependencies initialized +29ms
[Nest] 11020   - 05/19/2021, 9:42:55 PM   [LogMe] ENTER LOGME -> AppService -> getHello -> ["ANKUR"] +3ms
[Nest] 11020   - 05/19/2021, 9:42:55 PM   [LogMe] EXIT LOGME -> AppService -> getHello -> ["ANKUR"] -> "Hello ANKUR" +3ms

Here is the project code Github Link

NOTE: 
In this example although we used the NEST Framework, but its not a compulsion to use, we can use any framework but it should have the support of Decorators of Typescript and if you want to use  Javascript you need to use the Babel Transpiler.

Happy Coding :)

Saturday, April 11, 2020

Getter and Setter in JS

Let us suppose we have an object called User like this:
1
2
3
4
const user = {
    firstName: 'A',
    lastName: 'B',
}

Now suppose we want to return the full name of the function it will something be like this:

1
console.log(`${user.firstName} ${user.lastName}`)

But this is a naive approach and in case if we have to add something extra in the statement, we have to change every where, instead the better way is to give a function that will return this expression/value like:

1
2
3
4
5
6
7
8
9
const user = {
    firstName: 'A',
    lastName: 'B', 
    fullName () { // previous version was like fullName: function () {...} but changed in ES6
        return `${this.firstName} ${this.lastName}`
    }
}

console.log(${user.fullName())

Now this is good but:
  1. what if you want to use it as a field and not as a function, I mean, I want to use it something like: console.log(${user.fullName).
  2. And we want to set the value of firstName and lastName on the basis of value we are going to pass to fullName like user.fullName = 'Javascript rocks' 
For that we have 2 keywords called get and set and the use is like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
const user = {
    firstName: 'A',
    lastName: 'B', 
    get fullName () {
        return `${this.firstName} ${this.lastName}`
    }

    set fullName (value) {
        const tokens = value.split(' ');
        this.firstName = tokens[0];
        this.lastName = tokens[1];
    }
}

console.log('Before set', ${user.fullName})

user.fullName = 'Javascript Rocks'.

console.log('After set', ${user.fullName})

Here in this code there are 2 keywords we have seen,

  • get = for accessing the property (at line 4)
  • set = for setting the property (at line 8)
These 2 keywords make the function as a property and that is the reason at line 15 and line 19 we have accessed the fullName without the parenthesis.

That's it, its awesome right :)

Happy Coding :)

For reference, please check out this: https://www.youtube.com/watch?v=bl98dm7vJt0

Thursday, April 9, 2020

debouncing in javascript

So, we have seen the requirements where in which we are required to send the data to the server on an event that might be a click, hover, mouseEnter or anything.

So let us consider we are writing a click event for a button. So the basic code for the same would look something like this:

1
2
3
4
5
$(document).ready(() => {
    $("#btn").on('click', async (event) => {
        // do some api calls or anything
    })
})

Now suppose you are saving/posting the data to the server on every click, in that case if suppose, user clicked the button 2 3 times, it will save the same data 3 times with different ids.

In order to handle this we have 2 options:
  1. either disables the button once you click and enables it once the callback returns
  2. Write a debounce function to handle accidental clicks
Lets see first how debounce function is written.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const debounce = (fn, delay) => {
    let timeoutId;
    return (...args) => {
        if(timeoutId) clearTimeout(timeoutId);
        timeoutId = setTimeout(() => fn(...args),delay)
    }
}

$(document).on('ready', async() => {
    $('#btn').on('click', debounce(e=> {
        console.log('bye bye')
    }, 2000))
})

Explanation:
  1. In this code, we have first created a higher order function named debounce that is taking 2 params, the callback function and a delay to reset the functionality if, someone triggered the event twice.
  2. The debounce function is returning a function that is calling our callback passed at line 5.
  3. Now, instead of giving the callback directly to the event, we are calling debounce and passing our callback function implementation as well as the delay that is going to wait for certain time, before resetting the timeout.
That's it, this debounce function is a nice way of making sure that the accidental triggering of the events can be stopped and only the last event will be considered. This makes sure that all the events that are triggered before the timeout mentioned are going to keep on cancelling unless user stops the event creation and only the last triggered event is accepted and fires the actual callback.

Happy Coding :)

Thursday, January 16, 2020

forEach, map, filter, find, every, some, reduce in pure js implementation

These are normal functions but can be implemented with Array.prototype as well.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// ForEach loop
const myForEach = (array, cb) => {
  for (let i = 0; i < array.length; i++) {
    cb(array[i], i, array)
  }
}

// map function
const myMap = (array, cb) => {
  const result = []
  for (let i = 0; i < array.length; i++) {
    result.push(cb(array[i], i, array))
  }
  return result
}

// Find first element if predicate is passed
const myFilter = (array, cb) => {
  const result = []
  for (let i = 0; i < array.length; i++) {
    if (cb(array[i], i, array)) {
      result.push(array[i])
    }
  }
  return result
}

// Find first element if predicate is passed
const myFind = (array, cb) => {
  for (let i = 0; i < array.length; i++) {
    if (cb(array[i], i, array)) {
      return array[i]
    }
  }
  return null
}

// If all of the elemnts pass the predicate
const myEvery = (array, cb) => {
  for (let i = 0; i < array.length; i++) {
    if (!cb(array[i], i, array)) {
      return false
    }
  }
  return true
}

// If some of the elemnts pass the predicate
const mySome = (array, cb) => {
  for (let i = 0; i < array.length; i++) {
    if (cb(array[i], i, array)) {
      return true
    }
  }
  return false
}
const myReduce = (array, callback, initialVal) => {
  for (let i = 0; i < array.length; i++) {
    initialVal = initialVal ? callback(initialVal, array[i], i, array) : array[i]
  }
  return initialVal
}

// TESTING
const aa = [1, 2, 3]

console.log('===== MY FOREACH ======')
myForEach(aa, a => console.log(a))

console.log('\n\n===== MY MAP ======')
const retOfMyMap = myMap(aa, a => a * 2)
myForEach(retOfMyMap, a => console.log(a))

console.log('\n\n===== MY FILTER ======')
const retOfMyFilter = myFilter(aa, a => a % 2 === 1)
myForEach(retOfMyFilter, a => console.log(a))

console.log('\n\n===== MY FIND ======')
const retOfMyFind = myFind(aa, a => a > 1)
console.log(retOfMyFind)

console.log('\n\n===== MY EVERY ======')
const retOfMyEvery = myEvery(aa, a => a > 0)
console.log(retOfMyEvery)

console.log('\n\n===== MY SOME ======')
const retOfMySome = mySome(aa, a => a > 10)
console.log(retOfMySome)

console.log('\n\n===== MY REDUCE ======')
const retOfMyReduce = myReduce(aa, (a, b) => a * b)
console.log(retOfMyReduce)


Since these are normal functions that is why we have taken the reference of array as a part of functional parameters, but when we make the functions as a part of array prototype then all references of 'array' can be changed to this., like:

1
2
3
4
5
Array.prototype.myForEach = function(cb) {
  for (let i = 0; i < this.length; i++) {
    cb(this[i], i, this)
  }
}

NOTE: Here in this function we did not use the arrow functions, the reason is simple, if we use the arrow functions the lexical scope of the function will be the function itself and not around the array value that called the function, and that is the reason we placed the normal function instead of arrow functions.
You can take more info from: https://stackoverflow.com/questions/36225636/function-to-array-prototype

Happy coding
:)

Starting the live server of VSCode in SSL/Https Mode

Hi we all need a server many times in our development setup to host our files and work on it. For this, one way is to always add the server code and respond html files and js files without processing (if its a normal html project).

But we have a better option like live server plugin, that supports hot reloading as well, that means as soon as you change any files on your coding it will reload the browser window as well.

Live server plugin of VSCode exactly gives the support where in which, if you write some html file and you want to host it on the server you can use this plugin for starting the server for your coding folder.

Prerequisites:
  1. VScode
  2. Install Live server Plugin in VScode from: https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
  3. You can read the documentation, what is supports and what are its shortcuts.
The main problem is that sometimes we need to start the server in the https mode that is ssl mode, at that time we have to do certain config changes in order to start the live server in ssl mode. So here are the steps:
  1. We have to generate the key-pem file pair for starting the server in https mode.
  2. For that we first use following commands:
    1. Create a private key :
      openssl genrsa -aes256 -out localhost.key 2048
      For this we have to provide a password.
    2. Create the certificate:
      openssl req -days 3650 -new -newkey rsa:2048 -key localhost.key -x509 -out localhost.pem
      Give the details and provide password (from step 1) for generating the certificate
    3. Create a .vscode folder in root of your project and create settings.json file inside of it
    4. Add the following code in that:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "liveServer.settings.port": 5501,
  "liveServer.settings.root": "/",
  "liveServer.settings.CustomBrowser": "chrome",
  "liveServer.settings.https": {
    "enable": true,
    "cert": "PATH TO FOLDER/localhost.pem",
    "key": "PATH TO FOLDER/localhost.key",
    "passphrase": "PASSWORD OF STEP 1"
  }
}

Now if you start the live server by pressing Go Live button you server will be started in SSL mode and chrome will prompt you to verify the ssl website, since you are in local, just click advanced and proceed anyway, and boom your server is in ssl mode.

Here are the references I took help from:
  1. https://gist.github.com/prof3ssorSt3v3/edb2632a362b3731274cfab84e9973f9
  2. https://www.youtube.com/watch?time_continue=144&v=v4jgr0ppw8Q&feature=emb_logo
Here is the dummy code to check for starting the server in SSL mode https://github.com/ankur20us/demo-live-server-ssl

Happy Coding
:)

Wednesday, December 18, 2019

Super-test with mocking middleware In Jest

So, today we are going to see how do we mock the middleware if it is applied over the Express server.

So, here is our agenda:
  1. Create an express app
  2. Add a middleware to Authenticate the user
  3. Test the app using Jest (integration test NOT UNIT)
index.js

1
2
3
const server = require('./server')
const PORT = process.env.PORT || 3000
server.listen(PORT, () => console.log(`Server is live at localhost:${PORT}`))

server.js
1
2
3
4
5
6
7
const express = require('express')
const middleware = require('./middleware')
const welcomeRoute = require('./welcome-route')
const server = express()
server.use(express.json())
server.use('/api', middleware, welcomeRoute)
module.exports = server


is-user-authentic.js
1
2
3
4
5
const faker = require('faker/locale/en_US')
const isUserAuthentic = () => faker.random.arrayElement([true, false])
module.exports = {
  isUserAuthentic
}

middleware.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const { isUserAuthentic } = require('./is-user-authentic')

const middleware = (req, res, next) => { 
  if (!isUserAuthentic()) {
    res.sendStatus(401)
    return next(new Error('Unauthenticated user'))
  }
  next()
}
const myExport = module.exports = middleware

welcome-route.js
1
2
3
4
5
const { Router } = require('express')
const WelcomeService = require('./welcome-service')
const router = Router()
router.get('/', (_req, res) => res.json({ 'message': WelcomeService.message() }))
module.exports = router

welcome-service.js
1
2
3
module.exports = {
  message: () => 'hello world'
}

In this code, the flow is like:
  1. Start the server at 3000 (line 3, index.js)
  2. Middleware is applied to base path (line 6, server.js)
  3. If you hit http://localhost:3000/api, is-user-authentic will return true/false randomly which will return either return 'hello world' or 401 unauthorised
Now in order to test this, we will use jest mocking.

routes.test.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
const request = require('supertest')
const faker = require('faker/locale/en_US')

let app
let WelcomeServiceSpyOfMessage
let IsUserAuthenticSpyOnIsUserAuthentic

describe('test', () => {
  beforeEach(() => {

    /**
     * Always create spy then create server
     */
    const WelcomeService = require('../src/welcome-service')
    WelcomeServiceSpyOfMessage = jest.spyOn(
      WelcomeService,
      'message',
    )
    
    /**
     * Always create spy then create server
     */
    const IsUserAuthentic = require('../src/is-user-authentic')
    IsUserAuthenticSpyOnIsUserAuthentic = jest.spyOn(
      IsUserAuthentic,
      'isUserAuthentic'
    )
    app = require('../src/server')
  })

  afterEach(() => {
    /**
     * Most important since b'coz of caching, the mocked implementations sometimes does not resets 
     */
    jest.resetModules()
    jest.restoreAllMocks()
  })

  it('1. Mock implementation, with successful user auth [isUserAuthentic as true]', async () => {
    const mockedMessage = faker.lorem.sentence()
    WelcomeServiceSpyOfMessage.mockImplementation(() => mockedMessage)
    // --> For successful user authentication, sending true :
    IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => true)
    const result = await request(app)
      .get('/api')
    expect(result.statusCode).toBe(200)
    expect(result.body).toHaveProperty('message', mockedMessage)
  })

  it('2. After restored implementation, with successful user auth [isUserAuthentic as true]', async () => {
    /**
     * This will return { 'message' : 'hello world'},
     * since we restored the mock implementation, in afterEach
     * restoreAllMocks and resetModules,
     * works only for methods those are mocked
     * with .spyOn()
     */
    // --> For successful user authentication, sending back true
    IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => true)
    const result = await request(app)
      .get('/api')
    expect(result.statusCode).toBe(200)
    /**
     * This expectation is the same returning from the service
     */
    expect(result.body).toHaveProperty('message', 'hello world')
  })

  it('3. Returning user is Unauthorized, [isUserAuthentic as false]', async () => {
    // for Unauthorized, we return false
    IsUserAuthenticSpyOnIsUserAuthentic.mockImplementation(() => false)
    const result = await request(app)
      .get('/api')
    expect(result.statusCode).toBe(401)
  })
})

In this test there are certain things that needs to be taken care before loading the express server.

  1. Mock the middleware before you load the server otherwise if you mock middleware after the server is loaded new reference of the object will be mocked and even after the mock the original implementation will be called.
  2. In this test case, we loaded the server at line 28, but the spy was already hooked to the functions before that only.
  3. In afterEach we will reset modules and reset mocks to make sure mocked implementation of one test will not interfere in other tests.
  4. Now every time module is loaded then spy is added and mock will be hooked.
The source code for the above example is available at https://github.com/ankur20us/demo-jest-supertest

Happy Coding
:) 

Saturday, July 27, 2019

Sherlock and the Valid String - HackerRank - Easiest Solution

Hello everyone, today, while going through the problem of Sherlock & Valid String, I literally tried a lot and was not getting a simple and sober solution.

In fact, when I myself started implementing it, I found that the problem is not that complicated the way the solutions are available in other blogs, so I started the problem and here is the solution I came up with.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function isValid(s) {
  const countMap = {}; const countList = [];
  const arr = s.split('');
  arr.forEach((a) => countMap[a] = (countMap[a] || 0) + 1);
  Object.keys(countMap).forEach(k => countList.push(countMap[k]));
  countList.sort();
  const countSet = new Set(countList);

  const len = countList.length;

  if (countSet.size > 2) {
    return 'NO';
  } else if (countSet.size === 1) {
    return 'YES';
  } else if (countSet.size === 2) {
    const firstNum = countList[0];         const lastNum = countList[len - 1];
    const lastList = countList.slice(1);   const firstList = countList.slice(0, len - 1);
    const lastListSet = new Set(lastList); const firstListSet = new Set(firstList);
    return (
      (lastListSet.size === 1 && firstNum === 1)
      || (lastListSet.size === 1 && lastNum - firstNum === 1)
      || (firstListSet.size === 1 && lastNum - firstNum === 1)
    )
      ? 'YES' : 'NO';
  }
}

Explanation

Suppose the input was aabbc:

  1. Create a countMap with the number of occurrences of each character.
    • countMap = { a: 2, b: 2, c:1 };
  2. Make a list of the values of above maps( not keys ) and sort it.
    • countList = [1, 2, 2]
  3. Convert countList to countSet
    1. countSet = [1, 2]
  4. If (countSet.size > 2) the solution is not possible.
  5. If (countSet.size === 1), we have the "YES"
  6. If (countSet.size === 2), we have to process:
    1. We will create 6 variables for our ease, those are:
      1. firstNum  i.e first number of countList (sorted) = 1 (for our example)
      2. lastList i.e sub array of countList from 1..end = [2, 2]
      3. lastListSet i.e set over lastList, for removing duplicates = [2]
      4. lastNum i.e last number of countList (sorted) = 2
      5. firstList i.e sub array of countList from 0..end-1 = [1, 2]
      6. firstListSet i.e set over firstList, for removing duplicates = [1, 2]
    2. There are only 3 conditions which is "YES" those are:
      1. [ 1, X, X, X, X]
      2. [ X-1, X-1, X-1, X-1, X]
      3. [X, X, X, X, X+1]
    3. For our example 2.1 is true
    4. Apart from them there is no other way, a String will give "YES" and thats what we did

Happy coding,
:)