Testing Algolia API with Playwright #6625
Replies: 4 comments 1 reply
-
In general that is indeed a good option, alternatively you can add a custom searchClient that returns static responses for tests |
Beta Was this translation helpful? Give feedback.
-
Follow up to the above. I've begun work on the more complicated tests. First up is a no results response on a summary page that presents results across 3 indexes. test('Search with no results', async({page}, {project}) => {
await page.route(/algolia.net/, async (route, request) => {
const data = JSON.parse(request.postData())
const results = data.requests.map(r => ({
hits: [],
nbHits: 0,
index: r.indexName,
query: r.query
}))
route.fulfill({json: {results }})
})
await page.goto('/search/?query=foo')
await expect(page.locator('#NoResults')).toBeVisible()
}) As can be seen above, rather than comparing against a rote response in a json file we compose a response appropriate to the query. Curiously Algolia goes off the rails if you don't give an empty response for each index individually like this. The second test works with an even more complicated situation - My site has searches for indvidiual hospitals. If there are no results within the hospital (as determined by set filters) the code uses a no results query to refire the query without the filters and label the return as "Covenant Health results based on your search". I learned that this refire is tacked onto the end of the first set of queries which confused me at first but does make sense. Again, here in the Playwright test, is how we fulfill this. test('Search facility with no results, fallback to global with results', async({page}, {project}) => {
await page.route(/algolia.net/, async (route, request) => {
const data = JSON.parse(request.postData())
const results = data.requests.map(r => {
if (r.filters || r.indexName !== 'Providers') {
return {
hits: [],
nbHits: 0,
index: r.indexName,
query: r.query
}
} else {
return {
hits: [drAbadier], // contained in a json file.
nbHits: 1,
index: r.indexName,
query: r.query
}
}
})
route.fulfill({json: {results }})
})
await page.goto('/parkwest/search/?query=foo')
await expect(page.locator('#providers h3')).toContainText('Covenant Health Providers Based on Your Search')
}) And here we compose a response where only 1 of the three indexes receives results to see if the display is correct. |
Beta Was this translation helpful? Give feedback.
-
Today's follow up deals with Geolocation. I imagine a lot of developers gather the user's location elsewhere in their code and not a few end up storing it in local or session storage. My code needs to know that location to run the Haversine formula against the location data and display "X miles away" To test this we need to set the localStorage up. Playwright encourages these sorts of functions to be kept in the central tests directory in a fixtures file. const setUserLocation = async (page) => {
/*
* PHP is setup to spit out a minimus page on this route. The page is "<!DOCTYPE hml><html><body></body></html>"
*
* Playwright needs to be on *a* page to run a page.evaluate.
*/
await page.goto('/tests/?wrap=tests/setup.twig')
await page.evaluate(() => {
window.localStorage.setItem('covenantHealth.userLocation', JSON.stringify({"name":"Knoxville, TN","coords":{"latitude":35.9349364,"longitude":-84.14943319999999}}))
window.localStorage.setItem('covenantHealth__persisting', JSON.stringify([["userLocation", false]]))
})
}
export {
expect,
setUserLocation,
test
} The values I'm setting are particular to my application and how its persisting dataStorage works. The principle of using a page.evaluate to call window.localStorage.setItem() should remain consistent across libraries. The test itself test('Results with distance', async({page}, {project}) => {
// Remember to import this.
await setUserLocation(page)
await page.route(/algolia.net/, async (route, request) => {
const data = JSON.parse(request.postData())
const results = data.requests.map(r => {
// Important gotcha - distance queries usually happen on a replica index
if (r.indexName === 'Providers_distance') {
// snip - the code here isn't significantly different from previous examples.
} else if (r.indexName === 'SBX_Location_search_distance') {
//snip
} else {
//snip
}
})
route.fulfill({json: { results }})
})
await page.goto('/search/?query=foo')
}) I realize this particular corner case isn't that Algolia specific, but it is a task many tests of Algolia apps will have to do so I figured it would be helpful to cover. I think this covers the major bases but I'm open to questions on the topic. |
Beta Was this translation helpful? Give feedback.
-
Today's followup - Geolocation testing. A lot of Algolia sites use Geolocation. Again, this isn't too Algolia specific, but it is a problem set I would expect at least a few out there will run into test("Find Results Near Me", async({page, context}) => {
/*
* Set up Playwright's browser to allow Geolocation.
*/
await context.grantPermissions(['geolocation'])
await context.setGeolocation({
latitude: 35.9347109,
longitude: -84.1496195
})
await context.route(/algolia.net/, async (route, request) => {
const data = JSON.parse(request.postData())
const results = data.requests.map(r => ({
hits: [drCapps, drAbazid, drHagenson],
nbHits: 3,
hitsPerPage: 3,
index: r.indexName,
query: r.query,
facets // Facets will be displayed on the page, so a facets.json file holds the typical output of the query
}))
route.fulfill({json: { results }})
})
await page.route(/googleapis/, async(route) => {
route.fulfill({json: userLocation})
})
/* Rest of the test follows with the exact sequence of clicks and data entries to test */
`` |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
In effort to improve my site's relability I've been introducing tests across the board. I'm going to start this thread to share notes.
So my first working test doing this is pretty small.
So I use visual regression testing pretty heavily. I'll likely need to mask the google maps output of this page as I can't control when they'll add new pins. The algoliaResponse json I just captured with Playwright. This page currently gets 191 hits, and I'm pruning this down to three with different attributes so that I can verify their layouts work.
Long term I'll be adjusting this to test how my system reacts to no results.
If anyone else has explored this more than the above and would like to share I'd like to take a look.
Beta Was this translation helpful? Give feedback.
All reactions