Promise.all with async/await in JavaScript

Promise.all can be used to await an array of promises, all of which can resolve at any time individually. Imagine launching multiple simultaneous requests to many APIs for example, all with varying unpredictable response times.

Promise.all will only resolve once all of the promises in the input array have resolved.

The following example shows two functions which return in 1 and 2 seconds respectively. Note that we are using the sleep function from npm here for maximum simplicity. This can be installed with: npm install sleep.

const sleep = require('sleep')

const f = async () => {
  sleep.sleep(1) // 1 second
  console.log('f sleep done, returning...')
  return 'f result'
}

const g = async () => {
  sleep.sleep(2) // 2 seconds
  console.log('g sleep done, returning...')
  return 'g result'
}

(async () => {
  const promise1 = f()
  const promise2 = g()

  const allResults = await Promise.all( [promise1, promise2] )

  console.log('All results: ' + JSON.stringify(allResults))
})()

Note the IIFE because we cannot have a top-level async function using the async/await syntax.

If we don’t need the return values, we can simply do:

await Promise.all( [promise1, promise2] )

To capture only some of the results, we can use destructuring assignment:

const [ result1 ] = await Promise.all( [promise1, promise2] )

The combination of Promise.all and async/await provides a very readable and compact way to make many asynchronous calls and use the results.

 

Reduce verbose output and show only failing tests in Jest

Sometimes the output of running Jest unit tests is a bit too verbose, with the pass and fail statuses of all tests as well as the test coverage table.

To prevent outputting the code coverage report table, use:

jest --collectCoverage=false

(This assumes Jest is configured to show the code coverage report already.)

We can reduce the verbosity of the Jest output aside from the coverage table by using a custom reporter. Jest Silent Reporter is a good choice for this. To install it:

$ npm install jest-silent-reporter

Then run the tests with:

$ jest --reporters jest-silent-reporter

Now we will see only the failing test output.

The coverage report can still be shown after the silent reporter output.

So, for the minimum output possible we can combine the silent reporter and omit coverage report:

$ jest --collectCoverage=false --reporters jest-silent-reporter

We can add this command to our package.json to have the option to run a silent minimal output for all our tests easily, for example like this:

"scripts": {
  "unit:silent": "jest --reporters jest-silent-reporter --collectCoverage=false" 
}

Then we can just run:

$ npm run unit:silent

References

https://www.npmjs.com/package/jest-silent-reporter

 

Send email to a mailing list using the Mailgun API with cURL

Mailgun provides one of the nicest APIs for email communication.

This example assumes we have a mailing list already created and want to send an email to all recipients via the Mailgun API.

The way to do this is to POST to /messages and use the mailing list address as the recipient address in the API call. Here is the call being made via cURL:

$ curl --request POST \
 --url https://api:MY_API_KEY@api.mailgun.net/v3/mg.mydomain.com/messages \
 --form 'from=Name <noreply@mg.mydomain.com>' \
 --form "text=My email body" \
 --form "subject=My email subject line" \
 --form to=my-email-list@mg.mydomain.com \
 --form user=api:MY_API_KEY

Note that this API call uses form fields and not any JSON payload.

A successful response will look something like:

{
   "message": "Queued. Thank you.",
   "id": "..."
}

References

https://www.mailgun.com/email-api

Computed Property Names in JavaScript

Computed Property Names is an ES6 feature which allows the names of object properties in JavaScript object literal notation to be determined dynamically, i.e. computed.

JavaScript objects are really dictionaries, so it was always possible to dynamically create a string and use it as a key with the syntax object[‘property’] = value.

However, ES6 Computed Property Names allow us to use dynamically generated names within object literals. Example:

const myPropertyName = 'c'

const myObject = {
  a: 5,
  b: 10,
  [myPropertyName]: 15
} 

console.log(myObject.c) // prints 15

To stress that expressions can be used directly as computed property names, another example:

const fieldNumber = 3

const myObject = {
  field1: 5,
  field2: 10,
  ['field' + fieldNumber]: 15
}

console.log(myObject.field3) // prints 15

This can be very handy.

One more variation is to use template literals (string interpolation) for the computed property names — note that this still requires the square bracket syntax, however:

const fieldNumber = 3

const myObject = {
  field1: 5,
  field2: 10,
  [`field${fieldNumber}`]: 15
}

console.log(myObject.field3) // prints 15

 

Access the Clipboard Through the Terminal in macOS

macOS provides a very handy way to share data between graphical (GUI) applications and command-line (terminal) tools.

This is especially useful for working with APIs using JSON (or XML) which require large payloads.

The two binary commands are pbcopy and pbpaste: short for Pasteboard Copy and Pasteboard Paste respectively (the macOS term for Clipboard).

  • pbcopy takes the standard input and copies it to the pasteboard
  • pbpaste takes the pasteboard data and copies it to the standard output

Suppose we have a sample payload in file.json. We can send its contents to the clipboard by piping the data to pbcopy:

$ cat file.json | pbcopy

Now, we simply press Command+v in a GUI app like Postman or Insomnia.

In reverse, we can press Command+c in a GUI app and then in the terminal:

$ pbpaste
{
  "data": "test"
}

Or, redirect the standard output to a file:

$ pbpaste > file.json

Or, pipe the data straight into a another command, like the super-handy JSON viewing tool fx:

$ pbpaste | fx

Note that these commands are macOS specific; they do not exist in Linux.

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.

Running a Single Test Only Using Jest

Jest provides a convenient way to run only one unit test at a time.

First, run only the single test file which contains the single test to run, similar to the following:

jest my-test-suite.spec.js

The single test in the suite that we wish to run should be changed to use it.only() as in the example below:

describe('My test suite', () => {
  it('should meet condition 1', () => {
    expect(condition1).toEqual(true)
  })

  it.only('should meet condition 2', () => {
    expect(condition2).toEqual(true)
  })

  it('should meet condition 3', () => {
    expect(condition3).toEqual(true)
  })
})

Jest will run only the second test, and will show the others as skipped.

Note that it.only() can be used multiple times in the file, so that we can run only two or only several jest tests as desired.

Another way to run several tests only is to select the tests that should not be run, and use it.skip() for these. The specific tests only will be skipped.

There is also a way to run a single test suite at a time inside a file, which is handy for running a group of related tests: describe.only().