1 import {NO_ERRORS_SCHEMA} from '@angular/core';
2 import {async, ComponentFixture} from '@angular/core/testing';
3 import {SdcUiServices} from 'onap-ui-angular';
4 import 'rxjs/add/observable/of';
5 import {ConfigureFn, configureTests} from '../../../../../jest/test-config.helper';
6 import {CompositionGraphComponent} from "./composition-graph.component";
7 import {WorkspaceService} from "../../workspace/workspace.service";
8 import {ComponentInstance, GroupInstance, NodesFactory, ZoneInstance, ZoneInstanceMode} from "../../../../models";
9 import {EventListenerService} from "../../../../services";
11 CompositionGraphGeneralUtils,
12 CompositionGraphNodesUtils,
13 CompositionGraphZoneUtils,
14 MatchCapabilitiesRequirementsUtils, ServicePathGraphUtils
16 import {CompositionGraphLinkUtils} from "./utils/composition-graph-links-utils";
17 import {ConnectionWizardService} from "./connection-wizard/connection-wizard.service";
18 import {CommonGraphUtils} from "./common/common-graph-utils";
19 import {CompositionGraphPaletteUtils} from "./utils/composition-graph-palette-utils";
20 import {TopologyTemplateService} from "../../../services/component-services/topology-template.service";
21 import {ComponentInstanceServiceNg2} from "../../../services/component-instance-services/component-instance.service";
22 import {CompositionService} from "../composition.service";
23 import {ModalService} from '../../../services/modal.service';
24 import {Store} from '@ngxs/store';
25 import {PoliciesService} from '../../../services/policies.service';
26 import {GroupsService} from '../../../services/groups.service';
27 import {PolicyInstance} from "../../../../models/graph/zones/policy-instance";
28 import {ZoneInstanceType} from "../../../../models/graph/zones/zone-instance";
29 import {GRAPH_EVENTS} from "../../../../utils/constants";
30 import * as cytoscape from "cytoscape";
31 import {ComponentMetadata} from "../../../../models/component-metadata";
32 import {Zone} from "../../../../models/graph/zones/zone";
33 import {SelectedComponentType, SetSelectedComponentAction} from "../common/store/graph.actions";
35 describe('composition graph component', () => {
37 let fixture: ComponentFixture<CompositionGraphComponent>;
38 let instance: CompositionGraphComponent;
39 let eventServiceMock: Partial<EventListenerService>;
40 let compositionGraphZoneUtils: Partial<CompositionGraphZoneUtils>;
41 let generalGraphUtils: Partial<CompositionGraphGeneralUtils>;
42 let workspaceServiceMock: Partial<WorkspaceService>;
43 let policyService: Partial<PoliciesService>;
45 let compositionGraphLinkUtils: Partial<CompositionGraphLinkUtils>;
46 let nodesGraphUtils: Partial<CompositionGraphNodesUtils>;
48 let createPolicyInstance = () => {
49 let policy = new PolicyInstance();
50 policy.targets = {COMPONENT_INSTANCES: [], GROUPS: []};
51 return new ZoneInstance(policy, '', '');
58 notifyObservers: jest.fn(),
59 unRegisterObserver: jest.fn()
62 compositionGraphZoneUtils = {
63 endCyTagMode: jest.fn(),
64 showZoneTagIndications: jest.fn(),
65 hideZoneTagIndications: jest.fn(),
66 hideGroupZoneIndications: jest.fn(),
67 showGroupZoneIndications: jest.fn(),
68 startCyTagMode: jest.fn()
71 workspaceServiceMock = {
72 metadata: <ComponentMetadata>{
73 uniqueId: 'service_unique_id',
74 componentType: 'SERVICE'
78 compositionGraphLinkUtils = {
79 handleLinkClick: jest.fn(),
80 getModifyLinkMenu: jest.fn()
87 getSpecificPolicy: jest.fn()
91 zoomGraphTo: jest.fn()
95 onNodesPositionChanged: jest.fn()
98 const configure: ConfigureFn = (testBed) => {
99 testBed.configureTestingModule({
100 declarations: [CompositionGraphComponent],
102 schemas: [NO_ERRORS_SCHEMA],
104 {provide: NodesFactory, useValue: {}},
105 {provide: EventListenerService, useValue: eventServiceMock},
106 {provide: CompositionGraphZoneUtils, useValue: compositionGraphZoneUtils},
107 {provide: CompositionGraphGeneralUtils, useValue: generalGraphUtils},
108 {provide: CompositionGraphLinkUtils, useValue: compositionGraphLinkUtils},
109 {provide: CompositionGraphNodesUtils, useValue: nodesGraphUtils},
110 {provide: ConnectionWizardService, useValue: {}},
111 {provide: CommonGraphUtils, useValue: {}},
112 {provide: CompositionGraphPaletteUtils, useValue: {}},
113 {provide: TopologyTemplateService, useValue: {}},
114 {provide: ComponentInstanceServiceNg2, useValue: {}},
115 {provide: MatchCapabilitiesRequirementsUtils, useValue: {}},
116 {provide: CompositionService, useValue: {}},
117 {provide: SdcUiServices.LoaderService, useValue: {}},
118 {provide: WorkspaceService, useValue: workspaceServiceMock},
119 {provide: SdcUiServices.NotificationsService, useValue: {}},
120 {provide: SdcUiServices.simplePopupMenuService, useValue: {}},
121 {provide: ServicePathGraphUtils, useValue: {}},
122 {provide: ModalService, useValue: {}},
123 {provide: PoliciesService, useValue: policyService},
124 {provide: GroupsService, useValue: {}},
125 {provide: Store, useValue: storeStub},
130 configureTests(configure).then((testBed) => {
131 fixture = testBed.createComponent(CompositionGraphComponent);
132 instance = fixture.componentInstance;
133 instance._cy = cytoscape({});
138 it('composition graph component should be defined', () => {
139 expect(fixture).toBeDefined();
142 describe('on zone instance mode changed', () => {
143 let newZoneInstance: ZoneInstance;
147 newZoneInstance = createPolicyInstance();
148 instance.zoneTagMode = null;
150 instance.zones[ZoneInstanceType.POLICY] = new Zone('Policies', 'P', ZoneInstanceType.POLICY);
151 instance.zones[ZoneInstanceType.GROUP] = new Zone('Groups', 'G', ZoneInstanceType.GROUP);
152 instance.activeZoneInstance = createPolicyInstance();
155 it('zone instance in tag mode and we want to turn tag mode off', () => {
156 instance.zoneTagMode = 'some_zone_id';
157 instance.activeZoneInstance = newZoneInstance;
158 instance.zoneInstanceModeChanged(ZoneInstanceMode.NONE, newZoneInstance, ZoneInstanceType.POLICY);
159 expect(instance.eventListenerService.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_CANVAS_TAG_END, newZoneInstance);
160 expect(instance.activeZoneInstance.mode).toBe(ZoneInstanceMode.SELECTED)
163 it('we are not in tag mode and policy instance mode changed to NONE - group and zone tag indication need to be removed', () => {
164 instance.zoneInstanceModeChanged(ZoneInstanceMode.NONE, newZoneInstance, ZoneInstanceType.POLICY);
165 expect(instance.compositionGraphZoneUtils.hideZoneTagIndications).toHaveBeenCalledWith(instance._cy);
166 expect(instance.compositionGraphZoneUtils.hideGroupZoneIndications).toHaveBeenCalledWith(instance.zones[ZoneInstanceType.GROUP].instances);
169 it('we are not in tag mode and active zone instance gets hover/none - we dont actually change mode', () => {
170 let newMode = ZoneInstanceMode.SELECTED;
171 instance.zoneInstanceModeChanged(newMode, newZoneInstance, ZoneInstanceType.POLICY);
172 expect(newZoneInstance.mode).toBe(newMode);
175 it('we are not in tag mode and zone instance mode changed to HOVER mode', () => {
176 instance.zoneInstanceModeChanged(ZoneInstanceMode.HOVER, newZoneInstance, ZoneInstanceType.POLICY);
177 expect(instance.compositionGraphZoneUtils.showZoneTagIndications).toHaveBeenCalledWith(instance._cy, newZoneInstance);
178 expect(instance.compositionGraphZoneUtils.showGroupZoneIndications).toHaveBeenCalledWith(instance.zones[ZoneInstanceType.GROUP].instances, newZoneInstance);
179 expect(instance.eventListenerService.notifyObservers).not.toHaveBeenCalled();
182 it('we are not in tag mode and mode changed to SELECTED', () => {
183 instance.zoneInstanceModeChanged(ZoneInstanceMode.SELECTED, newZoneInstance, ZoneInstanceType.POLICY);
184 expect(instance.compositionGraphZoneUtils.showZoneTagIndications).toHaveBeenCalledWith(instance._cy, newZoneInstance);
185 expect(instance.compositionGraphZoneUtils.showGroupZoneIndications).toHaveBeenCalledWith(instance.zones[ZoneInstanceType.GROUP].instances, newZoneInstance);
186 expect(instance.activeZoneInstance).toBe(newZoneInstance);
187 expect(instance.eventListenerService.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_ZONE_INSTANCE_SELECTED, newZoneInstance);
188 expect(instance.store.dispatch).toHaveBeenCalledWith(new SetSelectedComponentAction({
189 component: newZoneInstance.instanceData,
190 type: SelectedComponentType[ZoneInstanceType[newZoneInstance.type]]
192 expect(instance.eventListenerService.notifyObservers).not.toHaveBeenCalledWith(GRAPH_EVENTS.ON_CANVAS_TAG_START, ZoneInstanceType.POLICY);
196 it('we are not in tag mode and and zone instance mode changed to TAG', () => {
197 instance.zoneInstanceModeChanged(ZoneInstanceMode.TAG, newZoneInstance, ZoneInstanceType.POLICY);
198 expect(instance.compositionGraphZoneUtils.showZoneTagIndications).toHaveBeenCalledWith(instance._cy, newZoneInstance);
199 expect(instance.compositionGraphZoneUtils.showGroupZoneIndications).toHaveBeenCalledWith(instance.zones[ZoneInstanceType.GROUP].instances, newZoneInstance);
200 expect(instance.activeZoneInstance).toBe(newZoneInstance);
201 expect(instance.eventListenerService.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_ZONE_INSTANCE_SELECTED, newZoneInstance);
202 expect(instance.store.dispatch).toHaveBeenCalledWith(new SetSelectedComponentAction({
203 component: newZoneInstance.instanceData,
204 type: SelectedComponentType[ZoneInstanceType[newZoneInstance.type]]
206 expect(instance.compositionGraphZoneUtils.startCyTagMode).toHaveBeenCalledWith(instance._cy);
207 expect(instance.eventListenerService.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_CANVAS_TAG_START, ZoneInstanceType.POLICY);
211 it('unset active zone instance', () => {
212 instance.activeZoneInstance = createPolicyInstance();
213 instance.unsetActiveZoneInstance();
214 expect(instance.activeZoneInstance).toBeNull();
215 expect(instance.zoneTagMode).toBeNull();
218 it('zone background clicked - we are not in tag mode and active zone instance exist', () => {
219 instance.activeZoneInstance = createPolicyInstance();
220 jest.spyOn(instance, 'unsetActiveZoneInstance');
221 jest.spyOn(instance, 'selectTopologyTemplate');
222 instance.zoneBackgroundClicked();
223 expect(instance.unsetActiveZoneInstance).toHaveBeenCalled();
224 expect(instance.selectTopologyTemplate).toHaveBeenCalled();
227 it('zone background clicked - we are not in tag mode and no active zone instance exist', () => {
228 jest.spyOn(instance, 'unsetActiveZoneInstance');
229 jest.spyOn(instance, 'selectTopologyTemplate');
230 instance.zoneBackgroundClicked();
231 expect(instance.unsetActiveZoneInstance).not.toHaveBeenCalled();
232 expect(instance.selectTopologyTemplate).not.toHaveBeenCalled();
235 it('on zoom in', () => {
236 jest.spyOn(instance, 'zoom');
238 expect(instance.generalGraphUtils.zoomGraphTo).toHaveBeenCalledWith(instance._cy, instance._cy.zoom() + .1);
241 it('on zoom out', () => {
242 jest.spyOn(instance, 'zoom');
243 instance.zoom(false);
244 expect(instance.generalGraphUtils.zoomGraphTo).toHaveBeenCalledWith(instance._cy, instance._cy.zoom() - .1);
247 describe('cytoscape tap end event have been called', () => {
249 it('canvas background was clicked while zone instance in tag mode, zone instance still selected in tag mode)', () => {
250 let event = <Cy.EventObject>{cyTarget: instance._cy};
251 instance.zoneTagMode = 'instance_in_tag'
252 instance.onTapEnd(event);
253 expect(instance.zoneTagMode).toBe('instance_in_tag');
256 it('canvas background was clicked and no zone instance selected, topology template is now selected', () => {
257 let event = <Cy.EventObject>{cyTarget: instance._cy};
258 jest.spyOn(instance, 'selectTopologyTemplate');
259 instance.onTapEnd(event);
260 expect(instance.selectTopologyTemplate).toHaveBeenCalled();
261 expect(instance.eventListenerService.notifyObservers).toHaveBeenCalledWith(GRAPH_EVENTS.ON_GRAPH_BACKGROUND_CLICKED);
264 it('canvas background was clicked and zone instance was selected, topology template is now selected and zone instance is unselected', () => {
265 let event = <Cy.EventObject>{cyTarget: instance._cy};
266 instance.activeZoneInstance = createPolicyInstance();
267 jest.spyOn(instance, 'selectTopologyTemplate');
268 jest.spyOn(instance, 'unsetActiveZoneInstance');
269 instance.onTapEnd(event);
270 expect(instance.selectTopologyTemplate).toHaveBeenCalled();
271 expect(instance.unsetActiveZoneInstance).toHaveBeenCalled();
275 it('canvas background was clicked and zone instance was selected, topology template is now selected and zone instance is unselected', () => {
276 let event = <Cy.EventObject>{cyTarget: instance._cy};
277 instance.activeZoneInstance = createPolicyInstance();
278 jest.spyOn(instance, 'selectTopologyTemplate');
279 jest.spyOn(instance, 'unsetActiveZoneInstance');
280 instance.onTapEnd(event);
281 expect(instance.selectTopologyTemplate).toHaveBeenCalled();
282 expect(instance.unsetActiveZoneInstance).toHaveBeenCalled();
285 it('on simple edge clicked, open link menu and handle link click', () => {
286 let event = <Cy.EventObject>{
288 isEdge: jest.fn().mockReturnValue(true),
289 data: jest.fn().mockReturnValue({type: 'simple'})
292 instance.openModifyLinkMenu = jest.fn();
293 instance.onTapEnd(event);
294 expect(instance.compositionGraphLinkUtils.handleLinkClick).toHaveBeenCalledWith(instance._cy, event);
295 expect(instance.openModifyLinkMenu).toHaveBeenCalled();
298 it('on service path edge clicked, no menu is opened', () => {
299 let event = <Cy.EventObject>{
301 isEdge: jest.fn().mockReturnValue(true),
302 data: jest.fn().mockReturnValue({type: 'service-path-link'})
305 instance.openModifyLinkMenu = jest.fn();
306 instance.onTapEnd(event);
307 expect(instance.compositionGraphLinkUtils.handleLinkClick).toHaveBeenCalledWith(instance._cy, event);
308 expect(instance.openModifyLinkMenu).not.toHaveBeenCalled();
311 it('on drop after drag event (position has changed), call onNodesPositionChanged to update node position', () => {
312 let event = <Cy.EventObject>{
314 isEdge: jest.fn().mockReturnValue(false),
315 position: jest.fn().mockReturnValue({x:2.11, y:2.44})
318 instance.currentlyClickedNodePosition = <Cy.Position>{x:2.33, y:2.44};
319 instance.onTapEnd(event);
320 let nodesMoved: Cy.CollectionNodes = instance._cy.$(':grabbed');
321 expect(instance.nodesGraphUtils.onNodesPositionChanged).toHaveBeenCalledWith(instance._cy, instance.topologyTemplate, nodesMoved);
325 it('on node clicked (position not changed) while zone instance selected, unset active zone and call set selected instance', () => {
326 let event = <Cy.EventObject>{
328 isEdge: jest.fn().mockReturnValue(false),
329 position: jest.fn().mockReturnValue({x:2.11, y:2.44}),
330 data: jest.fn().mockReturnValue({componentInstance: new ComponentInstance()})
333 instance.currentlyClickedNodePosition = <Cy.Position>{x:2.11, y:2.44};
334 instance.activeZoneInstance = createPolicyInstance();
335 jest.spyOn(instance, 'unsetActiveZoneInstance');
336 jest.spyOn(instance, 'selectComponentInstance');
337 instance.onTapEnd(event);
338 expect(instance.unsetActiveZoneInstance).toHaveBeenCalled();
339 expect(instance.selectComponentInstance).toHaveBeenCalledWith(event.cyTarget[0].data().componentInstance);
343 it('initial view mode will turn off all cytoscape events', () => {
344 jest.spyOn(instance, 'isViewOnly').mockReturnValue(true);
345 jest.spyOn(instance._cy, 'off');
346 instance.initViewMode();
347 expect(instance._cy.off).toHaveBeenCalledWith('drag');
348 expect(instance._cy.off).toHaveBeenCalledWith('handlemouseout');
349 expect(instance._cy.off).toHaveBeenCalledWith('handlemouseover');
350 expect(instance._cy.off).toHaveBeenCalledWith('canvasredraw');
351 expect(instance._cy.off).toHaveBeenCalledWith('handletagclick');