autocomplete_test.js 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  1. // Copyright 2006 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. goog.provide('goog.ui.ac.AutoCompleteTest');
  15. goog.setTestOnly('goog.ui.ac.AutoCompleteTest');
  16. goog.require('goog.a11y.aria');
  17. goog.require('goog.a11y.aria.Role');
  18. goog.require('goog.dom');
  19. goog.require('goog.dom.InputType');
  20. goog.require('goog.dom.TagName');
  21. goog.require('goog.events.EventHandler');
  22. goog.require('goog.events.EventTarget');
  23. goog.require('goog.string');
  24. goog.require('goog.testing.MockControl');
  25. goog.require('goog.testing.events');
  26. goog.require('goog.testing.jsunit');
  27. goog.require('goog.testing.mockmatchers');
  28. goog.require('goog.ui.ac.AutoComplete');
  29. goog.require('goog.ui.ac.InputHandler');
  30. goog.require('goog.ui.ac.RenderOptions');
  31. goog.require('goog.ui.ac.Renderer');
  32. /**
  33. * Mock DataStore
  34. * @constructor
  35. */
  36. function MockDS(opt_autoHilite) {
  37. this.autoHilite_ = opt_autoHilite;
  38. var disabledRow = {
  39. match: function(str) { return this.text.match(str); },
  40. rowDisabled: true,
  41. text: 'hello@u.edu'
  42. };
  43. this.rows_ = [
  44. '"Slartibartfast Theadore" <fjordmaster@magrathea.com>',
  45. '"Zaphod Beeblebrox" <theprez@universe.gov>',
  46. '"Ford Prefect" <ford@theguide.com>',
  47. '"Arthur Dent" <has.no.tea@gmail.com>',
  48. '"Marvin The Paranoid Android" <marv@googlemail.com>',
  49. 'the.mice@magrathea.com', 'the.mice@myotherdomain.com', 'hello@a.com',
  50. disabledRow, 'row@u.edu', 'person@a.edu'
  51. ];
  52. this.isRowDisabled = function(row) { return !!row.rowDisabled; };
  53. }
  54. MockDS.prototype.requestMatchingRows = function(
  55. token, maxMatches, matchHandler) {
  56. var escapedToken = goog.string.regExpEscape(token);
  57. var matcher = new RegExp('(^|\\W+)' + escapedToken);
  58. var matches = [];
  59. for (var i = 0; i < this.rows_.length && matches.length < maxMatches; ++i) {
  60. var row = this.rows_[i];
  61. if (row.match(matcher)) {
  62. matches.push(row);
  63. }
  64. }
  65. if (this.autoHilite_ === undefined) {
  66. matchHandler(token, matches);
  67. } else {
  68. var options = new goog.ui.ac.RenderOptions();
  69. options.setAutoHilite(this.autoHilite_);
  70. matchHandler(token, matches, options);
  71. }
  72. };
  73. /**
  74. * Mock Selection Handler
  75. */
  76. function MockSelect() {}
  77. goog.inherits(MockSelect, goog.events.EventTarget);
  78. MockSelect.prototype.selectRow = function(row) {
  79. this.selectedRow = row;
  80. };
  81. /**
  82. * Renderer subclass that exposes additional private members for testing.
  83. * @constructor
  84. */
  85. function TestRend() {
  86. goog.ui.ac.Renderer.call(this, goog.dom.getElement('test-area'));
  87. }
  88. goog.inherits(TestRend, goog.ui.ac.Renderer);
  89. TestRend.prototype.getRenderedRows = function() {
  90. return this.rows_;
  91. };
  92. TestRend.prototype.getHilitedRowIndex = function() {
  93. return this.hilitedRow_;
  94. };
  95. TestRend.prototype.getHilitedRowDiv = function() {
  96. return this.rowDivs_[this.hilitedRow_];
  97. };
  98. TestRend.prototype.getRowDiv = function(index) {
  99. return this.rowDivs_[index];
  100. };
  101. var handler;
  102. var inputElement;
  103. var mockControl;
  104. function setUp() {
  105. inputElement = goog.dom.createDom(
  106. goog.dom.TagName.INPUT, {type: goog.dom.InputType.TEXT});
  107. handler = new goog.events.EventHandler();
  108. mockControl = new goog.testing.MockControl();
  109. }
  110. function tearDown() {
  111. handler.dispose();
  112. mockControl.$tearDown();
  113. goog.dom.removeChildren(goog.dom.getElement('test-area'));
  114. }
  115. /**
  116. * Make sure results are truncated (or not) by setMaxMatches.
  117. */
  118. function testMaxMatches() {
  119. var ds = new MockDS();
  120. var rend = new TestRend();
  121. var select = new MockSelect();
  122. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  123. ac.setMaxMatches(2);
  124. ac.setToken('the');
  125. assertEquals(2, rend.getRenderedRows().length);
  126. ac.setToken('');
  127. ac.setMaxMatches(3);
  128. ac.setToken('the');
  129. assertEquals(3, rend.getRenderedRows().length);
  130. ac.setToken('');
  131. ac.setMaxMatches(1000);
  132. ac.setToken('the');
  133. assertEquals(4, rend.getRenderedRows().length);
  134. ac.setToken('');
  135. }
  136. function testHiliteViaMouse() {
  137. var ds = new MockDS();
  138. var rend = new TestRend();
  139. var select = new MockSelect();
  140. var updates = 0;
  141. var row = null;
  142. var rowNode = null;
  143. handler.listen(
  144. rend, goog.ui.ac.AutoComplete.EventType.ROW_HILITE, function(evt) {
  145. updates++;
  146. rowNode = evt.rowNode;
  147. });
  148. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  149. ac.setMaxMatches(4);
  150. ac.setToken('the');
  151. // Need to set the startRenderingRows_ time to something long ago, otherwise
  152. // the mouse event will not be fired. (The autocomplete logic waits for some
  153. // time to pass after rendering before firing mouseover events.)
  154. rend.startRenderingRows_ = -1;
  155. var hilitedRowDiv = rend.getRowDiv(3);
  156. goog.testing.events.fireMouseOverEvent(hilitedRowDiv);
  157. assertEquals(2, updates);
  158. assertTrue(goog.string.contains(rowNode.innerHTML, 'mice@myotherdomain.com'));
  159. }
  160. function testMouseClickBeforeHilite() {
  161. var ds = new MockDS();
  162. var rend = new TestRend();
  163. var select = new MockSelect();
  164. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  165. ac.setMaxMatches(4);
  166. ac.setToken('the');
  167. // Need to set the startRenderingRows_ time to something long ago, otherwise
  168. // the mouse event will not be fired. (The autocomplete logic waits for some
  169. // time to pass after rendering before firing mouseover events.)
  170. rend.startRenderingRows_ = -1;
  171. // hilite row 3...
  172. var hilitedRowDiv = rend.getRowDiv(3);
  173. goog.testing.events.fireMouseOverEvent(hilitedRowDiv);
  174. // but click row 2, to simulate mouse getting ahead of focus.
  175. var targetRowDiv = rend.getRowDiv(2);
  176. goog.testing.events.fireClickEvent(targetRowDiv);
  177. assertEquals('the.mice@magrathea.com', select.selectedRow);
  178. }
  179. function testMouseClickOnFirstRowBeforeHilite() {
  180. var ds = new MockDS();
  181. var rend = new TestRend();
  182. var select = new MockSelect();
  183. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  184. ac.setAutoHilite(false);
  185. ac.setMaxMatches(4);
  186. ac.setToken('the');
  187. // Click the first row before highlighting it, to simulate mouse getting ahead
  188. // of focus.
  189. var targetRowDiv = rend.getRowDiv(0);
  190. goog.testing.events.fireClickEvent(targetRowDiv);
  191. assertEquals(
  192. '"Zaphod Beeblebrox" <theprez@universe.gov>', select.selectedRow);
  193. }
  194. function testMouseClickOnRowAfterBlur() {
  195. var ds = new MockDS();
  196. var rend = new TestRend();
  197. var ih = new goog.ui.ac.InputHandler();
  198. ih.attachInput(inputElement);
  199. var ac = new goog.ui.ac.AutoComplete(ds, rend, ih);
  200. goog.testing.events.fireFocusEvent(inputElement);
  201. ac.setToken('the');
  202. var targetRowDiv = rend.getRowDiv(0);
  203. // Simulate the user clicking on an autocomplete row in the short time between
  204. // blur and autocomplete dismissal.
  205. goog.testing.events.fireBlurEvent(inputElement);
  206. assertNotThrows(function() {
  207. goog.testing.events.fireClickEvent(targetRowDiv);
  208. });
  209. }
  210. /*
  211. * Send AutoComplete a SELECT event with empty string for the row. We can't
  212. * simulate with a simple mouse click, so we dispatch the event directly.
  213. */
  214. function testSelectEventEmptyRow() {
  215. var ds = new MockDS();
  216. var rend = new TestRend();
  217. var select = new MockSelect();
  218. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  219. ac.setMaxMatches(4);
  220. ac.setToken('the');
  221. rend.startRenderingRows_ = -1;
  222. // hilight row 2 ('the.mice@...')
  223. var hilitedRowDiv = rend.getRowDiv(2);
  224. goog.testing.events.fireMouseOverEvent(hilitedRowDiv);
  225. assertUndefined(select.selectedRow);
  226. // Dispatch an event that does not specify a row.
  227. rend.dispatchEvent({type: goog.ui.ac.AutoComplete.EventType.SELECT, row: ''});
  228. assertEquals('the.mice@magrathea.com', select.selectedRow);
  229. }
  230. function testSuggestionsUpdateEvent() {
  231. var ds = new MockDS();
  232. var rend = new TestRend();
  233. var select = new MockSelect();
  234. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  235. var updates = 0;
  236. handler.listen(
  237. ac, goog.ui.ac.AutoComplete.EventType.SUGGESTIONS_UPDATE,
  238. function() { updates++; });
  239. ac.setToken('the');
  240. assertEquals(1, updates);
  241. ac.setToken('beeb');
  242. assertEquals(2, updates);
  243. ac.setToken('ford');
  244. assertEquals(3, updates);
  245. ac.dismiss();
  246. assertEquals(4, updates);
  247. ac.setToken('dent');
  248. assertEquals(5, updates);
  249. }
  250. function checkHilitedIndex(renderer, index) {
  251. assertEquals(index, renderer.getHilitedRowIndex());
  252. }
  253. function testGetRowCount() {
  254. var ds = new MockDS();
  255. var rend = new TestRend();
  256. var select = new MockSelect();
  257. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  258. assertEquals(0, ac.getRowCount());
  259. ac.setToken('Zaphod');
  260. assertEquals(1, ac.getRowCount());
  261. ac.setMaxMatches(2);
  262. ac.setToken('the');
  263. assertEquals(2, ac.getRowCount());
  264. }
  265. /**
  266. * Try using next and prev to navigate past the ends with default behavior of
  267. * allowFreeSelect_ and wrap_.
  268. */
  269. function testHiliteNextPrev_default() {
  270. var ds = new MockDS();
  271. var rend = new TestRend();
  272. var select = new MockSelect();
  273. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  274. var updates = 0;
  275. handler.listen(
  276. rend, goog.ui.ac.AutoComplete.EventType.ROW_HILITE,
  277. function() { updates++; });
  278. // make sure 'next' and 'prev' don't explode before any token is set
  279. ac.hiliteNext();
  280. ac.hilitePrev();
  281. ac.setMaxMatches(4);
  282. assertEquals(0, rend.getRenderedRows().length);
  283. // check a few times
  284. for (var i = 0; i < 3; ++i) {
  285. ac.setToken('');
  286. ac.setToken('the');
  287. assertEquals(4, rend.getRenderedRows().length);
  288. // check to see if we can select the last of the 4 items
  289. checkHilitedIndex(rend, 0);
  290. ac.hiliteNext();
  291. checkHilitedIndex(rend, 1);
  292. ac.hiliteNext();
  293. checkHilitedIndex(rend, 2);
  294. ac.hiliteNext();
  295. checkHilitedIndex(rend, 3);
  296. // try going over the edge
  297. ac.hiliteNext();
  298. checkHilitedIndex(rend, 3);
  299. // go back down
  300. ac.hilitePrev();
  301. checkHilitedIndex(rend, 2);
  302. ac.hilitePrev();
  303. checkHilitedIndex(rend, 1);
  304. ac.hilitePrev();
  305. checkHilitedIndex(rend, 0);
  306. ac.hilitePrev();
  307. checkHilitedIndex(rend, 0);
  308. }
  309. // 21 changes in the loop above (3 * 7)
  310. assertEquals(21, updates);
  311. }
  312. /**
  313. * Try using next and prev to navigate past the ends with default behavior of
  314. * allowFreeSelect_ and wrap_ and with a disabled first row.
  315. */
  316. function testHiliteNextPrevWithDisabledFirstRow_default() {
  317. var ds = new MockDS();
  318. var rend = new TestRend();
  319. var select = new MockSelect();
  320. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  321. var updates = 0;
  322. handler.listen(
  323. rend, goog.ui.ac.AutoComplete.EventType.ROW_HILITE,
  324. function() { updates++; });
  325. // make sure 'next' and 'prev' don't explode before any token is set
  326. ac.hiliteNext();
  327. ac.hilitePrev();
  328. ac.setMaxMatches(3);
  329. assertEquals(0, rend.getRenderedRows().length);
  330. // check a few times with disabled first row
  331. for (var i = 0; i < 3; ++i) {
  332. ac.setToken('');
  333. ac.setToken('edu');
  334. assertEquals(3, rend.getRenderedRows().length);
  335. // The first row is disabled, second should be highlighted.
  336. checkHilitedIndex(rend, 1);
  337. ac.hiliteNext();
  338. checkHilitedIndex(rend, 2);
  339. // try going over the edge
  340. ac.hiliteNext();
  341. checkHilitedIndex(rend, 2);
  342. // go back down
  343. ac.hilitePrev();
  344. checkHilitedIndex(rend, 1);
  345. // First row is disabled, make sure we don't highlight it.
  346. ac.hilitePrev();
  347. checkHilitedIndex(rend, 1);
  348. }
  349. // 9 changes in the loop above (3 * 3)
  350. assertEquals(9, updates);
  351. }
  352. /**
  353. * Try using next and prev to navigate past the ends with default behavior of
  354. * allowFreeSelect_ and wrap_ and with a disabled middle row.
  355. */
  356. function testHiliteNextPrevWithDisabledMiddleRow_default() {
  357. var ds = new MockDS();
  358. var rend = new TestRend();
  359. var select = new MockSelect();
  360. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  361. var updates = 0;
  362. handler.listen(
  363. rend, goog.ui.ac.AutoComplete.EventType.ROW_HILITE,
  364. function() { updates++; });
  365. // make sure 'next' and 'prev' don't explode before any token is set
  366. ac.hiliteNext();
  367. ac.hilitePrev();
  368. ac.setMaxMatches(3);
  369. assertEquals(0, rend.getRenderedRows().length);
  370. // check a few times with disabled middle row
  371. for (var i = 0; i < 3; ++i) {
  372. ac.setToken('');
  373. ac.setToken('u');
  374. assertEquals(3, rend.getRenderedRows().length);
  375. checkHilitedIndex(rend, 0);
  376. ac.hiliteNext();
  377. // Second row is disabled and should be skipped.
  378. checkHilitedIndex(rend, 2);
  379. // try going over the edge
  380. ac.hiliteNext();
  381. checkHilitedIndex(rend, 2);
  382. // go back down
  383. ac.hilitePrev();
  384. // Second row is disabled, make sure we don't highlight it.
  385. checkHilitedIndex(rend, 0);
  386. ac.hilitePrev();
  387. checkHilitedIndex(rend, 0);
  388. }
  389. // 9 changes in the loop above (3 * 3)
  390. assertEquals(9, updates);
  391. }
  392. /**
  393. * Try using next and prev to navigate past the ends with default behavior of
  394. * allowFreeSelect_ and wrap_ and with a disabled last row.
  395. */
  396. function testHiliteNextPrevWithDisabledLastRow_default() {
  397. var ds = new MockDS();
  398. var rend = new TestRend();
  399. var select = new MockSelect();
  400. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  401. var updates = 0;
  402. handler.listen(
  403. rend, goog.ui.ac.AutoComplete.EventType.ROW_HILITE,
  404. function() { updates++; });
  405. // make sure 'next' and 'prev' don't explode before any token is set
  406. ac.hiliteNext();
  407. ac.hilitePrev();
  408. ac.setMaxMatches(3);
  409. assertEquals(0, rend.getRenderedRows().length);
  410. // check a few times with disabled last row
  411. for (var i = 0; i < 3; ++i) {
  412. ac.setToken('');
  413. ac.setToken('h');
  414. assertEquals(3, rend.getRenderedRows().length);
  415. checkHilitedIndex(rend, 0);
  416. ac.hiliteNext();
  417. checkHilitedIndex(rend, 1);
  418. // try going over the edge since last row is disabled
  419. ac.hiliteNext();
  420. checkHilitedIndex(rend, 1);
  421. // go back down
  422. ac.hilitePrev();
  423. checkHilitedIndex(rend, 0);
  424. ac.hilitePrev();
  425. checkHilitedIndex(rend, 0);
  426. }
  427. // 9 changes in the loop above (3 * 3)
  428. assertEquals(9, updates);
  429. }
  430. /**
  431. * Try using next and prev to navigate past the ends with wrap_ off and
  432. * allowFreeSelect_ on.
  433. */
  434. function testHiliteNextPrev_allowFreeSelect() {
  435. var ds = new MockDS();
  436. var rend = new TestRend();
  437. var select = new MockSelect();
  438. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  439. ac.setAllowFreeSelect(true);
  440. // make sure 'next' and 'prev' don't explode before any token is set
  441. ac.hiliteNext();
  442. ac.hilitePrev();
  443. ac.setMaxMatches(4);
  444. assertEquals(0, rend.getRenderedRows().length);
  445. // check a few times
  446. for (var i = 0; i < 3; ++i) {
  447. ac.setToken('');
  448. ac.setToken('the');
  449. assertEquals(4, rend.getRenderedRows().length);
  450. // check to see if we can select the last of the 4 items
  451. checkHilitedIndex(rend, 0);
  452. ac.hiliteNext();
  453. checkHilitedIndex(rend, 1);
  454. ac.hiliteNext();
  455. checkHilitedIndex(rend, 2);
  456. ac.hiliteNext();
  457. checkHilitedIndex(rend, 3);
  458. // try going over the edge. Since allowFreeSelect is on, this will
  459. // deselect the last row.
  460. ac.hiliteNext();
  461. checkHilitedIndex(rend, -1);
  462. // go back down the list
  463. ac.hiliteNext();
  464. checkHilitedIndex(rend, 0);
  465. ac.hiliteNext();
  466. checkHilitedIndex(rend, 1);
  467. // go back up the list.
  468. ac.hilitePrev();
  469. checkHilitedIndex(rend, 0);
  470. // go back above the first, deselects first.
  471. ac.hilitePrev();
  472. checkHilitedIndex(rend, -1);
  473. }
  474. }
  475. /**
  476. * Try using next and prev to navigate past the ends with wrap_ off and
  477. * allowFreeSelect_ on, and a disabled first row.
  478. */
  479. function testHiliteNextPrevWithDisabledFirstRow_allowFreeSelect() {
  480. var ds = new MockDS();
  481. var rend = new TestRend();
  482. var select = new MockSelect();
  483. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  484. ac.setAllowFreeSelect(true);
  485. // make sure 'next' and 'prev' don't explode before any token is set
  486. ac.hiliteNext();
  487. ac.hilitePrev();
  488. ac.setMaxMatches(4);
  489. assertEquals(0, rend.getRenderedRows().length);
  490. // check a few times with disabled first row
  491. for (var i = 0; i < 3; ++i) {
  492. ac.setToken('');
  493. ac.setToken('edu');
  494. assertEquals(3, rend.getRenderedRows().length);
  495. // The first row is disabled, second should be highlighted.
  496. checkHilitedIndex(rend, 1);
  497. ac.hiliteNext();
  498. checkHilitedIndex(rend, 2);
  499. // Try going over the edge. Since allowFreeSelect is on, this will
  500. // deselect the last row.
  501. ac.hiliteNext();
  502. checkHilitedIndex(rend, -1);
  503. // go back down the list, first row is disabled
  504. ac.hiliteNext();
  505. checkHilitedIndex(rend, 1);
  506. ac.hiliteNext();
  507. checkHilitedIndex(rend, 2);
  508. // go back up the list.
  509. ac.hilitePrev();
  510. checkHilitedIndex(rend, 1);
  511. // first is disabled, so deselect the second.
  512. ac.hilitePrev();
  513. checkHilitedIndex(rend, -1);
  514. }
  515. }
  516. /**
  517. * Try using next and prev to navigate past the ends with wrap_ off and
  518. * allowFreeSelect_ on, and a disabled middle row.
  519. */
  520. function testHiliteNextPrevWithDisabledMiddleRow_allowFreeSelect() {
  521. var ds = new MockDS();
  522. var rend = new TestRend();
  523. var select = new MockSelect();
  524. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  525. ac.setAllowFreeSelect(true);
  526. // make sure 'next' and 'prev' don't explode before any token is set
  527. ac.hiliteNext();
  528. ac.hilitePrev();
  529. ac.setMaxMatches(4);
  530. assertEquals(0, rend.getRenderedRows().length);
  531. // check a few times with disabled middle row
  532. for (var i = 0; i < 3; ++i) {
  533. ac.setToken('');
  534. ac.setToken('u');
  535. assertEquals(3, rend.getRenderedRows().length);
  536. checkHilitedIndex(rend, 0);
  537. ac.hiliteNext();
  538. // Second row is disabled and should be skipped.
  539. checkHilitedIndex(rend, 2);
  540. // try going over the edge. Since allowFreeSelect is on, this will
  541. // deselect the last row.
  542. ac.hiliteNext();
  543. checkHilitedIndex(rend, -1);
  544. // go back down the list
  545. ac.hiliteNext();
  546. checkHilitedIndex(rend, 0);
  547. ac.hiliteNext();
  548. checkHilitedIndex(rend, 2);
  549. // go back up the list.
  550. ac.hilitePrev();
  551. checkHilitedIndex(rend, 0);
  552. // go back above the first, deselects first.
  553. ac.hilitePrev();
  554. checkHilitedIndex(rend, -1);
  555. }
  556. }
  557. /**
  558. * Try using next and prev to navigate past the ends with wrap_ off and
  559. * allowFreeSelect_ on, and a disabled last row.
  560. */
  561. function testHiliteNextPrevWithDisabledLastRow_allowFreeSelect() {
  562. var ds = new MockDS();
  563. var rend = new TestRend();
  564. var select = new MockSelect();
  565. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  566. ac.setAllowFreeSelect(true);
  567. // make sure 'next' and 'prev' don't explode before any token is set
  568. ac.hiliteNext();
  569. ac.hilitePrev();
  570. ac.setMaxMatches(4);
  571. assertEquals(0, rend.getRenderedRows().length);
  572. // check a few times with disabled last row
  573. for (var i = 0; i < 3; ++i) {
  574. ac.setToken('');
  575. ac.setToken('h');
  576. assertEquals(3, rend.getRenderedRows().length);
  577. checkHilitedIndex(rend, 0);
  578. ac.hiliteNext();
  579. checkHilitedIndex(rend, 1);
  580. // try going over the edge since last row is disabled. Since allowFreeSelect
  581. // is on, this will deselect the last row.
  582. ac.hiliteNext();
  583. checkHilitedIndex(rend, -1);
  584. // go back down the list
  585. ac.hiliteNext();
  586. checkHilitedIndex(rend, 0);
  587. ac.hiliteNext();
  588. checkHilitedIndex(rend, 1);
  589. // go back up the list.
  590. ac.hilitePrev();
  591. checkHilitedIndex(rend, 0);
  592. // go back above the first, deselects first.
  593. ac.hilitePrev();
  594. checkHilitedIndex(rend, -1);
  595. }
  596. }
  597. /**
  598. * Try using next and prev to navigate past the ends with wrap_ on
  599. * allowFreeSelect_ off.
  600. */
  601. function testHiliteNextPrev_wrap() {
  602. var ds = new MockDS();
  603. var rend = new TestRend();
  604. var select = new MockSelect();
  605. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  606. ac.setWrap(true);
  607. // make sure 'next' and 'prev' don't explode before any token is set
  608. ac.hiliteNext();
  609. ac.hilitePrev();
  610. ac.setMaxMatches(4);
  611. assertEquals(0, rend.getRenderedRows().length);
  612. // check a few times
  613. for (var i = 0; i < 3; ++i) {
  614. ac.setToken('');
  615. ac.setToken('the');
  616. assertEquals(4, rend.getRenderedRows().length);
  617. // check to see if we can select the last of the 4 items
  618. checkHilitedIndex(rend, 0);
  619. ac.hiliteNext();
  620. checkHilitedIndex(rend, 1);
  621. ac.hiliteNext();
  622. checkHilitedIndex(rend, 2);
  623. ac.hiliteNext();
  624. checkHilitedIndex(rend, 3);
  625. // try going over the edge. Since wrap is on, this will go back to 0.
  626. ac.hiliteNext();
  627. checkHilitedIndex(rend, 0);
  628. // go back down the list
  629. ac.hiliteNext();
  630. checkHilitedIndex(rend, 1);
  631. // go back up the list.
  632. ac.hilitePrev();
  633. checkHilitedIndex(rend, 0);
  634. // go back above the first, selects last.
  635. ac.hilitePrev();
  636. checkHilitedIndex(rend, 3);
  637. }
  638. }
  639. /**
  640. * Try using next and prev to navigate past the ends with wrap_ on
  641. * allowFreeSelect_ off and a disabled first row.
  642. */
  643. function testHiliteNextPrevWithDisabledFirstRow_wrap() {
  644. var ds = new MockDS();
  645. var rend = new TestRend();
  646. var select = new MockSelect();
  647. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  648. ac.setWrap(true);
  649. // make sure 'next' and 'prev' don't explode before any token is set
  650. ac.hiliteNext();
  651. ac.hilitePrev();
  652. ac.setMaxMatches(4);
  653. assertEquals(0, rend.getRenderedRows().length);
  654. // check a few times with disabled first row
  655. for (var i = 0; i < 3; ++i) {
  656. ac.setToken('');
  657. ac.setToken('edu');
  658. assertEquals(3, rend.getRenderedRows().length);
  659. // The first row is disabled, second should be highlighted.
  660. checkHilitedIndex(rend, 1);
  661. ac.hiliteNext();
  662. checkHilitedIndex(rend, 2);
  663. // try going over the edge. Since wrap is on and first row is disabled,
  664. // this will go back to 1.
  665. ac.hiliteNext();
  666. checkHilitedIndex(rend, 1);
  667. // go back down the list
  668. ac.hiliteNext();
  669. checkHilitedIndex(rend, 2);
  670. // go back up the list.
  671. ac.hilitePrev();
  672. checkHilitedIndex(rend, 1);
  673. // first is disabled, so wrap and select the last.
  674. ac.hilitePrev();
  675. checkHilitedIndex(rend, 2);
  676. }
  677. }
  678. /**
  679. * Try using next and prev to navigate past the ends with wrap_ on
  680. * allowFreeSelect_ off and a disabled middle row.
  681. */
  682. function testHiliteNextPrevWithDisabledMiddleRow_wrap() {
  683. var ds = new MockDS();
  684. var rend = new TestRend();
  685. var select = new MockSelect();
  686. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  687. ac.setWrap(true);
  688. // make sure 'next' and 'prev' don't explode before any token is set
  689. ac.hiliteNext();
  690. ac.hilitePrev();
  691. ac.setMaxMatches(4);
  692. assertEquals(0, rend.getRenderedRows().length);
  693. // check a few times with disabled middle row
  694. for (var i = 0; i < 3; ++i) {
  695. ac.setToken('');
  696. ac.setToken('u');
  697. assertEquals(3, rend.getRenderedRows().length);
  698. checkHilitedIndex(rend, 0);
  699. ac.hiliteNext();
  700. // Second row is disabled and should be skipped.
  701. checkHilitedIndex(rend, 2);
  702. // try going over the edge. Since wrap is on, this will go back to 0.
  703. ac.hiliteNext();
  704. checkHilitedIndex(rend, 0);
  705. // go back down the list
  706. ac.hiliteNext();
  707. checkHilitedIndex(rend, 2);
  708. // go back up the list.
  709. ac.hilitePrev();
  710. checkHilitedIndex(rend, 0);
  711. // go back above the first, selects last.
  712. ac.hilitePrev();
  713. checkHilitedIndex(rend, 2);
  714. }
  715. }
  716. /**
  717. * Try using next and prev to navigate past the ends with wrap_ on
  718. * allowFreeSelect_ off and a disabled last row.
  719. */
  720. function testHiliteNextPrevWithDisabledLastRow_wrap() {
  721. var ds = new MockDS();
  722. var rend = new TestRend();
  723. var select = new MockSelect();
  724. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  725. ac.setWrap(true);
  726. // make sure 'next' and 'prev' don't explode before any token is set
  727. ac.hiliteNext();
  728. ac.hilitePrev();
  729. ac.setMaxMatches(4);
  730. assertEquals(0, rend.getRenderedRows().length);
  731. // check a few times with disabled last row
  732. for (var i = 0; i < 3; ++i) {
  733. ac.setToken('');
  734. ac.setToken('h');
  735. assertEquals(3, rend.getRenderedRows().length);
  736. checkHilitedIndex(rend, 0);
  737. ac.hiliteNext();
  738. checkHilitedIndex(rend, 1);
  739. // try going over the edge since last row is disabled. Since wrap is on,
  740. // this will go back to 0.
  741. ac.hiliteNext();
  742. checkHilitedIndex(rend, 0);
  743. // go back down the list
  744. ac.hiliteNext();
  745. checkHilitedIndex(rend, 1);
  746. // go back up the list.
  747. ac.hilitePrev();
  748. checkHilitedIndex(rend, 0);
  749. // go back above the first, since wrap is on and last row is disabled, this
  750. // will select the second last.
  751. ac.hilitePrev();
  752. checkHilitedIndex(rend, 1);
  753. }
  754. }
  755. /**
  756. * Try using next and prev to navigate past the ends with wrap_ on
  757. * allowFreeSelect_ on.
  758. */
  759. function testHiliteNextPrev_wrapAndAllowFreeSelect() {
  760. var ds = new MockDS();
  761. var rend = new TestRend();
  762. var select = new MockSelect();
  763. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  764. ac.setWrap(true);
  765. ac.setAllowFreeSelect(true);
  766. // make sure 'next' and 'prev' don't explode before any token is set
  767. ac.hiliteNext();
  768. ac.hilitePrev();
  769. ac.setMaxMatches(4);
  770. assertEquals(0, rend.getRenderedRows().length);
  771. // check a few times
  772. for (var i = 0; i < 3; ++i) {
  773. ac.setToken('');
  774. ac.setToken('the');
  775. assertEquals(4, rend.getRenderedRows().length);
  776. // check to see if we can select the last of the 4 items
  777. checkHilitedIndex(rend, 0);
  778. ac.hiliteNext();
  779. checkHilitedIndex(rend, 1);
  780. ac.hiliteNext();
  781. checkHilitedIndex(rend, 2);
  782. ac.hiliteNext();
  783. checkHilitedIndex(rend, 3);
  784. // try going over the edge. Since free select is on, this should go
  785. // to -1.
  786. ac.hiliteNext();
  787. checkHilitedIndex(rend, -1);
  788. // go back down the list
  789. ac.hiliteNext();
  790. checkHilitedIndex(rend, 0);
  791. ac.hiliteNext();
  792. checkHilitedIndex(rend, 1);
  793. // go back up the list.
  794. ac.hilitePrev();
  795. checkHilitedIndex(rend, 0);
  796. // go back above the first, free select.
  797. ac.hilitePrev();
  798. checkHilitedIndex(rend, -1);
  799. // wrap to last
  800. ac.hilitePrev();
  801. checkHilitedIndex(rend, 3);
  802. }
  803. }
  804. /**
  805. * Try using next and prev to navigate past the ends with wrap_ on
  806. * allowFreeSelect_ on and a disabled first row.
  807. */
  808. function testHiliteNextPrevWithDisabledFirstRow_wrapAndAllowFreeSelect() {
  809. var ds = new MockDS();
  810. var rend = new TestRend();
  811. var select = new MockSelect();
  812. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  813. ac.setWrap(true);
  814. ac.setAllowFreeSelect(true);
  815. // make sure 'next' and 'prev' don't explode before any token is set
  816. ac.hiliteNext();
  817. ac.hilitePrev();
  818. ac.setMaxMatches(4);
  819. assertEquals(0, rend.getRenderedRows().length);
  820. // check a few times with disabled first row
  821. for (var i = 0; i < 3; ++i) {
  822. ac.setToken('');
  823. ac.setToken('edu');
  824. assertEquals(3, rend.getRenderedRows().length);
  825. // The first row is disabled, second should be highlighted.
  826. checkHilitedIndex(rend, 1);
  827. ac.hiliteNext();
  828. checkHilitedIndex(rend, 2);
  829. // try going over the edge. Since free select is on, this should go to -1.
  830. ac.hiliteNext();
  831. checkHilitedIndex(rend, -1);
  832. // go back down the list, fist row is disabled
  833. ac.hiliteNext();
  834. checkHilitedIndex(rend, 1);
  835. ac.hiliteNext();
  836. checkHilitedIndex(rend, 2);
  837. // go back up the list.
  838. ac.hilitePrev();
  839. checkHilitedIndex(rend, 1);
  840. // go back above the first, free select.
  841. ac.hilitePrev();
  842. checkHilitedIndex(rend, -1);
  843. // wrap to last
  844. ac.hilitePrev();
  845. checkHilitedIndex(rend, 2);
  846. }
  847. }
  848. /**
  849. * Try using next and prev to navigate past the ends with wrap_ on
  850. * allowFreeSelect_ on and a disabled middle row.
  851. */
  852. function testHiliteNextPrevWithDisabledMiddleRow_wrapAndAllowFreeSelect() {
  853. var ds = new MockDS();
  854. var rend = new TestRend();
  855. var select = new MockSelect();
  856. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  857. ac.setWrap(true);
  858. ac.setAllowFreeSelect(true);
  859. // make sure 'next' and 'prev' don't explode before any token is set
  860. ac.hiliteNext();
  861. ac.hilitePrev();
  862. ac.setMaxMatches(4);
  863. assertEquals(0, rend.getRenderedRows().length);
  864. // check a few times with disabled middle row
  865. for (var i = 0; i < 3; ++i) {
  866. ac.setToken('');
  867. ac.setToken('u');
  868. assertEquals(3, rend.getRenderedRows().length);
  869. checkHilitedIndex(rend, 0);
  870. ac.hiliteNext();
  871. // Second row is disabled and should be skipped.
  872. checkHilitedIndex(rend, 2);
  873. // try going over the edge. Since free select is on, this should go to -1
  874. ac.hiliteNext();
  875. checkHilitedIndex(rend, -1);
  876. // go back down the list
  877. ac.hiliteNext();
  878. checkHilitedIndex(rend, 0);
  879. ac.hiliteNext();
  880. checkHilitedIndex(rend, 2);
  881. // go back up the list.
  882. ac.hilitePrev();
  883. checkHilitedIndex(rend, 0);
  884. // go back above the first, free select.
  885. ac.hilitePrev();
  886. checkHilitedIndex(rend, -1);
  887. // wrap to last
  888. ac.hilitePrev();
  889. checkHilitedIndex(rend, 2);
  890. }
  891. }
  892. /**
  893. * Try using next and prev to navigate past the ends with wrap_ on
  894. * allowFreeSelect_ on and a disabled last row.
  895. */
  896. function testHiliteNextPrevWithDisabledLastRow_wrapAndAllowFreeSelect() {
  897. var ds = new MockDS();
  898. var rend = new TestRend();
  899. var select = new MockSelect();
  900. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  901. ac.setWrap(true);
  902. ac.setAllowFreeSelect(true);
  903. // make sure 'next' and 'prev' don't explode before any token is set
  904. ac.hiliteNext();
  905. ac.hilitePrev();
  906. ac.setMaxMatches(4);
  907. assertEquals(0, rend.getRenderedRows().length);
  908. // check a few times with disabled last row
  909. for (var i = 0; i < 3; ++i) {
  910. ac.setToken('');
  911. ac.setToken('h');
  912. assertEquals(3, rend.getRenderedRows().length);
  913. checkHilitedIndex(rend, 0);
  914. ac.hiliteNext();
  915. checkHilitedIndex(rend, 1);
  916. // try going over the edge since last row is disabled. Since free select is
  917. // on, this should go to -1
  918. ac.hiliteNext();
  919. checkHilitedIndex(rend, -1);
  920. // go back down the list
  921. ac.hiliteNext();
  922. checkHilitedIndex(rend, 0);
  923. ac.hiliteNext();
  924. checkHilitedIndex(rend, 1);
  925. // go back up the list.
  926. ac.hilitePrev();
  927. checkHilitedIndex(rend, 0);
  928. // go back above the first, free select.
  929. ac.hilitePrev();
  930. checkHilitedIndex(rend, -1);
  931. // wrap to the second last, since last is disabled.
  932. ac.hilitePrev();
  933. checkHilitedIndex(rend, 1);
  934. }
  935. }
  936. /**
  937. * Try using next and prev to navigate past the ends with wrap_ on
  938. * allowFreeSelect_ on AND turn autoHilite_ off.
  939. */
  940. function testHiliteNextPrev_wrapAndAllowFreeSelectNoAutoHilite() {
  941. var ds = new MockDS();
  942. var rend = new TestRend();
  943. var select = new MockSelect();
  944. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  945. ac.setWrap(true);
  946. ac.setAllowFreeSelect(true);
  947. ac.setAutoHilite(false);
  948. // make sure 'next' and 'prev' don't explode before any token is set
  949. ac.hiliteNext();
  950. ac.hilitePrev();
  951. ac.setMaxMatches(4);
  952. assertEquals(0, rend.getRenderedRows().length);
  953. // check a few times
  954. for (var i = 0; i < 3; ++i) {
  955. ac.setToken('');
  956. ac.setToken('the');
  957. assertEquals(4, rend.getRenderedRows().length);
  958. // check to see if we can select the last of the 4 items.
  959. // Initially nothing should be selected since autoHilite_ is off.
  960. checkHilitedIndex(rend, -1);
  961. ac.hilitePrev();
  962. checkHilitedIndex(rend, 3);
  963. ac.hiliteNext();
  964. checkHilitedIndex(rend, -1);
  965. ac.hiliteNext();
  966. checkHilitedIndex(rend, 0);
  967. ac.hiliteNext();
  968. checkHilitedIndex(rend, 1);
  969. ac.hiliteNext();
  970. checkHilitedIndex(rend, 2);
  971. ac.hiliteNext();
  972. checkHilitedIndex(rend, 3);
  973. // try going over the edge. Since free select is on, this should go
  974. // to -1.
  975. ac.hiliteNext();
  976. checkHilitedIndex(rend, -1);
  977. // go back down the list
  978. ac.hiliteNext();
  979. checkHilitedIndex(rend, 0);
  980. ac.hiliteNext();
  981. checkHilitedIndex(rend, 1);
  982. // go back up the list.
  983. ac.hilitePrev();
  984. checkHilitedIndex(rend, 0);
  985. // go back above the first, free select.
  986. ac.hilitePrev();
  987. checkHilitedIndex(rend, -1);
  988. // wrap to last
  989. ac.hilitePrev();
  990. checkHilitedIndex(rend, 3);
  991. }
  992. }
  993. /**
  994. * Try using next and prev to navigate past the ends with wrap_ on
  995. * allowFreeSelect_ on AND turn autoHilite_ off, and a disabled first row.
  996. */
  997. function
  998. testHiliteNextPrevWithDisabledFirstRow_wrapAndAllowFreeSelectNoAutoHilite() {
  999. var ds = new MockDS();
  1000. var rend = new TestRend();
  1001. var select = new MockSelect();
  1002. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1003. ac.setWrap(true);
  1004. ac.setAllowFreeSelect(true);
  1005. ac.setAutoHilite(false);
  1006. // make sure 'next' and 'prev' don't explode before any token is set
  1007. ac.hiliteNext();
  1008. ac.hilitePrev();
  1009. ac.setMaxMatches(4);
  1010. assertEquals(0, rend.getRenderedRows().length);
  1011. // check a few times with disabled first row
  1012. for (var i = 0; i < 3; ++i) {
  1013. ac.setToken('');
  1014. ac.setToken('edu');
  1015. assertEquals(3, rend.getRenderedRows().length);
  1016. // Initially nothing should be selected since autoHilite_ is off.
  1017. checkHilitedIndex(rend, -1);
  1018. ac.hilitePrev();
  1019. checkHilitedIndex(rend, 2);
  1020. ac.hiliteNext();
  1021. checkHilitedIndex(rend, -1);
  1022. ac.hiliteNext();
  1023. // First row is disabled.
  1024. checkHilitedIndex(rend, 1);
  1025. ac.hiliteNext();
  1026. checkHilitedIndex(rend, 2);
  1027. // try going over the edge. Since free select is on, this should go to -1
  1028. ac.hiliteNext();
  1029. checkHilitedIndex(rend, -1);
  1030. // go back down the list, first row is disabled
  1031. ac.hiliteNext();
  1032. checkHilitedIndex(rend, 1);
  1033. ac.hiliteNext();
  1034. checkHilitedIndex(rend, 2);
  1035. // go back up the list.
  1036. ac.hilitePrev();
  1037. checkHilitedIndex(rend, 1);
  1038. // go back above the first, free select.
  1039. ac.hilitePrev();
  1040. checkHilitedIndex(rend, -1);
  1041. // wrap to last
  1042. ac.hilitePrev();
  1043. checkHilitedIndex(rend, 2);
  1044. }
  1045. }
  1046. /**
  1047. * Try using next and prev to navigate past the ends with wrap_ on
  1048. * allowFreeSelect_ on AND turn autoHilite_ off, and a disabled middle row.
  1049. */
  1050. function
  1051. testHiliteNextPrevWithDisabledMiddleRow_wrapAndAllowFreeSelectNoAutoHilite() {
  1052. var ds = new MockDS();
  1053. var rend = new TestRend();
  1054. var select = new MockSelect();
  1055. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1056. ac.setWrap(true);
  1057. ac.setAllowFreeSelect(true);
  1058. ac.setAutoHilite(false);
  1059. // make sure 'next' and 'prev' don't explode before any token is set
  1060. ac.hiliteNext();
  1061. ac.hilitePrev();
  1062. ac.setMaxMatches(4);
  1063. assertEquals(0, rend.getRenderedRows().length);
  1064. // check a few times with disabled middle row
  1065. for (var i = 0; i < 3; ++i) {
  1066. ac.setToken('');
  1067. ac.setToken('u');
  1068. assertEquals(3, rend.getRenderedRows().length);
  1069. // Initially nothing should be selected since autoHilite_ is off.
  1070. checkHilitedIndex(rend, -1);
  1071. ac.hilitePrev();
  1072. checkHilitedIndex(rend, 2);
  1073. ac.hiliteNext();
  1074. checkHilitedIndex(rend, -1);
  1075. ac.hiliteNext();
  1076. checkHilitedIndex(rend, 0);
  1077. ac.hiliteNext();
  1078. // Second row is disabled
  1079. checkHilitedIndex(rend, 2);
  1080. // try going over the edge. Since free select is on, this should go to -1.
  1081. ac.hiliteNext();
  1082. checkHilitedIndex(rend, -1);
  1083. // go back down the list
  1084. ac.hiliteNext();
  1085. checkHilitedIndex(rend, 0);
  1086. ac.hiliteNext();
  1087. // Second row is disabled.
  1088. checkHilitedIndex(rend, 2);
  1089. // go back up the list.
  1090. ac.hilitePrev();
  1091. checkHilitedIndex(rend, 0);
  1092. // go back above the first, free select.
  1093. ac.hilitePrev();
  1094. checkHilitedIndex(rend, -1);
  1095. // wrap to last
  1096. ac.hilitePrev();
  1097. checkHilitedIndex(rend, 2);
  1098. }
  1099. }
  1100. /**
  1101. * Try using next and prev to navigate past the ends with wrap_ on
  1102. * allowFreeSelect_ on AND turn autoHilite_ off, and a disabled last row.
  1103. */
  1104. function
  1105. testHiliteNextPrevWithDisabledLastRow_wrapAndAllowFreeSelectNoAutoHilite() {
  1106. var ds = new MockDS();
  1107. var rend = new TestRend();
  1108. var select = new MockSelect();
  1109. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1110. ac.setWrap(true);
  1111. ac.setAllowFreeSelect(true);
  1112. ac.setAutoHilite(false);
  1113. // make sure 'next' and 'prev' don't explode before any token is set
  1114. ac.hiliteNext();
  1115. ac.hilitePrev();
  1116. ac.setMaxMatches(4);
  1117. assertEquals(0, rend.getRenderedRows().length);
  1118. // check a few times with disabled last row
  1119. for (var i = 0; i < 3; ++i) {
  1120. ac.setToken('');
  1121. ac.setToken('h');
  1122. assertEquals(3, rend.getRenderedRows().length);
  1123. // Initially nothing should be selected since autoHilite_ is off.
  1124. checkHilitedIndex(rend, -1);
  1125. ac.hilitePrev();
  1126. // Last row is disabled
  1127. checkHilitedIndex(rend, 1);
  1128. ac.hiliteNext();
  1129. checkHilitedIndex(rend, -1);
  1130. ac.hiliteNext();
  1131. checkHilitedIndex(rend, 0);
  1132. ac.hiliteNext();
  1133. checkHilitedIndex(rend, 1);
  1134. // try going over the edge. Since free select is on, this should go to -1.
  1135. ac.hiliteNext();
  1136. checkHilitedIndex(rend, -1);
  1137. // go back down the list
  1138. ac.hiliteNext();
  1139. checkHilitedIndex(rend, 0);
  1140. ac.hiliteNext();
  1141. checkHilitedIndex(rend, 1);
  1142. // go back up the list.
  1143. ac.hilitePrev();
  1144. checkHilitedIndex(rend, 0);
  1145. // go back above the first, free select.
  1146. ac.hilitePrev();
  1147. checkHilitedIndex(rend, -1);
  1148. // wrap to last
  1149. ac.hilitePrev();
  1150. checkHilitedIndex(rend, 1);
  1151. }
  1152. }
  1153. function testHiliteWithChangingNumberOfRows() {
  1154. var ds = new MockDS();
  1155. var rend = new TestRend();
  1156. var select = new MockSelect();
  1157. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1158. ac.setAutoHilite(true);
  1159. ac.setMaxMatches(4);
  1160. ac.setToken('m');
  1161. assertEquals(4, rend.getRenderedRows().length);
  1162. checkHilitedIndex(rend, 0);
  1163. ac.setToken('ma');
  1164. assertEquals(3, rend.getRenderedRows().length);
  1165. checkHilitedIndex(rend, 0);
  1166. // Hilite the second element
  1167. var id = rend.getRenderedRows()[1].id;
  1168. ac.hiliteId(id);
  1169. ac.setToken('mar');
  1170. assertEquals(1, rend.getRenderedRows().length);
  1171. checkHilitedIndex(rend, 0);
  1172. ac.setToken('ma');
  1173. assertEquals(3, rend.getRenderedRows().length);
  1174. checkHilitedIndex(rend, 0);
  1175. // Hilite the second element
  1176. var id = rend.getRenderedRows()[1].id;
  1177. ac.hiliteId(id);
  1178. ac.setToken('m');
  1179. assertEquals(4, rend.getRenderedRows().length);
  1180. checkHilitedIndex(rend, 0);
  1181. }
  1182. /**
  1183. * Checks that autohilite is disabled when there is no token; this allows the
  1184. * user to tab out of an empty autocomplete.
  1185. */
  1186. function testNoAutoHiliteWhenTokenIsEmpty() {
  1187. var ds = new MockDS();
  1188. var rend = new TestRend();
  1189. var select = new MockSelect();
  1190. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1191. ac.setWrap(true);
  1192. ac.setAllowFreeSelect(true);
  1193. ac.setAutoHilite(true);
  1194. ac.setMaxMatches(4);
  1195. ac.setToken('');
  1196. assertEquals(4, rend.getRenderedRows().length);
  1197. // No token; nothing should be hilited.
  1198. checkHilitedIndex(rend, -1);
  1199. ac.setToken('the');
  1200. assertEquals(4, rend.getRenderedRows().length);
  1201. // Now there is a token, so the first row should be highlighted.
  1202. checkHilitedIndex(rend, 0);
  1203. }
  1204. /**
  1205. * Checks that opt_preserveHilited works.
  1206. */
  1207. function testPreserveHilitedWithoutAutoHilite() {
  1208. var ds = new MockDS();
  1209. var rend = new TestRend();
  1210. var select = new MockSelect();
  1211. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1212. ac.setWrap(true);
  1213. ac.setAllowFreeSelect(true);
  1214. ac.setMaxMatches(4);
  1215. ac.setAutoHilite(false);
  1216. ac.setToken('m');
  1217. assertEquals(4, rend.getRenderedRows().length);
  1218. // No token; nothing should be hilited.
  1219. checkHilitedIndex(rend, -1);
  1220. // Hilite the second element
  1221. var id = rend.getRenderedRows()[1].id;
  1222. ac.hiliteId(id);
  1223. checkHilitedIndex(rend, 1);
  1224. // Re-render and check if the second element is still hilited
  1225. ac.renderRows(rend.getRenderedRows(), true /* preserve hilite */);
  1226. checkHilitedIndex(rend, 1);
  1227. // Re-render without preservation
  1228. ac.renderRows(rend.getRenderedRows());
  1229. checkHilitedIndex(rend, -1);
  1230. }
  1231. /**
  1232. * Checks that the autohilite argument "true" of the matcher is used.
  1233. */
  1234. function testAutoHiliteFromMatcherTrue() {
  1235. var ds = new MockDS(true);
  1236. var rend = new TestRend();
  1237. var select = new MockSelect();
  1238. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1239. ac.setWrap(true);
  1240. ac.setAllowFreeSelect(true);
  1241. ac.setAutoHilite(false); // Will be overruled.
  1242. ac.setMaxMatches(4);
  1243. ac.setToken('the');
  1244. assertEquals(4, rend.getRenderedRows().length);
  1245. // The first row should be highlighted.
  1246. checkHilitedIndex(rend, 0);
  1247. }
  1248. /**
  1249. * Checks that the autohilite argument "false" of the matcher is used.
  1250. */
  1251. function testAutoHiliteFromMatcherFalse() {
  1252. var ds = new MockDS(false);
  1253. var rend = new TestRend();
  1254. var select = new MockSelect();
  1255. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1256. ac.setWrap(true);
  1257. ac.setAllowFreeSelect(true);
  1258. ac.setAutoHilite(true); // Will be overruled.
  1259. ac.setMaxMatches(4);
  1260. ac.setToken('the');
  1261. assertEquals(4, rend.getRenderedRows().length);
  1262. // The first row should not be highlighted.
  1263. checkHilitedIndex(rend, -1);
  1264. }
  1265. /**
  1266. * Hilite using ids, the way mouse-based hiliting would work.
  1267. */
  1268. function testHiliteId() {
  1269. var ds = new MockDS();
  1270. var rend = new TestRend();
  1271. var select = new MockSelect();
  1272. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1273. // check a few times
  1274. for (var i = 0; i < 3; ++i) {
  1275. ac.setToken('m');
  1276. assertEquals(4, rend.getRenderedRows().length);
  1277. // try hiliting all 3
  1278. for (var x = 0; x < 4; ++x) {
  1279. var id = rend.getRenderedRows()[x].id;
  1280. ac.hiliteId(id);
  1281. assertEquals(ac.getIdOfIndex_(x), id);
  1282. }
  1283. }
  1284. }
  1285. /**
  1286. * Test selecting the hilited row
  1287. */
  1288. function testSelection() {
  1289. var ds = new MockDS();
  1290. var rend = new TestRend();
  1291. var select = new MockSelect();
  1292. var ac;
  1293. // try with default selection
  1294. ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1295. ac.setToken('m');
  1296. ac.selectHilited();
  1297. assertEquals(
  1298. '"Slartibartfast Theadore" <fjordmaster@magrathea.com>',
  1299. select.selectedRow);
  1300. // try second item
  1301. ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1302. ac.setToken('the');
  1303. ac.hiliteNext();
  1304. ac.selectHilited();
  1305. assertEquals('"Ford Prefect" <ford@theguide.com>', select.selectedRow);
  1306. }
  1307. /**
  1308. * Dismiss when empty and non-empty
  1309. */
  1310. function testDismiss() {
  1311. var ds = new MockDS();
  1312. var rend = new TestRend();
  1313. var select = new MockSelect();
  1314. // dismiss empty
  1315. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1316. var dismissed = 0;
  1317. handler.listen(ac, goog.ui.ac.AutoComplete.EventType.DISMISS, function() {
  1318. dismissed++;
  1319. });
  1320. ac.dismiss();
  1321. assertEquals(1, dismissed);
  1322. ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1323. ac.setToken('sir not seen in this picture');
  1324. ac.dismiss();
  1325. // dismiss with contents
  1326. ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1327. ac.setToken('t');
  1328. ac.dismiss();
  1329. }
  1330. function testTriggerSuggestionsOnUpdate() {
  1331. var ds = new MockDS();
  1332. var rend = new TestRend();
  1333. var select = new MockSelect();
  1334. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1335. var dismissCalled = 0;
  1336. rend.dismiss = function() { dismissCalled++; };
  1337. var updateCalled = 0;
  1338. select.update = function(opt_force) { updateCalled++; };
  1339. // Normally, menu is dismissed after selecting row (without updating).
  1340. ac.setToken('the');
  1341. ac.selectHilited();
  1342. assertEquals(1, dismissCalled);
  1343. assertEquals(0, updateCalled);
  1344. // But not if we re-trigger on update.
  1345. ac.setTriggerSuggestionsOnUpdate(true);
  1346. ac.setToken('the');
  1347. ac.selectHilited();
  1348. assertEquals(1, dismissCalled);
  1349. assertEquals(1, updateCalled);
  1350. }
  1351. function testDispose() {
  1352. var ds = new MockDS();
  1353. var rend = new TestRend();
  1354. var select = new MockSelect();
  1355. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1356. ac.setToken('the');
  1357. ac.dispose();
  1358. }
  1359. /**
  1360. * Ensure that activedescendant is updated properly.
  1361. */
  1362. function testRolesAndStates() {
  1363. function checkActiveDescendant(activeDescendant) {
  1364. assertNotNull(inputElement);
  1365. assertEquals(
  1366. goog.a11y.aria.getActiveDescendant(inputElement), activeDescendant);
  1367. }
  1368. function checkRole(el, role) {
  1369. assertNotNull(el);
  1370. assertEquals(goog.a11y.aria.getRole(el), role);
  1371. }
  1372. var ds = new MockDS();
  1373. var rend = new TestRend();
  1374. var select = new MockSelect();
  1375. var ac = new goog.ui.ac.AutoComplete(ds, rend, select);
  1376. ac.setTarget(inputElement);
  1377. // initially activedescendant is not set
  1378. checkActiveDescendant(null);
  1379. // highlight the matching row and check that activedescendant updates
  1380. ac.setToken('');
  1381. ac.setToken('the');
  1382. ac.hiliteNext();
  1383. checkActiveDescendant(rend.getHilitedRowDiv());
  1384. // highligted row should have a role of 'option'
  1385. checkRole(rend.getHilitedRowDiv(), goog.a11y.aria.Role.OPTION);
  1386. // closing the autocomplete should clear activedescendant
  1387. ac.dismiss();
  1388. checkActiveDescendant(null);
  1389. }
  1390. function testAttachInputWithAnchor() {
  1391. var anchorElement =
  1392. goog.dom.createDom(goog.dom.TagName.DIV, null, inputElement);
  1393. var mockRenderer = mockControl.createLooseMock(goog.ui.ac.Renderer, true);
  1394. mockRenderer.setAnchorElement(anchorElement);
  1395. var ignore = goog.testing.mockmatchers.ignoreArgument;
  1396. mockRenderer.renderRows(ignore, ignore, inputElement);
  1397. var mockInputHandler =
  1398. mockControl.createLooseMock(goog.ui.ac.InputHandler, true);
  1399. mockInputHandler.attachInputs(inputElement);
  1400. mockControl.$replayAll();
  1401. var autoComplete =
  1402. new goog.ui.ac.AutoComplete(null, mockRenderer, mockInputHandler);
  1403. autoComplete.attachInputWithAnchor(inputElement, anchorElement);
  1404. autoComplete.setTarget(inputElement);
  1405. autoComplete.renderRows(['abc', 'def']);
  1406. mockControl.$verifyAll();
  1407. }
  1408. function testDetachInputWithAnchor() {
  1409. var mockRenderer = mockControl.createLooseMock(goog.ui.ac.Renderer, true);
  1410. var mockInputHandler =
  1411. mockControl.createLooseMock(goog.ui.ac.InputHandler, true);
  1412. var anchorElement =
  1413. goog.dom.createDom(goog.dom.TagName.DIV, null, inputElement);
  1414. var inputElement2 = goog.dom.createDom(
  1415. goog.dom.TagName.INPUT, {type: goog.dom.InputType.TEXT});
  1416. var anchorElement2 =
  1417. goog.dom.createDom(goog.dom.TagName.DIV, null, inputElement2);
  1418. mockControl.$replayAll();
  1419. var autoComplete =
  1420. new goog.ui.ac.AutoComplete(null, mockRenderer, mockInputHandler);
  1421. autoComplete.attachInputWithAnchor(inputElement, anchorElement);
  1422. autoComplete.attachInputWithAnchor(inputElement2, anchorElement2);
  1423. autoComplete.detachInputs(inputElement, inputElement2);
  1424. assertFalse(goog.getUid(inputElement) in autoComplete.inputToAnchorMap_);
  1425. assertFalse(goog.getUid(inputElement2) in autoComplete.inputToAnchorMap_);
  1426. mockControl.$verifyAll();
  1427. }