Adrià Vilanova MartÃnez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | import {assert} from 'chai'; |
| 6 | import sinon from 'sinon'; |
| 7 | |
| 8 | import {MrSearchBar} from './mr-search-bar.js'; |
| 9 | import {prpcClient} from 'prpc-client-instance.js'; |
| 10 | import {issueRefToUrl} from 'shared/convertersV0.js'; |
| 11 | import {clientLoggerFake} from 'shared/test/fakes.js'; |
| 12 | |
| 13 | |
| 14 | window.CS_env = { |
| 15 | token: 'foo-token', |
| 16 | }; |
| 17 | |
| 18 | let element; |
| 19 | |
| 20 | describe('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 | }); |