Skip to content

Commit cd31559

Browse files
authored
ENG-9720 | fix(addons): Fix GitLab pagination Load More button not showing (#847)
1 parent bf56c47 commit cd31559

2 files changed

Lines changed: 107 additions & 2 deletions

File tree

src/app/shared/components/addons/storage-item-selector/storage-item-selector.component.spec.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { MockComponents, MockProvider } from 'ng-mocks';
22

33
import { DialogService } from 'primeng/dynamicdialog';
44

5+
import { signal, WritableSignal } from '@angular/core';
56
import { ComponentFixture, TestBed } from '@angular/core/testing';
67

78
import { OperationNames } from '@shared/enums/operation-names.enum';
9+
import { OperationInvocation } from '@shared/models/addons/operation-invocation.model';
810
import { AddonsSelectors } from '@shared/stores/addons';
911

1012
import { GoogleFilePickerComponent } from '../../google-file-picker/google-file-picker.component';
@@ -20,9 +22,11 @@ describe('StorageItemSelectorComponent', () => {
2022
let component: StorageItemSelectorComponent;
2123
let fixture: ComponentFixture<StorageItemSelectorComponent>;
2224
let mockDialogService: ReturnType<DialogServiceMockBuilder['build']>;
25+
let mockOperationInvocation: WritableSignal<OperationInvocation | null>;
2326

2427
beforeEach(async () => {
2528
mockDialogService = DialogServiceMockBuilder.create().withOpenMock().build();
29+
mockOperationInvocation = signal<OperationInvocation | null>(null);
2630

2731
await TestBed.configureTestingModule({
2832
imports: [
@@ -45,6 +49,10 @@ describe('StorageItemSelectorComponent', () => {
4549
selector: AddonsSelectors.getCreatedOrUpdatedConfiguredAddonSubmitting,
4650
value: false,
4751
},
52+
{
53+
selector: AddonsSelectors.getOperationInvocation,
54+
value: mockOperationInvocation,
55+
},
4856
],
4957
}),
5058
MockProvider(DialogService, mockDialogService),
@@ -53,6 +61,10 @@ describe('StorageItemSelectorComponent', () => {
5361

5462
fixture = TestBed.createComponent(StorageItemSelectorComponent);
5563
component = fixture.componentInstance;
64+
fixture.componentRef.setInput('isGoogleFilePicker', false);
65+
fixture.componentRef.setInput('accountName', 'test-account');
66+
fixture.componentRef.setInput('accountId', 'test-id');
67+
fixture.componentRef.setInput('operationInvocationResult', []);
5668
});
5769

5870
it('should create', () => {
@@ -115,4 +127,97 @@ describe('StorageItemSelectorComponent', () => {
115127
expect(breadcrumbs[0].id).toBe(itemId);
116128
expect(breadcrumbs[0].label).toBe(itemName);
117129
});
130+
131+
describe('showLoadMoreButton', () => {
132+
it('should return false when operationInvocation is null', () => {
133+
mockOperationInvocation.set(null);
134+
fixture.detectChanges();
135+
136+
expect(component.showLoadMoreButton()).toBe(false);
137+
});
138+
139+
it('should return false when nextSampleCursor is not present', () => {
140+
mockOperationInvocation.set({
141+
id: 'test-id',
142+
type: 'operation-invocation',
143+
invocationStatus: 'success',
144+
operationName: 'list_root_items',
145+
operationKwargs: {},
146+
operationResult: [],
147+
itemCount: 10,
148+
thisSampleCursor: 'cursor-1',
149+
});
150+
fixture.detectChanges();
151+
152+
expect(component.showLoadMoreButton()).toBe(false);
153+
});
154+
155+
it('should return true when nextSampleCursor differs from thisSampleCursor', () => {
156+
mockOperationInvocation.set({
157+
id: 'test-id',
158+
type: 'operation-invocation',
159+
invocationStatus: 'success',
160+
operationName: 'list_root_items',
161+
operationKwargs: {},
162+
operationResult: [],
163+
itemCount: 20,
164+
thisSampleCursor: 'cursor-1',
165+
nextSampleCursor: 'cursor-2',
166+
});
167+
fixture.detectChanges();
168+
169+
expect(component.showLoadMoreButton()).toBe(true);
170+
});
171+
172+
it('should return true for opaque/base64 cursors like GitLab uses', () => {
173+
// GitLab uses base64-encoded cursors where lexicographic comparison doesn't work
174+
mockOperationInvocation.set({
175+
id: 'test-id',
176+
type: 'operation-invocation',
177+
invocationStatus: 'success',
178+
operationName: 'list_root_items',
179+
operationKwargs: {},
180+
operationResult: [],
181+
itemCount: 20,
182+
thisSampleCursor: 'eyJpZCI6MTIzfQ==',
183+
nextSampleCursor: 'eyJpZCI6MTQ1fQ==',
184+
});
185+
fixture.detectChanges();
186+
187+
expect(component.showLoadMoreButton()).toBe(true);
188+
});
189+
190+
it('should return false when nextSampleCursor equals thisSampleCursor', () => {
191+
mockOperationInvocation.set({
192+
id: 'test-id',
193+
type: 'operation-invocation',
194+
invocationStatus: 'success',
195+
operationName: 'list_root_items',
196+
operationKwargs: {},
197+
operationResult: [],
198+
itemCount: 10,
199+
thisSampleCursor: 'cursor-1',
200+
nextSampleCursor: 'cursor-1',
201+
});
202+
fixture.detectChanges();
203+
204+
expect(component.showLoadMoreButton()).toBe(false);
205+
});
206+
207+
it('should return true when nextSampleCursor exists but thisSampleCursor is undefined', () => {
208+
mockOperationInvocation.set({
209+
id: 'test-id',
210+
type: 'operation-invocation',
211+
invocationStatus: 'success',
212+
operationName: 'list_root_items',
213+
operationKwargs: {},
214+
operationResult: [],
215+
itemCount: 20,
216+
nextSampleCursor: 'cursor-2',
217+
});
218+
fixture.detectChanges();
219+
220+
expect(component.showLoadMoreButton()).toBe(true);
221+
});
222+
});
118223
});

src/app/shared/components/addons/storage-item-selector/storage-item-selector.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,10 @@ export class StorageItemSelectorComponent implements OnInit {
199199

200200
readonly showLoadMoreButton = computed(() => {
201201
const invocation = this.operationInvocation();
202-
if (!invocation?.nextSampleCursor || !invocation?.thisSampleCursor) {
202+
if (!invocation?.nextSampleCursor) {
203203
return false;
204204
}
205-
return invocation.nextSampleCursor > invocation.thisSampleCursor;
205+
return invocation.nextSampleCursor !== invocation.thisSampleCursor;
206206
});
207207

208208
handleCreateOperationInvocation(

0 commit comments

Comments
 (0)