cascader-panel.spec.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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 getMenus = el => el.querySelectorAll('.el-cascader-menu');
  88. const getOptions = (el, menuIndex) => getMenus(el)[menuIndex].querySelectorAll('.el-cascader-node');
  89. const getValidOptions = (el, menuIndex) => getMenus(el)[menuIndex].querySelectorAll('.el-cascader-node[tabindex="-1"]');
  90. const getLabel = el => el.querySelector('.el-cascader-node__label').textContent;
  91. describe('CascaderPanel', () => {
  92. let vm;
  93. afterEach(() => {
  94. destroyVM(vm);
  95. });
  96. it('create', () => {
  97. vm = createTest(CascaderPanel, true);
  98. expect(vm.$el).to.exist;
  99. });
  100. it('expand and check', async() => {
  101. vm = createVue({
  102. template: `
  103. <el-cascader-panel
  104. ref="panel"
  105. v-model="value"
  106. :options="options"></el-cascader-panel>
  107. `,
  108. data() {
  109. return {
  110. value: [],
  111. options
  112. };
  113. }
  114. }, true);
  115. const el = vm.$el;
  116. const expandHandler = sinon.spy();
  117. const changeHandler = sinon.spy();
  118. vm.$refs.panel.$on('expand-change', expandHandler);
  119. vm.$refs.panel.$on('change', changeHandler);
  120. expect(getMenus(el).length).to.equal(1);
  121. expect(getOptions(el, 0).length).to.equal(2);
  122. const firstOption = getOptions(el, 0)[0];
  123. expect(getLabel(firstOption)).to.equal('Zhejiang');
  124. firstOption.click();
  125. await waitImmediate();
  126. expect(expandHandler.calledOnceWith(['zhejiang'])).to.be.true;
  127. expect(getMenus(el).length).to.equal(2);
  128. getOptions(el, 1)[0].click();
  129. await waitImmediate();
  130. expect(getMenus(el).length).to.equal(3);
  131. getOptions(el, 2)[0].click();
  132. await waitImmediate();
  133. expect(changeHandler.calledOnceWith(selectedValue)).to.be.true;
  134. expect(vm.value).to.deep.equal(selectedValue);
  135. });
  136. it('with default value', async() => {
  137. vm = createVue({
  138. template: `
  139. <el-cascader-panel
  140. ref="panel"
  141. v-model="value"
  142. :options="options"></el-cascader-panel>
  143. `,
  144. data() {
  145. return {
  146. value: selectedValue,
  147. options
  148. };
  149. }
  150. }, true);
  151. const el = vm.$el;
  152. await waitImmediate();
  153. expect(getMenus(el).length).to.equal(3);
  154. expect(getOptions(el, 0)[0].className).to.includes('in-active-path');
  155. expect(getOptions(el, 2)[0].className).to.includes('is-active');
  156. expect(getOptions(el, 2)[0].querySelector('.el-icon-check')).to.exist;
  157. });
  158. it('disabled options', async() => {
  159. vm = createVue({
  160. template: `
  161. <el-cascader-panel
  162. ref="panel"
  163. :value="value"
  164. :options="options"></el-cascader-panel>
  165. `,
  166. data() {
  167. return {
  168. value: [],
  169. options
  170. };
  171. }
  172. }, true);
  173. const el = vm.$el;
  174. const expandHandler = sinon.spy();
  175. vm.$refs.panel.$on('expand-change', expandHandler);
  176. expect(getOptions(el, 0).length).to.equal(2);
  177. expect(getValidOptions(el, 0).length).to.equal(1);
  178. const secondOption = getOptions(el, 0)[1];
  179. expect(secondOption.className).to.includes('is-disabled');
  180. secondOption.click();
  181. await waitImmediate();
  182. expect(expandHandler.called).to.be.false;
  183. expect(getMenus(el).length).to.equal(1);
  184. });
  185. it('expand by hover', async() => {
  186. vm = createVue({
  187. template: `
  188. <el-cascader-panel
  189. :options="options"
  190. :props="props"></el-cascader-panel>
  191. `,
  192. data() {
  193. return {
  194. options,
  195. props: {
  196. expandTrigger: 'hover'
  197. }
  198. };
  199. }
  200. }, true);
  201. const el = vm.$el;
  202. triggerEvent(getOptions(el, 0)[1], 'mouseenter');
  203. await waitImmediate();
  204. expect(getMenus(el).length).to.equal(1);
  205. triggerEvent(getOptions(el, 0)[0], 'mouseenter');
  206. await waitImmediate();
  207. expect(getMenus(el).length).to.equal(2);
  208. triggerEvent(getOptions(el, 1)[0], 'mouseenter');
  209. await waitImmediate();
  210. expect(getMenus(el).length).to.equal(3);
  211. });
  212. it('emit value only', async() => {
  213. vm = createVue({
  214. template: `
  215. <el-cascader-panel
  216. ref="panel"
  217. v-model="value"
  218. :options="options"
  219. :props="props"></el-cascader-panel>
  220. `,
  221. data() {
  222. return {
  223. value: 'xihu',
  224. options,
  225. props: {
  226. emitPath: false
  227. }
  228. };
  229. }
  230. }, true);
  231. const el = vm.$el;
  232. await waitImmediate();
  233. expect(getMenus(el).length).to.equal(3);
  234. expect(getOptions(el, 2)[0].querySelector('.el-icon-check')).to.exist;
  235. getOptions(el, 1)[1].click();
  236. await waitImmediate();
  237. getOptions(el, 2)[0].click();
  238. await waitImmediate();
  239. expect(vm.value).to.equal('jiangbei');
  240. });
  241. it('multiple mode', async() => {
  242. vm = createVue({
  243. template: `
  244. <el-cascader-panel
  245. v-model="value"
  246. :options="options"
  247. :props="props"></el-cascader-panel>
  248. `,
  249. data() {
  250. return {
  251. value: [],
  252. options: options,
  253. props: {
  254. multiple: true
  255. }
  256. };
  257. }
  258. }, true);
  259. const el = vm.$el;
  260. const checkbox = getOptions(el, 0)[0].querySelector('.el-checkbox');
  261. expect(checkbox).to.exist;
  262. expect(checkbox.querySelector('.el-checkbox__input').className).to.not.includes('is-checked');
  263. checkbox.querySelector('input').click();
  264. await waitImmediate();
  265. expect(checkbox.querySelector('.el-checkbox__input').className).to.includes('is-checked');
  266. expect(vm.value.length).to.equal(3);
  267. });
  268. it('multiple mode with disabled default value', async() => {
  269. vm = createVue({
  270. template: `
  271. <el-cascader-panel
  272. v-model="value"
  273. :options="options"
  274. :props="props"></el-cascader-panel>
  275. `,
  276. data() {
  277. return {
  278. value: [['zhejiang', 'ningbo', 'jiangdong']],
  279. options: options,
  280. props: {
  281. multiple: true
  282. }
  283. };
  284. }
  285. }, true);
  286. const el = vm.$el;
  287. const checkbox = getOptions(el, 0)[0].querySelector('.el-checkbox');
  288. await waitImmediate();
  289. expect(checkbox).to.exist;
  290. expect(checkbox.querySelector('.el-checkbox__input').className).to.includes('is-indeterminate');
  291. checkbox.querySelector('input').click();
  292. await waitImmediate();
  293. expect(checkbox.querySelector('.el-checkbox__input').className).to.includes('is-checked');
  294. expect(vm.value.length).to.equal(4);
  295. getOptions(el, 1)[1].click();
  296. await waitImmediate();
  297. getOptions(el, 2)[1].querySelector('input').click();
  298. await waitImmediate();
  299. expect(vm.value.length).to.equal(4);
  300. });
  301. it('check strictly in single mode', async() => {
  302. vm = createVue({
  303. template: `
  304. <el-cascader-panel
  305. v-model="value"
  306. :options="options"
  307. :props="props"></el-cascader-panel>
  308. `,
  309. data() {
  310. return {
  311. value: ['zhejiang'],
  312. options: options,
  313. props: {
  314. checkStrictly: true
  315. }
  316. };
  317. }
  318. }, true);
  319. const el = vm.$el;
  320. const radio = getOptions(el, 0)[0].querySelector('.el-radio');
  321. await waitImmediate();
  322. expect(radio).to.exist;
  323. expect(radio.className).to.includes('is-checked');
  324. getOptions(el, 0)[0].click();
  325. await waitImmediate();
  326. getOptions(el, 1)[0].querySelector('input').click();
  327. await waitImmediate();
  328. expect(vm.value).to.deep.equal(['zhejiang', 'hangzhou']);
  329. expect(getOptions(el, 0)[1].querySelector('.el-radio').className).to.includes('is-disabled');
  330. });
  331. it('check strictly in multiple mode', async() => {
  332. vm = createVue({
  333. template: `
  334. <el-cascader-panel
  335. v-model="value"
  336. :options="options"
  337. :props="props"></el-cascader-panel>
  338. `,
  339. data() {
  340. return {
  341. value: [['zhejiang']],
  342. options: options,
  343. props: {
  344. multiple: true,
  345. checkStrictly: true,
  346. emitPath: false
  347. }
  348. };
  349. }
  350. }, true);
  351. const el = vm.$el;
  352. const checkbox = getOptions(el, 0)[0].querySelector('.el-checkbox');
  353. await waitImmediate();
  354. expect(checkbox).to.exist;
  355. expect(checkbox.className).to.includes('is-checked');
  356. getOptions(el, 0)[0].click();
  357. await waitImmediate();
  358. expect(getOptions(el, 1)[0].querySelector('.el-checkbox').className).to.not.includes('is-checked');
  359. getOptions(el, 1)[0].querySelector('input').click();
  360. await waitImmediate();
  361. expect(vm.value).to.deep.equal(['zhejiang', 'hangzhou']);
  362. expect(getOptions(el, 0)[1].querySelector('.el-checkbox').className).to.includes('is-disabled');
  363. });
  364. it('custom props', async() => {
  365. vm = createVue({
  366. template: `
  367. <el-cascader-panel
  368. v-model="value"
  369. :options="options"
  370. :props="props"></el-cascader-panel>
  371. `,
  372. data() {
  373. return {
  374. value: [],
  375. options: options2,
  376. props: {
  377. value: 'id',
  378. label: 'name',
  379. children: 'areas',
  380. disabled: 'invalid'
  381. }
  382. };
  383. }
  384. }, true);
  385. const el = vm.$el;
  386. expect(getMenus(el).length).to.equal(1);
  387. expect(getOptions(el, 0).length).to.equal(2);
  388. expect(getValidOptions(el, 0).length).to.equal(1);
  389. const firstOption = getOptions(el, 0)[0];
  390. expect(getLabel(firstOption)).to.equal('Zhejiang');
  391. firstOption.click();
  392. await waitImmediate();
  393. expect(getMenus(el).length).to.equal(2);
  394. getOptions(el, 1)[0].click();
  395. await waitImmediate();
  396. expect(getMenus(el).length).to.equal(3);
  397. getOptions(el, 2)[0].click();
  398. await waitImmediate();
  399. expect(vm.value).to.deep.equal(selectedValue);
  400. });
  401. it('value key is same as label key', async() => {
  402. vm = createVue({
  403. template: `
  404. <el-cascader-panel
  405. v-model="value"
  406. :options="options"
  407. :props="props"></el-cascader-panel>
  408. `,
  409. data() {
  410. return {
  411. value: [],
  412. options,
  413. props: {
  414. label: 'value'
  415. }
  416. };
  417. }
  418. }, true);
  419. const el = vm.$el;
  420. expect(getMenus(el).length).to.equal(1);
  421. expect(getOptions(el, 0).length).to.equal(2);
  422. expect(getValidOptions(el, 0).length).to.equal(1);
  423. const firstOption = getOptions(el, 0)[0];
  424. expect(getLabel(firstOption)).to.equal('zhejiang');
  425. firstOption.click();
  426. await waitImmediate();
  427. expect(getMenus(el).length).to.equal(2);
  428. getOptions(el, 1)[0].click();
  429. await waitImmediate();
  430. expect(getMenus(el).length).to.equal(3);
  431. getOptions(el, 2)[0].click();
  432. await waitImmediate();
  433. expect(vm.value).to.deep.equal(selectedValue);
  434. });
  435. it('dynamic loading', async() => {
  436. vm = createVue({
  437. template: `
  438. <el-cascader-panel
  439. v-model="value"
  440. :props="props"></el-cascader-panel>
  441. `,
  442. data() {
  443. let id = 0;
  444. return {
  445. value: [],
  446. props: {
  447. lazy: true,
  448. lazyLoad(node, resolve) {
  449. const { level } = node;
  450. setTimeout(() => {
  451. const nodes = Array.from({ length: level + 1 })
  452. .map(() => ({
  453. value: ++id,
  454. label: `选项${id}`,
  455. leaf: level >= 2
  456. }));
  457. resolve(nodes);
  458. }, 1000);
  459. }
  460. }
  461. };
  462. }
  463. }, true);
  464. const el = vm.$el;
  465. await wait(1000);
  466. const firstOption = getOptions(el, 0)[0];
  467. firstOption.click();
  468. await waitImmediate();
  469. expect(firstOption.querySelector('i').className).to.includes('el-icon-loading');
  470. await wait(1000);
  471. expect(firstOption.querySelector('i').className).to.includes('el-icon-arrow-right');
  472. expect(getMenus(el).length).to.equal(2);
  473. getOptions(el, 1)[0].click();
  474. await wait(1000);
  475. getOptions(el, 2)[0].click();
  476. await waitImmediate();
  477. expect(vm.value.length).to.equal(3);
  478. });
  479. });