cascader-panel.spec.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. import {
  2. createTest,
  3. createVue,
  4. destroyVM,
  5. waitImmediate,
  6. wait,
  7. triggerEvent
  8. } from '../util';
  9. import CascaderPanel from 'packages/cascader-panel';
  10. const selectedValue = ['zhejiang', 'hangzhou', 'xihu'];
  11. const options = [{
  12. value: 'zhejiang',
  13. label: 'Zhejiang',
  14. children: [{
  15. value: 'hangzhou',
  16. label: 'Hangzhou',
  17. children: [{
  18. value: 'xihu',
  19. label: 'West Lake'
  20. }, {
  21. value: 'binjiang',
  22. label: 'Bin Jiang'
  23. }]
  24. }, {
  25. value: 'ningbo',
  26. label: 'NingBo',
  27. children: [{
  28. value: 'jiangbei',
  29. label: 'Jiang Bei'
  30. }, {
  31. value: 'jiangdong',
  32. label: 'Jiang Dong',
  33. disabled: true
  34. }]
  35. }]
  36. }, {
  37. value: 'jiangsu',
  38. label: 'Jiangsu',
  39. disabled: true,
  40. children: [{
  41. value: 'nanjing',
  42. label: 'Nanjing',
  43. children: [{
  44. value: 'zhonghuamen',
  45. label: 'Zhong Hua Men'
  46. }]
  47. }]
  48. }];
  49. const options2 = [{
  50. id: 'zhejiang',
  51. name: 'Zhejiang',
  52. areas: [{
  53. id: 'hangzhou',
  54. name: 'Hangzhou',
  55. areas: [{
  56. id: 'xihu',
  57. name: 'West Lake'
  58. }, {
  59. id: 'binjiang',
  60. name: 'Bin Jiang'
  61. }]
  62. }, {
  63. id: 'ningbo',
  64. name: 'NingBo',
  65. areas: [{
  66. id: 'jiangbei',
  67. label: 'Jiang Bei'
  68. }, {
  69. id: 'jiangdong',
  70. name: 'Jiang Dong',
  71. invalid: true
  72. }]
  73. }]
  74. }, {
  75. id: 'jiangsu',
  76. name: 'Jiangsu',
  77. invalid: true,
  78. areas: [{
  79. id: 'nanjing',
  80. name: 'Nanjing',
  81. areas: [{
  82. id: 'zhonghuamen',
  83. name: 'Zhong Hua Men'
  84. }]
  85. }]
  86. }];
  87. const options3 = [
  88. {
  89. value: 'shanghai',
  90. label: '上海',
  91. children: [
  92. {
  93. value: 'baoshan',
  94. label: '宝山'
  95. }
  96. ]
  97. },
  98. {
  99. value: 'beijing',
  100. label: '北京'
  101. }
  102. ];
  103. const getMenus = el => el.querySelectorAll('.el-cascader-menu');
  104. const getOptions = (el, menuIndex) => getMenus(el)[menuIndex].querySelectorAll('.el-cascader-node');
  105. const getValidOptions = (el, menuIndex) => getMenus(el)[menuIndex].querySelectorAll('.el-cascader-node[tabindex="-1"]');
  106. const getLabel = el => el.querySelector('.el-cascader-node__label').textContent;
  107. describe('CascaderPanel', () => {
  108. let vm;
  109. afterEach(() => {
  110. destroyVM(vm);
  111. });
  112. it('create', () => {
  113. vm = createTest(CascaderPanel, true);
  114. expect(vm.$el).to.exist;
  115. });
  116. it('expand and check', async() => {
  117. vm = createVue({
  118. template: `
  119. <el-cascader-panel
  120. ref="panel"
  121. v-model="value"
  122. :options="options"></el-cascader-panel>
  123. `,
  124. data() {
  125. return {
  126. value: [],
  127. options
  128. };
  129. }
  130. }, true);
  131. const el = vm.$el;
  132. const expandHandler = sinon.spy();
  133. const changeHandler = sinon.spy();
  134. vm.$refs.panel.$on('expand-change', expandHandler);
  135. vm.$refs.panel.$on('change', changeHandler);
  136. expect(getMenus(el).length).to.equal(1);
  137. expect(getOptions(el, 0).length).to.equal(2);
  138. const firstOption = getOptions(el, 0)[0];
  139. expect(getLabel(firstOption)).to.equal('Zhejiang');
  140. firstOption.click();
  141. await waitImmediate();
  142. expect(expandHandler.calledOnceWith(['zhejiang'])).to.be.true;
  143. expect(getMenus(el).length).to.equal(2);
  144. getOptions(el, 1)[0].click();
  145. await waitImmediate();
  146. expect(getMenus(el).length).to.equal(3);
  147. getOptions(el, 2)[0].click();
  148. await waitImmediate();
  149. expect(changeHandler.calledOnceWith(selectedValue)).to.be.true;
  150. expect(vm.value).to.deep.equal(selectedValue);
  151. });
  152. it('with default value', async() => {
  153. vm = createVue({
  154. template: `
  155. <el-cascader-panel
  156. ref="panel"
  157. v-model="value"
  158. :options="options"></el-cascader-panel>
  159. `,
  160. data() {
  161. return {
  162. value: selectedValue,
  163. options
  164. };
  165. }
  166. }, true);
  167. const el = vm.$el;
  168. await waitImmediate();
  169. expect(getMenus(el).length).to.equal(3);
  170. expect(getOptions(el, 0)[0].className).to.includes('in-active-path');
  171. expect(getOptions(el, 2)[0].className).to.includes('is-active');
  172. expect(getOptions(el, 2)[0].querySelector('.el-icon-check')).to.exist;
  173. });
  174. it('disabled options', async() => {
  175. vm = createVue({
  176. template: `
  177. <el-cascader-panel
  178. ref="panel"
  179. :value="value"
  180. :options="options"></el-cascader-panel>
  181. `,
  182. data() {
  183. return {
  184. value: [],
  185. options
  186. };
  187. }
  188. }, true);
  189. const el = vm.$el;
  190. const expandHandler = sinon.spy();
  191. vm.$refs.panel.$on('expand-change', expandHandler);
  192. expect(getOptions(el, 0).length).to.equal(2);
  193. expect(getValidOptions(el, 0).length).to.equal(1);
  194. const secondOption = getOptions(el, 0)[1];
  195. expect(secondOption.className).to.includes('is-disabled');
  196. secondOption.click();
  197. await waitImmediate();
  198. expect(expandHandler.called).to.be.false;
  199. expect(getMenus(el).length).to.equal(1);
  200. });
  201. it('expand by hover', async() => {
  202. vm = createVue({
  203. template: `
  204. <el-cascader-panel
  205. :options="options"
  206. :props="props"></el-cascader-panel>
  207. `,
  208. data() {
  209. return {
  210. options,
  211. props: {
  212. expandTrigger: 'hover'
  213. }
  214. };
  215. }
  216. }, true);
  217. const el = vm.$el;
  218. triggerEvent(getOptions(el, 0)[1], 'mouseenter');
  219. await waitImmediate();
  220. expect(getMenus(el).length).to.equal(1);
  221. triggerEvent(getOptions(el, 0)[0], 'mouseenter');
  222. await waitImmediate();
  223. expect(getMenus(el).length).to.equal(2);
  224. triggerEvent(getOptions(el, 1)[0], 'mouseenter');
  225. await waitImmediate();
  226. expect(getMenus(el).length).to.equal(3);
  227. });
  228. it('emit value only', async() => {
  229. vm = createVue({
  230. template: `
  231. <el-cascader-panel
  232. ref="panel"
  233. v-model="value"
  234. :options="options"
  235. :props="props"></el-cascader-panel>
  236. `,
  237. data() {
  238. return {
  239. value: 'xihu',
  240. options,
  241. props: {
  242. emitPath: false
  243. }
  244. };
  245. }
  246. }, true);
  247. const el = vm.$el;
  248. await waitImmediate();
  249. expect(getMenus(el).length).to.equal(3);
  250. expect(getOptions(el, 2)[0].querySelector('.el-icon-check')).to.exist;
  251. getOptions(el, 1)[1].click();
  252. await waitImmediate();
  253. getOptions(el, 2)[0].click();
  254. await waitImmediate();
  255. expect(vm.value).to.equal('jiangbei');
  256. });
  257. it('multiple mode', async() => {
  258. vm = createVue({
  259. template: `
  260. <el-cascader-panel
  261. v-model="value"
  262. :options="options"
  263. :props="props"></el-cascader-panel>
  264. `,
  265. data() {
  266. return {
  267. value: [],
  268. options: options,
  269. props: {
  270. multiple: true
  271. }
  272. };
  273. }
  274. }, true);
  275. const el = vm.$el;
  276. const checkbox = getOptions(el, 0)[0].querySelector('.el-checkbox');
  277. expect(checkbox).to.exist;
  278. expect(checkbox.querySelector('.el-checkbox__input').className).to.not.includes('is-checked');
  279. checkbox.querySelector('input').click();
  280. await waitImmediate();
  281. expect(checkbox.querySelector('.el-checkbox__input').className).to.includes('is-checked');
  282. expect(vm.value.length).to.equal(3);
  283. });
  284. it('multiple mode with disabled default value', async() => {
  285. vm = createVue({
  286. template: `
  287. <el-cascader-panel
  288. v-model="value"
  289. :options="options"
  290. :props="props"></el-cascader-panel>
  291. `,
  292. data() {
  293. return {
  294. value: [['zhejiang', 'ningbo', 'jiangdong']],
  295. options: options,
  296. props: {
  297. multiple: true
  298. }
  299. };
  300. }
  301. }, true);
  302. const el = vm.$el;
  303. const checkbox = getOptions(el, 0)[0].querySelector('.el-checkbox');
  304. await waitImmediate();
  305. expect(checkbox).to.exist;
  306. expect(checkbox.querySelector('.el-checkbox__input').className).to.includes('is-indeterminate');
  307. checkbox.querySelector('input').click();
  308. await waitImmediate();
  309. expect(checkbox.querySelector('.el-checkbox__input').className).to.includes('is-checked');
  310. expect(vm.value.length).to.equal(4);
  311. getOptions(el, 1)[1].click();
  312. await waitImmediate();
  313. getOptions(el, 2)[1].querySelector('input').click();
  314. await waitImmediate();
  315. expect(vm.value.length).to.equal(4);
  316. });
  317. it('check strictly in single mode', async() => {
  318. vm = createVue({
  319. template: `
  320. <el-cascader-panel
  321. v-model="value"
  322. :options="options"
  323. :props="props"></el-cascader-panel>
  324. `,
  325. data() {
  326. return {
  327. value: ['zhejiang'],
  328. options: options,
  329. props: {
  330. checkStrictly: true
  331. }
  332. };
  333. }
  334. }, true);
  335. const el = vm.$el;
  336. const radio = getOptions(el, 0)[0].querySelector('.el-radio');
  337. await waitImmediate();
  338. expect(radio).to.exist;
  339. expect(radio.className).to.includes('is-checked');
  340. getOptions(el, 0)[0].click();
  341. await waitImmediate();
  342. getOptions(el, 1)[0].querySelector('input').click();
  343. await waitImmediate();
  344. expect(vm.value).to.deep.equal(['zhejiang', 'hangzhou']);
  345. expect(getOptions(el, 0)[1].querySelector('.el-radio').className).to.includes('is-disabled');
  346. });
  347. it('check strictly in multiple mode', async() => {
  348. vm = createVue({
  349. template: `
  350. <el-cascader-panel
  351. v-model="value"
  352. :options="options"
  353. :props="props"></el-cascader-panel>
  354. `,
  355. data() {
  356. return {
  357. value: [['zhejiang']],
  358. options: options,
  359. props: {
  360. multiple: true,
  361. checkStrictly: true,
  362. emitPath: false
  363. }
  364. };
  365. }
  366. }, true);
  367. const el = vm.$el;
  368. const checkbox = getOptions(el, 0)[0].querySelector('.el-checkbox');
  369. await waitImmediate();
  370. expect(checkbox).to.exist;
  371. expect(checkbox.className).to.includes('is-checked');
  372. getOptions(el, 0)[0].click();
  373. await waitImmediate();
  374. expect(getOptions(el, 1)[0].querySelector('.el-checkbox').className).to.not.includes('is-checked');
  375. getOptions(el, 1)[0].querySelector('input').click();
  376. await waitImmediate();
  377. expect(vm.value).to.deep.equal(['zhejiang', 'hangzhou']);
  378. expect(getOptions(el, 0)[1].querySelector('.el-checkbox').className).to.includes('is-disabled');
  379. });
  380. it('custom props', async() => {
  381. vm = createVue({
  382. template: `
  383. <el-cascader-panel
  384. v-model="value"
  385. :options="options"
  386. :props="props"></el-cascader-panel>
  387. `,
  388. data() {
  389. return {
  390. value: [],
  391. options: options2,
  392. props: {
  393. value: 'id',
  394. label: 'name',
  395. children: 'areas',
  396. disabled: 'invalid'
  397. }
  398. };
  399. }
  400. }, true);
  401. const el = vm.$el;
  402. expect(getMenus(el).length).to.equal(1);
  403. expect(getOptions(el, 0).length).to.equal(2);
  404. expect(getValidOptions(el, 0).length).to.equal(1);
  405. const firstOption = getOptions(el, 0)[0];
  406. expect(getLabel(firstOption)).to.equal('Zhejiang');
  407. firstOption.click();
  408. await waitImmediate();
  409. expect(getMenus(el).length).to.equal(2);
  410. getOptions(el, 1)[0].click();
  411. await waitImmediate();
  412. expect(getMenus(el).length).to.equal(3);
  413. getOptions(el, 2)[0].click();
  414. await waitImmediate();
  415. expect(vm.value).to.deep.equal(selectedValue);
  416. });
  417. it('value key is same as label key', async() => {
  418. vm = createVue({
  419. template: `
  420. <el-cascader-panel
  421. v-model="value"
  422. :options="options"
  423. :props="props"></el-cascader-panel>
  424. `,
  425. data() {
  426. return {
  427. value: [],
  428. options,
  429. props: {
  430. label: 'value'
  431. }
  432. };
  433. }
  434. }, true);
  435. const el = vm.$el;
  436. expect(getMenus(el).length).to.equal(1);
  437. expect(getOptions(el, 0).length).to.equal(2);
  438. expect(getValidOptions(el, 0).length).to.equal(1);
  439. const firstOption = getOptions(el, 0)[0];
  440. expect(getLabel(firstOption)).to.equal('zhejiang');
  441. firstOption.click();
  442. await waitImmediate();
  443. expect(getMenus(el).length).to.equal(2);
  444. getOptions(el, 1)[0].click();
  445. await waitImmediate();
  446. expect(getMenus(el).length).to.equal(3);
  447. getOptions(el, 2)[0].click();
  448. await waitImmediate();
  449. expect(vm.value).to.deep.equal(selectedValue);
  450. });
  451. it('dynamic loading', async() => {
  452. vm = createVue({
  453. template: `
  454. <el-cascader-panel
  455. v-model="value"
  456. :props="props"></el-cascader-panel>
  457. `,
  458. data() {
  459. let id = 0;
  460. return {
  461. value: [],
  462. props: {
  463. lazy: true,
  464. lazyLoad(node, resolve) {
  465. const { level } = node;
  466. setTimeout(() => {
  467. const nodes = Array.from({ length: level + 1 })
  468. .map(() => ({
  469. value: ++id,
  470. label: `选项${id}`,
  471. leaf: level >= 2
  472. }));
  473. resolve(nodes);
  474. }, 1000);
  475. }
  476. }
  477. };
  478. }
  479. }, true);
  480. const el = vm.$el;
  481. await wait(1000);
  482. const firstOption = getOptions(el, 0)[0];
  483. firstOption.click();
  484. await waitImmediate();
  485. expect(firstOption.querySelector('i').className).to.includes('el-icon-loading');
  486. await wait(1000);
  487. expect(firstOption.querySelector('i').className).to.includes('el-icon-arrow-right');
  488. expect(getMenus(el).length).to.equal(2);
  489. getOptions(el, 1)[0].click();
  490. await wait(1000);
  491. getOptions(el, 2)[0].click();
  492. await waitImmediate();
  493. expect(vm.value.length).to.equal(3);
  494. });
  495. it('click leaf hidden children', async() => {
  496. vm = createVue({
  497. template: `
  498. <el-cascader-panel
  499. ref="panel"
  500. v-model="value"
  501. :options="options"></el-cascader-panel>
  502. `,
  503. data() {
  504. return {
  505. value: [],
  506. options: options3
  507. };
  508. }
  509. }, true);
  510. const el = vm.$el;
  511. const elOptions = getOptions(el, 0);
  512. const firstOption = elOptions[0];
  513. const twoOption = elOptions[1];
  514. firstOption.click();
  515. await waitImmediate();
  516. expect(getMenus(el).length).to.equal(2);
  517. twoOption.click();
  518. await waitImmediate();
  519. expect(getMenus(el).length).to.equal(1);
  520. });
  521. });