select.spec.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  1. import { createTest, createVue, triggerEvent, destroyVM } from '../util';
  2. import Select from 'packages/select';
  3. describe('Select', () => {
  4. const getSelectVm = (configs = {}, options) => {
  5. ['multiple', 'clearable', 'filterable', 'allowCreate', 'remote'].forEach(config => {
  6. configs[config] = configs[config] || false;
  7. });
  8. configs.multipleLimit = configs.multipleLimit || 0;
  9. if (!options) {
  10. options = [{
  11. value: '选项1',
  12. label: '黄金糕',
  13. disabled: false
  14. }, {
  15. value: '选项2',
  16. label: '双皮奶',
  17. disabled: false
  18. }, {
  19. value: '选项3',
  20. label: '蚵仔煎',
  21. disabled: false
  22. }, {
  23. value: '选项4',
  24. label: '龙须面',
  25. disabled: false
  26. }, {
  27. value: '选项5',
  28. label: '北京烤鸭',
  29. disabled: false
  30. }];
  31. }
  32. const vm = createVue({
  33. template: `
  34. <div>
  35. <el-select
  36. v-model="value"
  37. :multiple="multiple"
  38. :multiple-limit="multipleLimit"
  39. :popper-class="popperClass"
  40. :clearable="clearable"
  41. :filterable="filterable"
  42. :allow-create="allowCreate"
  43. :filterMethod="filterMethod"
  44. :remote="remote"
  45. :loading="loading"
  46. :remoteMethod="remoteMethod">
  47. <el-option
  48. v-for="item in options"
  49. :label="item.label"
  50. :key="item.value"
  51. :disabled="item.disabled"
  52. :value="item.value">
  53. </el-option>
  54. </el-select>
  55. </div>
  56. `,
  57. data() {
  58. return {
  59. options,
  60. multiple: configs.multiple,
  61. multipleLimit: configs.multipleLimit,
  62. clearable: configs.clearable,
  63. filterable: configs.filterable,
  64. allowCreate: configs.allowCreate,
  65. popperClass: configs.popperClass,
  66. loading: false,
  67. filterMethod: configs.filterMethod && configs.filterMethod(this),
  68. remote: configs.remote,
  69. remoteMethod: configs.remoteMethod && configs.remoteMethod(this),
  70. value: configs.multiple ? [] : ''
  71. };
  72. }
  73. }, true);
  74. return vm;
  75. };
  76. let vm;
  77. afterEach(() => {
  78. destroyVM(vm);
  79. });
  80. it('create', () => {
  81. vm = createTest(Select, true);
  82. expect(vm.$el.className).to.equal('el-select');
  83. expect(vm.$el.querySelector('.el-input__inner').placeholder).to.equal('请选择');
  84. vm.toggleMenu();
  85. expect(vm.visible).to.true;
  86. });
  87. it('options rendered correctly', () => {
  88. vm = getSelectVm();
  89. const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
  90. const result = [].every.call(options, (option, index) => {
  91. let text = option.querySelector('span').textContent;
  92. return text === vm.options[index].label;
  93. });
  94. expect(result).to.true;
  95. });
  96. it('custom dropdown class', () => {
  97. vm = getSelectVm({ popperClass: 'custom-dropdown' });
  98. const dropdown = vm.$el.querySelector('.el-select-dropdown');
  99. expect(dropdown.classList.contains('custom-dropdown')).to.true;
  100. });
  101. it('default value', done => {
  102. vm = createVue({
  103. template: `
  104. <div>
  105. <el-select v-model="value">
  106. <el-option
  107. v-for="item in options"
  108. :label="item.label"
  109. :value="item.value">
  110. </el-option>
  111. </el-select>
  112. </div>
  113. `,
  114. data() {
  115. return {
  116. options: [{
  117. value: '选项1',
  118. label: '黄金糕'
  119. }, {
  120. value: '选项2',
  121. label: '双皮奶'
  122. }],
  123. value: '选项2'
  124. };
  125. }
  126. }, true);
  127. setTimeout(() => {
  128. expect(vm.$el.querySelector('.el-input__inner').value).to.equal('双皮奶');
  129. done();
  130. }, 100);
  131. });
  132. it('single select', done => {
  133. sinon.stub(window.console, 'log');
  134. vm = createVue({
  135. template: `
  136. <div>
  137. <el-select v-model="value" @change="handleChange">
  138. <el-option
  139. v-for="item in options"
  140. :label="item.label"
  141. :value="item.value">
  142. <p>{{item.label}} {{item.value}}</p>
  143. </el-option>
  144. </el-select>
  145. </div>
  146. `,
  147. data() {
  148. return {
  149. options: [{
  150. value: '选项1',
  151. label: '黄金糕'
  152. }, {
  153. value: '选项2',
  154. label: '双皮奶'
  155. }, {
  156. value: '选项3',
  157. label: '蚵仔煎'
  158. }, {
  159. value: '选项4',
  160. label: '龙须面'
  161. }, {
  162. value: '选项5',
  163. label: '北京烤鸭'
  164. }],
  165. value: ''
  166. };
  167. },
  168. methods: {
  169. handleChange() {
  170. console.log('changed');
  171. }
  172. }
  173. }, true);
  174. const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
  175. expect(vm.value).to.equal('');
  176. triggerEvent(options[2], 'mouseenter');
  177. options[2].click();
  178. setTimeout(() => {
  179. expect(vm.value).to.equal('选项3');
  180. expect(window.console.log.callCount).to.equal(1);
  181. options[4].click();
  182. setTimeout(() => {
  183. expect(vm.value).to.equal('选项5');
  184. expect(window.console.log.callCount).to.equal(2);
  185. window.console.log.restore();
  186. done();
  187. }, 100);
  188. }, 100);
  189. });
  190. it('disabled option', done => {
  191. vm = getSelectVm();
  192. vm.options[1].disabled = true;
  193. setTimeout(() => {
  194. const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
  195. expect(options[1].classList.contains('is-disabled')).to.true;
  196. options[1].click();
  197. setTimeout(() => {
  198. expect(vm.value).to.equal('');
  199. done();
  200. }, 100);
  201. }, 100);
  202. });
  203. it('disabled select', () => {
  204. vm = createTest(Select, { disabled: true }, true);
  205. expect(vm.$el.querySelector('.el-input').classList.contains('is-disabled')).to.true;
  206. });
  207. it('visible event', done => {
  208. vm = createVue({
  209. template: `
  210. <div>
  211. <el-select v-model="value" @visible-change="handleVisibleChange">
  212. <el-option
  213. v-for="item in options"
  214. :label="item.label"
  215. :value="item.value">
  216. </el-option>
  217. </el-select>
  218. </div>
  219. `,
  220. data() {
  221. return {
  222. options: [],
  223. value: '',
  224. visible: ''
  225. };
  226. },
  227. methods: {
  228. handleVisibleChange(val) {
  229. this.visible = val;
  230. }
  231. }
  232. }, true);
  233. vm.$children[0].visible = true;
  234. setTimeout(() => {
  235. expect(vm.visible).to.true;
  236. done();
  237. }, 50);
  238. });
  239. it('keyboard operations', done => {
  240. vm = getSelectVm();
  241. const select = vm.$children[0];
  242. let i = 8;
  243. while (i--) {
  244. select.navigateOptions('next');
  245. }
  246. select.navigateOptions('prev');
  247. setTimeout(() => {
  248. expect(select.hoverIndex).to.equal(0);
  249. select.selectOption();
  250. setTimeout(() => {
  251. expect(select.value).to.equal('选项1');
  252. done();
  253. }, 100);
  254. }, 100);
  255. });
  256. it('clearable', done => {
  257. vm = getSelectVm({ clearable: true });
  258. const select = vm.$children[0];
  259. vm.value = '选项1';
  260. select.inputHovering = true;
  261. setTimeout(() => {
  262. const icon = vm.$el.querySelector('.el-input__icon');
  263. expect(icon.classList.contains('el-icon-circle-close')).to.true;
  264. icon.click();
  265. expect(vm.value).to.equal('');
  266. done();
  267. }, 100);
  268. });
  269. it('custom el-option template', () => {
  270. vm = createVue({
  271. template: `
  272. <div>
  273. <el-select v-model="value">
  274. <el-option
  275. v-for="item in options"
  276. :label="item.label"
  277. :value="item.value">
  278. <p>{{item.label}} {{item.value}}</p>
  279. </el-option>
  280. </el-select>
  281. </div>
  282. `,
  283. data() {
  284. return {
  285. options: [{
  286. value: 'value',
  287. label: 'label'
  288. }],
  289. value: ''
  290. };
  291. }
  292. }, true);
  293. expect(vm.$el.querySelector('.el-select-dropdown__item p').textContent).to.equal('label value');
  294. });
  295. it('option group', () => {
  296. vm = createVue({
  297. template: `
  298. <div>
  299. <el-select v-model="value">
  300. <el-option-group
  301. v-for="group in options"
  302. :disabled="group.disabled"
  303. :label="group.label">
  304. <el-option
  305. v-for="item in group.options"
  306. :label="item.label"
  307. :value="item.value">
  308. </el-option>
  309. </el-option-group>
  310. </el-select>
  311. </div>
  312. `,
  313. data() {
  314. return {
  315. options: [{
  316. label: '热门城市',
  317. options: [{
  318. value: 'Shanghai',
  319. label: '上海'
  320. }, {
  321. value: 'Beijing',
  322. label: '北京'
  323. }]
  324. }, {
  325. label: '城市名',
  326. disabled: true,
  327. options: [{
  328. value: 'Chengdu',
  329. label: '成都'
  330. }, {
  331. value: 'Shenzhen',
  332. label: '深圳'
  333. }, {
  334. value: 'Guangzhou',
  335. label: '广州'
  336. }, {
  337. value: 'Dalian',
  338. label: '大连'
  339. }]
  340. }],
  341. value: ''
  342. };
  343. }
  344. }, true);
  345. const groups = vm.$el.querySelectorAll('.el-select-group__wrap');
  346. const options = groups[1].querySelectorAll('.el-select-dropdown__item');
  347. expect(groups.length).to.equal(2);
  348. expect(options.length).to.equal(4);
  349. expect(options[0].querySelector('span').textContent).to.equal('成都');
  350. });
  351. it('filterable', done => {
  352. vm = getSelectVm({ filterable: true });
  353. const select = vm.$children[0];
  354. setTimeout(() => {
  355. select.selectedLabel = '面';
  356. select.onInputChange();
  357. select.visible = true;
  358. setTimeout(() => {
  359. expect(select.filteredOptionsCount).to.equal(1);
  360. done();
  361. }, 10);
  362. }, 10);
  363. });
  364. it('filterable with custom filter-method', done => {
  365. const filterMethod = vm => {
  366. return query => {
  367. vm.options = vm.options.filter(option => option.label.indexOf(query) === -1);
  368. };
  369. };
  370. vm = getSelectVm({ filterable: true, filterMethod });
  371. const select = vm.$children[0];
  372. select.$el.querySelector('input').focus();
  373. setTimeout(() => {
  374. select.selectedLabel = '面';
  375. select.onInputChange();
  376. setTimeout(() => {
  377. expect(select.filteredOptionsCount).to.equal(4);
  378. done();
  379. }, 10);
  380. }, 10);
  381. });
  382. it('allow create', done => {
  383. vm = getSelectVm({ filterable: true, allowCreate: true });
  384. const select = vm.$children[0];
  385. select.$el.querySelector('input').focus();
  386. setTimeout(() => {
  387. select.selectedLabel = 'new';
  388. select.onInputChange();
  389. setTimeout(() => {
  390. const options = document.querySelectorAll('.el-select-dropdown__item span');
  391. const target = [].filter.call(options, option => option.innerText === 'new');
  392. target[0].click();
  393. setTimeout(() => {
  394. expect(select.value.indexOf('new') > -1).to.true;
  395. done();
  396. }, 10);
  397. }, 10);
  398. }, 10);
  399. });
  400. it('multiple select', done => {
  401. vm = getSelectVm({ multiple: true });
  402. const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
  403. vm.value = ['选项1'];
  404. setTimeout(() => {
  405. options[1].click();
  406. options[3].click();
  407. setTimeout(() => {
  408. expect(vm.value.indexOf('选项2') > -1 && vm.value.indexOf('选项4') > -1).to.true;
  409. const tagCloseIcons = vm.$el.querySelectorAll('.el-tag__close');
  410. tagCloseIcons[0].click();
  411. setTimeout(() => {
  412. expect(vm.value.indexOf('选项1')).to.equal(-1);
  413. done();
  414. }, 100);
  415. }, 100);
  416. }, 100);
  417. });
  418. it('multiple delete-tag', done => {
  419. sinon.stub(window.console, 'log');
  420. vm = createVue({
  421. template: `
  422. <div>
  423. <el-select v-model="value" multiple @delete-tag="handleDeleteTag">
  424. <el-option
  425. v-for="item in options"
  426. :label="item.label"
  427. :value="item.value">
  428. <p>{{item.label}} {{item.value}}</p>
  429. </el-option>
  430. </el-select>
  431. </div>
  432. `,
  433. data() {
  434. return {
  435. options: [{
  436. value: '选项1',
  437. label: '黄金糕'
  438. }, {
  439. value: '选项2',
  440. label: '双皮奶'
  441. }, {
  442. value: '选项3',
  443. label: '蚵仔煎'
  444. }, {
  445. value: '选项4',
  446. label: '龙须面'
  447. }, {
  448. value: '选项5',
  449. label: '北京烤鸭'
  450. }],
  451. value: ['选项1', '选项3']
  452. };
  453. },
  454. methods: {
  455. handleDeleteTag() {
  456. console.log('delete tag');
  457. }
  458. }
  459. }, true);
  460. const tagCloseIcons = vm.$el.querySelectorAll('.el-tag__close');
  461. expect(vm.value.length).to.equal(2);
  462. tagCloseIcons[1].click();
  463. setTimeout(() => {
  464. expect(vm.value.length).to.equal(1);
  465. expect(window.console.log.callCount).to.equal(1);
  466. tagCloseIcons[0].click();
  467. setTimeout(() => {
  468. expect(vm.value.length).to.equal(0);
  469. expect(window.console.log.callCount).to.equal(2);
  470. window.console.log.restore();
  471. done();
  472. }, 100);
  473. }, 100);
  474. });
  475. it('multiple limit', done => {
  476. vm = getSelectVm({ multiple: true, multipleLimit: 1 });
  477. const options = vm.$el.querySelectorAll('.el-select-dropdown__item');
  478. options[1].click();
  479. setTimeout(() => {
  480. expect(vm.value.indexOf('选项2') > -1).to.true;
  481. options[3].click();
  482. setTimeout(() => {
  483. expect(vm.value.indexOf('选项4')).to.equal(-1);
  484. done();
  485. }, 50);
  486. }, 50);
  487. });
  488. it('multiple remote search', done => {
  489. const remoteMethod = vm => {
  490. return query => {
  491. vm.loading = true;
  492. setTimeout(() => {
  493. vm.options = vm.options.filter(option => {
  494. return option.label.indexOf(query) > -1;
  495. });
  496. vm.loading = false;
  497. }, 200);
  498. };
  499. };
  500. vm = getSelectVm({
  501. multiple: true,
  502. remote: true,
  503. filterable: true,
  504. remoteMethod
  505. });
  506. const select = vm.$children[0];
  507. vm.$nextTick(() => {
  508. select.query = '面';
  509. setTimeout(() => {
  510. expect(select.filteredOptionsCount).to.equal(1);
  511. select.query = '';
  512. select.options[0].$el.click();
  513. vm.$nextTick(() => {
  514. expect(vm.value[0]).to.equal('选项4');
  515. select.deletePrevTag({ target: select.$refs.input });
  516. select.deletePrevTag({ target: select.$refs.input });
  517. select.resetInputState({ keyCode: 1 });
  518. vm.$nextTick(() => {
  519. expect(vm.value.length).to.equal(0);
  520. done();
  521. });
  522. });
  523. }, 250);
  524. });
  525. });
  526. });