|
| 1 | +import {ComponentFixture, TestBed} from '@angular/core/testing'; |
| 2 | +import {NgxPopperjsModule, NgxPopperjsContentComponent} from 'ngx-popperjs'; |
| 3 | +import { |
| 4 | + NodeService, |
| 5 | + AbstractBaseGroup, |
| 6 | + WorkflowPrompt, |
| 7 | + State, |
| 8 | + WorkflowEvent, |
| 9 | +} from '../../classes'; |
| 10 | +import {NodeTypes, ValueTypes, InputTypes} from '../../enum'; |
| 11 | +import {InvalidEntityError} from '../../errors'; |
| 12 | +import BPMNModdle from 'bpmn-moddle'; |
| 13 | +import {LocalizationPipe} from '../../pipes/localization.pipe'; |
| 14 | +import { |
| 15 | + AndGroup, |
| 16 | + BpmnNodesService, |
| 17 | + ChangeColumnValueAction, |
| 18 | + LocalizationProviderService, |
| 19 | + OnAddItemEvent, |
| 20 | + OnChangeEvent, |
| 21 | + OnIntervalEvent, |
| 22 | + OnValueEvent, |
| 23 | + OrGroup, |
| 24 | + SendEmailAction, |
| 25 | + ValueInput, |
| 26 | +} from '../../services'; |
| 27 | +import {GroupComponent} from './group.component'; |
| 28 | +import {TooltipRenderComponent} from '../tooltip-render/tooltip-render.component'; |
| 29 | +import {BPMN_NODES} from '../../const'; |
| 30 | +import {NodeComponent} from '../node/node.component'; |
| 31 | +import { |
| 32 | + ElementRef, |
| 33 | + Renderer2, |
| 34 | + ViewContainerRef, |
| 35 | + ChangeDetectorRef, |
| 36 | +} from '@angular/core'; |
| 37 | +import {AllowedValues, RecordOfAnyType} from '../../types'; |
| 38 | +import {popper} from '@popperjs/core'; |
| 39 | + |
| 40 | +describe('GroupComponent', () => { |
| 41 | + let component: GroupComponent<any>; |
| 42 | + let fixture: ComponentFixture<GroupComponent<any>>; |
| 43 | + const mockEvents: any = [ |
| 44 | + { |
| 45 | + id: 'event1', |
| 46 | + trigger: true, |
| 47 | + type: 'someType' /* Add other properties as needed */, |
| 48 | + }, |
| 49 | + { |
| 50 | + id: 'event2', |
| 51 | + trigger: false, |
| 52 | + type: 'someOtherType' /* Add other properties as needed */, |
| 53 | + }, |
| 54 | + ]; |
| 55 | + |
| 56 | + const mockActions: any = [ |
| 57 | + { |
| 58 | + id: 'action1', |
| 59 | + trigger: true, |
| 60 | + type: 'someActionType' /* Add other properties as needed */, |
| 61 | + }, |
| 62 | + { |
| 63 | + id: 'action2', |
| 64 | + trigger: false, |
| 65 | + type: 'anotherActionType' /* Add other properties as needed */, |
| 66 | + }, |
| 67 | + ]; |
| 68 | + const eventStub = new OnChangeEvent({}, '', '', ''); |
| 69 | + let nodeServiceSpy: any; |
| 70 | + beforeEach(async () => { |
| 71 | + const nodeServiceMock = { |
| 72 | + getActions: () => [], |
| 73 | + getEvents: () => [], |
| 74 | + getNodeByName: eventStub, |
| 75 | + getGroupByName: () => {}, |
| 76 | + getGroups: () => [], |
| 77 | + mapInputs: () => [], |
| 78 | + }; |
| 79 | + nodeServiceSpy = jasmine.createSpyObj('NodeService', nodeServiceMock); |
| 80 | + nodeServiceSpy.getEvents.and.returnValue(mockEvents); |
| 81 | + nodeServiceSpy.getActions.and.returnValue(mockActions); |
| 82 | + |
| 83 | + await TestBed.configureTestingModule({ |
| 84 | + declarations: [ |
| 85 | + GroupComponent, |
| 86 | + NodeComponent, |
| 87 | + TooltipRenderComponent, |
| 88 | + LocalizationPipe, |
| 89 | + ], |
| 90 | + providers: [ |
| 91 | + {provide: NodeService, useValue: nodeServiceSpy}, |
| 92 | + LocalizationProviderService, |
| 93 | + LocalizationPipe, |
| 94 | + ], |
| 95 | + imports: [NgxPopperjsModule], |
| 96 | + }).compileComponents(); |
| 97 | + }); |
| 98 | + |
| 99 | + beforeEach(() => { |
| 100 | + fixture = TestBed.createComponent(GroupComponent); |
| 101 | + component = fixture.componentInstance; |
| 102 | + component.group = new AndGroup({}, '', NodeTypes.EVENT, false); |
| 103 | + component.isLast = false; |
| 104 | + component.isFirst = false; |
| 105 | + component.eventGroups = []; |
| 106 | + component.nodeType = NodeTypes.ACTION; |
| 107 | + component.nodeType = NodeTypes.EVENT; |
| 108 | + component.allColumns = []; |
| 109 | + |
| 110 | + fixture.detectChanges(); |
| 111 | + }); |
| 112 | + |
| 113 | + it('should create', () => { |
| 114 | + expect(component).toBeTruthy(); |
| 115 | + }); |
| 116 | + |
| 117 | + it('should initialize events and actions properties', () => { |
| 118 | + component.ngOnInit(); |
| 119 | + expect(component.events).toEqual(mockEvents); |
| 120 | + expect(component.actions).toEqual(mockActions); |
| 121 | + }); |
| 122 | + |
| 123 | + it('should set the templateMap', () => { |
| 124 | + component.ngAfterViewInit(); |
| 125 | + |
| 126 | + expect(component.templateMap).toBeDefined(); |
| 127 | + }); |
| 128 | + |
| 129 | + it('should emit the remove event', () => { |
| 130 | + spyOn(component.remove, 'emit'); |
| 131 | + component.removeClick(); |
| 132 | + expect(component.remove.emit).toHaveBeenCalledWith(true); |
| 133 | + }); |
| 134 | + |
| 135 | + it('should emit the add event', () => { |
| 136 | + spyOn(component.add, 'emit'); |
| 137 | + component.addClick(); |
| 138 | + expect(component.add.emit).toHaveBeenCalledWith(true); |
| 139 | + }); |
| 140 | + |
| 141 | + it('should add the node to the group', () => { |
| 142 | + component.onNodeAdd(eventStub, 'groupType', 'groupId', 'id'); |
| 143 | + expect(component.group.children.length).toBeGreaterThan(0); |
| 144 | + }); |
| 145 | + |
| 146 | + it('should throw an error if the node type is neither EVENT nor ACTION', () => { |
| 147 | + const node = eventStub; |
| 148 | + nodeServiceSpy.getNodeByName.and.throwError(''); |
| 149 | + expect(() => |
| 150 | + component.onNodeAdd(node, 'groupType', 'groupId', 'id'), |
| 151 | + ).toThrowError(''); |
| 152 | + }); |
| 153 | + |
| 154 | + it('should remove the node at the given index from the group', () => { |
| 155 | + component.group.children.push({ |
| 156 | + node: eventStub, |
| 157 | + inputs: [], |
| 158 | + }); |
| 159 | + component.onNodeRemove(0); |
| 160 | + expect(component.group.children.length).toEqual(0); |
| 161 | + }); |
| 162 | + |
| 163 | + it('should emit the eventRemoved event', () => { |
| 164 | + spyOn(component.eventRemoved, 'emit'); |
| 165 | + component.onNodeRemove(0); |
| 166 | + expect(component.eventRemoved.emit).toHaveBeenCalled(); |
| 167 | + }); |
| 168 | + |
| 169 | + it('should return a function that hides the popper and emits the value', () => { |
| 170 | + const popper = {hide: () => {}} as NgxPopperjsContentComponent; |
| 171 | + const callback = component.createCallback( |
| 172 | + { |
| 173 | + node: eventStub, |
| 174 | + inputs: [], |
| 175 | + }, |
| 176 | + new ValueInput(), |
| 177 | + popper, |
| 178 | + ); |
| 179 | + spyOn(popper, 'hide'); |
| 180 | + |
| 181 | + callback(); |
| 182 | + expect(popper.hide).toHaveBeenCalled(); |
| 183 | + }); |
| 184 | + |
| 185 | + const popperSpy = jasmine.createSpyObj('NgxPopperjsContentComponent', [ |
| 186 | + 'show', |
| 187 | + 'hide', |
| 188 | + ]); |
| 189 | + |
| 190 | + it('should hide the previous popper and show the current popper', () => { |
| 191 | + const event = new MouseEvent('click'); |
| 192 | + component.prevPopperRef = popperSpy; // Assign the spy object to prevPopperRef |
| 193 | + |
| 194 | + // Act |
| 195 | + component.onPoperClick(event, popperSpy); |
| 196 | + |
| 197 | + // Assert |
| 198 | + expect(component.prevPopperRef.hide).toHaveBeenCalled(); |
| 199 | + expect(popperSpy.show).toHaveBeenCalled(); // Spy on the show method of popperSpy |
| 200 | + }); |
| 201 | + |
| 202 | + it('should set the tooltipText, showsTooltip, topPosition, and leftPosition properties', () => { |
| 203 | + const event = new MouseEvent('click'); |
| 204 | + component.showTooltip( |
| 205 | + event, |
| 206 | + { |
| 207 | + node: eventStub, |
| 208 | + inputs: [], |
| 209 | + }, |
| 210 | + new ValueInput(), |
| 211 | + ); |
| 212 | + expect(component.tooltipText).toBe('Select a column first'); |
| 213 | + expect(component.showsTooltip).toBe(true); |
| 214 | + expect(component.topPosition).toBe(event.clientY + 10); |
| 215 | + expect(component.leftPosition).toBe(event.clientX); |
| 216 | + }); |
| 217 | + |
| 218 | + it('should reset the showsTooltip, topPosition, and leftPosition properties', () => { |
| 219 | + component.hideTooltip(); |
| 220 | + expect(component.showsTooltip).toBe(false); |
| 221 | + expect(component.topPosition).toBeNull(); |
| 222 | + expect(component.leftPosition).toBeNull(); |
| 223 | + }); |
| 224 | + |
| 225 | + it('should return a function that hides the previous popper', () => { |
| 226 | + const mockElementRef = {} as ElementRef<any>; |
| 227 | + const mockRenderer = {} as Renderer2; |
| 228 | + const mockViewContainerRef = {} as ViewContainerRef; |
| 229 | + const mockChangeDetectorRef = {} as ChangeDetectorRef; |
| 230 | + |
| 231 | + const mockNgxPopperjsContentComponent = jasmine.createSpyObj( |
| 232 | + 'NgxPopperjsContentComponent', |
| 233 | + ['hide'], |
| 234 | + ); |
| 235 | + |
| 236 | + component.prevPopperRef = mockNgxPopperjsContentComponent; |
| 237 | + |
| 238 | + const hidePopperFn = component.hidePopper(); |
| 239 | + hidePopperFn(); |
| 240 | + |
| 241 | + expect(component.prevPopperRef.hide).toHaveBeenCalled(); |
| 242 | + }); |
| 243 | + |
| 244 | + it('should set enableActionIcon to false if the node type is OnChangeEvent and the value is ValueTypes.AnyValue', () => { |
| 245 | + const element = {node: eventStub, inputs: []}; |
| 246 | + const input = new ValueInput(); |
| 247 | + element.node.type = NodeTypes.EVENT; |
| 248 | + element.node.getIdentifier = () => 'OnChangeEvent'; |
| 249 | + element.node.state.change('valueInputType', 'valueInputType'); |
| 250 | + spyOn(component.itemChanged, 'emit'); |
| 251 | + component.addValue(element, input, ValueTypes.AnyValue); |
| 252 | + expect(component.enableActionIcon).toBe(false); |
| 253 | + expect(component.itemChanged.emit).toHaveBeenCalledWith({ |
| 254 | + field: input.getIdentifier(), |
| 255 | + value: ValueTypes.AnyValue, |
| 256 | + element: element, |
| 257 | + }); |
| 258 | + }); |
| 259 | + |
| 260 | + it('should set enableActionIcon to true if the node type is OnChangeEvent and the value is not ValueTypes.AnyValue', () => { |
| 261 | + const element = {node: eventStub, inputs: []}; |
| 262 | + const input = new ValueInput(); |
| 263 | + |
| 264 | + element.node.type = NodeTypes.EVENT; |
| 265 | + element.node.getIdentifier = () => 'OnChangeEvent'; |
| 266 | + |
| 267 | + element.node.state.change('valueInputType', 'valueInputType'); |
| 268 | + spyOn(component.itemChanged, 'emit'); |
| 269 | + component.addValue(element, input, 'value'); |
| 270 | + expect(component.enableActionIcon).toBe(true); |
| 271 | + expect(component.itemChanged.emit).toHaveBeenCalledWith({ |
| 272 | + field: input.getIdentifier(), |
| 273 | + value: 'value', |
| 274 | + element: element, |
| 275 | + }); |
| 276 | + }); |
| 277 | + |
| 278 | + it('should set the selectedItems to the list of selected items', () => { |
| 279 | + // Arrange |
| 280 | + const list = [{id: '1'}, {id: '2'}, {id: '3'}]; |
| 281 | + |
| 282 | + // Act |
| 283 | + component.onSelectAll(list as any[]); // Casting to any[] to resolve type issue |
| 284 | + |
| 285 | + // Assert |
| 286 | + expect(component.selectedItems.length).toBe(3); |
| 287 | + }); |
| 288 | + |
| 289 | + it('should prevent the default action if the key is not a digit or backspace/delete', () => { |
| 290 | + // Arrange |
| 291 | + const event = new KeyboardEvent('keypress', {keyCode: 65}); |
| 292 | + spyOn(event, 'preventDefault'); |
| 293 | + const targetWithMockedValue = {value: 'test'} as EventTarget & { |
| 294 | + value: string; |
| 295 | + }; |
| 296 | + spyOnProperty(event, 'target', 'get').and.returnValue( |
| 297 | + targetWithMockedValue, |
| 298 | + ); |
| 299 | + |
| 300 | + // Act |
| 301 | + component.handleKeyPress(event); |
| 302 | + |
| 303 | + // Assert |
| 304 | + expect(event.preventDefault).toHaveBeenCalled(); |
| 305 | + }); |
| 306 | + it('should prevent the default action if the input value is not a valid number', () => { |
| 307 | + // Arrange |
| 308 | + const event = new KeyboardEvent('keypress', {keyCode: 48}); |
| 309 | + spyOn(event, 'preventDefault'); |
| 310 | + const targetWithMockedValue = {value: 'test'} as EventTarget & { |
| 311 | + value: string; |
| 312 | + }; |
| 313 | + spyOnProperty(event, 'target', 'get').and.returnValue( |
| 314 | + targetWithMockedValue, |
| 315 | + ); |
| 316 | + |
| 317 | + // Act |
| 318 | + component.handleKeyPress(event); |
| 319 | + |
| 320 | + // Assert |
| 321 | + expect(event.preventDefault).toHaveBeenCalled(); |
| 322 | + }); |
| 323 | + it('should not prevent the default action if the key is a digit or backspace/delete and the input value is a valid number', () => { |
| 324 | + // Arrange |
| 325 | + const event1 = new KeyboardEvent('keypress', {keyCode: 48}); |
| 326 | + const event2 = new KeyboardEvent('keypress', {keyCode: 8}); |
| 327 | + const targetWithMockedValue1 = {value: '0'} as EventTarget & { |
| 328 | + value: string; |
| 329 | + }; |
| 330 | + const targetWithMockedValue2 = {value: 'test'} as EventTarget & { |
| 331 | + value: string; |
| 332 | + }; |
| 333 | + spyOnProperty(event1, 'target', 'get').and.returnValue( |
| 334 | + targetWithMockedValue1, |
| 335 | + ); |
| 336 | + spyOnProperty(event2, 'target', 'get').and.returnValue( |
| 337 | + targetWithMockedValue2, |
| 338 | + ); |
| 339 | + |
| 340 | + spyOn(event1, 'preventDefault'); |
| 341 | + spyOn(event2, 'preventDefault'); |
| 342 | + |
| 343 | + // Act |
| 344 | + component.handleKeyPress(event1); |
| 345 | + component.handleKeyPress(event2); |
| 346 | + |
| 347 | + // Assert |
| 348 | + expect(event1.preventDefault).not.toHaveBeenCalled(); |
| 349 | + expect(event2.preventDefault).toHaveBeenCalled(); |
| 350 | + }); |
| 351 | +}); |
0 commit comments