ng2-tree-hackaday
Version:
angular2 component for visualizing data that can be naturally represented as a tree
799 lines (567 loc) • 35.2 kB
text/typescript
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Component, ElementRef, DebugElement } from '@angular/core';
import { TreeInternalComponent } from '../src/tree-internal.component';
import { TreeComponent } from '../src/tree.component';
import { TreeModel, Ng2TreeSettings } from '../src/tree.types';
import { TreeService } from '../src/tree.service';
import { NodeMenuService } from '../src/menu/node-menu.service';
import { NodeMenuComponent } from '../src/menu/node-menu.component';
import { NodeDraggableService } from '../src/draggable/node-draggable.service';
import { NodeDraggableDirective } from '../src/draggable/node-draggable.directive';
import { NodeEditableDirective } from '../src/editable/node-editable.directive';
import { NodeMenuAction } from '../src/menu/menu.events';
import * as EventUtils from '../src/utils/event.utils';
import { CapturedNode } from '../src/draggable/captured-node';
let fixture;
let masterInternalTreeEl;
let masterComponentInstance;
let lordInternalTreeEl;
let lordComponentInstance;
let faceInternalTreeEl;
let faceComponentInstance;
let nodeMenuService;
let nodeDraggableService;
let treeService;
const tree: TreeModel = {
value: 'Master',
children: [
{value: 'Servant#1'},
{value: 'Servant#2'}
]
};
const tree2: TreeModel = {
value: 'Lord',
children: [
{
value: 'Disciple#1',
children: [
{value: 'SubDisciple#1'},
{value: 'SubDisciple#2'}
]
},
{value: 'Disciple#2'}
]
};
const tree3: TreeModel = {
value: 'Face',
settings: {
'static': true
},
children: [
{
value: 'Eyes',
children: [
{
value: 'Retina',
settings: {
'static': false
}
},
{value: 'Eyebrow'}
]
},
{value: 'Lips'}
]
};
describe('TreeInternalComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent, TreeInternalComponent, TreeComponent, NodeEditableDirective, NodeMenuComponent, NodeDraggableDirective],
providers: [NodeMenuService, NodeDraggableService, TreeService]
});
fixture = TestBed.createComponent(TestComponent);
masterInternalTreeEl = fixture.debugElement.query(By.css('#master')).query(By.directive(TreeInternalComponent));
masterComponentInstance = masterInternalTreeEl.componentInstance;
lordInternalTreeEl = fixture.debugElement.query(By.css('#lord')).query(By.directive(TreeInternalComponent));
lordComponentInstance = lordInternalTreeEl.componentInstance;
faceInternalTreeEl = fixture.debugElement.query(By.css('#face')).query(By.directive(TreeInternalComponent));
faceComponentInstance = faceInternalTreeEl.componentInstance;
nodeMenuService = TestBed.get(NodeMenuService);
nodeDraggableService = TestBed.get(NodeDraggableService);
treeService = TestBed.get(TreeService);
fixture.detectChanges();
});
it('should be created by angular', () => {
expect(fixture).not.toBeNull();
expect(nodeMenuService).not.toBeNull();
expect(nodeDraggableService).not.toBeNull();
expect(treeService).not.toBeNull();
});
it('should have properly set tree property', () => {
expect(masterComponentInstance.tree).toBeDefined();
expect(masterComponentInstance.tree.value).toEqual('Master');
});
it('should hide menu when appropriate event has occurred', () => {
spyOn(nodeMenuService, 'hideMenuForAllNodesExcept');
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterComponentInstance.isMenuVisible).toEqual(true);
expect(event.preventDefault).toHaveBeenCalled();
expect(nodeMenuService.hideMenuForAllNodesExcept).toHaveBeenCalledTimes(1);
expect(nodeMenuService.hideMenuForAllNodesExcept).toHaveBeenCalledWith(masterComponentInstance.element);
});
it('should unselect selected node when another node is selected', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Left;
const allNodeValues: DebugElement[] = masterInternalTreeEl.queryAll(By.css('.node-value'));
expect(allNodeValues[0].nativeElement.innerText).toEqual('Master');
allNodeValues[0].triggerEventHandler('click', event);
fixture.detectChanges();
expect(masterComponentInstance.isSelected).toEqual(true);
expect(allNodeValues[0].nativeElement.classList.contains('node-selected')).toEqual(true);
const servantNumber1El = allNodeValues[1].parent.parent.parent.parent;
const servantNumber2El = allNodeValues[2].parent.parent.parent.parent;
expect(servantNumber1El.componentInstance.isSelected).toEqual(false);
expect(allNodeValues[1].nativeElement.classList.contains('node-selected')).toEqual(false);
expect(servantNumber2El.componentInstance.isSelected).toEqual(false);
expect(allNodeValues[2].nativeElement.classList.contains('node-selected')).toEqual(false);
allNodeValues[1].triggerEventHandler('click', event);
fixture.detectChanges();
expect(masterComponentInstance.isSelected).toEqual(false);
expect(allNodeValues[0].nativeElement.classList.contains('node-selected')).toEqual(false);
expect(servantNumber1El.componentInstance.isSelected).toEqual(true);
expect(allNodeValues[1].nativeElement.classList.contains('node-selected')).toEqual(true);
expect(servantNumber2El.componentInstance.isSelected).toEqual(false);
expect(allNodeValues[2].nativeElement.classList.contains('node-selected')).toEqual(false);
});
it('should drag node to the tree (though technically every node IS a tree)', () => {
const internalTreeChildren = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const servant1InternalTreeEl = internalTreeChildren[0];
const servant2InternalTreeEl = internalTreeChildren[1];
expect(servant1InternalTreeEl.componentInstance.tree.value).toEqual('Servant#1');
expect(servant1InternalTreeEl.componentInstance.tree.positionInParent).toEqual(0);
expect(servant2InternalTreeEl.componentInstance.tree.value).toEqual('Servant#2');
expect(servant2InternalTreeEl.componentInstance.tree.positionInParent).toEqual(1);
expect(masterInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Servant#1');
expect(masterInternalTreeEl.componentInstance.tree.children[1].value).toEqual('Servant#2');
const capturedNode = new CapturedNode(servant1InternalTreeEl.componentInstance.element, servant1InternalTreeEl.componentInstance.tree);
nodeDraggableService.fireNodeDragged(capturedNode, servant2InternalTreeEl.componentInstance.element);
fixture.detectChanges();
expect(servant1InternalTreeEl.componentInstance.tree.positionInParent).toEqual(1);
expect(servant2InternalTreeEl.componentInstance.tree.positionInParent).toEqual(0);
expect(masterInternalTreeEl.componentInstance.tree.children[1].value).toEqual('Servant#1');
expect(masterInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Servant#2');
const masterElement = fixture.debugElement.nativeElement;
const nodeValues = masterElement.querySelectorAll('.node-value');
expect(nodeValues[0].innerText).toEqual('Master');
expect(nodeValues[1].innerText).toEqual('Servant#2');
expect(nodeValues[2].innerText).toEqual('Servant#1');
});
it('should not add node to the children of a sibling branch node', () => {
const internalTreeChildren = lordInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const disciple1InternalTreeEl = internalTreeChildren[0];
const disciple2InternalTreeEl = internalTreeChildren[3];
expect(disciple1InternalTreeEl.componentInstance.tree.value).toEqual('Disciple#1');
expect(disciple2InternalTreeEl.componentInstance.tree.value).toEqual('Disciple#2');
expect(lordInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Disciple#1');
expect(lordInternalTreeEl.componentInstance.tree.children[1].value).toEqual('Disciple#2');
const capturedNode = new CapturedNode(disciple1InternalTreeEl.componentInstance.element, disciple1InternalTreeEl.componentInstance.tree);
nodeDraggableService.fireNodeDragged(capturedNode, disciple2InternalTreeEl.componentInstance.element);
fixture.detectChanges();
expect(disciple1InternalTreeEl.componentInstance.tree.positionInParent).toEqual(1);
expect(disciple2InternalTreeEl.componentInstance.tree.positionInParent).toEqual(0);
expect(lordInternalTreeEl.componentInstance.tree.children[1].value).toEqual('Disciple#1');
expect(lordInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Disciple#2');
expect(lordInternalTreeEl.componentInstance.tree.children.length).toEqual(2);
expect(disciple2InternalTreeEl.componentInstance.tree.children).toBeNull();
const lordElement = lordInternalTreeEl.nativeElement;
const nodeValues = lordElement.querySelectorAll('.node-value');
expect(nodeValues[0].innerText).toEqual('Lord');
expect(nodeValues[1].innerText).toEqual('Disciple#2');
expect(nodeValues[2].innerText).toEqual('Disciple#1');
expect(nodeValues[3].innerText).toEqual('SubDisciple#1');
expect(nodeValues[4].innerText).toEqual('SubDisciple#2');
});
it('should be impossible to drag parent onto its child', () => {
const internalTreeChildren = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const servant2InternalTreeEl = internalTreeChildren[1];
const capturedNode = new CapturedNode(masterComponentInstance.element, masterComponentInstance.tree);
nodeDraggableService.fireNodeDragged(capturedNode, servant2InternalTreeEl.componentInstance.element);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Servant#1');
expect(masterInternalTreeEl.componentInstance.tree.children[1].value).toEqual('Servant#2');
const masterElement = fixture.debugElement.nativeElement;
const nodeValues = masterElement.querySelectorAll('.node-value');
expect(nodeValues[0].innerText).toEqual('Master');
expect(nodeValues[1].innerText).toEqual('Servant#1');
expect(nodeValues[2].innerText).toEqual('Servant#2');
});
it('should be possible to drag node from one subtree to another subtree in the same parent tree', () => {
const internalTreeChildren = lordInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const disciple1InternalTreeEl = internalTreeChildren[0];
const subDisciple1InternalTreeEl = internalTreeChildren[1];
const subDisciple2InternalTreeEl = internalTreeChildren[2];
const disciple2InternalTreeEl = internalTreeChildren[3];
expect(disciple1InternalTreeEl.componentInstance.tree.value).toEqual('Disciple#1');
expect(subDisciple1InternalTreeEl.componentInstance.tree.value).toEqual('SubDisciple#1');
expect(subDisciple2InternalTreeEl.componentInstance.tree.value).toEqual('SubDisciple#2');
expect(disciple2InternalTreeEl.componentInstance.tree.value).toEqual('Disciple#2');
const capturedNode = new CapturedNode(subDisciple1InternalTreeEl.componentInstance.element, subDisciple1InternalTreeEl.componentInstance.tree);
nodeDraggableService.fireNodeDragged(capturedNode, disciple2InternalTreeEl.componentInstance.element);
fixture.detectChanges();
expect(lordInternalTreeEl.componentInstance.tree.children.length).toEqual(3);
expect(lordInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Disciple#1');
expect(lordInternalTreeEl.componentInstance.tree.children[1].value).toEqual('SubDisciple#1');
expect(lordInternalTreeEl.componentInstance.tree.children[2].value).toEqual('Disciple#2');
expect(disciple1InternalTreeEl.componentInstance.tree.children.length).toEqual(1);
expect(disciple1InternalTreeEl.componentInstance.tree.children[0].value).toEqual('SubDisciple#2');
const lordElement = lordInternalTreeEl.nativeElement;
const nodeValues = lordElement.querySelectorAll('.node-value');
expect(nodeValues[0].innerText).toEqual('Lord');
expect(nodeValues[1].innerText).toEqual('Disciple#1');
expect(nodeValues[2].innerText).toEqual('SubDisciple#2');
expect(nodeValues[3].innerText).toEqual('SubDisciple#1');
expect(nodeValues[4].innerText).toEqual('Disciple#2');
});
it('should be possible to drag node from one subtree to another subtree in different parent trees', () => {
const lordInternalTreeChildren = lordInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const disciple1InternalTreeEl = lordInternalTreeChildren[0];
const subDisciple1InternalTreeEl = lordInternalTreeChildren[1];
const masterInternalTreeChildren = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const servant1InternalTreeEl = masterInternalTreeChildren[0];
const capturedNode = new CapturedNode(servant1InternalTreeEl.componentInstance.element, servant1InternalTreeEl.componentInstance.tree);
nodeDraggableService.fireNodeDragged(capturedNode, subDisciple1InternalTreeEl.componentInstance.element);
fixture.detectChanges();
expect(disciple1InternalTreeEl.componentInstance.tree.children.length).toEqual(3);
expect(disciple1InternalTreeEl.componentInstance.tree.children[0].value).toEqual('Servant#1');
expect(disciple1InternalTreeEl.componentInstance.tree.children[1].value).toEqual('SubDisciple#1');
expect(disciple1InternalTreeEl.componentInstance.tree.children[2].value).toEqual('SubDisciple#2');
expect(masterInternalTreeEl.componentInstance.tree.children.length).toEqual(1);
expect(masterInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Servant#2');
const lordElement = lordInternalTreeEl.nativeElement;
const lordNodeValues = lordElement.querySelectorAll('.node-value');
expect(lordNodeValues[0].innerText).toEqual('Lord');
expect(lordNodeValues[1].innerText).toEqual('Disciple#1');
expect(lordNodeValues[2].innerText).toEqual('Servant#1');
expect(lordNodeValues[3].innerText).toEqual('SubDisciple#1');
expect(lordNodeValues[4].innerText).toEqual('SubDisciple#2');
expect(lordNodeValues[5].innerText).toEqual('Disciple#2');
const masterElement = masterInternalTreeEl.nativeElement;
const masterNodeValues = masterElement.querySelectorAll('.node-value');
expect(masterNodeValues[0].innerText).toEqual('Master');
expect(masterNodeValues[1].innerText).toEqual('Servant#2');
});
it('add node to its children', () => {
const lordInternalTreeChildren = lordInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const disciple1InternalTreeEl = lordInternalTreeChildren[0];
const masterInternalTreeChildren = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const servant1InternalTreeEl = masterInternalTreeChildren[0];
const capturedNode = new CapturedNode(servant1InternalTreeEl.componentInstance.element, servant1InternalTreeEl.componentInstance.tree);
nodeDraggableService.fireNodeDragged(capturedNode, disciple1InternalTreeEl.componentInstance.element);
fixture.detectChanges();
expect(disciple1InternalTreeEl.componentInstance.tree.children.length).toEqual(3);
expect(disciple1InternalTreeEl.componentInstance.tree.children[0].value).toEqual('SubDisciple#1');
expect(disciple1InternalTreeEl.componentInstance.tree.children[1].value).toEqual('SubDisciple#2');
expect(disciple1InternalTreeEl.componentInstance.tree.children[2].value).toEqual('Servant#1');
expect(masterInternalTreeEl.componentInstance.tree.children.length).toEqual(1);
expect(masterInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Servant#2');
const lordElement = lordInternalTreeEl.nativeElement;
const lordNodeValues = lordElement.querySelectorAll('.node-value');
expect(lordNodeValues[0].innerText).toEqual('Lord');
expect(lordNodeValues[1].innerText).toEqual('Disciple#1');
expect(lordNodeValues[2].innerText).toEqual('SubDisciple#1');
expect(lordNodeValues[3].innerText).toEqual('SubDisciple#2');
expect(lordNodeValues[4].innerText).toEqual('Servant#1');
expect(lordNodeValues[5].innerText).toEqual('Disciple#2');
const masterElement = masterInternalTreeEl.nativeElement;
const masterNodeValues = masterElement.querySelectorAll('.node-value');
expect(masterNodeValues[0].innerText).toEqual('Master');
expect(masterNodeValues[1].innerText).toEqual('Servant#2');
});
it('should be possible to collapse node', () => {
const foldingControl = masterInternalTreeEl.query(By.css('.folding'));
expect(masterInternalTreeEl.componentInstance.tree.isNodeExpanded()).toEqual(true);
foldingControl.triggerEventHandler('click');
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.tree.isNodeExpanded()).toEqual(false);
const children = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
expect(children.length).toEqual(0);
});
it('should be possible to expand node', () => {
const foldingControl = masterInternalTreeEl.query(By.css('.folding'));
expect(masterInternalTreeEl.componentInstance.tree.isNodeExpanded()).toEqual(true);
foldingControl.triggerEventHandler('click');
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.tree.isNodeExpanded()).toEqual(false);
let children = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
expect(children.length).toEqual(0);
foldingControl.triggerEventHandler('click');
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.tree.isNodeExpanded()).toEqual(true);
children = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
expect(children.length).toEqual(2);
});
it('should show menu on node', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterComponentInstance.isMenuVisible).toEqual(true);
const menus = masterInternalTreeEl.queryAll(By.css('.node-menu'));
expect(menus.length).toEqual(1);
expect(menus[0].queryAll(By.css('.node-menu-item')).length).toEqual(4);
});
it('should remove node by click on appropriate menu item', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
const servantEls = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const servant1El = servantEls[0];
servant1El.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(servant1El.componentInstance.isMenuVisible).toEqual(true);
const menu = servant1El.query(By.css('.node-menu'));
const menuItemRemove: DebugElement = menu.query(By.css('.remove')).parent;
const eventRemove = {button: EventUtils.MouseButtons.Left};
menuItemRemove.triggerEventHandler('click', eventRemove);
fixture.detectChanges();
const remainedSevantEls = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
expect(remainedSevantEls.length).toEqual(1);
expect(remainedSevantEls[0].componentInstance.tree.value).toEqual('Servant#2');
});
it('should hide menu on click outside of menu', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
const servantEls = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const servant1El = servantEls[0];
servant1El.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(servant1El.componentInstance.isMenuVisible).toEqual(true);
expect(servant1El.query(By.css('.node-menu'))).toBeDefined();
nodeMenuService.fireMenuEvent(null, NodeMenuAction.Close);
fixture.detectChanges();
expect(servant1El.componentInstance.isMenuVisible).toEqual(false);
expect(servant1El.query(By.css('.node-menu'))).toBeNull();
});
it('should rename node on enter', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.isMenuVisible).toEqual(true);
const menu = masterInternalTreeEl.query(By.css('.node-menu'));
const menuItemRename: DebugElement = menu.query(By.css('.rename')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuItemRename.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeDefined();
inputRename.triggerEventHandler('keyup.enter', {target: {value: 'bla'}});
fixture.detectChanges();
expect(masterComponentInstance.tree.value).toEqual('bla');
});
it('should rename node on blur', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.isMenuVisible).toEqual(true);
const menu = masterInternalTreeEl.query(By.css('.node-menu'));
const menuItemRename: DebugElement = menu.query(By.css('.rename')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuItemRename.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeDefined();
inputRename.triggerEventHandler('blur', {target: {value: 'bla'}});
fixture.detectChanges();
expect(masterComponentInstance.tree.value).toEqual('bla');
});
it('should cancel renaming node on escape pressed', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.isMenuVisible).toEqual(true);
const menu = masterInternalTreeEl.query(By.css('.node-menu'));
const menuItemRename: DebugElement = menu.query(By.css('.rename')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuItemRename.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeDefined();
inputRename.nativeElement.value = '121212';
inputRename.triggerEventHandler('keyup.esc', {target: {value: 'bla'}});
fixture.detectChanges();
expect(masterComponentInstance.tree.value).toEqual('Master');
});
it('should not rename node on empty input', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.isMenuVisible).toEqual(true);
const menu = masterInternalTreeEl.query(By.css('.node-menu'));
const menuItemRename: DebugElement = menu.query(By.css('.rename')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuItemRename.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeDefined();
inputRename.triggerEventHandler('blur', {target: {value: ''}});
fixture.detectChanges();
expect(masterComponentInstance.tree.value).toEqual('Master');
});
it('should create a leaf child when NewTag operation activated on a branch node', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.isMenuVisible).toEqual(true);
const menu = masterInternalTreeEl.query(By.css('.node-menu'));
const menuNewTag: DebugElement = menu.query(By.css('.new-tag')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuNewTag.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeDefined();
inputRename.triggerEventHandler('keyup.enter', {target: {value: 'bla'}});
fixture.detectChanges();
expect(masterComponentInstance.tree.children.length).toEqual(3);
expect(masterComponentInstance.tree.children[2].value).toEqual('bla');
expect(masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent))[2].nativeElement.querySelector('.node-value').innerText).toEqual('bla');
});
it('should create a sibling leaf when NewTag operation was activated on a node that is leaf', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
const servant1El = masterInternalTreeEl.query(By.directive(TreeInternalComponent));
servant1El.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(servant1El.componentInstance.isMenuVisible).toEqual(true);
const menu = servant1El.query(By.css('.node-menu'));
const menuNewTag: DebugElement = menu.query(By.css('.new-tag')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuNewTag.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeTruthy();
inputRename.triggerEventHandler('keyup.enter', {target: {value: 'bla'}});
fixture.detectChanges();
expect(masterComponentInstance.tree.children.length).toEqual(3);
expect(masterComponentInstance.tree.children[2].value).toEqual('bla');
expect(masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent))[2].nativeElement.querySelector('.node-value').innerText).toEqual('bla');
});
it('should not create a node with empty value', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.isMenuVisible).toEqual(true);
const menu = masterInternalTreeEl.query(By.css('.node-menu'));
const menuNewTag: DebugElement = menu.query(By.css('.new-tag')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuNewTag.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeDefined();
inputRename.triggerEventHandler('keyup.enter', {target: {value: '\r\n\t '}});
fixture.detectChanges();
expect(masterComponentInstance.tree.children.length).toEqual(2);
expect(masterComponentInstance.tree.children[0].value).toEqual('Servant#1');
expect(masterComponentInstance.tree.children[1].value).toEqual('Servant#2');
const servantEls = masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
expect(servantEls.length).toEqual(2);
expect(servantEls[0].nativeElement.querySelector('.node-value').innerText).toEqual('Servant#1');
expect(servantEls[1].nativeElement.querySelector('.node-value').innerText).toEqual('Servant#2');
});
it('should create a branch node when NewFolder operation activated', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
masterInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(masterInternalTreeEl.componentInstance.isMenuVisible).toEqual(true);
const menu = masterInternalTreeEl.query(By.css('.node-menu'));
const menuNewTag: DebugElement = menu.query(By.css('.new-folder')).parent;
const eventRename = {button: EventUtils.MouseButtons.Left};
menuNewTag.triggerEventHandler('click', eventRename);
fixture.detectChanges();
const inputRename = masterInternalTreeEl.query(By.css('input.node-value'));
expect(inputRename).toBeDefined();
inputRename.triggerEventHandler('keyup.enter', {target: {value: 'Branch'}});
fixture.detectChanges();
expect(masterComponentInstance.tree.children.length).toEqual(3);
expect(masterComponentInstance.tree.children[2].value).toEqual('Branch');
expect(masterComponentInstance.tree.children[2].isBranch()).toEqual(true);
expect(masterComponentInstance.tree.children[2].children).toBeDefined();
expect(masterComponentInstance.tree.children[2].children.length).toEqual(0);
expect(masterInternalTreeEl.queryAll(By.directive(TreeInternalComponent))[2].nativeElement.querySelector('.node-value').innerText).toEqual('Branch');
});
it('shouldn\'t show root of the tree', () => {
expect(faceComponentInstance.tree.isRoot()).toEqual(true, 'Element that has rootless class should be a root of the tree');
const treeUl = faceInternalTreeEl.query(By.css('.tree'));
expect(treeUl.classes['rootless']).toEqual(true, 'Tree with hidden root should have "rootless" css class');
const valueContainer = faceInternalTreeEl.query(By.css('.value-container'));
expect(valueContainer.classes['rootless']).toEqual(true, 'Element which contains tree value should also have "rootless" css class');
});
it('should not propagate root visibility to its children - in other words only root should be modified in the tree and hidden', () => {
const childEl = faceInternalTreeEl.query(By.directive(TreeInternalComponent));
expect(childEl.componentInstance.tree.isRoot()).toEqual(false);
expect(childEl.query(By.css('.tree')).classes['rootless']).toEqual(false, 'Only element with root tree node can have rootless class');
expect(childEl.query(By.css('.value-container')).classes['rootless']).toEqual(false, 'Only element with root tree node can have rootless class');
});
describe('Static Tree', () => {
it('should not show menu', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
faceInternalTreeEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(faceComponentInstance.isMenuVisible).toEqual(false);
expect(faceInternalTreeEl.query(By.css('.node-menu'))).toEqual(null);
const childEl = faceInternalTreeEl.query(By.directive(TreeInternalComponent));
expect(childEl.componentInstance.isMenuVisible).toEqual(false);
expect(childEl.query(By.css('.node-menu'))).toEqual(null);
});
it('should allow to override static option for it\'s children', () => {
const event = jasmine.createSpyObj('e', ['preventDefault']);
event.button = EventUtils.MouseButtons.Right;
const childEl = faceInternalTreeEl.queryAll(By.directive(TreeInternalComponent))[1];
childEl.query(By.css('.value-container')).triggerEventHandler('contextmenu', event);
fixture.detectChanges();
expect(childEl.componentInstance.tree.value).toEqual('Retina');
expect(childEl.componentInstance.isMenuVisible).toEqual(true);
expect(childEl.query(By.css('.node-menu'))).toBeTruthy();
});
it('should not be draggable', () => {
const internalTreeChildren = faceInternalTreeEl.queryAll(By.directive(TreeInternalComponent));
const eyesEl = internalTreeChildren[0];
const lipsEl = internalTreeChildren[3];
expect(eyesEl.componentInstance.tree.value).toEqual('Eyes');
expect(eyesEl.componentInstance.tree.positionInParent).toEqual(0);
expect(lipsEl.componentInstance.tree.value).toEqual('Lips');
expect(lipsEl.componentInstance.tree.positionInParent).toEqual(1);
const capturedNode = new CapturedNode(eyesEl.componentInstance.element, eyesEl.componentInstance.tree);
nodeDraggableService.fireNodeDragged(capturedNode, lipsEl.componentInstance.element);
fixture.detectChanges();
expect(eyesEl.componentInstance.tree.positionInParent).toEqual(0);
expect(lipsEl.componentInstance.tree.positionInParent).toEqual(1);
expect(faceInternalTreeEl.componentInstance.tree.children[0].value).toEqual('Eyes');
expect(faceInternalTreeEl.componentInstance.tree.children[1].value).toEqual('Lips');
const nativeElement = faceInternalTreeEl.nativeElement;
const nodeValues = nativeElement.querySelectorAll('.node-value');
expect(nodeValues[0].innerText).toEqual('Face');
expect(nodeValues[1].innerText).toEqual('Eyes');
expect(nodeValues[2].innerText).toEqual('Retina');
expect(nodeValues[3].innerText).toEqual('Eyebrow');
expect(nodeValues[4].innerText).toEqual('Lips');
});
})
});
@Component({
template: `
<div><tree id="master" [tree]="tree"></tree></div>
<div><tree id="lord" [tree]="tree2"></tree></div>
<div><tree id="face" [tree]="tree3" [settings]="settings"></tree></div>
`
})
class TestComponent {
public tree: TreeModel = tree;
public tree2: TreeModel = tree2;
public tree3: TreeModel = tree3;
public settings: Ng2TreeSettings = {
rootIsVisible: false
};
public constructor(public treeHolder: ElementRef) {
}
}