Skip to content

Commit 0c443eb

Browse files
bors[bot]bidoubiwa
andauthored
Merge #393
393: Add integration and unit tests on filters r=bidoubiwa a=bidoubiwa Co-authored-by: Charlotte Vermandel <[email protected]> Co-authored-by: bors[bot] <26634292+bors[bot]@users.noreply.github.com>
2 parents be0c0aa + 6c479e0 commit 0c443eb

File tree

7 files changed

+206
-57
lines changed

7 files changed

+206
-57
lines changed

playgrounds/react/src/App.js

Lines changed: 43 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'instantsearch.css/themes/algolia-min.css'
2-
import React, { Component } from 'react'
2+
import React from 'react'
33
import {
44
InstantSearch,
55
InfiniteHits,
@@ -22,59 +22,50 @@ const searchClient = instantMeiliSearch(
2222
}
2323
)
2424

25-
class App extends Component {
26-
render() {
27-
return (
28-
<div className="ais-InstantSearch">
29-
<h1>MeiliSearch + React InstantSearch</h1>
30-
<h2>
31-
Search in Steam video games{' '}
32-
<span role="img" aria-label="emoji">
33-
🎮
34-
</span>
35-
</h2>
36-
<p>
37-
This is not the official Steam dataset but only for demo purpose.
38-
Enjoy searching with MeiliSearch!
39-
</p>
40-
<InstantSearch
41-
indexName="steam-video-games"
42-
searchClient={searchClient}
43-
>
44-
<Stats />
45-
<div className="left-panel">
46-
<ClearRefinements />
47-
<h2>Genres</h2>
48-
<RefinementList attribute="genres" />
49-
<h2>Players</h2>
50-
<RefinementList attribute="players" />
51-
<h2>Platforms</h2>
52-
<RefinementList attribute="platforms" />
53-
<h2>Misc</h2>
54-
<RefinementList attribute="misc" />
55-
<Configure hitsPerPage={6} />
56-
</div>
57-
<div className="right-panel">
58-
<SearchBox />
59-
<InfiniteHits hitComponent={Hit} />
60-
</div>
61-
</InstantSearch>
25+
const App = () => (
26+
<div className="ais-InstantSearch">
27+
<h1>MeiliSearch + React InstantSearch</h1>
28+
<h2>
29+
Search in Steam video games{' '}
30+
<span role="img" aria-label="emoji">
31+
🎮
32+
</span>
33+
</h2>
34+
<p>
35+
This is not the official Steam dataset but only for demo purpose. Enjoy
36+
searching with MeiliSearch!
37+
</p>
38+
<InstantSearch indexName="steam-video-games" searchClient={searchClient}>
39+
<Stats />
40+
<div className="left-panel">
41+
<ClearRefinements />
42+
<h2>Genres</h2>
43+
<RefinementList attribute="genres" />
44+
<h2>Players</h2>
45+
<RefinementList attribute="players" />
46+
<h2>Platforms</h2>
47+
<RefinementList attribute="platforms" />
48+
<h2>Misc</h2>
49+
<RefinementList attribute="misc" />
50+
<Configure hitsPerPage={6} />
6251
</div>
63-
)
64-
}
65-
}
66-
67-
function Hit(props) {
68-
return (
69-
<div key={props.hit.id}>
70-
<div className="hit-name">
71-
<Highlight attribute="name" hit={props.hit} />
52+
<div className="right-panel">
53+
<SearchBox />
54+
<InfiniteHits hitComponent={Hit} />
7255
</div>
73-
<img src={props.hit.image} align="left" alt={props.hit.name} />
74-
<div className="hit-info">price: {props.hit.price}</div>
75-
<div className="hit-info">release date: {props.hit.releaseDate}</div>
56+
</InstantSearch>
57+
</div>
58+
)
59+
60+
const Hit = ({ hit }) => (
61+
<div key={hit.id}>
62+
<div className="hit-name">
63+
<Highlight attribute="name" hit={hit} />
7664
</div>
77-
)
78-
}
65+
<img src={hit.image} align="left" alt={hit.name} />
66+
<div className="hit-info">price: {hit.price}</div>
67+
<div className="hit-info">release date: {hit.releaseDate}</div>
68+
</div>
69+
)
7970

8071
export default App
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { mergeFiltersAndNumericFilters } from '../'
2+
3+
const filtersTestsParameters = [
4+
{
5+
filters: '',
6+
numericFilters: [],
7+
returnFilter: '',
8+
},
9+
{
10+
filters: 'hello = hello',
11+
numericFilters: [],
12+
returnFilter: '(hello = hello)',
13+
},
14+
{
15+
filters: '(hello = hello AND (hello1 = hello1 OR hello2 = hello2))',
16+
numericFilters: [],
17+
returnFilter: '((hello = hello AND (hello1 = hello1 OR hello2 = hello2)))',
18+
},
19+
{
20+
filters: '(hello = hello AND (hello1 = hello1 OR hello2 = hello2))',
21+
numericFilters: [],
22+
returnFilter: '((hello = hello AND (hello1 = hello1 OR hello2 = hello2)))',
23+
},
24+
{
25+
filters: '',
26+
numericFilters: [' 1 < hello ', ' hello < 2 '],
27+
returnFilter: '1 < hello AND hello < 2',
28+
},
29+
{
30+
filters: ' ',
31+
numericFilters: [' ', ' '],
32+
returnFilter: '',
33+
},
34+
{
35+
filters: 'hello = hello AND hello1 = hello1',
36+
numericFilters: [' 1 < hello ', ' hello < 2 '],
37+
returnFilter:
38+
'1 < hello AND hello < 2 AND (hello = hello AND hello1 = hello1)',
39+
},
40+
]
41+
42+
describe.each(filtersTestsParameters)(
43+
'Filter tests',
44+
({ filters, numericFilters, returnFilter }) => {
45+
it(`Should return ${returnFilter} pages when filter is ${filters} and Numeric Filters is ${JSON.stringify(
46+
numericFilters
47+
)}`, () => {
48+
const response = mergeFiltersAndNumericFilters(filters, numericFilters)
49+
expect(response).toBe(returnFilter)
50+
})
51+
}
52+
)

src/transformers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './to-meilisearch-params'
2+
export * from './to-meilisearch-filters'
23
export * from './to-instantsearch-response'
34
export * from './to-instantsearch-hits'
45
export * from './to-instantsearch-highlight'
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { MergeFiltersAndNumericFilters } from '../types'
2+
3+
const mergeFiltersAndNumericFilters: MergeFiltersAndNumericFilters = (
4+
filters,
5+
numericFilters
6+
) => {
7+
const trimFilters = filters ? filters.trim() : ''
8+
const enClosedFilter = trimFilters ? `(${trimFilters})` : ''
9+
const joinedNumericFilters = numericFilters
10+
? numericFilters
11+
.map((filter) => filter.trim())
12+
.filter((x) => x)
13+
.join(' AND ')
14+
: ''
15+
16+
const filter = [joinedNumericFilters, enClosedFilter]
17+
.filter((x) => x)
18+
.join(' AND ')
19+
.trim()
20+
return filter
21+
}
22+
23+
export { mergeFiltersAndNumericFilters }

src/transformers/to-meilisearch-params.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { TransformToMeiliSearchParams } from '../types'
2+
import { mergeFiltersAndNumericFilters } from './to-meilisearch-filters'
23

34
export const transformToMeiliSearchParams: TransformToMeiliSearchParams = function (
45
{
@@ -14,11 +15,7 @@ export const transformToMeiliSearchParams: TransformToMeiliSearchParams = functi
1415
{ paginationTotalHits, placeholderSearch }
1516
) {
1617
const limit = paginationTotalHits
17-
18-
const filter = [numericFilters.join(' AND '), filters.trim()]
19-
.filter((x) => x)
20-
.join(' AND ')
21-
.trim()
18+
const filter = mergeFiltersAndNumericFilters(filters, numericFilters)
2219

2320
// Creates search params object compliant with MeiliSearch
2421
return {

src/types/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ export type ReplaceHighlightTags = (
6262
highlightPostTag?: string
6363
) => string
6464

65+
export type MergeFiltersAndNumericFilters = (
66+
filters?: string,
67+
numericFilters?: string[]
68+
) => string
69+
6570
export type CreateSnippetResult = (
6671
snippetsParams: HighLightParams & SnippetsParams & FormattedHit
6772
) => { formattedHit: any } & ISSearchParams

tests/configure.filters.tests.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { searchClient, dataset, Movies } from './assets/utils'
2+
3+
describe('Instant MeiliSearch Browser test', () => {
4+
beforeAll(async () => {
5+
try {
6+
await searchClient.MeiliSearchClient.deleteIndex('movies')
7+
} catch (e) {
8+
// movies does not exist
9+
}
10+
const moviesUpdate = await searchClient.MeiliSearchClient.index(
11+
'movies'
12+
).addDocuments(dataset)
13+
await searchClient.MeiliSearchClient.index('movies').waitForPendingUpdate(
14+
moviesUpdate.updateId
15+
)
16+
})
17+
18+
test('Test multiple filters', async () => {
19+
const response = await searchClient.search([
20+
{
21+
indexName: 'movies',
22+
params: {
23+
filters:
24+
'title = "Four Rooms" OR title = "Ariel" AND release_date > 593395200',
25+
query: '',
26+
},
27+
},
28+
])
29+
30+
const hit = <Movies>response.results[0].hits[0]
31+
expect(hit.title).toEqual('Four Rooms')
32+
})
33+
34+
test('Test empty', async () => {
35+
const response = await searchClient.search([
36+
{
37+
indexName: 'movies',
38+
params: {
39+
filters: '',
40+
query: '',
41+
},
42+
},
43+
])
44+
45+
const hit = <Movies>response.results[0].hits[0]
46+
expect(hit.title).toEqual('Ariel')
47+
})
48+
49+
test('Test multiple filters', async () => {
50+
const response = await searchClient.search([
51+
{
52+
indexName: 'movies',
53+
params: {
54+
filters: 'title = "Four Rooms" OR title = "Ariel"',
55+
numericFilters: ['release_date > 593395200'],
56+
query: '',
57+
},
58+
},
59+
])
60+
61+
const hit = <Movies>response.results[0].hits[0]
62+
expect(hit.title).toEqual('Four Rooms')
63+
})
64+
65+
test('Only numeric filters', async () => {
66+
const response = await searchClient.search([
67+
{
68+
indexName: 'movies',
69+
params: {
70+
filters: 'title = "Four Rooms" OR title = "Ariel"',
71+
numericFilters: ['release_date > 593395200'],
72+
query: '',
73+
},
74+
},
75+
])
76+
77+
const hit = <Movies>response.results[0].hits[0]
78+
expect(hit.title).toEqual('Four Rooms')
79+
})
80+
})

0 commit comments

Comments
 (0)