Closed thetwosents closed 6 years ago
@thetwosents Thank you for opening this issue.
Because PlacesAutocomplete
component has a dependency on Google Maps Places library it has to be available under the window object.
One way to get around this is to mock window.google
object in your test.
Example:
const setupGoogleMock = () => {
/*** Mock Google Maps JavaScript API ***/
const google = {
maps: {
places: {
AutocompleteService: () => {},
PlacesServiceStatus: {
INVALID_REQUEST: 'INVALID_REQUEST',
NOT_FOUND: 'NOT_FOUND',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
},
},
Geocoder: () => {},
GeocoderStatus: {
ERROR: 'ERROR',
INVALID_REQUEST: 'INVALID_REQUEST',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
},
},
};
global.window.google = google;
};
// in test file.
beforeAll(() => {
setupGoogleMock();
});
Hope this helps!
Thanks for providing the above setup, however I get the following error:
TypeError: window.google.maps.Geocoder is not a constructor
Any ideas on how to fix?
@con322 I had the same problem before. window.google.maps.Geocoder
is a class so just put Geocoder:class{},
.
If you are using function in google map classes, e.g:
fitBounds()
under window.google.maps.Map
class:
Just Map:class{ setTilt(){} fitBounds(){}},
Here's my google map classes mock under setupTests.js
window.google ={
maps:{
Marker:class{},
Map:class{ setTilt(){} fitBounds(){}},
LatLngBounds:class{},
places:{
Autocomplete: class {},
AutocompleteService:class{},
PlacesServiceStatus: {
INVALID_REQUEST: 'INVALID_REQUEST',
NOT_FOUND: 'NOT_FOUND',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
},
PlacesAutocomplete:{
INVALID_REQUEST: 'INVALID_REQUEST',
NOT_FOUND: 'NOT_FOUND',
OK: 'OK',
OVER_QUERY_LIMIT: 'OVER_QUERY_LIMIT',
REQUEST_DENIED: 'REQUEST_DENIED',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
ZERO_RESULTS: 'ZERO_RESULTS',
}
},
MarkerClusterer:class{},
Geocoder:class{},
}
};
As a newbie, I appreciate this thread, but I continue to bang my head against the wall.
In my case, I'm trying to mock PlacesService.getDetails
. Adding PlacesService: class {}
resolves constructor issue, but leaves me with getDetails
being undefined.
How do I define getDetails
under PlacesService?
UPDATE: I may have gotten it figured out, but I don't understand it :-~
PlacesService: class { getDetails() {}},
I prefer to mock the library instead. Simple example:
interface Props {
children: Function;
}
jest.mock('react-places-autocomplete', () => {
const React = require('react'); // eslint-disable-line
class PlacesAutocomplete extends React.Component<Props> {
renderProps = {
getInputProps: jest.fn(({ placeholder, className }) => ({ placeholder, className })),
suggestions: [],
getSuggestionItemProps: jest.fn(),
};
render() {
return <>{this.props.children(this.renderProps)}</>;
}
}
return PlacesAutocomplete;
});
Then you can still test changes to props, changes from within the render function etc that you couldn't do with shallow rendering, but you don't need to worry about internal requirements like the google API.
Has the API changed from AutocompleteService to AutocompletionService? I haven't been able to get this to work with cypress and was wondering if the API has changed. On the network tab it shows AutocompletionService.GetPredictions
I am using beta version of Maps Javascript API (to call reverse geocode) which returns Promise.
In order to mock google.maps.Geocode
and google.maps.Geocode.geocode
I did the following in line with the comment above.
export const setupGoogleMock = (): void => {
window.google = {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
maps: {
Geocoder: jest.fn().mockImplementation(() => {
return {
geocode: jest.fn().mockResolvedValue({
results: [
{
formatted_address: `State St, Chicago, IL 60601, USA`,
},
],
}),
};
}),
},
};
};
test('reverseGeo', async () => {
setupGoogleMock();
expect(await reverseGeo({lat: 22.99, lng: 88.22})).toBe(`State St, Chicago, IL 60601, USA`);
});
It works for me to mock test the following function:
export const reverseGeo = async(latlng: google.maps.GeocoderRequest): Promise<string> => {
const geocoder = new google.maps.Geocoder();
const { results } = await geocoder.geocode({ location: latlng });
if (results && results[0]) {
return results[0].formatted_address;
}
return null;
}
In my case @OscarBarrett 's solution worked, with a small addition: window.google = undefined
So:
interface Props {
children: Function;
}
jest.mock('react-places-autocomplete', () => {
const React = require('react'); // eslint-disable-line
class PlacesAutocomplete extends React.Component<Props> {
renderProps = {
getInputProps: jest.fn(({ placeholder, className }) => ({
placeholder,
className
})),
suggestions: [],
getSuggestionItemProps: jest.fn()
};
render() {
return <>{this.props.children(this.renderProps)}</>;
}
}
return PlacesAutocomplete;
});
window.google = undefined;
@suvasishm I follow your example, it seems to work, but when I check the "coverage", it seems the test did not cover too much...
@suvasishm I follow your example, it seems to work, but when I check the "coverage", it seems the test did not cover too much...
Well, the goal was to having a functional mock for the library API. Coverage would probably depend on what your code does with the mocked response.
I am still having issue with the mock, I am a newbee here with jest testing but I get an error of dispatch of null when I mock the useplaceservice I am trying to test getPredictions function
Bless @hibiken and @chiamtc
You guys solved a problem I had for two days until I found your solutions and mixed them for my case. You are heroes! Thank you!
Hi, thank you for the solution. I still had this error :
e.LatLng is not a constructor
I fixed it by adding LatLng: class {}
but then i have this one that i don't know how to fix :
Cannot read properties of undefined (reading 'match')
Google has an official maps mocking library now, looks neat.
Do you want to request a feature or report a bug? Bug What is the current behavior? Throws error "Google Maps JavaScript API library must be loaded" when running npm run test.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.
create-react-app, setup react-places-autocomplete then install enzyme and jest. run npm test and it will break.
What is the expected behavior? Be able to run jest / enzyme without breaking app
Which versions of ReactPlacesAutocomplete, and which browser / OS are affected by this issue? Chrome,Mac, RPA6.1.3