Skip to content

Commit

Permalink
feat: allow to customization stabilization options
Browse files Browse the repository at this point in the history
  • Loading branch information
gregberge committed Oct 27, 2024
1 parent ea3593a commit 073c081
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 36 deletions.
1 change: 0 additions & 1 deletion packages/api-client/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
dts: true,
clean: true,
format: ["esm"],
});
7 changes: 6 additions & 1 deletion packages/browser/src/global/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ import {
teardown,
SetupOptions,
TeardownOptions,
StabilizationOptions,
getStabilityFailureReasons,
} from "./stabilization";
import { getColorScheme, getMediaType } from "./media";

const ArgosGlobal = {
waitForStability: () => waitForStability(document),
waitForStability: (options?: StabilizationOptions) =>
waitForStability(document, options),
getStabilityFailureReasons: (options?: StabilizationOptions) =>
getStabilityFailureReasons(document, options),
setup: (options: SetupOptions = {}) => setup(document, options),
teardown: (options: TeardownOptions = {}) => teardown(document, options),
getColorScheme: () => getColorScheme(window),
Expand Down
68 changes: 61 additions & 7 deletions packages/browser/src/global/stabilization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,14 +255,68 @@ function waitForNoBusy(document: Document) {
return elements.every((element) => !checkIsVisible(element));
}

export type StabilizationOptions = {
/**
* Wait for [aria-busy="true"] elements to be invisible.
* @default true
*/
ariaBusy?: boolean;
/**
* Wait for images to be loaded.
* @default true
*/
images?: boolean;
/**
* Wait for fonts to be loaded.
* @default true
*/
fonts?: boolean;
};

/**
* Get the stabilization state of the document.
*/
function getStabilityState(document: Document, options?: StabilizationOptions) {
const { ariaBusy = true, images = true, fonts = true } = options ?? {};
return {
ariaBusy: ariaBusy ? waitForNoBusy(document) : true,
images: images ? waitForImagesToLoad(document) : true,
fonts: fonts ? waitForFontsToLoad(document) : true,
};
}

const VALIDATION_ERRORS: Record<keyof StabilizationOptions, string> = {
ariaBusy: "Some elements still have `aria-busy='true'`",
images: "Some images are still loading",
fonts: "Some fonts are still loading",
};

/**
* Get the stability failure reasons.
*/
export function getStabilityFailureReasons(
document: Document,
options?: StabilizationOptions,
) {
const stabilityState = getStabilityState(document, options);
return Object.entries(stabilityState).reduce<string[]>(
(reasons, [key, value]) => {
if (!value) {
reasons.push(VALIDATION_ERRORS[key as keyof typeof VALIDATION_ERRORS]);
}
return reasons;
},
[],
);
}

/**
* Wait for the document to be stable.
*/
export function waitForStability(document: Document) {
const results = [
waitForNoBusy(document),
waitForImagesToLoad(document),
waitForFontsToLoad(document),
];
return results.every(Boolean);
export function waitForStability(
document: Document,
options?: StabilizationOptions,
) {
const stabilityState = getStabilityState(document, options);
return Object.values(stabilityState).every(Boolean);
}
1 change: 1 addition & 0 deletions packages/browser/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./viewport";
export * from "./script";
export type { StabilizationOptions } from "./global/stabilization";
1 change: 0 additions & 1 deletion packages/cli/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ import { defineConfig } from "tsup";

export default defineConfig({
entry: ["src/index.ts"],
clean: true,
format: ["esm"],
});
1 change: 0 additions & 1 deletion packages/core/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
dts: true,
clean: true,
format: ["esm"],
});
40 changes: 32 additions & 8 deletions packages/cypress/src/support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "cypress-wait-until";
import {
ArgosGlobal,
resolveViewport,
StabilizationOptions,
type ViewportOption,
} from "@argos-ci/browser";
import { getGlobalScript } from "@argos-ci/browser";
Expand All @@ -21,16 +22,27 @@ type ArgosScreenshotOptions = Partial<
* Viewports to take screenshots of.
*/
viewports?: ViewportOption[];

/**
* Custom CSS evaluated during the screenshot process.
*/
argosCSS?: string;

/**
* Sensitivity threshold between 0 and 1.
* The higher the threshold, the less sensitive the diff will be.
* @default 0.5
*/
threshold?: number;

/**
* Stabilization.
* By default, it waits for the UI to stabilize before taking a screenshot.
* Set to `false` to disable stabilization.
* Pass an object to customize the stabilization process.
* @default true
*/
stabilize?: boolean | StabilizationOptions;
};

declare global {
Expand Down Expand Up @@ -88,7 +100,12 @@ Cypress.Commands.add(
"argosScreenshot",
{ prevSubject: ["optional", "element", "window", "document"] },
(subject, name, options = {}) => {
const { viewports, argosCSS, ...cypressOptions } = options;
const {
viewports,
argosCSS,
stabilize = true,
...cypressOptions
} = options;
if (!name) {
throw new Error("The `name` argument is required.");
}
Expand All @@ -104,13 +121,20 @@ Cypress.Commands.add(
const teardown = setup(options);

function stabilizeAndScreenshot(name: string) {
cy.waitUntil(() =>
cy
.window({ log: false })
.then((window) =>
((window as any).__ARGOS__ as ArgosGlobal).waitForStability(),
),
);
if (stabilize) {
const stabilizationOptions =
typeof stabilize === "object" ? stabilize : {};

cy.waitUntil(() =>
cy
.window({ log: false })
.then((window) =>
((window as any).__ARGOS__ as ArgosGlobal).waitForStability(
stabilizationOptions,
),
),
);
}

let ref: any = {};

Expand Down
2 changes: 0 additions & 2 deletions packages/cypress/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ export default defineConfig([
{
entry: ["src/support.ts"],
dts: true,
clean: true,
format: ["esm"],
},
{
entry: ["src/task.ts"],
dts: true,
clean: true,
format: ["esm", "cjs"],
},
]);
2 changes: 0 additions & 2 deletions packages/gitlab/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ export default defineConfig([
{
entry: ["src/index.ts"],
dts: true,
clean: true,
format: ["esm"],
},
{
entry: ["src/cli.ts"],
dts: false,
clean: true,
format: ["esm"],
},
]);
42 changes: 39 additions & 3 deletions packages/playwright/src/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
resolveViewport,
ArgosGlobal,
getGlobalScript,
StabilizationOptions,
} from "@argos-ci/browser";
import {
getMetadataPath,
Expand Down Expand Up @@ -70,6 +71,15 @@ export type ArgosScreenshotOptions = {
* @default "./screenshots"
*/
root?: string;

/**
* Stabilization.
* By default, it waits for the UI to stabilize before taking a screenshot.
* Set to `false` to disable stabilization.
* Pass an object to customize the stabilization process.
* @default true
*/
stabilize?: boolean | StabilizationOptions;
} & LocatorOptions &
ScreenshotOptions<LocatorScreenshotOptions> &
ScreenshotOptions<PageScreenshotOptions>;
Expand Down Expand Up @@ -196,6 +206,7 @@ export async function argosScreenshot(
hasText,
viewports,
argosCSS,
stabilize = true,
root = DEFAULT_SCREENSHOT_ROOT,
...playwrightOptions
} = options;
Expand Down Expand Up @@ -272,9 +283,34 @@ export async function argosScreenshot(
};

const stabilizeAndScreenshot = async (name: string) => {
await page.waitForFunction(() =>
((window as any).__ARGOS__ as ArgosGlobal).waitForStability(),
);
if (stabilize) {
const stabilizationOptions =
typeof stabilize === "object" ? stabilize : {};
try {
await page.waitForFunction(
(options) =>
((window as any).__ARGOS__ as ArgosGlobal).waitForStability(
options,
),
stabilizationOptions,
);
} catch (error) {
const reasons = await page.evaluate(
(options) =>
(
(window as any).__ARGOS__ as ArgosGlobal
).getStabilityFailureReasons(options),
stabilizationOptions,
);
throw new Error(
`
Failed to stabilize screenshot, found the following issues:
${reasons.map((reason) => `- ${reason}`).join("\n")}
`.trim(),
{ cause: error },
);
}
}

const names = getScreenshotNames(name, testInfo);

Expand Down
2 changes: 0 additions & 2 deletions packages/playwright/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ export default defineConfig([
{
entry: ["src/index.ts"],
dts: true,
clean: true,
external: ["@playwright/test"],
format: ["esm"],
},
{
entry: ["src/reporter.ts"],
dts: true,
clean: true,
format: ["esm"],
},
]);
Loading

0 comments on commit 073c081

Please sign in to comment.