Skip to content

Commit 073b901

Browse files
authored
Merge pull request #374 from parthlambdatest/Dot-6247_2
[Dot-6247] update find selector logic
2 parents 7bfe56c + 99480f0 commit 073b901

File tree

4 files changed

+108
-52
lines changed

4 files changed

+108
-52
lines changed

src/lib/ctx.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ export default (options: Record<string, string>): Context => {
200200
isSnapshotCaptured: false,
201201
sessionCapabilitiesMap: new Map<string, any[]>(),
202202
buildToSnapshotCountMap: new Map<string, number>(),
203+
sessionIdToSnapshotNameMap: new Map<string, string[]>(),
203204
fetchResultsForBuild: new Array<string>,
204205
orgId: 0,
205206
userId: 0,

src/lib/processSnapshot.ts

Lines changed: 87 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -501,19 +501,19 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
501501
for (const [key, value] of Object.entries(options[ignoreOrSelectDOM])) {
502502
switch (key) {
503503
case 'id':
504-
selectors.push(...value.map(e => '#' + e));
504+
selectors.push(...value.map(e => e.startsWith('#') ? e : '#' + e));
505505
break;
506506
case 'class':
507-
selectors.push(...value.map(e => '.' + e));
507+
selectors.push(...value.map(e => e.startsWith('.') ? e : '.' + e));
508508
break;
509509
case 'xpath':
510-
selectors.push(...value.map(e => 'xpath=' + e));
510+
selectors.push(...value.map(e => e.startsWith('xpath=') ? e : 'xpath=' + e));
511511
break;
512512
case 'cssSelector':
513513
selectors.push(...value);
514514
break;
515515
case 'coordinates':
516-
selectors.push(...value.map(e => `coordinates=${e}`));
516+
selectors.push(...value.map(e =>`coordinates=${e}`));
517517
break;
518518
}
519519
}
@@ -648,14 +648,7 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
648648
}
649649

650650
// snapshot options
651-
if (processedOptions.element) {
652-
let l = await page.locator(processedOptions.element).all()
653-
if (l.length === 0) {
654-
throw new Error(`for snapshot ${snapshot.name} viewport ${viewportString}, no element found for selector ${processedOptions.element}`);
655-
} else if (l.length > 1) {
656-
throw new Error(`for snapshot ${snapshot.name} viewport ${viewportString}, multiple elements found for selector ${processedOptions.element}`);
657-
}
658-
} else if (selectors.length) {
651+
if (selectors.length) {
659652
let height = 0;
660653
height = await page.evaluate(() => {
661654
const DEFAULT_HEIGHT = 16384;
@@ -707,52 +700,96 @@ export default async function processSnapshot(snapshot: Snapshot, ctx: Context):
707700
optionWarnings.add(`for snapshot ${snapshot.name} viewport ${viewportString}, coordinates may not be accurate for multiple viewports`);
708701
}
709702

710-
703+
711704
const coordinateElement = {
712705
type: 'coordinates',
713706
...validation.coords
714707
};
715708
locators.push(coordinateElement as any);
716709
continue;
717-
}
718-
719-
let l = await page.locator(selector).all()
720-
if (l.length === 0) {
721-
optionWarnings.add(`for snapshot ${snapshot.name} viewport ${viewportString}, no element found for selector ${selector}`);
722-
continue;
723-
}
724-
locators.push(...l);
725-
}
726710

727-
for (const locator of locators) {
728-
if (locator && typeof locator === 'object' && locator.hasOwnProperty('type') && (locator as any).type === 'coordinates') {
729-
const coordLocator = locator as any;
730-
const { top, bottom, left, right } = coordLocator;
731-
processedOptions[ignoreOrSelectBoxes][viewportString].push({
732-
left: left,
733-
top: top,
734-
right: right,
735-
bottom: bottom
736-
});
737-
continue;
738-
}
739-
740-
let bb = await locator.boundingBox();
741-
if (bb) {
742-
// Calculate top and bottom from the bounding box properties
743-
const top = bb.y;
744-
const bottom = bb.y + bb.height;
745-
746-
// Only push if top and bottom are within the calculated height
747-
if (top <= height && bottom <= height) {
748-
processedOptions[ignoreOrSelectBoxes][viewportString].push({
749-
left: bb.x,
750-
top: top,
751-
right: bb.x + bb.width,
752-
bottom: bottom
753-
});
711+
} else {
712+
const isXPath = selector.startsWith('xpath=');
713+
const selectorValue = isXPath ? selector.substring(6) : selector;
714+
715+
const boxes = await page.evaluate(({ selectorValue, isXPath }) => {
716+
try {
717+
// First, determine the page height
718+
const DEFAULT_HEIGHT = 16384;
719+
const DEFAULT_WIDTH = 7680;
720+
const body = document.body;
721+
const html = document.documentElement;
722+
723+
let pageHeight;
724+
let pageWidth;
725+
726+
if (!body || !html) {
727+
pageHeight = DEFAULT_HEIGHT;
728+
pageWidth = DEFAULT_WIDTH;
729+
} else {
730+
const measurements = [
731+
body?.scrollHeight || 0,
732+
body?.offsetHeight || 0,
733+
html?.clientHeight || 0,
734+
html?.scrollHeight || 0,
735+
html?.offsetHeight || 0
736+
];
737+
738+
const allMeasurementsInvalid = measurements.every(measurement => !measurement);
739+
740+
if (allMeasurementsInvalid) {
741+
pageHeight = DEFAULT_HEIGHT;
742+
} else {
743+
pageHeight = Math.max(...measurements);
744+
}
745+
746+
const measurementsWidth = [
747+
body?.scrollWidth || 0,
748+
body?.offsetWidth || 0,
749+
html?.clientWidth || 0,
750+
html?.scrollWidth || 0,
751+
html?.offsetWidth || 0
752+
];
753+
754+
const allMeasurementsInvalidWidth = measurementsWidth.every(measurement => !measurement);
755+
756+
if (allMeasurementsInvalidWidth) {
757+
pageWidth = DEFAULT_WIDTH;
758+
} else {
759+
pageWidth = Math.max(...measurementsWidth);
760+
}
761+
}
762+
763+
let elements = [];
764+
765+
if (isXPath) {
766+
// Use XPath evaluation
767+
const xpathResult = document.evaluate(
768+
selectorValue,
769+
document,
770+
null,
771+
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
772+
null
773+
);
774+
775+
for (let i = 0; i < xpathResult.snapshotLength; i++) {
776+
elements.push(xpathResult.snapshotItem(i));
777+
}
778+
} else {
779+
elements = Array.from(document.querySelectorAll(selectorValue));
780+
}
781+
782+
return elements;
783+
784+
} catch (error) {
785+
}
786+
787+
}, { selectorValue, isXPath });
788+
789+
if (boxes && boxes.length >= 1) {
790+
processedOptions[ignoreOrSelectBoxes][viewportString].push(...boxes);
754791
} else {
755-
ctx.log.debug(`Bounding box for selector skipped due to exceeding height: ${JSON.stringify({ top, bottom, height })}`);
792+
optionWarnings.add(`for snapshot ${snapshot.name} viewport ${viewportString}, no element found for selector ${selector}`);
756793
}
757794
}
758795
}

src/lib/snapshotQueue.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,25 @@ export default class Queue {
291291
}
292292

293293
if (!this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name) && !this.ctx.config.allowDuplicateSnapshotNames) {
294-
drop = true;
295-
this.ctx.log.info(`Skipping duplicate SmartUI snapshot '${snapshot.name}'. To capture duplicate screenshots, please set the 'allowDuplicateSnapshotNames' or 'delayedUpload' configuration as true in your config file.`);
294+
// check if sessionIdToSnapshotNameMap has snapshot name for the sessionId
295+
if (this.ctx.sessionIdToSnapshotNameMap && snapshot.options && snapshot.options.sessionId) {
296+
if (this.ctx.sessionIdToSnapshotNameMap.has(snapshot.options.sessionId)) {
297+
console.log(`snapshot.options.sessionId`,snapshot.options.sessionId, `this.ctx.sessionIdToSnapshotNameMap`,JSON.stringify([...this.ctx.sessionIdToSnapshotNameMap]));
298+
const existingNames = this.ctx.sessionIdToSnapshotNameMap.get(snapshot.options.sessionId) || [];
299+
if (existingNames.includes(snapshot.name)) {
300+
drop = true;
301+
this.ctx.log.info(`Skipping123 duplicate SmartUI snapshot '${snapshot.name}'. To capture duplicate screenshots, please set the 'allowDuplicateSnapshotNames' or 'delayedUpload' configuration as true in your config file.`);
302+
} else {
303+
existingNames.push(snapshot.name);
304+
this.ctx.sessionIdToSnapshotNameMap.set(snapshot.options.sessionId, existingNames);
305+
}
306+
} else {
307+
this.ctx.sessionIdToSnapshotNameMap.set(snapshot.options.sessionId, [snapshot.name]);
308+
}
309+
} else {
310+
drop = true;
311+
this.ctx.log.info(`Skipping duplicate SmartUI snapshot '${snapshot.name}'. To capture duplicate screenshots, please set the 'allowDuplicateSnapshotNames' or 'delayedUpload' configuration as true in your config file.`);
312+
}
296313
}
297314

298315
if (this.ctx.config.delayedUpload && snapshot && snapshot.name && this.snapshotNames.includes(snapshot.name)) {

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export interface Context {
8282
sessionCapabilitiesMap?: Map<string, any[]>;
8383
buildToSnapshotCountMap?: Map<string, number>;
8484
fetchResultsForBuild?: Array<string>;
85+
sessionIdToSnapshotNameMap?: Map<string, string[]>;
8586
orgId?: number;
8687
userId?: number;
8788
mergeBranchSource?: string;

0 commit comments

Comments
 (0)