tests.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. var chai = require("chai");
  2. var sinon = require("sinon");
  3. var sinonChai = require("sinon-chai");
  4. var should = chai.should();
  5. chai.use(sinonChai);
  6. require('jsdom-global')();
  7. var $ = require('jquery');
  8. require('../../src/js/jquery.orgchart');
  9. describe('orgchart -- unit tests', function () {
  10. document.body.innerHTML = '<div id="chart-container"></div>';
  11. var $container = $('#chart-container'),
  12. ds = {
  13. 'id': 'n1',
  14. 'name': 'Lao Lao',
  15. 'title': 'general manager',
  16. 'children': [
  17. { 'id': 'n2', 'name': 'Bo Miao', 'title': 'department manager' },
  18. { 'id': 'n3', 'name': 'Su Miao', 'title': 'department manager',
  19. 'children': [
  20. { 'id': 'n5', 'name': 'Tie Hua', 'title': 'senior engineer',
  21. 'children': [
  22. { 'id': 'n8', 'name': 'Dan Dan', 'title': 'engineer' }
  23. ]
  24. },
  25. { 'id': 'n6', 'name': 'Hei Hei', 'title': 'senior engineer',
  26. 'children': [
  27. { 'id': 'n9', 'name': 'Er Dan', 'title': 'engineer' }
  28. ]
  29. },
  30. { 'id': 'n7', 'name': 'Pang Pang', 'title': 'senior engineer',
  31. 'children': [
  32. { 'id': 'n10', 'name': 'San Dan', 'title': 'engineer' }
  33. ]
  34. }
  35. ]
  36. },
  37. { 'id': 'n4', 'name': 'Hong Miao', 'title': 'department manager' }
  38. ]
  39. },
  40. oc = {},
  41. hierarchy = {
  42. id: 'n1',
  43. children: [
  44. { id: 'n2' },
  45. { id: 'n3',
  46. children: [
  47. { id: 'n5',
  48. children: [
  49. { id: 'n8' }
  50. ]
  51. },
  52. { id: 'n6',
  53. children: [
  54. { id: 'n9' }
  55. ]
  56. },
  57. { id: 'n7',
  58. children: [
  59. { id: 'n10' }
  60. ]
  61. }
  62. ]
  63. },
  64. { id: 'n4' }
  65. ]
  66. },
  67. $laolao,
  68. $bomiao,
  69. $sumiao,
  70. $hongmiao,
  71. $chunmiao,
  72. $tiehua,
  73. $heihei,
  74. $pangpang,
  75. $dandan,
  76. $erdan,
  77. $sandan;
  78. beforeEach(function () {
  79. oc = $('#chart-container').orgchart({
  80. 'data': ds,
  81. 'nodeContent': 'title'
  82. }),
  83. $laolao = $('#n1'),
  84. $bomiao = $('#n2'),
  85. $sumiao = $('#n3'),
  86. $hongmiao = $('#n4'),
  87. $tiehua = $('#n5'),
  88. $heihei = $('#n6'),
  89. $pangpang = $('#n7'),
  90. $dandan = $('#n8');
  91. $erdan = $('#n9');
  92. $sandan = $('#n10');
  93. });
  94. afterEach(function () {
  95. $laolao = $bomiao = $sumiao = $hongmiao = $tiehua = $heihei = $pangpang = $dandan = $erdan = $sandan = null;
  96. $container.empty();
  97. });
  98. it('loopChart()', function () {
  99. oc.loopChart($('.orgchart')).should.deep.equal(hierarchy);
  100. });
  101. it('getHierarchy()', function () {
  102. oc.getHierarchy().should.deep.equal(hierarchy);
  103. var oc2 = $('#chart-container').orgchart({
  104. 'data': { name: 'Lao Lao',
  105. 'children': [
  106. { name: 'Bo Miao' }
  107. ]
  108. }
  109. });
  110. oc2.getHierarchy().should.include('Error');
  111. oc2.$chart.empty();
  112. oc2.getHierarchy().should.include('Error');
  113. oc2.$chart = undefined;
  114. oc2.getHierarchy().should.include('Error');
  115. });
  116. it('getNodeState()', function () {
  117. oc.init({ 'depth': 2 }).$chart.on('init.orgchart', function () {
  118. oc.getNodeState($laolao, 'parent').should.deep.equal({ 'exist': false, 'visible': false });
  119. oc.getNodeState($laolao, 'children').should.deep.equal({ 'exist': true, 'visible': true });
  120. oc.getNodeState($laolao, 'siblings').should.deep.equal({ 'exist': false, 'visible': false });
  121. oc.getNodeState($bomiao, 'parent').should.deep.equal({ 'exist': true, 'visible': true });
  122. oc.getNodeState($bomiao, 'children').should.deep.equal({ 'exist': false, 'visible': false });
  123. oc.getNodeState($bomiao, 'siblings').should.deep.equal({ 'exist': true, 'visible': true });
  124. oc.getNodeState($sumiao, 'parent').should.deep.equal({ 'exist': true, 'visible': true });
  125. oc.getNodeState($sumiao, 'children').should.deep.equal({ 'exist': true, 'visible': false });
  126. oc.getNodeState($sumiao, 'siblings').should.deep.equal({ 'exist': true, 'visible': true });
  127. oc.getNodeState($tiehua, 'parent').should.deep.equal({ 'exist': true, 'visible': true });
  128. oc.getNodeState($tiehua, 'children').should.deep.equal({ 'exist': false, 'visible': false });
  129. oc.getNodeState($tiehua, 'siblings').should.deep.equal({ 'exist': true, 'visible': false });
  130. oc.getNodeState($heihei, 'parent').should.deep.equal({ 'exist': true, 'visible': true });
  131. oc.getNodeState($heihei, 'children').should.deep.equal({ 'exist': true, 'visible': false });
  132. oc.getNodeState($heihei, 'siblings').should.deep.equal({ 'exist': true, 'visible': false });
  133. oc.getNodeState($pangpang, 'parent').should.deep.equal({ 'exist': true, 'visible': false });
  134. oc.getNodeState($pangpang, 'children').should.deep.equal({ 'exist': true, 'visible': false });
  135. oc.getNodeState($pangpang, 'siblings').should.deep.equal({ 'exist': false, 'visible': false });
  136. oc.getNodeState($dandan, 'parent').should.deep.equal({ 'exist': true, 'visible': false });
  137. oc.getNodeState($dandan, 'children').should.deep.equal({ 'exist': false, 'visible': false });
  138. oc.getNodeState($dandan, 'siblings').should.deep.equal({ 'exist': false, 'visible': false });
  139. });
  140. });
  141. it('getRelatedNodes()', function () {
  142. oc.getRelatedNodes().should.deep.equal($());
  143. oc.getRelatedNodes($('td:first'), 'children').should.deep.equal($());
  144. oc.getRelatedNodes($('.node:first'), 'child').should.deep.equal($());
  145. oc.getRelatedNodes($laolao, 'parent').should.deep.equal($());
  146. oc.getRelatedNodes($laolao, 'children').toArray().should.members([$bomiao[0], $sumiao[0], $hongmiao[0]]);
  147. oc.getRelatedNodes($laolao, 'siblings').should.deep.equal($());
  148. oc.getRelatedNodes($bomiao, 'parent').should.deep.equal($laolao);
  149. oc.getRelatedNodes($bomiao, 'children').should.have.lengthOf(0);
  150. oc.getRelatedNodes($bomiao, 'siblings').toArray().should.members([$sumiao[0], $hongmiao[0]]);
  151. });
  152. it('hideParent()', function () {
  153. var spy = sinon.spy(oc, 'hideParent');
  154. var spy2 = sinon.spy(oc, 'hideSiblings');
  155. oc.hideParent($heihei);
  156. spy.should.have.been.callCount(2);
  157. spy.getCall(0).should.have.been.calledWithMatch($heihei);
  158. spy.getCall(1).should.have.been.calledWithMatch($sumiao);
  159. spy2.should.have.been.callCount(2);
  160. spy2.getCall(0).should.have.been.calledWithMatch($heihei);
  161. spy2.getCall(1).should.have.been.calledWithMatch($sumiao);
  162. });
  163. it('hideParentEnd()', function () {
  164. var spy = sinon.spy(oc, 'hideParentEnd');
  165. var $upperLevel = $heihei.closest('.nodes').siblings();
  166. $sumiao.addClass('sliding slide-down').one('transitionend', { 'upperLevel': $upperLevel }, spy.bind(oc));
  167. $sumiao.trigger('transitionend');
  168. spy.should.have.been.called;
  169. $sumiao.is('sliding').should.be.false;
  170. $upperLevel.filter('.hidden').should.lengthOf(3);
  171. should.equal($upperLevel.eq(1).attr('style'), undefined);
  172. should.equal($upperLevel.eq(2).attr('style'), undefined);
  173. });
  174. it('showParent()', function () {
  175. var spy = sinon.spy(oc, 'repaint');
  176. $laolao.add($sumiao).closest('tr').nextUntil('.nodes').addBack().addClass('hidden');
  177. oc.showParent($heihei);
  178. spy.should.have.been.called;
  179. var $upperLevel = $heihei.closest('.nodes').siblings();
  180. $upperLevel.filter('.hidden').should.lengthOf(0);
  181. var $lines = $upperLevel.eq(2).children();
  182. $lines.first().is('.hidden').should.be.false;
  183. $lines.last().is('.hidden').should.be.false;
  184. $lines.filter('.hidden').should.lengthOf($lines.length - 2);
  185. $sumiao.is('.sliding').should.be.true;
  186. $sumiao.is('.slide-down').should.be.false;
  187. });
  188. it('showParentEnd()', function () {
  189. var spy = sinon.spy(oc, 'showParentEnd');
  190. var spy2 = sinon.spy(oc, 'isInAction');
  191. var spy3 = sinon.spy(oc, 'switchVerticalArrow');
  192. $sumiao.addClass('sliding').removeClass('slide-down').one('transitionend', { 'node': $heihei }, spy.bind(oc));
  193. $sumiao.trigger('transitionend');
  194. spy.should.have.been.called;
  195. $sumiao.is('.sliding').should.be.false;
  196. spy2.should.have.been.calledWith($heihei);
  197. spy3.should.not.have.been.called;
  198. });
  199. it('hideChildren()', function () {
  200. var spy = sinon.spy(oc, 'repaint');
  201. oc.hideChildren($sumiao);
  202. spy.should.have.been.called;
  203. $sumiao.closest('table').find('.lines').filter('[style*="visibility: hidden"]').should.lengthOf(8);
  204. $tiehua.is('.sliding,.slide-up').should.be.true;
  205. $heihei.is('.sliding,.slide-up').should.be.true;
  206. $pangpang.is('.sliding,.slide-up').should.be.true;
  207. $erdan.is('.sliding,.slide-up').should.be.true;
  208. });
  209. it('hideChildrenEnd()', function () {
  210. var spy = sinon.spy(oc, 'hideChildrenEnd');
  211. var spy2 = sinon.spy(oc, 'isInAction');
  212. var spy3 = sinon.spy(oc, 'switchVerticalArrow');
  213. $tiehua.addClass('sliding slide-up').one('transitionend', { 'animatedNodes': $tiehua, 'lowerLevel': $sumiao.closest('tr').siblings(), 'isVerticalDesc': false, 'node': $sumiao }, spy.bind(oc));
  214. $tiehua.trigger('transitionend');
  215. spy.should.have.been.called;
  216. $tiehua.is('.sliding').should.be.false;
  217. $tiehua.closest('.nodes').is('.hidden').should.be.true;
  218. var $lines = $tiehua.closest('.nodes').prevAll('.lines');
  219. should.equal($lines.eq(0).attr('style'), undefined);
  220. $lines.eq(0).is('.hidden').should.be.true;
  221. should.equal($lines.eq(1).attr('style'), undefined);
  222. $lines.eq(1).is('.hidden').should.be.true;
  223. spy2.should.have.been.calledWith($sumiao);
  224. spy3.should.not.have.been.called;
  225. });
  226. it('showChildren()', function () {
  227. var spy = sinon.spy(oc, 'repaint');
  228. $sumiao.closest('tr').siblings('.nodes').find('.node').addClass('sliding slide-up');
  229. $sumiao.closest('tr').nextUntil('.nodes').addBack().addClass('hidden');
  230. oc.showChildren($sumiao);
  231. spy.should.have.been.calledWith($tiehua[0]);
  232. $tiehua.is('.sliding:not(.slide-up)').should.be.true;
  233. $heihei.is('.sliding:not(.slide-up)').should.be.true;
  234. $pangpang.is('.sliding:not(.slide-up)').should.be.true;
  235. $erdan.is('.sliding,.slide-up').should.be.true;
  236. });
  237. it('showChildrenEnd()', function () {
  238. var spy = sinon.spy(oc, 'showChildrenEnd');
  239. var spy2 = sinon.spy(oc, 'isInAction');
  240. var spy3 = sinon.spy(oc, 'switchVerticalArrow');
  241. $tiehua.addClass('sliding').one('transitionend', { 'node': $sumiao, 'animatedNodes': $tiehua }, spy.bind(oc));
  242. $tiehua.trigger('transitionend');
  243. spy.should.have.been.called;
  244. $tiehua.is('.sliding').should.be.false;
  245. spy2.should.have.been.calledWith($sumiao);
  246. spy3.should.not.have.been.called;
  247. });
  248. describe('hideSiblings()', function () {
  249. context('when passing only one parameter -- node', function () {
  250. it('should hide all the sibling nodes and their descendants', function () {
  251. oc.hideSiblings($heihei);
  252. $tiehua.is('.sliding.slide-right').should.be.true;
  253. $dandan.is('.sliding.slide-right').should.be.true;
  254. $pangpang.is('.sliding.slide-left').should.be.true;
  255. $sandan.is('.sliding.slide-left').should.be.true;
  256. $heihei.closest('.nodes').prevAll('.lines').filter(function () {
  257. return $(this).css('visibility') === 'hidden';
  258. }).should.lengthOf(2);
  259. });
  260. });
  261. context('when passing two parameters -- node and direction', function () {
  262. it('hide the left side sibling nodes and their descendants', function () {
  263. oc.hideSiblings($heihei, 'left');
  264. $tiehua.is('.sliding.slide-right').should.be.true;
  265. $dandan.is('.sliding.slide-right').should.be.true;
  266. $pangpang.is('.sliding').should.be.false;
  267. });
  268. it('hide the right side sibling nodes and their descendants', function () {
  269. oc.hideSiblings($heihei, 'right');
  270. $pangpang.is('.sliding.slide-left').should.be.true;
  271. $sandan.is('.sliding.slide-left').should.be.true;
  272. $tiehua.is('.sliding').should.be.false;
  273. });
  274. });
  275. });
  276. describe('hideSiblingsEnd()', function () {
  277. context('when invoking transitionend event without specifying direction', function () {
  278. it('clean up final classList for hidden siblings', function () {
  279. var spy = sinon.spy(oc, 'hideSiblingsEnd');
  280. var spy2 = sinon.spy(oc, 'isInAction');
  281. var spy3 = sinon.spy(oc, 'switchVerticalArrow');
  282. var $lines = $heihei.closest('.nodes').prevAll('.lines');
  283. var $nodeContainer = $heihei.closest('table').parent();
  284. oc.hideSiblings($heihei);
  285. $tiehua.one('transitionend', {
  286. 'node': $heihei,
  287. 'nodeContainer': $nodeContainer,
  288. 'direction': undefined,
  289. 'animatedNodes': $tiehua,
  290. 'lines': $lines
  291. }, spy.bind(oc));
  292. $tiehua.trigger('transitionend');
  293. spy.should.have.been.called;
  294. $lines.filter(function () {
  295. return $(this).attr('style') === undefined;
  296. }).should.lengthOf(2);
  297. $lines.eq(0).children().slice(1, -1).filter(function () {
  298. return $(this).is('.hidden');
  299. }).should.lengthOf(4);
  300. $tiehua.is('.slide-right:not(.sliding)').should.be.true;
  301. $dandan.is('.slide-up:not(.sliding, .slide-right)').should.be.true;
  302. $pangpang.is('.slide-left:not(.sibling)').should.be.true;
  303. $sandan.is('.slide-up:not(.sliding, .slide-left)').should.be.true;
  304. $nodeContainer.siblings('.hidden').should.lengthOf(2);
  305. $nodeContainer.siblings().find('.lines.hidden, .nodes.hidden').should.lengthOf(6);
  306. spy2.should.have.been.calledWith($heihei);
  307. spy3.should.not.have.been.called;
  308. });
  309. });
  310. context('when invoking transitionend event with specifying direction', function () {
  311. it('clean up final classList for left side hidden siblings', function () {
  312. var spy = sinon.spy(oc, 'hideSiblingsEnd');
  313. var spy2 = sinon.spy(oc, 'isInAction');
  314. var spy3 = sinon.spy(oc, 'switchVerticalArrow');
  315. var $lines = $heihei.closest('.nodes').prevAll('.lines');
  316. var $nodeContainer = $heihei.closest('table').parent();
  317. oc.hideSiblings($heihei, 'left');
  318. $tiehua.one('transitionend', {
  319. 'node': $heihei,
  320. 'nodeContainer': $nodeContainer,
  321. 'direction': 'left',
  322. 'animatedNodes': $tiehua,
  323. 'lines': $lines
  324. }, spy.bind(oc));
  325. $tiehua.trigger('transitionend');
  326. spy.should.have.been.called;
  327. $lines.filter(function () {
  328. return $(this).attr('style') === undefined;
  329. }).should.lengthOf(2);
  330. $lines.eq(0).children().slice(1, 3).filter(function () {
  331. return $(this).is('.hidden');
  332. }).should.lengthOf(2);
  333. $tiehua.is('.slide-right:not(.sliding)').should.be.true;
  334. $dandan.is('.slide-up:not(.slide-right)').should.be.true;
  335. $pangpang.is('.slide-left').should.be.false;
  336. $sandan.is('.slide-up').should.be.false;
  337. $nodeContainer.prevAll('.hidden').should.lengthOf(1);
  338. $nodeContainer.prevAll().find('.lines.hidden, .nodes.hidden').should.lengthOf(3);
  339. $nodeContainer.nextAll().find('.lines.hidden, .nodes.hidden').should.lengthOf(0);
  340. spy2.should.have.been.calledWith($heihei);
  341. spy3.should.not.have.been.called;
  342. });
  343. it('clean up final classList for right side hidden siblings', function () {
  344. var spy = sinon.spy(oc, 'hideSiblingsEnd');
  345. var spy2 = sinon.spy(oc, 'isInAction');
  346. var spy3 = sinon.spy(oc, 'switchVerticalArrow');
  347. var $lines = $heihei.closest('.nodes').prevAll('.lines');
  348. var $nodeContainer = $heihei.closest('table').parent();
  349. oc.hideSiblings($heihei, 'right');
  350. $tiehua.one('transitionend', {
  351. 'node': $heihei,
  352. 'nodeContainer': $nodeContainer,
  353. 'direction': 'right',
  354. 'animatedNodes': $tiehua,
  355. 'lines': $lines
  356. }, spy.bind(oc));
  357. $tiehua.trigger('transitionend');
  358. spy.should.have.been.called;
  359. $lines.filter(function () {
  360. return $(this).attr('style') === undefined;
  361. }).should.lengthOf(2);
  362. $lines.eq(0).children().slice(1, 3).filter(function () {
  363. return $(this).is('.hidden');
  364. }).should.lengthOf(2);
  365. $tiehua.is('.slide-right').should.be.false;
  366. $dandan.is('.slide-up').should.be.false;
  367. $pangpang.is('.slide-left:not(.slidiing)').should.be.true;
  368. $sandan.is('.slide-up:not(.slide-left)').should.be.true;
  369. $nodeContainer.nextAll('.hidden').should.lengthOf(1);
  370. $nodeContainer.nextAll().find('.lines.hidden, .nodes.hidden').should.lengthOf(3);
  371. $nodeContainer.prevAll().find('.lines.hidden, .nodes.hidden').should.lengthOf(0);
  372. spy2.should.have.been.calledWith($heihei);
  373. spy3.should.not.have.been.called;
  374. });
  375. });
  376. });
  377. });