UNPKG

@saucelabs/visual

Version:

JS client bindings for Sauce Labs Visual

325 lines (323 loc) 9.13 kB
import { BaselinesOrderBy, BranchesOrderBy, Browser, BuildByCustomIdDocument, BuildDocument, BuildMode, BuildStatus, BuildStatusDocument, BuildWithDiffsByCustomIdDocument, BuildWithDiffsDocument, BuildsOrderBy, CommentAction, CommentsOrderBy, CreateBuildDocument, CreateSnapshotDocument, CreateSnapshotFromWebDriverDocument, CreateSnapshotUploadDocument, DiffFeedbacksOrderBy, DiffStatus, DiffingMethod, DiffsForTestResultDocument, DiffsOrderBy, DomFormat, FinishBuildDocumentDocument, GroupByOption, MergeBaselinesDocument, OperatingSystem, OrgStatsOrderBy, ProjectsOrderBy, ScrollOption, SelectorType, SnapshotsOrderBy, UpdateDiffDocument, UpdateDiffStatus, VisualApiRegion, WebdriverSessionInfoDocument, displayStatusTable, ensureError, getApi, regions, selectiveRegionOptionsToDiffingOptions, selectiveRegionToRegionIn, selectiveRegionsToRegionIn, selectiveRegionsToRegionInSync } from "./chunk-JCFCNGGA.js"; import "./chunk-3IT7HMR5.js"; // src/utils.ts import { type } from "arktype"; import fs from "fs/promises"; import * as os from "os"; import { backOff } from "exponential-backoff"; var getFullPageConfig = async (main, local, getId) => { const isNoConfig = !main && !local; const isLocalOff = local === false; if (isNoConfig || isLocalOff) { return; } const globalCfg = typeof main === "object" ? main : {}; const localCfg = typeof local === "object" ? local : {}; const { scrollElement, ...rest } = { ...globalCfg, ...localCfg }; const result = rest; if (scrollElement && getId) { result.scrollElement = await getId(await scrollElement); } return result; }; var isSkipMode = () => { const VISUAL_SKIP_ENV_VAR = "SAUCE_VISUAL_SKIP"; return Boolean(process.env[VISUAL_SKIP_ENV_VAR]); }; var makeValidate = (t) => (x) => { const { data, problems } = t(x); if (problems) { throw new Error(problems.toLocaleString()); } return data; }; var ignoreRegionType = type({ width: "integer", height: "integer", x: "integer", y: "integer", "name?": "string | null | undefined" }); var isIgnoreRegion = ignoreRegionType.allows; var validateIgnoreRegion = makeValidate(ignoreRegionType); var elementIn = type({ id: "string", "name?": "string | undefined" }); var isElementIn = elementIn.allows; var validateElementIn = makeValidate(elementIn); var regionType = type([ { element: "unknown", enableOnly: "any" }, "|", { element: "unknown", disableOnly: "any" } ]); var isRegionType = (item) => typeof item === "object" && regionType.allows(item); var isIgnoreSelectorType = (item) => typeof item === "object" && typeof item.selector === "object" && Object.values(SelectorType).includes(item.selector.type) && typeof item.selector.value === "string"; var validateRegionType = makeValidate(elementIn); var getDiffingOptions = (region) => { const { element: __, ...rest } = region; if ("enableOnly" in rest || "disableOnly" in rest) { return selectiveRegionOptionsToDiffingOptions(rest); } return void 0; }; var parseRegionsForAPI = async (ignore, resolveItem) => { const promisedIgnorables = ignore.map( async (itemOrRegionOrSelector) => { 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: void 0 }; })(); const elements = isIgnoreRegion(item) || isIgnoreSelectorType(item) ? [item] : await resolveItem(item); return elements.map((element) => ({ ...element, diffingOptions })); } ); const flattened = (await Promise.all(promisedIgnorables)).flat(); return { ignoreRegions: flattened.filter(isIgnoreRegion), ignoreElements: flattened.filter(isElementIn), ignoreSelectors: flattened.filter(isIgnoreSelectorType) }; }; var domScriptPath = `${os.tmpdir()}/sauce-visual-dom-capture.js`; var downloadDomScript = async (api) => { try { const script = await api.domCaptureScript(); script && await fs.writeFile(domScriptPath, script); } catch (err) { console.error(`Cannot get dom capturing script. ${err}`); } }; var getDomScript = async () => { try { return (await fs.readFile(domScriptPath)).toString(); } catch (err) { if (err.code !== "ENOENT") { console.error(err); } } }; var removeDomScriptFile = async () => { try { await fs.unlink(domScriptPath); } catch (err) { } }; var getEnvOpts = () => { const { SAUCE_USERNAME, SAUCE_ACCESS_KEY, SAUCE_REGION, SAUCE_BUILD_NAME, SAUCE_BRANCH_NAME, SAUCE_DEFAULT_BRANCH_NAME, SAUCE_PROJECT_NAME, SAUCE_VISUAL_BUILD_NAME, SAUCE_VISUAL_PROJECT, SAUCE_VISUAL_BRANCH, SAUCE_VISUAL_DEFAULT_BRANCH, SAUCE_VISUAL_BUILD_ID, SAUCE_VISUAL_CUSTOM_ID } = process.env; if (SAUCE_BUILD_NAME) { console.warn( "Sauce Labs Visual: SAUCE_BUILD_NAME is deprecated and will be removed in a future version. Please use SAUCE_VISUAL_BUILD_NAME instead" ); } if (SAUCE_BRANCH_NAME) { console.warn( "Sauce Labs Visual: SAUCE_BRANCH_NAME is deprecated and will be removed in a future version. Please use SAUCE_VISUAL_BRANCH instead" ); } if (SAUCE_DEFAULT_BRANCH_NAME) { console.warn( "Sauce Labs Visual: SAUCE_DEFAULT_BRANCH_NAME is deprecated and will be removed in a future version. Please use SAUCE_VISUAL_DEFAULT_BRANCH instead" ); } if (SAUCE_PROJECT_NAME) { console.warn( "Sauce Labs Visual: SAUCE_PROJECT_NAME is deprecated and will be removed in a future version. Please use SAUCE_VISUAL_PROJECT instead" ); } return { branch: SAUCE_VISUAL_BRANCH || SAUCE_BRANCH_NAME || null, defaultBranch: SAUCE_VISUAL_DEFAULT_BRANCH || SAUCE_DEFAULT_BRANCH_NAME || null, buildId: SAUCE_VISUAL_BUILD_ID ?? null, project: SAUCE_VISUAL_PROJECT || SAUCE_PROJECT_NAME || null, user: SAUCE_USERNAME ?? void 0, key: SAUCE_ACCESS_KEY ?? void 0, region: SAUCE_REGION ?? "us-west-1", buildName: SAUCE_VISUAL_BUILD_NAME || SAUCE_BUILD_NAME || "Sauce Visual Build", customId: SAUCE_VISUAL_CUSTOM_ID ?? null }; }; var getVisualResults = async (api, filter) => { const { buildId, diffIds } = filter; const initialStatusSummary = { ["APPROVED" /* Approved */]: 0, ["EQUAL" /* Equal */]: 0, ["UNAPPROVED" /* Unapproved */]: 0, ["REJECTED" /* Rejected */]: 0, ["QUEUED" /* Queued */]: 0, ["ERRORED" /* Errored */]: 0 }; if (!buildId) { throw new Error( "No Sauce Visual build present, cannot determine visual results." ); } if (diffIds.length === 0) { return initialStatusSummary; } return await backOff( async () => { const summary = { ...initialStatusSummary }; const diffsForTestResult = await api.diffsForTestResult(buildId); if (!diffsForTestResult) { return summary; } const filterDiffsById = (diff) => diffIds.includes(diff.id); const statusSummary = diffsForTestResult.nodes.filter(filterDiffsById).reduce((statusSummary2, diff) => { statusSummary2[diff.status]++; return statusSummary2; }, summary); if (statusSummary["QUEUED" /* Queued */] > 0) { throw new Error("Some diffs are still in the queued state."); } return statusSummary; }, { maxDelay: 1e4, numOfAttempts: 10 } ); }; export { BaselinesOrderBy, BranchesOrderBy, Browser, BuildByCustomIdDocument, BuildDocument, BuildMode, BuildStatus, BuildStatusDocument, BuildWithDiffsByCustomIdDocument, BuildWithDiffsDocument, BuildsOrderBy, CommentAction, CommentsOrderBy, CreateBuildDocument, CreateSnapshotDocument, CreateSnapshotFromWebDriverDocument, CreateSnapshotUploadDocument, DiffFeedbacksOrderBy, DiffStatus, DiffingMethod, DiffsForTestResultDocument, DiffsOrderBy, DomFormat, FinishBuildDocumentDocument, GroupByOption, MergeBaselinesDocument, OperatingSystem, OrgStatsOrderBy, ProjectsOrderBy, ScrollOption, SelectorType, SnapshotsOrderBy, UpdateDiffDocument, UpdateDiffStatus, VisualApiRegion, WebdriverSessionInfoDocument, displayStatusTable, domScriptPath, downloadDomScript, ensureError, getApi, getDiffingOptions, getDomScript, getEnvOpts, getFullPageConfig, getVisualResults, isElementIn, isIgnoreRegion, isIgnoreSelectorType, isRegionType, isSkipMode, makeValidate, parseRegionsForAPI, regions, removeDomScriptFile, selectiveRegionOptionsToDiffingOptions, selectiveRegionToRegionIn, selectiveRegionsToRegionIn, selectiveRegionsToRegionInSync, validateElementIn, validateIgnoreRegion, validateRegionType };