Skip to content

Commit d8cb7d9

Browse files
committed
[PER-10107] Add/Update unit tests
1 parent b900c53 commit d8cb7d9

File tree

11 files changed

+886
-281
lines changed

11 files changed

+886
-281
lines changed
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { ElementRef, Pipe, PipeTransform } from '@angular/core';
3+
import { of } from 'rxjs';
4+
import { provideRouter } from '@angular/router';
5+
import { Deferred } from '@root/vendor/deferred';
6+
7+
import { DataService } from '@shared/services/data/data.service';
8+
import { PromptService } from '@shared/services/prompt/prompt.service';
9+
import { ApiService } from '@shared/services/api/api.service';
10+
import { MessageService } from '@shared/services/message/message.service';
11+
import { AccountService } from '@shared/services/account/account.service';
12+
import { DragService } from '@shared/services/drag/drag.service';
13+
import { ShareLinksService } from '@root/app/share-links/services/share-links.service';
14+
import { EditService } from '@core/services/edit/edit.service';
15+
import { DeviceService } from '@shared/services/device/device.service';
16+
import { provideNoopAnimations } from '@angular/platform-browser/animations';
17+
import { FileListItemComponent } from './file-list-item.component';
18+
19+
@Pipe({ name: 'itemTypeIcon' })
20+
class MockItemTypeIconPipe implements PipeTransform {
21+
transform(value: any): any {
22+
return value;
23+
}
24+
}
25+
26+
@Pipe({ name: 'prDate' })
27+
export class MockPrDatePipe implements PipeTransform {
28+
transform(value: any, format?: string): string {
29+
return `mocked-date${format ? `-${format}` : ''}`;
30+
}
31+
}
32+
33+
@Pipe({ name: 'prConstants' })
34+
export class MockPrConstantsPipe implements PipeTransform {
35+
transform(value: string): string {
36+
return `mocked-${value}`;
37+
}
38+
}
39+
40+
describe('FileListItemComponent', () => {
41+
let component: FileListItemComponent;
42+
let fixture: ComponentFixture<FileListItemComponent>;
43+
let editService: EditService;
44+
45+
const mockEditService = {
46+
moveItems: jasmine.createSpy().and.returnValue(Promise.resolve()),
47+
updateItems: jasmine.createSpy().and.returnValue(Promise.resolve()),
48+
};
49+
50+
const mockDeviceService = {
51+
isMobileWidth: jasmine.createSpy().and.returnValue(false),
52+
};
53+
54+
beforeEach(async () => {
55+
await TestBed.configureTestingModule({
56+
imports: [MockItemTypeIconPipe, MockPrDatePipe, MockPrConstantsPipe],
57+
declarations: [FileListItemComponent],
58+
providers: [
59+
provideNoopAnimations(),
60+
provideRouter([]),
61+
{ provide: ElementRef, useValue: { nativeElement: {} } },
62+
{
63+
provide: DataService,
64+
useValue: {
65+
registerItem: jasmine.createSpy(),
66+
unregisterItem: jasmine.createSpy(),
67+
getSelectedItems: () => new Map(),
68+
beginPreparingForNavigate: jasmine.createSpy(),
69+
fetchLeanItems: jasmine.createSpy(),
70+
setItemMultiSelectStatus: jasmine.createSpy(),
71+
currentFolder: { type: '' },
72+
},
73+
},
74+
{
75+
provide: PromptService,
76+
useValue: {
77+
prompt: jasmine
78+
.createSpy()
79+
.and.returnValue(
80+
Promise.resolve({ displayName: 'Updated Name' }),
81+
),
82+
confirm: jasmine.createSpy().and.returnValue(Promise.resolve()),
83+
},
84+
},
85+
{
86+
provide: ApiService,
87+
useValue: { folder: { getWithChildren: jasmine.createSpy() } },
88+
},
89+
{
90+
provide: MessageService,
91+
useValue: { showError: jasmine.createSpy() },
92+
},
93+
{
94+
provide: AccountService,
95+
useValue: {
96+
getArchive: () => ({ archiveId: '123' }),
97+
checkMinimumAccess: () => true,
98+
},
99+
},
100+
{
101+
provide: DragService,
102+
useValue: {
103+
events: () => of(),
104+
dispatch: jasmine.createSpy(),
105+
getDestinationFromDropTarget: () => ({
106+
displayName: 'Target Folder',
107+
}),
108+
},
109+
},
110+
{
111+
provide: ShareLinksService,
112+
useValue: {
113+
isUnlistedShare: async () => await Promise.resolve(false),
114+
},
115+
},
116+
{ provide: EditService, useValue: mockEditService },
117+
{ provide: DeviceService, useValue: mockDeviceService },
118+
],
119+
}).compileComponents();
120+
121+
fixture = TestBed.createComponent(FileListItemComponent);
122+
component = fixture.componentInstance;
123+
editService = TestBed.inject(EditService);
124+
125+
component.item = {
126+
displayDT: new Date().toISOString(),
127+
displayName: 'Test Item',
128+
archiveNbr: '123',
129+
folder_linkId: '456',
130+
type: '',
131+
isFolder: false,
132+
isRecord: false,
133+
dataStatus: 0,
134+
isFetching: false,
135+
update: jasmine.createSpy(),
136+
fetched: Promise.resolve(true),
137+
} as any;
138+
139+
component.folderView = '' as any;
140+
fixture.detectChanges();
141+
});
142+
143+
it('should create', () => {
144+
expect(component).toBeTruthy();
145+
});
146+
147+
it('should register and unregister item', async () => {
148+
await component.ngOnInit();
149+
150+
expect(TestBed.inject(DataService).registerItem).toHaveBeenCalled();
151+
component.ngOnDestroy();
152+
153+
expect(TestBed.inject(DataService).unregisterItem).toHaveBeenCalledWith(
154+
component.item,
155+
);
156+
});
157+
158+
it('should handle drag events', () => {
159+
const dragEvent = {
160+
type: 'start',
161+
srcComponent: {},
162+
targetTypes: ['folder'],
163+
} as any;
164+
component.item.isFolder = true;
165+
component.onDragServiceEvent(dragEvent);
166+
167+
expect(component.isDragTarget).toBeTrue();
168+
});
169+
170+
it('should handle drop and confirm move', async () => {
171+
await component.onDrop({} as any);
172+
173+
expect(editService.moveItems).toHaveBeenCalled();
174+
});
175+
176+
it('should reject drop and show error', async () => {
177+
editService.moveItems = jasmine
178+
.createSpy()
179+
.and.returnValue(Promise.reject({ getMessage: () => 'Error' }));
180+
await component.onDrop({} as any).catch(() => {
181+
expect(TestBed.inject(MessageService).showError).toHaveBeenCalledWith({
182+
message: 'Error occurred',
183+
});
184+
});
185+
});
186+
187+
it('should preview unlisted record', () => {
188+
component.isUnlistedShare = true;
189+
component.item.isFolder = false;
190+
spyOn(component, 'goToItem');
191+
component.showUnlistedPreview();
192+
193+
expect(component.goToItem).toHaveBeenCalled();
194+
});
195+
196+
it('should emit itemClicked on mobile or non-selectable', () => {
197+
component.isUnlistedShare = false;
198+
component.canSelect = false;
199+
mockDeviceService.isMobileWidth.and.returnValue(true);
200+
spyOn(component.itemClicked, 'emit');
201+
spyOn(component, 'goToItem');
202+
component.onItemClick(new MouseEvent('click'));
203+
204+
expect(component.goToItem).toHaveBeenCalled();
205+
expect(component.itemClicked.emit).toHaveBeenCalled();
206+
});
207+
208+
it('should handle double click and clear timeout', () => {
209+
(component as any).singleClickTimeout = setTimeout(() => {}, 100);
210+
spyOn(component, 'goToItem');
211+
component.onItemDoubleClick();
212+
213+
expect((component as any).singleClickTimeout).toBeNull();
214+
expect(component.goToItem).toHaveBeenCalled();
215+
});
216+
217+
it('should emit itemClicked on single click', (done) => {
218+
spyOn(component.itemClicked, 'emit');
219+
component.onItemSingleClick(new MouseEvent('click'));
220+
setTimeout(() => {
221+
expect(component.itemClicked.emit).toHaveBeenCalled();
222+
done();
223+
}, 150);
224+
});
225+
226+
it('should handle touch click', () => {
227+
const mockTouch = { clientX: 100, clientY: 100 };
228+
const touchStartEvent = { touches: { item: () => mockTouch } };
229+
const touchEndEvent = {
230+
changedTouches: { item: () => mockTouch },
231+
preventDefault: () => {},
232+
target: {
233+
classList: {
234+
contains: () => false,
235+
},
236+
},
237+
};
238+
spyOn(component, 'onItemClick');
239+
component.onItemTouchStart(touchStartEvent);
240+
component.onItemTouchEnd(touchEndEvent as any);
241+
242+
expect(component.onItemClick).toHaveBeenCalled();
243+
});
244+
245+
it('should prompt for update and save changes', async () => {
246+
await component.promptForUpdate();
247+
248+
expect(component.item.update).toHaveBeenCalled();
249+
expect(editService.updateItems).toHaveBeenCalled();
250+
});
251+
252+
it('should resolve update if no changes', () => {
253+
const deferred = new Deferred();
254+
component.item.displayName = 'Same';
255+
component.saveUpdates({ displayName: 'Same' }, deferred);
256+
deferred.promise.then(() => {
257+
expect(component.item.update).not.toHaveBeenCalled();
258+
});
259+
});
260+
261+
it('should reject update and restore original data', async () => {
262+
const deferred = new Deferred();
263+
editService.updateItems = jasmine
264+
.createSpy()
265+
.and.returnValue(Promise.reject({ getMessage: () => 'Error' }));
266+
await component.saveUpdates({ displayName: 'New' }, deferred).catch(() => {
267+
expect(component.item.update).toHaveBeenCalledWith({
268+
displayName: 'Test Item',
269+
});
270+
271+
expect(TestBed.inject(MessageService).showError).toHaveBeenCalled();
272+
});
273+
});
274+
275+
it('should update multi-select status', () => {
276+
component.isMultiSelected = true;
277+
component.onMultiSelectChange();
278+
279+
expect(
280+
TestBed.inject(DataService).setItemMultiSelectStatus,
281+
).toHaveBeenCalledWith(component.item, true);
282+
});
283+
284+
it('should emit itemVisible on intersection', () => {
285+
spyOn(component.itemVisible, 'emit');
286+
component.onIntersection({ target: {} as Element, visible: true });
287+
288+
expect(component.itemVisible.emit).toHaveBeenCalled();
289+
});
290+
291+
it('should toggle hover flags', () => {
292+
component.onMouseOverName();
293+
294+
expect(component.isNameHovered).toBeTrue();
295+
component.onMouseLeaveName();
296+
297+
expect(component.isNameHovered).toBeFalse();
298+
});
299+
});

src/app/file-browser/components/file-list-item/file-list-item.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ export class FileListItemComponent
204204
public canEdit = true;
205205
public isZip = false;
206206
public date: string = '';
207+
public isUnlistedShare = false;
207208

208209
private folderThumb200: string;
209210
private folderThumb500: string;
@@ -221,7 +222,6 @@ export class FileListItemComponent
221222
private mouseDownDragTimeout: ReturnType<typeof setTimeout>;
222223
private waitingForDoubleClick = false;
223224
private touchStartEvent: TouchEvent;
224-
private isUnlistedShare = false;
225225

226226
subscriptions: Subscription[] = [];
227227

0 commit comments

Comments
 (0)