blob: c758a41733819dccb996051d6e9439d7f12cfcdc [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {assert} from 'chai';
6import sinon from 'sinon';
7
8import {MrSearchBar} from './mr-search-bar.js';
9import {prpcClient} from 'prpc-client-instance.js';
10import {issueRefToUrl} from 'shared/convertersV0.js';
11import {clientLoggerFake} from 'shared/test/fakes.js';
12
13
14window.CS_env = {
15 token: 'foo-token',
16};
17
18let element;
19
20describe('mr-search-bar', () => {
21 beforeEach(() => {
22 element = document.createElement('mr-search-bar');
23 document.body.appendChild(element);
24 });
25
26 afterEach(() => {
27 document.body.removeChild(element);
28 });
29
30 it('initializes', () => {
31 assert.instanceOf(element, MrSearchBar);
32 });
33
34 it('render user saved queries', async () => {
35 element.userDisplayName = 'test@user.com';
36 element.userSavedQueries = [
37 {name: 'test query', queryId: 101},
38 {name: 'hello world', queryId: 202},
39 ];
40
41 await element.updateComplete;
42
43 const queryOptions = element.shadowRoot.querySelectorAll(
44 '.user-query');
45
46 assert.equal(queryOptions.length, 2);
47
48 assert.equal(queryOptions[0].value, '101');
49 assert.equal(queryOptions[0].textContent, 'test query');
50
51 assert.equal(queryOptions[1].value, '202');
52 assert.equal(queryOptions[1].textContent, 'hello world');
53 });
54
55 it('render project saved queries', async () => {
56 element.userDisplayName = 'test@user.com';
57 element.projectSavedQueries = [
58 {name: 'test query', queryId: 101},
59 {name: 'hello world', queryId: 202},
60 ];
61
62 await element.updateComplete;
63
64 const queryOptions = element.shadowRoot.querySelectorAll(
65 '.project-query');
66
67 assert.equal(queryOptions.length, 2);
68
69 assert.equal(queryOptions[0].value, '101');
70 assert.equal(queryOptions[0].textContent, 'test query');
71
72 assert.equal(queryOptions[1].value, '202');
73 assert.equal(queryOptions[1].textContent, 'hello world');
74 });
75
76 it('search input resets form value when initialQuery changes', async () => {
77 element.initialQuery = 'first query';
78 await element.updateComplete;
79
80 const queryInput = element.shadowRoot.querySelector('#searchq');
81
82 assert.equal(queryInput.value, 'first query');
83
84 // Simulate a user typing something into the search form.
85 queryInput.value = 'blah';
86
87 element.initialQuery = 'second query';
88 await element.updateComplete;
89
90 // 'blah' disappears because the new initialQuery causes the form to
91 // reset.
92 assert.equal(queryInput.value, 'second query');
93 });
94
95 it('unrelated property changes do not reset query form', async () => {
96 element.initialQuery = 'first query';
97 await element.updateComplete;
98
99 const queryInput = element.shadowRoot.querySelector('#searchq');
100
101 assert.equal(queryInput.value, 'first query');
102
103 // Simulate a user typing something into the search form.
104 queryInput.value = 'blah';
105
106 element.initialCan = '5';
107 await element.updateComplete;
108
109 assert.equal(queryInput.value, 'blah');
110 });
111
112 it('spell check is off for search bar', async () => {
113 await element.updateComplete;
114 const searchElement = element.shadowRoot.querySelector('#searchq');
115 assert.equal(searchElement.getAttribute('spellcheck'), 'false');
116 });
117
118 describe('search form submit', () => {
119 let prpcClientStub;
120 beforeEach(() => {
121 element.clientLogger = clientLoggerFake();
122
123 element._page = sinon.stub();
124 sinon.stub(window, 'open');
125
126 element.projectName = 'chromium';
127 prpcClientStub = sinon.stub(prpcClient, 'call');
128 });
129
130 afterEach(() => {
131 window.open.restore();
132 prpcClient.call.restore();
133 });
134
135 it('prevents default', async () => {
136 await element.updateComplete;
137
138 const form = element.shadowRoot.querySelector('form');
139
140 // Note: HTMLFormElement's submit function does not run submit handlers
141 // but clicking a submit buttons programmatically works.
142 const event = new Event('submit');
143 sinon.stub(event, 'preventDefault');
144 form.dispatchEvent(event);
145
146 sinon.assert.calledOnce(event.preventDefault);
147 });
148
149 it('uses initial values when no form changes', async () => {
150 element.initialQuery = 'test query';
151 element.initialCan = '3';
152
153 await element.updateComplete;
154
155 const form = element.shadowRoot.querySelector('form');
156
157 form.dispatchEvent(new Event('submit'));
158
159 sinon.assert.calledOnce(element._page);
160 sinon.assert.calledWith(element._page,
161 '/p/chromium/issues/list?q=test%20query&can=3');
162 });
163
164 it('adds form values to url', async () => {
165 await element.updateComplete;
166
167 const form = element.shadowRoot.querySelector('form');
168
169 form.q.value = 'test';
170 form.can.value = '1';
171
172 form.dispatchEvent(new Event('submit'));
173
174 sinon.assert.calledOnce(element._page);
175 sinon.assert.calledWith(element._page,
176 '/p/chromium/issues/list?q=test&can=1');
177 });
178
179 it('trims query', async () => {
180 await element.updateComplete;
181
182 const form = element.shadowRoot.querySelector('form');
183
184 form.q.value = ' abc ';
185 form.can.value = '1';
186
187 form.dispatchEvent(new Event('submit'));
188
189 sinon.assert.calledOnce(element._page);
190 sinon.assert.calledWith(element._page,
191 '/p/chromium/issues/list?q=abc&can=1');
192 });
193
194 it('jumps to issue for digit-only query', async () => {
195 prpcClientStub.returns(Promise.resolve({issue: 'hello world'}));
196
197 await element.updateComplete;
198
199 const form = element.shadowRoot.querySelector('form');
200
201 form.q.value = '123';
202 form.can.value = '1';
203
204 form.dispatchEvent(new Event('submit'));
205
206 await element._navigateToNext;
207
208 const expected = issueRefToUrl('hello world', {q: '123', can: '1'});
209 sinon.assert.calledWith(element._page, expected);
210 });
211
212 it('only keeps kept query params', async () => {
213 element.queryParams = {fakeParam: 'test', x: 'Status'};
214 element.keptParams = ['x'];
215
216 await element.updateComplete;
217
218 const form = element.shadowRoot.querySelector('form');
219
220 form.dispatchEvent(new Event('submit'));
221
222 sinon.assert.calledOnce(element._page);
223 sinon.assert.calledWith(element._page,
224 '/p/chromium/issues/list?x=Status&q=&can=2');
225 });
226
227 it('on shift+enter opens search in new tab', async () => {
228 await element.updateComplete;
229
230 const form = element.shadowRoot.querySelector('form');
231
232 form.q.value = 'test';
233 form.can.value = '1';
234
235 // Dispatch event from an input in the form.
236 form.q.dispatchEvent(new KeyboardEvent('keypress',
237 {key: 'Enter', shiftKey: true, bubbles: true}));
238
239 sinon.assert.calledOnce(window.open);
240 sinon.assert.calledWith(window.open,
241 '/p/chromium/issues/list?q=test&can=1', '_blank', 'noopener');
242 });
243 });
244});