-
Notifications
You must be signed in to change notification settings - Fork 66.9k
Expand file tree
/
Copy pathapi-ai-search-autocomplete.ts
More file actions
157 lines (139 loc) · 5.45 KB
/
api-ai-search-autocomplete.ts
File metadata and controls
157 lines (139 loc) · 5.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* To be able to run these tests you need to index the fixtures!
* And you need to have an Elasticsearch URL to connect to for the server.
*
* To index the fixtures, run:
*
* ELASTICSEARCH_URL=http://localhost:9200 npm run index-test-fixtures
*
* This will replace any "real" Elasticsearch indexes you might have so
* once you're done working on vitest tests you need to index real
* content again.
*/
import { expect, test, vi } from 'vitest'
import { describeIfElasticsearchURL } from '@/tests/helpers/conditional-runs'
import { get } from '@/tests/helpers/e2etest'
import type { AutocompleteSearchResponse } from '@/search/types'
if (!process.env.ELASTICSEARCH_URL) {
console.warn(
'None of the API search middleware tests are run because ' +
"the environment variable 'ELASTICSEARCH_URL' is currently not set.",
)
}
const aiSearchEndpoint = '/api/search/ai-search-autocomplete/v1'
const getSearchEndpointWithParams = (searchParams: URLSearchParams) =>
`${aiSearchEndpoint}?${searchParams}`
// This suite only runs if $ELASTICSEARCH_URL is set.
describeIfElasticsearchURL('search/ai-search-autocomplete v1 middleware', () => {
vi.setConfig({ testTimeout: 60 * 1000 })
test('perform a basic ai autocomplete search', async () => {
const sp = new URLSearchParams()
// To see why this will work,
// see src/search/tests/fixtures/data/ai/*
sp.set('query', 'how do I')
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
const results = JSON.parse(res.body) as AutocompleteSearchResponse
expect(results.meta).toBeTruthy()
expect(results.meta.found.value).toBeGreaterThanOrEqual(1)
expect(results.meta.found.relation).toBeTruthy()
expect(results.hits).toBeTruthy()
const hit = results.hits[0]
expect(hit.term).toBe('How do I clone a repository?')
expect(hit.highlights).toBeTruthy()
expect(hit.highlights[0]).toBe('<mark>How do I</mark> clone a repository?')
// Check that it can be cached at the CDN
expect(res.headers['set-cookie']).toBeUndefined()
expect(res.headers['cache-control']).toContain('public')
expect(res.headers['cache-control']).toMatch(/max-age=[1-9]/)
expect(res.headers['surrogate-control']).toContain('public')
expect(res.headers['surrogate-control']).toMatch(/max-age=[1-9]/)
expect(res.headers['surrogate-key']).toBe('every-deployment')
})
test('invalid version', async () => {
const sp = new URLSearchParams()
sp.set('query', 'fo')
sp.set('version', 'never-heard-of')
const res = await get(`${aiSearchEndpoint}?${sp}`)
expect(res.statusCode).toBe(400)
expect(JSON.parse(res.body).error).toBeTruthy()
})
test('variations on version name', async () => {
const sp = new URLSearchParams()
sp.set('query', 'fo')
sp.set('version', 'enterprise-cloud')
{
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
}
sp.set('version', 'ghec')
{
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
}
sp.set('version', 'fpt')
{
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
}
sp.set('version', 'free-pro-team@latest')
{
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
}
})
test('invalid language', async () => {
const sp = new URLSearchParams()
sp.set('query', 'fo')
sp.set('language', 'xx')
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(400)
expect(JSON.parse(res.body).error).toBeTruthy()
})
test('only english supported', async () => {
const sp = new URLSearchParams()
sp.set('query', 'fo')
sp.set('language', 'ja')
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(400)
expect(JSON.parse(res.body).error).toBeTruthy()
})
test('fuzzy autocomplete search', async () => {
const sp = new URLSearchParams()
sp.set('query', 'cl') // Short for "clone"
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
const results = JSON.parse(res.body) as AutocompleteSearchResponse
// 'cl" matches "How do I clone a repository?"
const hit = results.hits[0]
expect(hit.term).toBe('How do I clone a repository?')
// Highlighting behavior will highlight the matching "term" which is an entire word
// In this case that word is "clone" when the query is "cl"
expect(hit.highlights[0]).toBe('How do I <mark>clone</mark> a repository?')
})
test('autocomplete term search', async () => {
const sp = new URLSearchParams()
sp.set('query', 'clone')
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
const results = JSON.parse(res.body) as AutocompleteSearchResponse
const hit = results.hits[0]
expect(hit.term).toBe('How do I clone a repository?')
expect(hit.highlights).toBeTruthy()
expect(hit.highlights[0]).toBe('How do I <mark>clone</mark> a repository?')
})
test('support empty query', async () => {
const sp = new URLSearchParams()
// No query at all
{
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
}
// Empty query
{
sp.set('query', '')
const res = await get(getSearchEndpointWithParams(sp))
expect(res.statusCode).toBe(200)
}
})
})