Variations and Gotchas of the Arrow Function Syntax in JavaScript

ES6 introduced into JavaScript the extremely useful syntax for defining functions known as arrow functions. This refers to the notation:

argument => result

 

Arrow function notation can be used for both named and unnamed (anonymous) functions. Arrow functions allow for very compact definitions.

Example: define the successor function:

const f = ( x => x + 1 )

The parentheses around the function can be dropped:

const f = x => x + 1

It is slightly unclear when seen for the first time but soon becomes very natural.

Note that the above does not require a return; the expression on the right hand side of the arrow is the returned value.

If more than one statement is needed to define the function, braces must be introduced. The above example can also be written as:

const f = x => {
  const result = x + 1
  return result
}

Note that the following is problematic:

const f = x => { x + 1 } // does not return

This is very important: if braces are used, a return statement is necessary.

In short, if braces are present, a return statement is needed; if more than one statement is used in the function, braces must be used.

Another valid form:

const f = x => { 
  return x + 1
}

The argument list can be made explicit with parentheses:

const f = (x) => {
  return x + 1
}

This is required for functions of  multiple arguments, as in the following example:

const sum = (x, y) => x + y

The parentheses around the argument list cannot be dropped in this case.

A function with zero arguments also requires the parentheses around the (empty) argument list as follows:

const f = () => value

 

Use git grep to search for strings across all branches

Git includes a grep command to search through commits to a repo as well as the local files in the repo directory: git grep. Sometimes it is useful to search for a string throughout an entire repo, e.g. to find where an error message is produced.

By itself, git grep searches the currently checked out branch and local files for a regular expression. Sometimes the text we want to find is on another branch, which may actually be deployed and running in some environment. Therefore, it is useful to search through all branches of a repository to be certain where some string of interest is generated, a file is written, etc.

To search through all branches of a git repo for a string, use:

$ git grep str $(git rev-list --all)

To search through all branches ignoring string case:

$ git grep -i str $(git rev-list --all)

This can also be done with regular expressions:

$ git grep -i RegEx $(git rev-list --all)

Jest: Expect a String Result to be Numeric

JavaScript unit tests in Jest may need to assert that a string result from a function is numeric, i.e. a string containing only numbers.

Since we do not have a convenient matcher like toBeNumeric(), none of the ways currently looks quite perfect, but several possible ways are below, some more readable than others.

First, suppose we have a simple function to return a numeric string:

func.js:

const func = () => {
  return "12345"
}

module.exports = func

Then our unit test in the first form: using toBeNaN(), negated, combined together with the Number constructor:

func.spec.js:

const func = require('./func')

describe('numeric string result', () => {
  it('should be numeric', () => {
    expect(Number(func())).not.toBeNaN() // numeric
  })
})

 

The above is somewhat clear, but the following may be more readable to some:

const func = require('./func')

describe('numeric string result', () => {
  it('should be numeric', () => {
    expect(Number.isNaN(func())).toBe(false)
  })
})

 

Another way is to use a Regular Expression (regex) to expect a numeric string, however, this is most readable for integers:

const func = require('./func')

describe('numeric string result', () => {
  it('should be numeric', () => {
    expect(func()).toMatch(/[0-9]+/) // string of integers
  })
})

The regex would become more complex if we wanted to accept any kind of numeric notation, including real numbers or large numbers with exponential notation, for example.

Perhaps the highest readability is achieved by breaking out the numeric check into its own convenience function, as below:

const func = require('./func')

const isNumeric = (string) => {
  return !Number.isNaN(string)
} 

describe('numeric string result', () => {
  it('should be numeric', () => {
    expect(isNumeric(func())).toBe(true)
  })
})

Expect a function to throw an exception in Jest

Unit testing functions in JavaScript using Jest sometimes requires checking if an exception was thrown, or testing the specific type of exception thrown.

Suppose we want to test the following function using Node.js and assert that it indeed throws an error:

func.js:

const func = () => {
  throw new Error('my error')
}

module.exports = func

func.test.js:

const func = require('./func')

describe('exception test', () => {
  it('should throw an error', () => {
    expect(func).toThrow()
  })
})

Note that func should not be called within the expect; calling the function will cause the error to be thrown unexpectedly.

We can also assert that an error is not thrown using:

expect(func).not.toThrow()

If we need to assert the specific name of the thrown error, we can use the following form:

it('should throw an error', () => {
  expect(func).toThrowError('my error')
})

If no exceptions are thrown, Jest will report:

Expected the function to throw an error. 
But it didn't throw anything.
Expecting Async Functions to Throw Exceptions

 

Writing a unit test to expect an async function to throw an exception can be done as follows. First we define the async function in a module, then in the test code we use the rejects property to test for any thrown errors. Essentially, we are asserting that our function causes a promise rejection.

async-func.js:

const func = async () => {
  throw new Error('my error')
} 

module.exports = func

async-func.test.js:

const func = require('./async-func.js')

describe('exception test', () => {
  it('should throw an error', async () => {
    await expect(func()).rejects.toThrow()
  })
})

Note that the function passed to it() is async itself so that we can use await inside.

Note also that func is called inside expect in this case; this will cause a promise rejection which can then be tested within the rejects property.

The case of testing for a specific error to be thrown inside the async function is similar and looks like this:

it('should throw an error', async () => { 
  await expect(func()).rejects.toThrowError('my error')
})
Expect a Function with Parameters to Throw an Exception

If we want to expect a function to throw an exception for certain input parameters, the key point is that we must pass in a function definition and not call our function inside the expect. The code is below for an example of a function which should throw an exception for negative integer inputs:

func.js:

const func = (n) => {
  if (n < 0) {
    throw new Error("negative input")
  }
  return n
}

module.exports = func

func.spec.js:

const func = require('./func.js')

describe('exception test', () => {
  it('should throw an exception', () => {
    expect(
    () => func(-1) // Do not simply call func
    ).toThrow()
  })
})

We pass an anonymous function to expect, which will throw for the input. Expect can then determine that this function will throw.