How to mock Google Places with Cypress


Why doesn’t it work as expected?

If we take a closer look at the response, whether it be the Google autocomplete predictions response or, for example, the Google geocode service response, we’ll notice something odd. The stringified JSON has been wrapped and prefixed with some data as in the example below.

/**/_xdc_._arqn3n && _xdc_._arqn3n({
  "predictions" : [
     ...
  ],
  "status" : "OK"
})

This prefixed data is the problem. The values here are expected by the Google package responsible for parsing the response… but they are not always the same. If they don’t match up, we get an error.

The solution!

Luckily for us, this data is included in the request URL in a param called callback. We can extract this value from the URL during the lifecycle of a cy.intercept and wrap our mock data with it to satisfy the parser and resolve the error.

// Util function stored elsewhere e.g. cypress/utils/
export const wrapResponse = (request, mockData) => {
  const searchParams = new URLSearchParams(request.url);
  const callbackParam = searchParams.get("callback");
  request.reply(
    `${callbackParam} && ${callbackParam}(${JSON.stringify(mockData)})`,
  );
};

// A cypress intercept making use of the wrapResponse util
cy.intercept(
  "https://maps.googleapis.com/maps/api/place/js/AutocompletionService*",
  (request) => wrapResponse(request, mockData),
);
The mockData value is simply the JS object part of the regular response, as if it hadn't been wrapped with all that other stuff.

Happy testing!