Skip to content

Commit

Permalink
wdio - ignore selectors (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
paweltomaszewskisaucelabs authored Nov 14, 2024
1 parent eef0989 commit 7a88f8d
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 35 deletions.
6 changes: 6 additions & 0 deletions visual-js/.changeset/curvy-foxes-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@saucelabs/wdio-sauce-visual-service": patch
"@saucelabs/visual": patch
---

add ignore region selectors for appium native fullpage
32 changes: 22 additions & 10 deletions visual-js/visual-wdio/src/SauceVisualService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import {
VisualApi,
WebdriverSession,
getVisualResults,
isIgnoreSelectorType,
IgnoreSelectorIn,
} from '@saucelabs/visual';

import logger from '@wdio/logger';
Expand Down Expand Up @@ -114,6 +116,11 @@ type CucumberWorld = {
export type CheckOptions = {
ignore?: Array<Ignorable>;

/**
* XPath selectors to ignore changes (available only with full-page screenshots and mobile native apps).
*/
ignoreSelectors?: Array<string>;

regions?: Array<RegionType<Ignorable>>;
/**
* A querySelector compatible selector of an element that we should crop the screenshot to.
Expand Down Expand Up @@ -367,11 +374,12 @@ export default class SauceVisualService implements Services.ServiceInstance {

const resolveIgnorable = async (
element: Ignorable | Promise<RegionIn>,
): Promise<Array<RegionIn | ElementIn>> => {
): Promise<Array<RegionIn | ElementIn | IgnoreSelectorIn>> => {
if (isIgnoreRegion(element)) return [element];

const awaited = await element;
if (isIgnoreRegion(awaited)) return [awaited];
if (isIgnoreSelectorType(awaited)) return [awaited];

const wdioElements = isWdioElement(awaited) ? [awaited] : awaited;

Expand All @@ -381,14 +389,21 @@ export default class SauceVisualService implements Services.ServiceInstance {
}));
};

const { ignoreRegions, ignoreElements } = await parseRegionsForAPI(
[...(options.regions ?? []), ...(options.ignore ?? [])],
resolveIgnorable,
);
const { ignoreRegions, ignoreElements, ignoreSelectors } =
await parseRegionsForAPI(
[...(options.regions ?? []), ...(options.ignore ?? [])],
resolveIgnorable,
);

const sessionId = browser.sessionId;
const jobId = (browser.capabilities as any)['jobUuid'] || sessionId;

const fullPageConfig = await getFullPageConfig<WdioElement>(
this.fullPage,
options.fullPage,
(el) => el.elementId,
);

const clipSelector = options.clipSelector ?? this.clipSelector;
const clipElement = clipSelector
? await browser.$(clipSelector).elementId
Expand All @@ -405,6 +420,7 @@ export default class SauceVisualService implements Services.ServiceInstance {
buildUuid: buildId,
name: name,
ignoreRegions,
ignoreSelectors,
ignoreElements,
diffingOptions: selectiveRegionOptionsToDiffingOptions({
disableOnly: options.disable ?? [],
Expand All @@ -414,11 +430,7 @@ export default class SauceVisualService implements Services.ServiceInstance {
options.diffingMethod || this.diffingMethod || DiffingMethod.Balanced,
suiteName: this.test?.parent,
testName: this.test?.title,
fullPageConfig: await getFullPageConfig<WdioElement>(
this.fullPage,
options.fullPage,
(el) => el.elementId,
),
fullPageConfig,
baselineOverride: options.baselineOverride || this.baselineOverride,
});
uploadedDiffIds.push(...result.diffs.nodes.flatMap((diff) => diff.id));
Expand Down
4 changes: 3 additions & 1 deletion visual-js/visual-wdio/src/guarded-types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { type } from 'arktype';
import {
FullPageScreenshotOptions,
IgnoreSelectorIn,
makeValidate,
RegionIn,
} from '@saucelabs/visual';
Expand Down Expand Up @@ -28,4 +29,5 @@ export type Ignorable =
| WdioElement[]
| Promise<WdioElement>
| Promise<WdioElement[]>
| RegionIn;
| RegionIn
| IgnoreSelectorIn;
59 changes: 55 additions & 4 deletions visual-js/visual/src/graphql/__generated__/graphql.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 45 additions & 12 deletions visual-js/visual/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
DiffStatus,
ElementIn,
FullPageConfigIn,
IgnoreSelectorIn,
InputMaybe,
RegionIn,
SelectorType,
} from './graphql/__generated__/graphql';
import { FullPageScreenshotOptions, RegionType, VisualEnvOpts } from './types';
import { selectiveRegionOptionsToDiffingOptions } from './common/selective-region';
Expand Down Expand Up @@ -85,6 +87,13 @@ const regionType: Type<RegionType<unknown>> = type([
]);
export const isRegionType = (item: unknown): item is RegionType<unknown> =>
typeof item === 'object' && regionType.allows(item);

// arktype has problem to check enums
export const isIgnoreSelectorType = (item: any): item is IgnoreSelectorIn =>
typeof item === 'object' &&
typeof item.selector === 'object' &&
Object.values(SelectorType).includes(item.selector.type) &&
typeof item.selector.value === 'string';
export const validateRegionType = makeValidate(elementIn);

export const getDiffingOptions = <T>(
Expand All @@ -103,24 +112,47 @@ export const getDiffingOptions = <T>(
* @param resolveItem A callback to resolve an element and gather the required data for the API.
*/
export const parseRegionsForAPI = async <T>(
ignore: (T | RegionIn | RegionType<T> | Promise<RegionIn>)[],
ignore: (
| T
| RegionIn
| RegionType<T>
| Promise<RegionIn>
| IgnoreSelectorIn
)[],
resolveItem: (
item: T | Promise<RegionIn>,
) => Promise<(RegionIn | ElementIn)[]>,
) => Promise<(RegionIn | ElementIn | IgnoreSelectorIn)[]>,
): Promise<{
ignoreRegions: RegionIn[];
ignoreElements: ElementIn[];
ignoreSelectors: IgnoreSelectorIn[];
}> => {
const promisedIgnorables: Promise<(RegionIn | ElementIn)[]>[] = ignore.map(
async (itemOrRegion): Promise<Array<RegionIn | ElementIn>> => {
const { item, diffingOptions } = isRegionType(itemOrRegion)
? {
item: itemOrRegion.element,
diffingOptions: getDiffingOptions(itemOrRegion),
}
: { item: itemOrRegion, diffingOptions: undefined };

const elements = isIgnoreRegion(item) ? [item] : await resolveItem(item);
const promisedIgnorables: Promise<
(RegionIn | ElementIn | IgnoreSelectorIn)[]
>[] = ignore.map(
async (
itemOrRegionOrSelector,
): Promise<Array<RegionIn | ElementIn | IgnoreSelectorIn>> => {
const { item, diffingOptions } = (() => {
if (isRegionType(itemOrRegionOrSelector)) {
return {
item: itemOrRegionOrSelector.element,
diffingOptions: getDiffingOptions(itemOrRegionOrSelector),
};
} else if (isIgnoreSelectorType(itemOrRegionOrSelector)) {
return {
item: itemOrRegionOrSelector,
diffingOptions: itemOrRegionOrSelector.diffingOptions,
};
}

return { item: itemOrRegionOrSelector, diffingOptions: undefined };
})();

const elements =
isIgnoreRegion(item) || isIgnoreSelectorType(item)
? [item]
: await resolveItem(item);
return elements.map((element) => ({
...element,
diffingOptions,
Expand All @@ -133,6 +165,7 @@ export const parseRegionsForAPI = async <T>(
return {
ignoreRegions: flattened.filter(isIgnoreRegion),
ignoreElements: flattened.filter(isElementIn),
ignoreSelectors: flattened.filter(isIgnoreSelectorType),
};
};

Expand Down
Loading

0 comments on commit 7a88f8d

Please sign in to comment.