Skip to content

Commit

Permalink
feat: add argosCSS option to inject custom CSS
Browse files Browse the repository at this point in the history
  • Loading branch information
gregberge committed Dec 13, 2023
1 parent 12e0748 commit 9ab7efd
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 32 deletions.
9 changes: 4 additions & 5 deletions packages/browser/src/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import {
waitForStability,
setup,
teardown,
PrepareForScreenshotOptions,
SetupOptions,
TeardownOptions,
} from "./stabilization";
import { getColorScheme, getMediaType } from "./media";

const ArgosGlobal = {
waitForStability: () => waitForStability(document),
setup: (options: PrepareForScreenshotOptions = {}) =>
setup(document, options),
teardown: (options: PrepareForScreenshotOptions = {}) =>
teardown(document, options),
setup: (options: SetupOptions = {}) => setup(document, options),
teardown: (options: TeardownOptions = {}) => teardown(document, options),
getColorScheme: () => getColorScheme(window),
getMediaType: () => getMediaType(window),
};
Expand Down
32 changes: 22 additions & 10 deletions packages/browser/src/stabilization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,22 @@ export function restoreSpellCheck(document: Document) {
/**
* Inject global styles in the DOM.
*/
export function injectGlobalStyles(document: Document) {
export function injectGlobalStyles(
document: Document,
css: string,
id: string,
) {
const style = document.createElement("style");
style.textContent = GLOBAL_CSS;
style.id = "argos-global-styles";
style.textContent = css;
style.id = id;
document.head.appendChild(style);
}

/**
* Remove global styles from the DOM.
*/
export function removeGlobalStyles(document: Document) {
const style = document.getElementById("argos-global-styles");
export function removeGlobalStyles(document: Document, id: string) {
const style = document.getElementById(id);
if (style) {
style.remove();
}
Expand Down Expand Up @@ -146,30 +150,38 @@ export function restoreElementPositions(document: Document) {
});
}

export type PrepareForScreenshotOptions = { fullPage?: boolean };
export type SetupOptions = { fullPage?: boolean; argosCSS?: string };

/**
* Setup the document for screenshots.
*/
export function setup(
document: Document,
{ fullPage }: PrepareForScreenshotOptions = {},
{ fullPage, argosCSS }: SetupOptions = {},
) {
injectGlobalStyles(document);
injectGlobalStyles(document, GLOBAL_CSS, "argos-reset-style");
if (argosCSS) {
injectGlobalStyles(document, argosCSS, "argos-user-style");
}
disableSpellCheck(document);
if (fullPage) {
stabilizeElementPositions(document);
}
}

export type TeardownOptions = { fullPage?: boolean; argosCSS?: string };

/**
* Restore the document after screenshots.
*/
export function teardown(
document: Document,
{ fullPage }: PrepareForScreenshotOptions = {},
{ fullPage, argosCSS }: SetupOptions = {},
) {
removeGlobalStyles(document);
removeGlobalStyles(document, "argos-reset-style");
if (argosCSS) {
removeGlobalStyles(document, "argos-user-style");
}
restoreSpellCheck(document);
if (fullPage) {
restoreElementPositions(document);
Expand Down
7 changes: 7 additions & 0 deletions packages/cypress/cypress/e2e/argosScreenshot.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,11 @@ describe("argosScreenshot", () => {
cy.readFile(`${screenshotsFolder}/specific-target.png`);
});
});

it("supports argosCSS option", () => {
cy.visit("cypress/pages/index.html");
cy.argosScreenshot("argosCSS-option", {
argosCSS: "body { background: blue; }",
});
});
});
1 change: 1 addition & 0 deletions packages/cypress/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ By default screenshots are stored in `cypress/screenshots` folder, relative to c
- `options`: Explore [cy.screenshot command options](https://docs.cypress.io/api/commands/screenshot) for details.
- `options.element`: Use an ElementHandle or string selector to capture a specific element's screenshot.
- `options.viewports`: Define specific viewports for capturing screenshots. More on [viewports configuration](https://argos-ci.com/docs/viewports).
- `options.argosCSS`: Specific CSS applied during the screenshot process.

## Helper Attributes for Visual Testing

Expand Down
16 changes: 13 additions & 3 deletions packages/cypress/src/support.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ declare global {
argosScreenshot: (
name: string,
options?: Partial<Loggable & Timeoutable & ScreenshotOptions> & {
/**
* Viewports to take screenshots of.
*/
viewports?: ViewportOption[];
/**
* Custom CSS evaluated during the screenshot process.
*/
argosCSS?: string;
},
) => Chainable<null>;
}
Expand Down Expand Up @@ -55,7 +62,7 @@ function readArgosCypressVersion() {
Cypress.Commands.add(
"argosScreenshot",
{ prevSubject: ["optional", "element", "window", "document"] },
(subject, name, { viewports, ...options } = {}) => {
(subject, name, { viewports, argosCSS, ...options } = {}) => {
if (!name) {
throw new Error("The `name` argument is required.");
}
Expand All @@ -71,7 +78,7 @@ Cypress.Commands.add(
const fullPage = !options.capture || options.capture === "fullPage";

cy.window({ log: false }).then((window) =>
((window as any).__ARGOS__ as ArgosGlobal).setup({ fullPage }),
((window as any).__ARGOS__ as ArgosGlobal).setup({ fullPage, argosCSS }),
);

function stabilizeAndScreenshot(name: string) {
Expand Down Expand Up @@ -153,7 +160,10 @@ Cypress.Commands.add(

// Teardown Argos
cy.window({ log: false }).then((window) =>
((window as any).__ARGOS__ as ArgosGlobal).teardown({ fullPage }),
((window as any).__ARGOS__ as ArgosGlobal).teardown({
fullPage,
argosCSS,
}),
);

// Restore the original viewport
Expand Down
1 change: 1 addition & 0 deletions packages/playwright/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ Execute your Playwright tests in the usual manner. Screenshots will be auto-uplo
- `options`: Explore [Page.screenshot command options](https://playwright.dev/docs/api/class-page#page-screenshot) for details.
- `options.element`: Use an ElementHandle or string selector to capture a specific element's screenshot.
- `options.viewports`: Define specific viewports for capturing screenshots. More on [viewports configuration](https://argos-ci.com/docs/viewports).
- `options.argosCSS`: Specific CSS applied during the screenshot process.

### Argos Reporter

Expand Down
8 changes: 8 additions & 0 deletions packages/playwright/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ test.describe("#argosScreenshot", () => {
});
});

test.describe("with argosCSS", () => {
test("works", async () => {
await argosScreenshot(page, "argosCSS-option", {
argosCSS: "body { background: blue; }",
});
});
});

test.describe("with cjs version", () => {
test("works", async () => {
await argosScreenshotCjs(page, "full-page-cjs");
Expand Down
28 changes: 21 additions & 7 deletions packages/playwright/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export type ArgosScreenshotOptions = {
* Viewports to take screenshots of.
*/
viewports?: ViewportOption[];
/**
* Custom CSS evaluated during the screenshot process.
*/
argosCSS?: string;
} & LocatorOptions &
ScreenshotOptions<LocatorScreenshotOptions> &
ScreenshotOptions<PageScreenshotOptions>;
Expand Down Expand Up @@ -75,7 +79,14 @@ function getViewportSize(page: Page) {
export async function argosScreenshot(
page: Page,
name: string,
{ element, has, hasText, viewports, ...options }: ArgosScreenshotOptions = {},
{
element,
has,
hasText,
viewports,
argosCSS,
...options
}: ArgosScreenshotOptions = {},
) {
if (!page) {
throw new Error("A Playwright `page` object is required.");
Expand Down Expand Up @@ -108,9 +119,9 @@ export async function argosScreenshot(
options.fullPage !== undefined ? options.fullPage : handle === page;

await page.evaluate(
({ fullPage }) =>
((window as any).__ARGOS__ as ArgosGlobal).setup({ fullPage }),
{ fullPage },
({ fullPage, argosCSS }) =>
((window as any).__ARGOS__ as ArgosGlobal).setup({ fullPage, argosCSS }),
{ fullPage, argosCSS },
);

async function collectMetadata(
Expand Down Expand Up @@ -215,9 +226,12 @@ export async function argosScreenshot(

// Teardown Argos
await page.evaluate(
({ fullPage }) =>
((window as any).__ARGOS__ as ArgosGlobal).teardown({ fullPage }),
{ fullPage },
({ fullPage, argosCSS }) =>
((window as any).__ARGOS__ as ArgosGlobal).teardown({
fullPage,
argosCSS,
}),
{ fullPage, argosCSS },
);

// Restore the original viewport size
Expand Down
1 change: 1 addition & 0 deletions packages/puppeteer/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Screenshots are stored in `screenshots/argos` folder, relative to current direct
- `options` - See [Page.screenshot command options](https://pptr.dev/next/api/puppeteer.page.screenshot/)
- `options.element` - Accept an ElementHandle or a string selector to screenshot an element
- `options.viewports` - Specifies the viewports for which to capture screenshots. See [viewports configuration](https://argos-ci.com/docs/viewports).
- `options.argosCSS`: Specific CSS applied during the screenshot process.

## Helper Attributes for Visual Testing

Expand Down
21 changes: 14 additions & 7 deletions packages/puppeteer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export type ArgosScreenshotOptions = Omit<
* Viewports to take screenshots of.
*/
viewports?: ViewportOption[];
/**
* Custom CSS evaluated during the screenshot process.
*/
argosCSS?: string;
};

async function getPuppeteerVersion(): Promise<string> {
Expand Down Expand Up @@ -67,7 +71,7 @@ async function getBrowserInfo(page: Page) {
export async function argosScreenshot(
page: Page,
name: string,
{ element, viewports, ...options }: ArgosScreenshotOptions = {},
{ element, viewports, argosCSS, ...options }: ArgosScreenshotOptions = {},
) {
if (!page) {
throw new Error("A Puppeteer `page` object is required.");
Expand All @@ -90,9 +94,9 @@ export async function argosScreenshot(
options.fullPage !== undefined ? options.fullPage : element === undefined;

await page.evaluate(
({ fullPage }) =>
((window as any).__ARGOS__ as ArgosGlobal).setup({ fullPage }),
{ fullPage },
({ fullPage, argosCSS }) =>
((window as any).__ARGOS__ as ArgosGlobal).setup({ fullPage, argosCSS }),
{ fullPage, argosCSS },
);

async function collectMetadata(): Promise<ScreenshotMetadata> {
Expand Down Expand Up @@ -195,9 +199,12 @@ export async function argosScreenshot(

// Teardown Argos
await page.evaluate(
({ fullPage }) =>
((window as any).__ARGOS__ as ArgosGlobal).teardown({ fullPage }),
{ fullPage },
({ fullPage, argosCSS }) =>
((window as any).__ARGOS__ as ArgosGlobal).teardown({
fullPage,
argosCSS,
}),
{ fullPage, argosCSS },
);

// Restore the original viewport
Expand Down
6 changes: 6 additions & 0 deletions packages/puppeteer/test.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@ describe("argosScreenshot", () => {
});
});

it("supports argosCSS option", async () => {
await argosScreenshot(page, "argosCSS-option", {
argosCSS: "body { background: blue; }",
});
});

describe("with cjs version", () => {
it("works", async () => {
await argosScreenshotCjs(page, "cjs");
Expand Down

0 comments on commit 9ab7efd

Please sign in to comment.