Skip to content

Commit fa77bbb

Browse files
authored
fix(query-bar): retain current query when new query is applied COMPASS-8262 (#6649)
* retain current query when new query is applied from autocomplete * tests * fix up * remove usage of lodash * memo map function
1 parent aa7664f commit fa77bbb

File tree

5 files changed

+244
-119
lines changed

5 files changed

+244
-119
lines changed

packages/compass-query-bar/src/components/option-editor.spec.tsx

Lines changed: 136 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
waitFor,
88
userEvent,
99
} from '@mongodb-js/testing-library-compass';
10-
import { OptionEditor } from './option-editor';
10+
import { OptionEditor, getOptionBasedQueries } from './option-editor';
1111
import type { SinonSpy } from 'sinon';
1212
import { applyFromHistory } from '../stores/query-bar-reducer';
1313
import sinon from 'sinon';
@@ -47,7 +47,8 @@ describe('OptionEditor', function () {
4747
insertEmptyDocOnFocus
4848
onChange={() => {}}
4949
value=""
50-
savedQueries={[]}
50+
recentQueries={[]}
51+
favoriteQueries={[]}
5152
onApplyQuery={applyFromHistory}
5253
></OptionEditor>
5354
);
@@ -69,7 +70,8 @@ describe('OptionEditor', function () {
6970
insertEmptyDocOnFocus
7071
onChange={() => {}}
7172
value="{ foo: 1 }"
72-
savedQueries={[]}
73+
recentQueries={[]}
74+
favoriteQueries={[]}
7375
onApplyQuery={applyFromHistory}
7476
></OptionEditor>
7577
);
@@ -91,7 +93,8 @@ describe('OptionEditor', function () {
9193
insertEmptyDocOnFocus
9294
onChange={() => {}}
9395
value=""
94-
savedQueries={[]}
96+
favoriteQueries={[]}
97+
recentQueries={[]}
9598
onApplyQuery={applyFromHistory}
9699
></OptionEditor>
97100
);
@@ -119,7 +122,8 @@ describe('OptionEditor', function () {
119122
insertEmptyDocOnFocus
120123
onChange={() => {}}
121124
value=""
122-
savedQueries={[]}
125+
favoriteQueries={[]}
126+
recentQueries={[]}
123127
onApplyQuery={applyFromHistory}
124128
></OptionEditor>
125129
);
@@ -149,7 +153,8 @@ describe('OptionEditor', function () {
149153
insertEmptyDocOnFocus
150154
onChange={() => {}}
151155
value=""
152-
savedQueries={[]}
156+
favoriteQueries={[]}
157+
recentQueries={[]}
153158
onApplyQuery={applyFromHistory}
154159
></OptionEditor>
155160
);
@@ -167,7 +172,7 @@ describe('OptionEditor', function () {
167172
});
168173
});
169174

170-
describe('when render filter bar with the query history autocompleter', function () {
175+
describe('when rendering filter option', function () {
171176
let onApplySpy: SinonSpy;
172177
let preferencesAccess: PreferencesAccess;
173178

@@ -182,64 +187,54 @@ describe('OptionEditor', function () {
182187
insertEmptyDocOnFocus
183188
onChange={() => {}}
184189
value=""
185-
savedQueries={[
190+
recentQueries={[
186191
{
187-
type: 'recent',
188-
lastExecuted: new Date(),
189-
queryProperties: {
190-
filter: { a: 1 },
191-
},
192-
},
193-
{
194-
type: 'favorite',
195-
lastExecuted: new Date(),
196-
queryProperties: {
197-
filter: { a: 2 },
198-
sort: { a: -1 },
199-
},
192+
_lastExecuted: new Date(),
193+
filter: { a: 1 },
200194
},
195+
]}
196+
favoriteQueries={[
201197
{
202-
type: 'recent',
203-
lastExecuted: new Date(),
204-
queryProperties: {
205-
filter: { a: 2 },
206-
sort: { a: -1 },
207-
update: { a: 10 },
208-
},
198+
_lastExecuted: new Date(),
199+
filter: { a: 2 },
200+
sort: { a: -1 },
209201
},
210202
]}
211203
onApplyQuery={onApplySpy}
212204
/>
213205
</PreferencesProvider>
214206
);
207+
userEvent.click(screen.getByRole('textbox'));
208+
await waitFor(() => {
209+
screen.getByLabelText('Completions');
210+
});
215211
});
216212

217213
afterEach(function () {
218214
cleanup();
219215
});
220216

221-
it('filter applied correctly when autocomplete option is clicked', async function () {
222-
userEvent.click(screen.getByRole('textbox'));
223-
await waitFor(() => {
224-
expect(screen.getAllByText('{ a: 1 }')[0]).to.be.visible;
225-
expect(screen.getByText('{ a: 2 }, sort: { a: -1 }')).to.be.visible;
226-
expect(
227-
screen.queryByText('{ a: 2 }, sort: { a: -1 }, update: { a: 10 }')
228-
).to.be.null;
229-
});
217+
it('renders autocomplete options', function () {
218+
expect(screen.getAllByText('{ a: 1 }')[0]).to.be.visible;
219+
expect(screen.getByText('{ a: 2 }, sort: { a: -1 }')).to.be.visible;
220+
});
230221

222+
it('calls onApply with correct params', async function () {
231223
// Simulate selecting the autocomplete option
232224
userEvent.click(screen.getByText('{ a: 2 }, sort: { a: -1 }'));
233225
await waitFor(() => {
234-
expect(onApplySpy.lastCall).to.be.calledWithExactly({
235-
filter: { a: 2 },
236-
sort: { a: -1 },
237-
});
226+
expect(onApplySpy.lastCall).to.be.calledWithExactly(
227+
{
228+
filter: { a: 2 },
229+
sort: { a: -1 },
230+
},
231+
[]
232+
);
238233
});
239234
});
240235
});
241236

242-
describe('when render project bar with the query history autocompleter', function () {
237+
describe('when rendering project option', function () {
243238
let onApplySpy: SinonSpy;
244239
let preferencesAccess: PreferencesAccess;
245240

@@ -254,62 +249,124 @@ describe('OptionEditor', function () {
254249
insertEmptyDocOnFocus
255250
onChange={() => {}}
256251
value=""
257-
savedQueries={[
258-
{
259-
type: 'favorite',
260-
lastExecuted: new Date(),
261-
queryProperties: {
262-
project: { a: 1 },
263-
},
264-
},
252+
favoriteQueries={[
265253
{
266-
type: 'favorite',
267-
lastExecuted: new Date(),
268-
queryProperties: {
269-
filter: { a: 2 },
270-
sort: { a: -1 },
271-
},
254+
_lastExecuted: new Date(),
255+
project: { a: 1 },
272256
},
257+
]}
258+
recentQueries={[
273259
{
274-
type: 'recent',
275-
lastExecuted: new Date(),
276-
queryProperties: {
277-
filter: { a: 2 },
278-
sort: { a: -1 },
279-
project: { a: 0 },
280-
},
260+
_lastExecuted: new Date(),
261+
project: { a: 0 },
281262
},
282263
]}
283264
onApplyQuery={onApplySpy}
284265
/>
285266
</PreferencesProvider>
286267
);
268+
userEvent.click(screen.getByRole('textbox'));
269+
await waitFor(() => {
270+
screen.getByLabelText('Completions');
271+
});
287272
});
288273

289274
afterEach(function () {
290275
cleanup();
291276
});
292277

293-
it('only queries with project property are shown in project editor', async function () {
294-
userEvent.click(screen.getByRole('textbox'));
295-
await waitFor(() => {
296-
expect(screen.getAllByText('project: { a: 1 }')[0]).to.be.visible;
297-
expect(screen.queryByText('{ a: 2 }, sort: { a: -1 }')).to.be.null;
298-
expect(screen.getByText('{ a: 2 }, sort: { a: -1 }, project: { a: 0 }'))
299-
.to.be.visible;
300-
});
278+
it('renders autocomplete options', function () {
279+
expect(screen.getAllByText('project: { a: 1 }')[0]).to.be.visible;
280+
expect(screen.getAllByText('project: { a: 0 }')[0]).to.be.visible;
281+
});
301282

283+
it('calls onApply with correct params', async function () {
302284
// Simulate selecting the autocomplete option
303-
userEvent.click(
304-
screen.getByText('{ a: 2 }, sort: { a: -1 }, project: { a: 0 }')
305-
);
285+
userEvent.click(screen.getByText('project: { a: 0 }'));
306286
await waitFor(() => {
307-
expect(onApplySpy.lastCall).to.be.calledWithExactly({
308-
filter: { a: 2 },
309-
sort: { a: -1 },
310-
project: { a: 0 },
311-
});
287+
expect(onApplySpy).to.have.been.calledOnceWithExactly(
288+
{
289+
project: { a: 0 },
290+
},
291+
['filter', 'collation', 'sort', 'hint', 'skip', 'limit', 'maxTimeMS']
292+
);
312293
});
313294
});
314295
});
296+
297+
describe('getOptionBasedQueries', function () {
298+
const savedQueries = [
299+
{
300+
_lastExecuted: new Date(),
301+
filter: { a: 1 },
302+
project: { b: 1 },
303+
sort: { c: 1 },
304+
collation: { locale: 'en' },
305+
hint: { a: 1 },
306+
skip: 1,
307+
limit: 1,
308+
},
309+
];
310+
311+
it('filters out update queries', function () {
312+
const queries = getOptionBasedQueries('filter', 'recent', [
313+
...savedQueries,
314+
{ _lastExecuted: new Date(), update: { a: 1 }, filter: { a: 2 } },
315+
]);
316+
expect(queries.length).to.equal(1);
317+
});
318+
319+
it('filters out empty queries', function () {
320+
const queries = getOptionBasedQueries('filter', 'recent', [
321+
...savedQueries,
322+
{ _lastExecuted: new Date() },
323+
]);
324+
expect(queries.length).to.equal(1);
325+
});
326+
327+
it('filters out duplicate queries', function () {
328+
const queries = getOptionBasedQueries('filter', 'recent', [
329+
...savedQueries,
330+
...savedQueries,
331+
...savedQueries,
332+
{ _lastExecuted: new Date() },
333+
{ _lastExecuted: new Date() },
334+
]);
335+
expect(queries.length).to.equal(1);
336+
});
337+
338+
const optionNames = [
339+
'filter',
340+
'project',
341+
'sort',
342+
'collation',
343+
'hint',
344+
] as const;
345+
for (const name of optionNames) {
346+
it(`maps query for ${name}`, function () {
347+
const queries = getOptionBasedQueries(name, 'recent', savedQueries);
348+
349+
// For filter, we include all the query properties and for the rest
350+
// we only include that specific option.
351+
const queryProperties =
352+
name === 'filter'
353+
? Object.fromEntries(
354+
Object.entries(savedQueries[0]).filter(
355+
([key]) => key !== '_lastExecuted'
356+
)
357+
)
358+
: {
359+
[name]: savedQueries[0][name],
360+
};
361+
362+
expect(queries).to.deep.equal([
363+
{
364+
lastExecuted: savedQueries[0]._lastExecuted,
365+
queryProperties,
366+
type: 'recent',
367+
},
368+
]);
369+
});
370+
}
371+
});
315372
});

0 commit comments

Comments
 (0)