autocomplete.spec.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. import { createVue, triggerClick, destroyVM } from '../util';
  2. describe('Autocomplete', () => {
  3. let vm;
  4. afterEach(() => {
  5. destroyVM(vm);
  6. });
  7. it('create', done => {
  8. vm = createVue({
  9. template: `
  10. <div>
  11. <button class="btn">a</button>
  12. <el-autocomplete
  13. ref="autocomplete"
  14. v-model="state"
  15. :fetch-suggestions="querySearch"
  16. placeholder="请输入内容autocomplete1"
  17. ></el-autocomplete>
  18. </div>
  19. `,
  20. data() {
  21. return {
  22. restaurants: [],
  23. state: ''
  24. };
  25. },
  26. methods: {
  27. querySearch(queryString, cb) {
  28. var restaurants = this.restaurants;
  29. var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
  30. cb(results);
  31. },
  32. createFilter(queryString) {
  33. return (restaurant) => {
  34. return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
  35. };
  36. },
  37. loadAll() {
  38. return [
  39. { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
  40. { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
  41. { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
  42. { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
  43. ];
  44. }
  45. },
  46. mounted() {
  47. this.restaurants = this.loadAll();
  48. }
  49. }, true);
  50. let elm = vm.$el;
  51. let inputElm = elm.querySelector('input');
  52. inputElm.focus();
  53. expect(inputElm.getAttribute('placeholder')).to.be.equal('请输入内容autocomplete1');
  54. setTimeout(_ => {
  55. const suggestions = vm.$refs.autocomplete.$refs.suggestions.$el;
  56. expect(suggestions.style.display).to.not.equal('none');
  57. expect(suggestions.querySelectorAll('.el-autocomplete-suggestion__list li').length).to.be.equal(4);
  58. triggerClick(document);
  59. setTimeout(_ => {
  60. expect(suggestions.style.display).to.be.equal('none');
  61. done();
  62. }, 500);
  63. }, 500);
  64. });
  65. it('select', done => {
  66. vm = createVue({
  67. template: `
  68. <el-autocomplete
  69. v-model="state"
  70. ref="autocomplete"
  71. :fetch-suggestions="querySearch"
  72. placeholder="请输入内容autocomplete2"
  73. ></el-autocomplete>
  74. `,
  75. data() {
  76. return {
  77. restaurants: [],
  78. state: ''
  79. };
  80. },
  81. methods: {
  82. querySearch(queryString, cb) {
  83. var restaurants = this.restaurants;
  84. var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
  85. cb(results);
  86. },
  87. createFilter(queryString) {
  88. return (restaurant) => {
  89. return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
  90. };
  91. },
  92. loadAll() {
  93. return [
  94. { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
  95. { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
  96. { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
  97. { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
  98. ];
  99. }
  100. },
  101. mounted() {
  102. this.restaurants = this.loadAll();
  103. }
  104. }, true);
  105. const autocomplete = vm.$refs.autocomplete;
  106. const elm = vm.$el;
  107. const inputElm = elm.querySelector('input');
  108. const spy = sinon.spy();
  109. autocomplete.$on('select', spy);
  110. inputElm.focus();
  111. setTimeout(_ => {
  112. const suggestions = autocomplete.$refs.suggestions.$el;
  113. const suggestionList = suggestions.querySelectorAll('.el-autocomplete-suggestion__list li');
  114. suggestionList[1].click();
  115. setTimeout(_ => {
  116. expect(inputElm.value).to.be.equal('Hot honey 首尔炸鸡(仙霞路)');
  117. expect(vm.state).to.be.equal('Hot honey 首尔炸鸡(仙霞路)');
  118. expect(spy.withArgs().calledOnce).to.be.true;
  119. expect(suggestions.style.display).to.be.equal('none');
  120. done();
  121. }, 500);
  122. }, 500);
  123. });
  124. it('props', done => {
  125. vm = createVue({
  126. template: `
  127. <el-autocomplete
  128. v-model="state"
  129. ref="autocomplete"
  130. value-key="address"
  131. :fetch-suggestions="querySearch"
  132. placeholder="请输入内容autocomplete2"
  133. ></el-autocomplete>
  134. `,
  135. data() {
  136. return {
  137. restaurants: [],
  138. state: ''
  139. };
  140. },
  141. methods: {
  142. querySearch(queryString, cb) {
  143. var restaurants = this.restaurants;
  144. var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
  145. cb(results);
  146. },
  147. createFilter(queryString) {
  148. return (restaurant) => {
  149. return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
  150. };
  151. },
  152. loadAll() {
  153. return [
  154. { 'name': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
  155. { 'name': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
  156. { 'name': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
  157. { 'name': '泷千家(天山西路店)', 'address': '天山西路438号' }
  158. ];
  159. }
  160. },
  161. mounted() {
  162. this.restaurants = this.loadAll();
  163. }
  164. }, true);
  165. const autocomplete = vm.$refs.autocomplete;
  166. const elm = vm.$el;
  167. const inputElm = elm.querySelector('input');
  168. const spy = sinon.spy();
  169. autocomplete.$on('select', spy);
  170. inputElm.focus();
  171. setTimeout(_ => {
  172. const suggestions = autocomplete.$refs.suggestions.$el;
  173. const suggestionList = suggestions.querySelectorAll('.el-autocomplete-suggestion__list li');
  174. expect(suggestionList[1].innerHTML === '上海市长宁区淞虹路661号');
  175. suggestionList[1].click();
  176. setTimeout(_ => {
  177. expect(inputElm.value).to.be.equal('上海市长宁区淞虹路661号');
  178. expect(vm.state).to.be.equal('上海市长宁区淞虹路661号');
  179. expect(spy.withArgs().calledOnce).to.be.true;
  180. expect(suggestions.style.display).to.be.equal('none');
  181. done();
  182. }, 500);
  183. }, 500);
  184. });
  185. it('highlight', done => {
  186. vm = createVue({
  187. template: `
  188. <el-autocomplete
  189. ref="autocomplete"
  190. v-model="state"
  191. :fetch-suggestions="querySearch"
  192. placeholder="请输入内容autocomplete3"
  193. ></el-autocomplete>
  194. `,
  195. data() {
  196. return {
  197. restaurants: [],
  198. state: ''
  199. };
  200. },
  201. methods: {
  202. querySearch(queryString, cb) {
  203. var restaurants = this.restaurants;
  204. var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
  205. cb(results);
  206. },
  207. createFilter(queryString) {
  208. return (restaurant) => {
  209. return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
  210. };
  211. },
  212. loadAll() {
  213. return [
  214. { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
  215. { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
  216. { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
  217. { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' },
  218. { 'value': '胖仙女纸杯蛋糕(上海凌空店)', 'address': '上海市长宁区金钟路968号1幢18号楼一层商铺18-101' },
  219. { 'value': '贡茶', 'address': '上海市长宁区金钟路633号' },
  220. { 'value': '豪大大香鸡排超级奶爸', 'address': '上海市嘉定区曹安公路曹安路1685号' },
  221. { 'value': '茶芝兰(奶茶,手抓饼)', 'address': '上海市普陀区同普路1435号' },
  222. { 'value': '十二泷町', 'address': '上海市北翟路1444弄81号B幢-107' },
  223. { 'value': '星移浓缩咖啡', 'address': '上海市嘉定区新郁路817号' },
  224. { 'value': '阿姨奶茶/豪大大', 'address': '嘉定区曹安路1611号' },
  225. { 'value': '新麦甜四季甜品炸鸡', 'address': '嘉定区曹安公路2383弄55号' },
  226. { 'value': 'Monica摩托主题咖啡店', 'address': '嘉定区江桥镇曹安公路2409号1F,2383弄62号1F' },
  227. { 'value': '浮生若茶(凌空soho店)', 'address': '上海长宁区金钟路968号9号楼地下一层' },
  228. { 'value': 'NONO JUICE 鲜榨果汁', 'address': '上海市长宁区天山西路119号' },
  229. { 'value': 'CoCo都可(北新泾店)', 'address': '上海市长宁区仙霞西路' },
  230. { 'value': '快乐柠檬(神州智慧店)', 'address': '上海市长宁区天山西路567号1层R117号店铺' },
  231. { 'value': 'Merci Paul cafe', 'address': '上海市普陀区光复西路丹巴路28弄6号楼819' },
  232. { 'value': '猫山王(西郊百联店)', 'address': '上海市长宁区仙霞西路88号第一层G05-F01-1-306' },
  233. { 'value': '枪会山', 'address': '上海市普陀区棕榈路' },
  234. { 'value': '纵食', 'address': '元丰天山花园(东门) 双流路267号' },
  235. { 'value': '钱记', 'address': '上海市长宁区天山西路' }
  236. ];
  237. }
  238. },
  239. mounted() {
  240. this.restaurants = this.loadAll();
  241. }
  242. }, true);
  243. const autocomplete = vm.$refs.autocomplete;
  244. const inputElm = autocomplete.$el.querySelector('input');
  245. inputElm.focus();
  246. setTimeout(_ => {
  247. autocomplete.highlight(8);
  248. vm.$nextTick(_ => {
  249. const suggestions = autocomplete.$refs.suggestions.$el.querySelector('.el-autocomplete-suggestion__wrap');
  250. let suggestionsList = suggestions.querySelectorAll('.el-autocomplete-suggestion__list li');
  251. let highlightedItem = suggestionsList[8];
  252. expect(highlightedItem.classList.contains('highlighted')).to.be.true;
  253. expect(suggestions.scrollTop === highlightedItem.scrollHeight).to.be.true;
  254. done();
  255. });
  256. }, 500);
  257. });
  258. it('highlight out of bounds', done => {
  259. vm = createVue({
  260. template: `
  261. <el-autocomplete
  262. ref="autocomplete"
  263. v-model="state"
  264. :fetch-suggestions="querySearch"
  265. placeholder="请输入内容autocomplete3"
  266. ></el-autocomplete>
  267. `,
  268. data() {
  269. return {
  270. restaurants: [],
  271. state: ''
  272. };
  273. },
  274. methods: {
  275. querySearch(queryString, cb) {
  276. var restaurants = this.restaurants;
  277. var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
  278. cb(results);
  279. },
  280. createFilter(queryString) {
  281. return (restaurant) => {
  282. return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
  283. };
  284. },
  285. loadAll() {
  286. return [
  287. { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
  288. { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
  289. { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
  290. { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' },
  291. { 'value': '胖仙女纸杯蛋糕(上海凌空店)', 'address': '上海市长宁区金钟路968号1幢18号楼一层商铺18-101' },
  292. { 'value': '贡茶', 'address': '上海市长宁区金钟路633号' },
  293. { 'value': '豪大大香鸡排超级奶爸', 'address': '上海市嘉定区曹安公路曹安路1685号' },
  294. { 'value': '茶芝兰(奶茶,手抓饼)', 'address': '上海市普陀区同普路1435号' },
  295. { 'value': '十二泷町', 'address': '上海市北翟路1444弄81号B幢-107' },
  296. { 'value': '星移浓缩咖啡', 'address': '上海市嘉定区新郁路817号' },
  297. { 'value': '阿姨奶茶/豪大大', 'address': '嘉定区曹安路1611号' },
  298. { 'value': '新麦甜四季甜品炸鸡', 'address': '嘉定区曹安公路2383弄55号' }
  299. ];
  300. }
  301. },
  302. mounted() {
  303. this.restaurants = this.loadAll();
  304. }
  305. }, true);
  306. const autocomplete = vm.$refs.autocomplete;
  307. let inputElm = vm.$el.querySelector('input');
  308. inputElm.focus();
  309. setTimeout(_ => {
  310. autocomplete.highlight(15);
  311. vm.$nextTick(_ => {
  312. const suggestions = autocomplete.$refs.suggestions.$el;
  313. const suggestionsList = suggestions.querySelectorAll('.el-autocomplete-suggestion__list li');
  314. let highlightedItem = suggestionsList[11];
  315. expect(highlightedItem.className).to.be.equal('highlighted');
  316. done();
  317. });
  318. }, 500);
  319. });
  320. it('triggerOnFocus', done => {
  321. vm = createVue({
  322. template: `
  323. <el-autocomplete
  324. ref="autocomplete"
  325. v-model="state"
  326. :fetch-suggestions="querySearch"
  327. :trigger-on-focus="false"
  328. placeholder="请输入内容autocomplete1"
  329. ></el-autocomplete>
  330. `,
  331. data() {
  332. return {
  333. restaurants: [],
  334. state: ''
  335. };
  336. },
  337. methods: {
  338. querySearch(queryString, cb) {
  339. var restaurants = this.restaurants;
  340. var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
  341. cb(results);
  342. },
  343. createFilter(queryString) {
  344. return (restaurant) => {
  345. return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
  346. };
  347. },
  348. loadAll() {
  349. return [
  350. { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
  351. { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
  352. { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
  353. { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
  354. ];
  355. }
  356. },
  357. mounted() {
  358. this.restaurants = this.loadAll();
  359. }
  360. }, true);
  361. let inputElm = vm.$el.querySelector('input');
  362. inputElm.focus();
  363. setTimeout(_ => {
  364. let suggestions = vm.$refs.autocomplete.$refs.suggestions.$el;
  365. expect(suggestions.style.display).to.be.equal('none');
  366. done();
  367. }, 500);
  368. });
  369. it('event:focus & blur', done => {
  370. vm = createVue({
  371. template: `
  372. <el-autocomplete
  373. ref="input"
  374. v-model="state"
  375. :fetch-suggestions="querySearch"
  376. :trigger-on-focus="false"
  377. placeholder="请输入内容autocomplete1"
  378. ></el-autocomplete>
  379. `,
  380. data() {
  381. return {
  382. restaurants: [],
  383. state: ''
  384. };
  385. },
  386. methods: {
  387. querySearch(queryString, cb) {
  388. var restaurants = this.restaurants;
  389. var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
  390. cb(results);
  391. },
  392. createFilter(queryString) {
  393. return (restaurant) => {
  394. return (restaurant.value.indexOf(queryString.toLowerCase()) === 0);
  395. };
  396. },
  397. loadAll() {
  398. return [
  399. { 'value': '三全鲜食(北新泾店)', 'address': '长宁区新渔路144号' },
  400. { 'value': 'Hot honey 首尔炸鸡(仙霞路)', 'address': '上海市长宁区淞虹路661号' },
  401. { 'value': '新旺角茶餐厅', 'address': '上海市普陀区真北路988号创邑金沙谷6号楼113' },
  402. { 'value': '泷千家(天山西路店)', 'address': '天山西路438号' }
  403. ];
  404. }
  405. },
  406. mounted() {
  407. this.restaurants = this.loadAll();
  408. }
  409. }, true);
  410. const spyFocus = sinon.spy();
  411. const spyBlur = sinon.spy();
  412. vm.$refs.input.$on('focus', spyFocus);
  413. vm.$refs.input.$on('blur', spyBlur);
  414. vm.$el.querySelector('input').focus();
  415. vm.$el.querySelector('input').blur();
  416. vm.$nextTick(_ => {
  417. expect(spyFocus.calledOnce).to.be.true;
  418. expect(spyBlur.calledOnce).to.be.true;
  419. done();
  420. });
  421. });
  422. });