Skip to content

Commit 1e5a10f

Browse files
Bifuracted code to handle android and ios selectors seperately
1 parent 6edf68d commit 1e5a10f

File tree

2 files changed

+211
-29
lines changed

2 files changed

+211
-29
lines changed

percy/providers/genericProvider.js

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,24 @@ class GenericProvider {
245245
async getRegionsByElements(elementsArray, elements) {
246246
for (let index = 0; index < elements.length; index++) {
247247
try {
248-
const selector = `element: ${index}`;
249-
250-
const ignoredRegion = await this.getRegionObject(selector, elements[index]);
248+
let identifier;
249+
const element = elements[index];
250+
251+
const capabilities = await this.driver.getCapabilities();
252+
const platformName = (capabilities.platformName || '').toLowerCase();
253+
254+
if (platformName === 'android') {
255+
// Android identifiers
256+
identifier = await element.getAttribute('resource-id') ||
257+
await element.getAttribute('class');
258+
} else if(platformName === 'ios') {
259+
// iOS identifiers
260+
identifier = await element.getAttribute('name') ||
261+
await element.getAttribute('type');
262+
}
263+
264+
const selector = `element: ${index} ${identifier ? `${identifier}` : ''}`.trim();
265+
const ignoredRegion = await this.getRegionObject(selector, element);
251266
elementsArray.push(ignoredRegion);
252267
} catch (e) {
253268
log.info(`Correct Mobile Element not passed at index ${index}.`);

test/percy/providers/genericProvider.test.mjs

Lines changed: 193 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -152,22 +152,43 @@ describe('GenericProvider', () => {
152152
describe('getRegionsByElements', () => {
153153
let getRegionObjectSpy;
154154
let mockElement;
155+
let mockDriver;
155156

156157
beforeEach(() => {
157158
getRegionObjectSpy = spyOn(provider, 'getRegionObject').and.resolveTo({});
158-
mockElement = {
159-
getAttribute: jasmine.createSpy().and.returnValue('some-class')
159+
mockDriver = {
160+
getCapabilities: jasmine.createSpy('getCapabilities')
160161
};
161162
});
162163

163164
it('should get regions for each element', async () => {
165+
// Set up mock driver with platform capability
166+
mockDriver.getCapabilities.and.resolveTo({ platformName: 'android' });
167+
164168
const elementsArray = [];
169+
mockElement = {
170+
getAttribute: jasmine.createSpy('getAttribute')
171+
.and.callFake(attr => {
172+
if (attr === 'resource-id') return 'test_id';
173+
if (attr === 'class') return 'android.widget.Button';
174+
return null;
175+
})
176+
};
165177
const elements = [mockElement, mockElement, mockElement];
166178

167-
await provider.getRegionsByElements.call({ driver, getRegionObject: getRegionObjectSpy }, elementsArray, elements);
179+
await provider.getRegionsByElements.call(
180+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
181+
elementsArray,
182+
elements
183+
);
168184

169185
expect(getRegionObjectSpy).toHaveBeenCalledTimes(3);
170186
expect(elementsArray).toEqual([{}, {}, {}]);
187+
188+
// Verify each call had correct selector
189+
for (let i = 0; i < 3; i++) {
190+
expect(getRegionObjectSpy.calls.argsFor(i)[0]).toBe(`element: ${i} test_id`);
191+
}
171192
});
172193

173194
it('should ignore when error', async () => {
@@ -181,33 +202,179 @@ describe('GenericProvider', () => {
181202
expect(elementsArray).toEqual([]);
182203
});
183204

184-
it('should add regions for valid elements', async () => {
185-
const elementsArray = [];
186-
const mockElements = [
187-
{
188-
getRect: jasmine.createSpy().and.resolveTo({ x: 10, y: 20, width: 100, height: 50 })
189-
},
190-
{
191-
getRect: jasmine.createSpy().and.resolveTo({ x: 30, y: 40, width: 200, height: 60 })
192-
}
193-
];
205+
describe('Platform specific tests', () => {
206+
it('should handle unknown platform', async () => {
207+
mockDriver.getCapabilities.and.resolveTo({ platformName: 'unknown' });
208+
const elementsArray = [];
209+
mockElement = {
210+
getAttribute: jasmine.createSpy('getAttribute')
211+
.and.returnValue('some-value')
212+
};
213+
214+
await provider.getRegionsByElements.call(
215+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
216+
elementsArray,
217+
[mockElement]
218+
);
219+
220+
expect(getRegionObjectSpy).toHaveBeenCalledTimes(1);
221+
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0');
222+
expect(elementsArray).toEqual([{}]);
223+
});
194224

195-
await provider.getRegionsByElements.call({ driver, getRegionObject: getRegionObjectSpy }, elementsArray, mockElements);
225+
it('should handle missing platformName in capabilities', async () => {
226+
mockDriver.getCapabilities.and.resolveTo({});
227+
const elementsArray = [];
228+
mockElement = {
229+
getAttribute: jasmine.createSpy('getAttribute')
230+
.and.returnValue('some-value')
231+
};
232+
233+
await provider.getRegionsByElements.call(
234+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
235+
elementsArray,
236+
[mockElement]
237+
);
238+
239+
expect(getRegionObjectSpy).toHaveBeenCalledTimes(1);
240+
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0');
241+
expect(elementsArray).toEqual([{}]);
242+
});
243+
describe('Android', () => {
244+
beforeEach(() => {
245+
mockDriver.getCapabilities.and.resolveTo({ platformName: 'android' });
246+
});
247+
248+
it('should use resource-id as primary identifier', async () => {
249+
const elementsArray = [];
250+
mockElement = {
251+
getAttribute: jasmine.createSpy('getAttribute')
252+
.and.callFake(attr => {
253+
if (attr === 'resource-id') return 'test_resource_id';
254+
if (attr === 'class') return 'android.widget.Button';
255+
return null;
256+
})
257+
};
258+
259+
await provider.getRegionsByElements.call(
260+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
261+
elementsArray,
262+
[mockElement]
263+
);
264+
265+
expect(getRegionObjectSpy).toHaveBeenCalledTimes(1);
266+
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0 test_resource_id');
267+
expect(elementsArray).toEqual([{}]);
268+
});
269+
270+
it('should fallback to class when resource-id is not available', async () => {
271+
const elementsArray = [];
272+
mockElement = {
273+
getAttribute: jasmine.createSpy('getAttribute')
274+
.and.callFake(attr => {
275+
if (attr === 'resource-id') return null;
276+
if (attr === 'class') return 'android.widget.Button';
277+
return null;
278+
})
279+
};
280+
281+
await provider.getRegionsByElements.call(
282+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
283+
elementsArray,
284+
[mockElement]
285+
);
286+
287+
expect(getRegionObjectSpy).toHaveBeenCalledTimes(1);
288+
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0 android.widget.Button');
289+
expect(elementsArray).toEqual([{}]);
290+
});
291+
});
196292

197-
expect(getRegionObjectSpy).toHaveBeenCalledTimes(2);
198-
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0');
199-
expect(getRegionObjectSpy.calls.argsFor(1)[0]).toBe('element: 1');
200-
expect(elementsArray).toEqual([{}, {}]);
293+
describe('iOS', () => {
294+
beforeEach(() => {
295+
mockDriver.getCapabilities.and.resolveTo({ platformName: 'ios' });
296+
});
297+
298+
it('should use name as primary identifier', async () => {
299+
const elementsArray = [];
300+
mockElement = {
301+
getAttribute: jasmine.createSpy('getAttribute')
302+
.and.callFake(attr => {
303+
if (attr === 'name') return 'TestButton';
304+
if (attr === 'type') return 'XCUIElementTypeButton';
305+
return null;
306+
})
307+
};
308+
309+
await provider.getRegionsByElements.call(
310+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
311+
elementsArray,
312+
[mockElement]
313+
);
314+
315+
expect(getRegionObjectSpy).toHaveBeenCalledTimes(1);
316+
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0 TestButton');
317+
expect(elementsArray).toEqual([{}]);
318+
});
319+
320+
it('should fallback to type when name is not available', async () => {
321+
const elementsArray = [];
322+
mockElement = {
323+
getAttribute: jasmine.createSpy('getAttribute')
324+
.and.callFake(attr => {
325+
if (attr === 'name') return null;
326+
if (attr === 'type') return 'XCUIElementTypeButton';
327+
return null;
328+
})
329+
};
330+
331+
await provider.getRegionsByElements.call(
332+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
333+
elementsArray,
334+
[mockElement]
335+
);
336+
337+
expect(getRegionObjectSpy).toHaveBeenCalledTimes(1);
338+
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0 XCUIElementTypeButton');
339+
expect(elementsArray).toEqual([{}]);
340+
});
341+
});
201342
});
202343

203-
it('should handle empty elements array', async () => {
204-
const elementsArray = [];
205-
const mockElements = [];
206-
207-
await provider.getRegionsByElements.call({ driver, getRegionObject: getRegionObjectSpy }, elementsArray, mockElements);
208-
209-
expect(getRegionObjectSpy).not.toHaveBeenCalled();
210-
expect(elementsArray).toEqual([]);
344+
describe('Error handling', () => {
345+
it('should handle elements with no identifiers', async () => {
346+
mockDriver.getCapabilities.and.resolveTo({ platformName: 'android' });
347+
const elementsArray = [];
348+
mockElement = {
349+
getAttribute: jasmine.createSpy('getAttribute').and.returnValue(null)
350+
};
351+
352+
await provider.getRegionsByElements.call(
353+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
354+
elementsArray,
355+
[mockElement]
356+
);
357+
358+
expect(getRegionObjectSpy).toHaveBeenCalledTimes(1);
359+
expect(getRegionObjectSpy.calls.argsFor(0)[0]).toBe('element: 0');
360+
expect(elementsArray).toEqual([{}]);
361+
});
362+
363+
it('should handle capability errors', async () => {
364+
mockDriver.getCapabilities.and.rejectWith(new Error('Capabilities not found'));
365+
const elementsArray = [];
366+
mockElement = {
367+
getAttribute: jasmine.createSpy('getAttribute')
368+
};
369+
370+
await provider.getRegionsByElements.call(
371+
{ driver: mockDriver, getRegionObject: getRegionObjectSpy },
372+
elementsArray,
373+
[mockElement]
374+
);
375+
376+
expect(elementsArray).toEqual([]);
377+
});
211378
});
212379
});
213380

0 commit comments

Comments
 (0)