I am trying to test a react webapp (created in a separate project), that contains a popup where there’s an input containing a google auto-complete for cities:
(I changed text because of language)
I have in “search city” a text input where if data is inserted, google searches for cities and returns results (eg I search Rome, Italy):
When I press “save data” there’s a function that checks google results, then closes the popup:
in a file:
export const useGoogleApiDesktop = () => { let autocompleteService if (window.google && window.google.maps) { autocompleteService = new window.google.maps.places.AutocompleteService() } }
in another file (the one called):
const googleApi = useGoogleApiDesktop() const onSubmitClick = useCallback(async () => { [...] const res: GoogleApiPlacesResponse = await googleApi.autocompleteService.getPlacePredictions({ input: addressComputed, types: ['(cities)'], componentRestrictions: { country: 'it' } }) }, [])
When I use it in plain browser, everything works fine; but if I try to launch it with cypress to test it, it returns me this error:
I am trying to avoid this error and simply go on and close the popup, since during my tests I do not need to write anything on that line; I only need to write something on the other textareas and close the popup.
Since I couldn’t do it, I’ve tried to stub that call, but I am totally new in using cy.stub()
and does not work:
function selectAddress(bookingConfig) { // opens the popup cy.get('.reservationsWhereAdd').click() // trying to add the google library const win = cy.state('window') const document = win.document const script = document.createElement('script') script.src = `https://maps.googleapis.com/maps/api/js?key=[myApiKey]&libraries=places&language=it` script.async = true // this is commented since I don't think I need it // window.initMap = function () { // // JS API is loaded and available // console.log('lanciato') // } // Append the ‘script’ element to ‘head’ document.head.appendChild(script) // type something in some fields cy.get('#street').type(bookingConfig.street) cy.get('#streetNumber').type(bookingConfig.streetNum) cy.get('#nameOnTheDoorbell').type(bookingConfig.nameOnTheDoorbell) cy.get('#addressAlias').type(bookingConfig.addressAlias) // this correctly finds and prints the object console.log('--->', win.google.maps.places) cy.stub(googleApi.autocompleteService, 'getPlacePredictions') // this closes the popup cy.get('.flex-1 > .btn').click() }
this cy.stub
however does not works, and I don’t get why: it says
googleApi is not defined
Any idea on how to solve this? Thanks!
UPDATE:
After the error, working with the cypress window, I manually closed the popup, reopened it, filled the fields, and clicked on save data. It worked, so I added a cy.wait(1000)
just after opening the popup and it works for 95% of the times (9 times on 10). Any Idea on how to “wait for loading the google api, then fill the fields”?
Advertisement
Answer
As the update block said, I discovered that the problem was that it kept really long time to load the google API, because it’s not local and needs time to be retrieved.
So at first I just put a cy.wait(2000)
before executing my code; but this couldn’t be the answer: what happens if I run the code on a slow network? Or if it takes more time for my application to load?
So, i created a command, that first waits for the google API to load; if it fails to load after 5 attempts, the test fails. Then, after that, my code is being executed. This way my test won’t fail really easily.
Here’s the code:
in cypress/support/command.js
Cypress.Commands.add('waitForGoogleApi', () => { let mapWaitCount = 0 const mapWaitMax = 5 cyMapLoad() function cyMapLoad() { mapWaitCount++ cy.window().then(win => { if (typeof win.google != 'undefined') { console.log(`Done at attempt #${mapWaitCount}:`, win) return true } else if (mapWaitCount <= mapWaitMax) { console.log('Waiting attempt #' + mapWaitCount) // just log cy.wait(2000) cyMapLoad() } else if (mapWaitCount > mapWaitMax) { console.log('Failed to load google api') return false } }) } })
in file you want to use it:
cy.waitForGoogleApi().then(() => { // here comes the code to execute after loading the google Apis })