orgchart
Version:
Simple and direct organization chart(tree-like hierarchy) plugin based on pure DOM and jQuery.
444 lines (406 loc) • 19.1 kB
JavaScript
var chai = require("chai");
var sinon = require("sinon");
var sinonChai = require("sinon-chai");
var should = chai.should();
chai.use(sinonChai);
require('jsdom-global')();
var $ = require('jquery');
require('../../src/js/jquery.orgchart');
describe('orgchart -- unit tests', function () {
document.body.innerHTML = '<div id="chart-container"></div>';
var $container = $('#chart-container'),
ds = {
'id': 'n1',
'name': 'Lao Lao',
'title': 'general manager',
'children': [
{ 'id': 'n2', 'name': 'Bo Miao', 'title': 'department manager' },
{ 'id': 'n3', 'name': 'Su Miao', 'title': 'department manager',
'children': [
{ 'id': 'n5', 'name': 'Tie Hua', 'title': 'senior engineer',
'children': [
{ 'id': 'n8', 'name': 'Dan Dan', 'title': 'engineer' }
]
},
{ 'id': 'n6', 'name': 'Hei Hei', 'title': 'senior engineer',
'children': [
{ 'id': 'n9', 'name': 'Er Dan', 'title': 'engineer' }
]
},
{ 'id': 'n7', 'name': 'Pang Pang', 'title': 'senior engineer',
'children': [
{ 'id': 'n10', 'name': 'San Dan', 'title': 'engineer' }
]
}
]
},
{ 'id': 'n4', 'name': 'Hong Miao', 'title': 'department manager' }
]
},
oc = {},
hierarchy = {
id: 'n1',
children: [
{ id: 'n2' },
{ id: 'n3',
children: [
{ id: 'n5',
children: [
{ id: 'n8' }
]
},
{ id: 'n6',
children: [
{ id: 'n9' }
]
},
{ id: 'n7',
children: [
{ id: 'n10' }
]
}
]
},
{ id: 'n4' }
]
},
$laolao,
$bomiao,
$sumiao,
$hongmiao,
$chunmiao,
$tiehua,
$heihei,
$pangpang,
$dandan,
$erdan,
$sandan;
beforeEach(function () {
oc = $('#chart-container').orgchart({
'data': ds,
'nodeContent': 'title'
}),
$laolao = $('#n1'),
$bomiao = $('#n2'),
$sumiao = $('#n3'),
$hongmiao = $('#n4'),
$tiehua = $('#n5'),
$heihei = $('#n6'),
$pangpang = $('#n7'),
$dandan = $('#n8');
$erdan = $('#n9');
$sandan = $('#n10');
});
afterEach(function () {
$laolao = $bomiao = $sumiao = $hongmiao = $tiehua = $heihei = $pangpang = $dandan = $erdan = $sandan = null;
$container.empty();
});
it('loopChart()', function () {
oc.loopChart($('.orgchart')).should.deep.equal(hierarchy);
});
it('getHierarchy()', function () {
oc.getHierarchy().should.deep.equal(hierarchy);
var oc2 = $('#chart-container').orgchart({
'data': { name: 'Lao Lao',
'children': [
{ name: 'Bo Miao' }
]
}
});
oc2.getHierarchy().should.include('Error');
oc2.$chart.empty();
oc2.getHierarchy().should.include('Error');
oc2.$chart = undefined;
oc2.getHierarchy().should.include('Error');
});
it('getNodeState()', function (done) {
var check = function () {
try {
$laolao = $('#n1');
$bomiao = $('#n2');
$sumiao = $('#n3');
$hongmiao = $('#n4');
$tiehua = $('#n5');
$heihei = $('#n6');
$pangpang = $('#n7');
$dandan = $('#n8');
$erdan = $('#n9');
$sandan = $('#n10');
oc.getNodeState($laolao).should.deep.equal({ 'exist': true, 'visible': true }, "laolao->self");
oc.getNodeState($laolao, 'parent').should.deep.equal({ 'exist': false, 'visible': false }, "laolao->parent");
oc.getNodeState($laolao, 'children').should.deep.equal({ 'exist': true, 'visible': true }, "laolao->children");
oc.getNodeState($laolao, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, "laolao->siblings");
oc.getNodeState($bomiao).should.deep.equal({ 'exist': true, 'visible': true }, "bomiao->self");
oc.getNodeState($bomiao, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "bomiao->parent");
oc.getNodeState($bomiao, 'children').should.deep.equal({ 'exist': false, 'visible': false }, "bomiao->children");
oc.getNodeState($bomiao, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, "bomiao->siblings");
oc.getNodeState($sumiao).should.deep.equal({ 'exist': true, 'visible': true }, "sumiao->self");
oc.getNodeState($sumiao, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "sumiao->parent");
oc.getNodeState($sumiao, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "sumiao->children");
oc.getNodeState($sumiao, 'siblings').should.deep.equal({ 'exist': true, 'visible': true }, "sumiao->siblings");
oc.getNodeState($tiehua).should.deep.equal({ 'exist': true, 'visible': false }, "tiehua->self");
oc.getNodeState($tiehua, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "tiehua->parent");
oc.getNodeState($tiehua, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "tiehua->children");
oc.getNodeState($tiehua, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, "tiehua->siblings");
oc.getNodeState($heihei).should.deep.equal({ 'exist': true, 'visible': false }, "heihei->self");
oc.getNodeState($heihei, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "heihei->parent");
oc.getNodeState($heihei, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "heihei->children");
oc.getNodeState($heihei, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, "heihei->siblings");
oc.getNodeState($pangpang).should.deep.equal({ 'exist': true, 'visible': false }, "pangpang->self");
oc.getNodeState($pangpang, 'parent').should.deep.equal({ 'exist': true, 'visible': true }, "pangpang->parent");
oc.getNodeState($pangpang, 'children').should.deep.equal({ 'exist': true, 'visible': false }, "pangpang->children");
oc.getNodeState($pangpang, 'siblings').should.deep.equal({ 'exist': true, 'visible': false }, "pangpang->siblings");
oc.getNodeState($dandan).should.deep.equal({ 'exist': true, 'visible': false }, "dandan->self");
oc.getNodeState($dandan, 'parent').should.deep.equal({ 'exist': true, 'visible': false }, "dandan->parent");
oc.getNodeState($dandan, 'children').should.deep.equal({ 'exist': false, 'visible': false }, "dandan->children");
oc.getNodeState($dandan, 'siblings').should.deep.equal({ 'exist': false, 'visible': false }, "dandan->siblings");
done();
} catch(err) {
done(err);
}
};
if (typeof MutationObserver !== 'undefined') {
oc.init({ 'visibleLevel': 2, 'verticalLevel': 3 }).$chart.one('init.orgchart', check);
} else {
oc.init({ 'visibleLevel': 2, 'verticalLevel': 3 });
setTimeout(check, 0);
}
});
it('getRelatedNodes()', function () {
oc.getRelatedNodes().should.deep.equal($());
oc.getRelatedNodes({}, 'children').should.deep.equal($());
oc.getRelatedNodes($('.hierarchy:first'), 'children').should.deep.equal($());
oc.getRelatedNodes($('.node:first'), 'child').should.deep.equal($());
oc.getRelatedNodes($laolao, 'parent').should.deep.equal($());
oc.getRelatedNodes($laolao, 'children').toArray().should.members([$bomiao[0], $sumiao[0], $hongmiao[0]]);
oc.getRelatedNodes($laolao, 'siblings').should.deep.equal($());
oc.getRelatedNodes($bomiao, 'parent').should.deep.equal($laolao);
oc.getRelatedNodes($bomiao, 'children').should.have.lengthOf(0);
oc.getRelatedNodes($bomiao, 'siblings').toArray().should.members([$sumiao[0], $hongmiao[0]]);
});
it('getParent()', function () {
oc.getParent().should.deep.equal($());
oc.getParent({}).should.deep.equal($());
oc.getParent($('.hierarchy:first')).should.deep.equal($());
oc.getParent($laolao).should.deep.equal($());
oc.getParent($bomiao).should.deep.equal($laolao);
oc.getParent($sandan).should.deep.equal($pangpang);
});
it('getSiblings()', function () {
oc.getSiblings().should.deep.equal($());
oc.getSiblings({}).should.deep.equal($());
oc.getSiblings($('.hierarchy:first')).should.deep.equal($());
oc.getSiblings($laolao).should.deep.equal($());
oc.getSiblings($bomiao).toArray().should.members([$sumiao[0], $hongmiao[0]]);
oc.getSiblings($sandan).should.deep.equal($());
});
it('getChildren()', function () {
oc.getChildren().should.deep.equal($());
oc.getChildren({}).should.deep.equal($());
oc.getChildren($('.hierarchy:first')).should.deep.equal($());
oc.getChildren($laolao).toArray().should.members([$bomiao[0], $sumiao[0], $hongmiao[0]]);
oc.getChildren($bomiao).should.deep.equal($());
oc.getChildren($sumiao).toArray().should.members([$tiehua[0], $heihei[0], $pangpang[0]]);
oc.getChildren($sandan).should.deep.equal($());
});
it('hideParent()', function () {
var spy = sinon.spy(oc, 'hideParent');
var spy2 = sinon.spy(oc, 'hideSiblings');
oc.hideParent($heihei);
spy.should.have.been.callCount(2);
spy.getCall(0).should.have.been.calledWithMatch($heihei);
spy.getCall(1).should.have.been.calledWithMatch($sumiao);
spy2.should.have.been.callCount(2);
spy2.getCall(0).should.have.been.calledWithMatch($heihei);
spy2.getCall(1).should.have.been.calledWithMatch($sumiao);
});
it('hideParentEnd()', function () {
var spy = sinon.spy(oc, 'hideParentEnd');
var $parent = $heihei.closest('.nodes').siblings('.node');
$sumiao.addClass('sliding slide-down').one('transitionend', { 'parent': $parent }, spy.bind(oc));
$sumiao.trigger('transitionend');
spy.should.have.been.called;
$sumiao.is('sliding').should.be.false;
$parent.is('.hidden').should.be.true;
});
it('showParent()', function () {
var spy = sinon.spy(oc, 'repaint');
$heihei.closest('.hierarchy').addClass('isAncestorsCollapsed');
$sumiao.addClass('slide-down hidden').closest('.hierarchy').addClass('isAncestorsCollapsed');
$laolao.addClass('slide-down hidden');
oc.showParent($heihei);
spy.should.have.been.called;
$heihei.closest('.hierarchy').is('.isAncestorsCollapsed').should.be.false;
$sumiao.is('.slide-down, .hidden').should.be.false;
$sumiao.closest('.hierarchy').is('.isAncestorsCollapsed').should.be.true;
$laolao.is('.slide-down.hidden').should.be.true;
$sumiao.is('.sliding').should.be.true;
$sumiao.is('.slide-down').should.be.false;
});
it('showParentEnd()', function () {
var spy = sinon.spy(oc, 'showParentEnd');
var spy2 = sinon.spy(oc, 'isInAction');
var spy3 = sinon.spy(oc, 'switchVerticalArrow');
$sumiao.addClass('sliding').removeClass('slide-down').one('transitionend', { 'node': $heihei }, spy.bind(oc));
$sumiao.trigger('transitionend');
spy.should.have.been.called;
$sumiao.is('.sliding').should.be.false;
spy2.should.have.been.calledWith($heihei);
spy3.should.not.have.been.called;
});
it('hideChildren()', function () {
var spy = sinon.spy(oc, 'repaint');
oc.hideChildren($sumiao);
spy.should.have.been.called;
$sumiao.closest('.hierarchy').is('.isChildrenCollapsed').should.be.true;
$sumiao.siblings('.nodes').children('.isCollapsedDescendant').should.lengthOf(3);
$tiehua.is('.sliding.slide-up').should.be.true;
$heihei.is('.sliding.slide-up').should.be.true;
$pangpang.is('.sliding.slide-up').should.be.true;
$erdan.is('.sliding.slide-up').should.be.true;
});
it('hideChildrenEnd()', function () {
var spy = sinon.spy(oc, 'hideChildrenEnd');
var spy2 = sinon.spy(oc, 'isInAction');
var spy3 = sinon.spy(oc, 'switchVerticalArrow');
$tiehua.addClass('sliding slide-up').one('transitionend', { 'animatedNodes': $tiehua, 'lowerLevel': $sumiao.closest('tr').siblings(), 'isVerticalDesc': false, 'node': $sumiao }, spy.bind(oc));
$tiehua.trigger('transitionend');
spy.should.have.been.called;
$tiehua.is('.sliding').should.be.false;
$tiehua.closest('.nodes').is('.hidden').should.be.true;
spy2.should.have.been.calledWith($sumiao);
spy3.should.not.have.been.called;
});
it('showChildren()', function () {
var spy = sinon.spy(oc, 'repaint');
$sumiao.siblings('.nodes').find('.node').addClass('slide-up');
$sumiao.siblings('.nodes').find('.nodes').addBack().addClass('hidden');
oc.showChildren($sumiao);
spy.should.have.been.calledWith($tiehua[0]);
$tiehua.is('.sliding:not(.slide-up)').should.be.true;
$heihei.is('.sliding:not(.slide-up)').should.be.true;
$pangpang.is('.sliding:not(.slide-up)').should.be.true;
$erdan.is('.slide-up:not(.sliding)').should.be.true;
});
it('showChildrenEnd()', function () {
var spy = sinon.spy(oc, 'showChildrenEnd');
var spy2 = sinon.spy(oc, 'isInAction');
var spy3 = sinon.spy(oc, 'switchVerticalArrow');
$tiehua.addClass('sliding').one('transitionend', { 'node': $sumiao, 'animatedNodes': $tiehua }, spy.bind(oc));
$tiehua.trigger('transitionend');
spy.should.have.been.called;
$tiehua.is('.sliding').should.be.false;
spy2.should.have.been.calledWith($sumiao);
spy3.should.not.have.been.called;
});
describe('hideSiblings()', function () {
context('when passing only one parameter -- node', function () {
it('should hide all the sibling nodes and their descendants', function () {
oc.hideSiblings($heihei);
$tiehua.is('.sliding.slide-right').should.be.true;
$dandan.is('.sliding.slide-right').should.be.true;
$pangpang.is('.sliding.slide-left').should.be.true;
$sandan.is('.sliding.slide-left').should.be.true;
$heihei.closest('.hierarchy').is('.isSiblingsCollapsed').should.be.true;
$heihei.closest('.hierarchy').siblings('.isChildrenCollapsed.isCollapsedSibling').should.lengthOf(2);
});
});
context('when passing two parameters -- node and direction', function () {
it('hide the left side sibling nodes and their descendants', function () {
oc.hideSiblings($heihei, 'left');
$heihei.closest('.hierarchy').is('.isSiblingsCollapsed.left-sibs').should.be.true;
$heihei.closest('.hierarchy').prev().is('.isChildrenCollapsed.isCollapsedSibling').should.be.true;
$heihei.closest('.hierarchy').next().is('.isChildrenCollapsed, .isCollapsedSibling').should.be.false;
$tiehua.is('.sliding.slide-right').should.be.true;
$dandan.is('.sliding.slide-right').should.be.true;
$pangpang.is('.sliding').should.be.false;
});
it('hide the right side sibling nodes and their descendants', function () {
oc.hideSiblings($heihei, 'right');
$heihei.closest('.hierarchy').is('.isSiblingsCollapsed.right-sibs').should.be.true;
$heihei.closest('.hierarchy').next().is('.isChildrenCollapsed.isCollapsedSibling').should.be.true;
$heihei.closest('.hierarchy').prev().is('.isChildrenCollapsed, .isCollapsedSibling').should.be.false;
$pangpang.is('.sliding.slide-left').should.be.true;
$sandan.is('.sliding.slide-left').should.be.true;
$tiehua.is('.sliding').should.be.false;
});
});
});
describe('hideSiblingsEnd()', function () {
context('when invoking transitionend event without specifying direction', function () {
it('clean up final classList for hidden siblings', function () {
var spy = sinon.spy(oc, 'hideSiblingsEnd');
var spy2 = sinon.spy(oc, 'isInAction');
var spy3 = sinon.spy(oc, 'switchVerticalArrow');
var $nodeContainer = $heihei.closest('.hierarchy');
oc.hideSiblings($heihei);
$tiehua.one('transitionend', {
'node': $heihei,
'nodeContainer': $nodeContainer,
'direction': undefined,
'animatedNodes': $tiehua
}, spy.bind(oc));
$tiehua.trigger('transitionend');
spy.should.have.been.called;
$tiehua.is('.slide-right:not(.sliding)').should.be.true;
$dandan.is('.slide-up:not(.sliding, .slide-right)').should.be.true;
$pangpang.is('.slide-left:not(.sibling)').should.be.true;
$sandan.is('.slide-up:not(.sliding, .slide-left)').should.be.true;
$nodeContainer.siblings('.hidden').should.lengthOf(2);
$nodeContainer.siblings().find('.nodes.hidden').should.lengthOf(2);
spy2.should.have.been.calledWith($heihei);
spy3.should.not.have.been.called;
});
});
context('when invoking transitionend event with specifying direction', function () {
it('clean up final classList for left side hidden siblings', function () {
var spy = sinon.spy(oc, 'hideSiblingsEnd');
var spy2 = sinon.spy(oc, 'isInAction');
var spy3 = sinon.spy(oc, 'switchVerticalArrow');
var $nodeContainer = $heihei.closest('.hierarchy');
oc.hideSiblings($heihei, 'left');
$tiehua.one('transitionend', {
'node': $heihei,
'nodeContainer': $nodeContainer,
'direction': 'left',
'animatedNodes': $tiehua
}, spy.bind(oc));
$tiehua.trigger('transitionend');
spy.should.have.been.called;
$tiehua.is('.slide-right:not(.sliding)').should.be.true;
$dandan.is('.slide-up:not(.slide-right)').should.be.true;
$pangpang.is('.slide-left').should.be.false;
$sandan.is('.slide-up').should.be.false;
$nodeContainer.prevAll('.hidden').should.lengthOf(1);
$nodeContainer.prevAll().find('.nodes.hidden').should.lengthOf(1);
$nodeContainer.nextAll().find('.nodes.hidden').should.lengthOf(0);
spy2.should.have.been.calledWith($heihei);
spy3.should.not.have.been.called;
});
it('clean up final classList for right side hidden siblings', function () {
var spy = sinon.spy(oc, 'hideSiblingsEnd');
var spy2 = sinon.spy(oc, 'isInAction');
var spy3 = sinon.spy(oc, 'switchVerticalArrow');
var $nodeContainer = $heihei.closest('.hierarchy');
oc.hideSiblings($heihei, 'right');
$tiehua.one('transitionend', {
'node': $heihei,
'nodeContainer': $nodeContainer,
'direction': 'right',
'animatedNodes': $tiehua
}, spy.bind(oc));
$tiehua.trigger('transitionend');
spy.should.have.been.called;
$tiehua.is('.slide-right').should.be.false;
$dandan.is('.slide-up').should.be.false;
$pangpang.is('.slide-left:not(.slidiing)').should.be.true;
$sandan.is('.slide-up:not(.slide-left)').should.be.true;
$nodeContainer.nextAll('.hidden').should.lengthOf(1);
$nodeContainer.nextAll().find('.nodes.hidden').should.lengthOf(1);
$nodeContainer.prevAll().find('.nodes.hidden').should.lengthOf(0);
spy2.should.have.been.calledWith($heihei);
spy3.should.not.have.been.called;
});
});
});
});