feat(vrt): allow providing screenshot style (#28229)
This commit is contained in:
Родитель
da6a36062e
Коммит
0a7a10d0f6
|
@ -749,6 +749,9 @@ Returns the buffer with the captured screenshot.
|
|||
### option: ElementHandle.screenshot.maskColor = %%-screenshot-option-mask-color-%%
|
||||
* since: v1.34
|
||||
|
||||
### option: ElementHandle.screenshot.style = %%-screenshot-option-style-%%
|
||||
* since: v1.41
|
||||
|
||||
## async method: ElementHandle.scrollIntoViewIfNeeded
|
||||
* since: v1.8
|
||||
|
||||
|
|
|
@ -1913,6 +1913,9 @@ Returns the buffer with the captured screenshot.
|
|||
### option: Locator.screenshot.maskColor = %%-screenshot-option-mask-color-%%
|
||||
* since: v1.34
|
||||
|
||||
### option: Locator.screenshot.style = %%-screenshot-option-style-%%
|
||||
* since: v1.41
|
||||
|
||||
## async method: Locator.scrollIntoViewIfNeeded
|
||||
* since: v1.14
|
||||
|
||||
|
|
|
@ -1541,6 +1541,9 @@ Snapshot name.
|
|||
### option: LocatorAssertions.toHaveScreenshot#1.maskColor = %%-screenshot-option-mask-color-%%
|
||||
* since: v1.35
|
||||
|
||||
### option: LocatorAssertions.toHaveScreenshot#1.style = %%-screenshot-option-style-%%
|
||||
* since: v1.41
|
||||
|
||||
### option: LocatorAssertions.toHaveScreenshot#1.omitBackground = %%-screenshot-option-omit-background-%%
|
||||
* since: v1.23
|
||||
|
||||
|
@ -1587,6 +1590,9 @@ Note that screenshot assertions only work with Playwright test runner.
|
|||
### option: LocatorAssertions.toHaveScreenshot#2.maskColor = %%-screenshot-option-mask-color-%%
|
||||
* since: v1.35
|
||||
|
||||
### option: LocatorAssertions.toHaveScreenshot#2.style = %%-screenshot-option-style-%%
|
||||
* since: v1.41
|
||||
|
||||
### option: LocatorAssertions.toHaveScreenshot#2.omitBackground = %%-screenshot-option-omit-background-%%
|
||||
* since: v1.23
|
||||
|
||||
|
|
|
@ -3399,6 +3399,9 @@ Returns the buffer with the captured screenshot.
|
|||
### option: Page.screenshot.maskColor = %%-screenshot-option-mask-color-%%
|
||||
* since: v1.34
|
||||
|
||||
### option: Page.screenshot.style = %%-screenshot-option-style-%%
|
||||
* since: v1.41
|
||||
|
||||
## async method: Page.selectOption
|
||||
* since: v1.8
|
||||
* discouraged: Use locator-based [`method: Locator.selectOption`] instead. Read more about [locators](../locators.md).
|
||||
|
|
|
@ -161,6 +161,9 @@ Snapshot name.
|
|||
### option: PageAssertions.toHaveScreenshot#1.maskColor = %%-screenshot-option-mask-color-%%
|
||||
* since: v1.35
|
||||
|
||||
### option: PageAssertions.toHaveScreenshot#1.style = %%-screenshot-option-style-%%
|
||||
* since: v1.41
|
||||
|
||||
### option: PageAssertions.toHaveScreenshot#1.omitBackground = %%-screenshot-option-omit-background-%%
|
||||
* since: v1.23
|
||||
|
||||
|
@ -212,6 +215,9 @@ Note that screenshot assertions only work with Playwright test runner.
|
|||
### option: PageAssertions.toHaveScreenshot#2.maskColor = %%-screenshot-option-mask-color-%%
|
||||
* since: v1.35
|
||||
|
||||
### option: PageAssertions.toHaveScreenshot#2.style = %%-screenshot-option-style-%%
|
||||
* since: v1.41
|
||||
|
||||
### option: PageAssertions.toHaveScreenshot#2.omitBackground = %%-screenshot-option-omit-background-%%
|
||||
* since: v1.23
|
||||
|
||||
|
|
|
@ -1132,6 +1132,13 @@ Defaults to `"css"`.
|
|||
|
||||
When set to `"hide"`, screenshot will hide text caret. When set to `"initial"`, text caret behavior will not be changed. Defaults to `"hide"`.
|
||||
|
||||
## screenshot-option-style
|
||||
- `style` <string>
|
||||
|
||||
Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements invisible
|
||||
or change their properties to help you creating repeatable screenshots. This stylesheet pierces the Shadow DOM and applies
|
||||
to the inner frames.
|
||||
|
||||
## screenshot-options-common-list-v1.8
|
||||
- %%-screenshot-option-animations-%%
|
||||
- %%-screenshot-option-omit-background-%%
|
||||
|
|
|
@ -47,6 +47,7 @@ export default defineConfig({
|
|||
- `animations` ?<[ScreenshotAnimations]<"allow"|"disabled">> See [`option: animations`] in [`method: Page.screenshot`]. Defaults to `"disabled"`.
|
||||
- `caret` ?<[ScreenshotCaret]<"hide"|"initial">> See [`option: caret`] in [`method: Page.screenshot`]. Defaults to `"hide"`.
|
||||
- `scale` ?<[ScreenshotScale]<"css"|"device">> See [`option: scale`] in [`method: Page.screenshot`]. Defaults to `"css"`.
|
||||
- `style` ?<[string]> See [`option: style`] in [`method: Page.screenshot`].
|
||||
- `toMatchSnapshot` ?<[Object]> Configuration for the [`method: SnapshotAssertions.toMatchSnapshot#1`] method.
|
||||
- `threshold` ?<[float]> an acceptable perceived color difference between the same pixel in compared images, ranging from `0` (strict) and `1` (lax). `"pixelmatch"` comparator computes color difference in [YIQ color space](https://en.wikipedia.org/wiki/YIQ) and defaults `threshold` value to `0.2`.
|
||||
- `maxDiffPixels` ?<[int]> an acceptable amount of pixels that could be different, unset by default.
|
||||
|
|
|
@ -1071,6 +1071,7 @@ scheme.PageExpectScreenshotParams = tObject({
|
|||
selector: tString,
|
||||
}))),
|
||||
maskColor: tOptional(tString),
|
||||
style: tOptional(tString),
|
||||
})),
|
||||
});
|
||||
scheme.PageExpectScreenshotResult = tObject({
|
||||
|
@ -1095,6 +1096,7 @@ scheme.PageScreenshotParams = tObject({
|
|||
selector: tString,
|
||||
}))),
|
||||
maskColor: tOptional(tString),
|
||||
style: tOptional(tString),
|
||||
});
|
||||
scheme.PageScreenshotResult = tObject({
|
||||
binary: tBinary,
|
||||
|
@ -1896,6 +1898,7 @@ scheme.ElementHandleScreenshotParams = tObject({
|
|||
selector: tString,
|
||||
}))),
|
||||
maskColor: tOptional(tString),
|
||||
style: tOptional(tString),
|
||||
});
|
||||
scheme.ElementHandleScreenshotResult = tObject({
|
||||
binary: tBinary,
|
||||
|
|
|
@ -847,7 +847,7 @@ export class Frame extends SdkObject {
|
|||
return result;
|
||||
}
|
||||
|
||||
async maskSelectors(selectors: ParsedSelector[], color?: string): Promise<void> {
|
||||
async maskSelectors(selectors: ParsedSelector[], color: string): Promise<void> {
|
||||
const context = await this._utilityContext();
|
||||
const injectedScript = await context.injectedScript();
|
||||
await injectedScript.evaluate((injected, { parsed, color }) => {
|
||||
|
|
|
@ -118,8 +118,8 @@ export class Highlight {
|
|||
this._innerUpdateHighlight(elements, options);
|
||||
}
|
||||
|
||||
maskElements(elements: Element[], color?: string) {
|
||||
this._innerUpdateHighlight(elements, { color: color ? color : '#F0F' });
|
||||
maskElements(elements: Element[], color: string) {
|
||||
this._innerUpdateHighlight(elements, { color: color });
|
||||
}
|
||||
|
||||
private _innerUpdateHighlight(elements: Element[], options: HighlightOptions) {
|
||||
|
|
|
@ -1125,7 +1125,7 @@ export class InjectedScript {
|
|||
return error;
|
||||
}
|
||||
|
||||
maskSelectors(selectors: ParsedSelector[], color?: string) {
|
||||
maskSelectors(selectors: ParsedSelector[], color: string) {
|
||||
if (this._highlight)
|
||||
this.hideHighlight();
|
||||
this._highlight = new Highlight(this);
|
||||
|
|
|
@ -28,24 +28,25 @@ import { MultiMap } from '../utils/multimap';
|
|||
|
||||
declare global {
|
||||
interface Window {
|
||||
__cleanupScreenshot?: () => void;
|
||||
__pwCleanupScreenshot?: () => void;
|
||||
}
|
||||
}
|
||||
|
||||
export type ScreenshotOptions = {
|
||||
type?: 'png' | 'jpeg',
|
||||
quality?: number,
|
||||
omitBackground?: boolean,
|
||||
animations?: 'disabled' | 'allow',
|
||||
mask?: { frame: Frame, selector: string}[],
|
||||
maskColor?: string,
|
||||
fullPage?: boolean,
|
||||
clip?: Rect,
|
||||
scale?: 'css' | 'device',
|
||||
caret?: 'hide' | 'initial',
|
||||
type?: 'png' | 'jpeg';
|
||||
quality?: number;
|
||||
omitBackground?: boolean;
|
||||
animations?: 'disabled' | 'allow';
|
||||
mask?: { frame: Frame, selector: string}[];
|
||||
maskColor?: string;
|
||||
fullPage?: boolean;
|
||||
clip?: Rect;
|
||||
scale?: 'css' | 'device';
|
||||
caret?: 'hide' | 'initial';
|
||||
style?: string;
|
||||
};
|
||||
|
||||
function inPagePrepareForScreenshots(hideCaret: boolean, disableAnimations: boolean) {
|
||||
function inPagePrepareForScreenshots(screenshotStyle: string, disableAnimations: boolean) {
|
||||
const collectRoots = (root: Document | ShadowRoot, roots: (Document|ShadowRoot)[] = []): (Document|ShadowRoot)[] => {
|
||||
roots.push(root);
|
||||
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||
|
@ -58,29 +59,23 @@ function inPagePrepareForScreenshots(hideCaret: boolean, disableAnimations: bool
|
|||
return roots;
|
||||
};
|
||||
|
||||
let documentRoots: (Document|ShadowRoot)[] | undefined;
|
||||
const memoizedRoots = () => documentRoots ??= collectRoots(document);
|
||||
|
||||
const styleTags: Element[] = [];
|
||||
if (hideCaret) {
|
||||
for (const root of memoizedRoots()) {
|
||||
const styleTag = document.createElement('style');
|
||||
styleTag.textContent = `
|
||||
*:not(#playwright-aaaaaaaaaa.playwright-bbbbbbbbbbb.playwright-cccccccccc.playwright-dddddddddd.playwright-eeeeeeeee) {
|
||||
caret-color: transparent !important;
|
||||
}
|
||||
`;
|
||||
if (root === document)
|
||||
document.documentElement.append(styleTag);
|
||||
else
|
||||
root.append(styleTag);
|
||||
styleTags.push(styleTag);
|
||||
}
|
||||
}
|
||||
const infiniteAnimationsToResume: Set<Animation> = new Set();
|
||||
const roots = collectRoots(document);
|
||||
const cleanupCallbacks: (() => void)[] = [];
|
||||
for (const root of roots) {
|
||||
const styleTag = document.createElement('style');
|
||||
styleTag.textContent = screenshotStyle;
|
||||
if (root === document)
|
||||
document.documentElement.append(styleTag);
|
||||
else
|
||||
root.append(styleTag);
|
||||
|
||||
cleanupCallbacks.push(() => {
|
||||
styleTag.remove();
|
||||
});
|
||||
|
||||
}
|
||||
if (disableAnimations) {
|
||||
const infiniteAnimationsToResume: Set<Animation> = new Set();
|
||||
const handleAnimations = (root: Document|ShadowRoot): void => {
|
||||
for (const animation of root.getAnimations()) {
|
||||
if (!animation.effect || animation.playbackRate === 0 || infiniteAnimationsToResume.has(animation))
|
||||
|
@ -106,7 +101,7 @@ function inPagePrepareForScreenshots(hideCaret: boolean, disableAnimations: bool
|
|||
}
|
||||
}
|
||||
};
|
||||
for (const root of memoizedRoots()) {
|
||||
for (const root of roots) {
|
||||
const handleRootAnimations: (() => void) = handleAnimations.bind(null, root);
|
||||
handleRootAnimations();
|
||||
root.addEventListener('transitionrun', handleRootAnimations);
|
||||
|
@ -116,23 +111,22 @@ function inPagePrepareForScreenshots(hideCaret: boolean, disableAnimations: bool
|
|||
root.removeEventListener('animationstart', handleRootAnimations);
|
||||
});
|
||||
}
|
||||
cleanupCallbacks.push(() => {
|
||||
for (const animation of infiniteAnimationsToResume) {
|
||||
try {
|
||||
animation.play();
|
||||
} catch (e) {
|
||||
// animation.play() should never throw, but
|
||||
// we'd like to be on the safe side.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.__cleanupScreenshot = () => {
|
||||
for (const styleTag of styleTags)
|
||||
styleTag.remove();
|
||||
|
||||
for (const animation of infiniteAnimationsToResume) {
|
||||
try {
|
||||
animation.play();
|
||||
} catch (e) {
|
||||
// animation.play() should never throw, but
|
||||
// we'd like to be on the safe side.
|
||||
}
|
||||
}
|
||||
window.__pwCleanupScreenshot = () => {
|
||||
for (const cleanupCallback of cleanupCallbacks)
|
||||
cleanupCallback();
|
||||
delete window.__cleanupScreenshot;
|
||||
delete window.__pwCleanupScreenshot;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -178,7 +172,7 @@ export class Screenshotter {
|
|||
return this._queue.postTask(async () => {
|
||||
progress.log('taking page screenshot');
|
||||
const { viewportSize } = await this._originalViewportSize(progress);
|
||||
await this._preparePageForScreenshot(progress, options.caret !== 'initial', options.animations === 'disabled');
|
||||
await this._preparePageForScreenshot(progress, screenshotStyle(options), options.animations === 'disabled');
|
||||
progress.throwIfAborted(); // Avoid restoring after failure - should be done by cleanup.
|
||||
|
||||
if (options.fullPage) {
|
||||
|
@ -207,7 +201,7 @@ export class Screenshotter {
|
|||
progress.log('taking element screenshot');
|
||||
const { viewportSize } = await this._originalViewportSize(progress);
|
||||
|
||||
await this._preparePageForScreenshot(progress, options.caret !== 'initial', options.animations === 'disabled');
|
||||
await this._preparePageForScreenshot(progress, screenshotStyle(options), options.animations === 'disabled');
|
||||
progress.throwIfAborted(); // Do not do extra work.
|
||||
|
||||
await handle._waitAndScrollIntoViewIfNeeded(progress, true /* waitForVisible */);
|
||||
|
@ -231,14 +225,11 @@ export class Screenshotter {
|
|||
});
|
||||
}
|
||||
|
||||
async _preparePageForScreenshot(progress: Progress, hideCaret: boolean, disableAnimations: boolean) {
|
||||
if (!hideCaret && !disableAnimations)
|
||||
return;
|
||||
|
||||
async _preparePageForScreenshot(progress: Progress, screenshotStyle: string, disableAnimations: boolean) {
|
||||
if (disableAnimations)
|
||||
progress.log(' disabled all CSS animations');
|
||||
await Promise.all(this._page.frames().map(async frame => {
|
||||
await frame.nonStallingEvaluateInExistingContext('(' + inPagePrepareForScreenshots.toString() + `)(${hideCaret}, ${disableAnimations})`, false, 'utility').catch(() => {});
|
||||
await frame.nonStallingEvaluateInExistingContext('(' + inPagePrepareForScreenshots.toString() + `)(${JSON.stringify(screenshotStyle)}, ${disableAnimations})`, false, 'utility').catch(() => {});
|
||||
}));
|
||||
if (!process.env.PW_TEST_SCREENSHOT_NO_FONTS_READY) {
|
||||
progress.log('waiting for fonts to load...');
|
||||
|
@ -252,7 +243,7 @@ export class Screenshotter {
|
|||
|
||||
async _restorePageAfterScreenshot() {
|
||||
await Promise.all(this._page.frames().map(async frame => {
|
||||
frame.nonStallingEvaluateInExistingContext('window.__cleanupScreenshot && window.__cleanupScreenshot()', false, 'utility').catch(() => {});
|
||||
frame.nonStallingEvaluateInExistingContext('window.__pwCleanupScreenshot && window.__pwCleanupScreenshot()', false, 'utility').catch(() => {});
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -276,7 +267,7 @@ export class Screenshotter {
|
|||
progress.throwIfAborted(); // Avoid extra work.
|
||||
|
||||
await Promise.all([...framesToParsedSelectors.keys()].map(async frame => {
|
||||
await frame.maskSelectors(framesToParsedSelectors.get(frame), options.maskColor);
|
||||
await frame.maskSelectors(framesToParsedSelectors.get(frame), options.maskColor || '#F0F');
|
||||
}));
|
||||
progress.cleanupWhenAborted(cleanup);
|
||||
return cleanup;
|
||||
|
@ -368,3 +359,16 @@ export function validateScreenshotOptions(options: ScreenshotOptions): 'png' | '
|
|||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
function screenshotStyle(options: ScreenshotOptions): string {
|
||||
const parts: string[] = [];
|
||||
if (options.caret !== 'initial') {
|
||||
parts.push(`
|
||||
*:not(#playwright-aaaaaaaaaa.playwright-bbbbbbbbbbb.playwright-cccccccccc.playwright-dddddddddd.playwright-eeeeeeeee) {
|
||||
caret-color: transparent !important;
|
||||
}`);
|
||||
}
|
||||
if (options.style)
|
||||
parts.push(options.style);
|
||||
return parts.join('\n');
|
||||
}
|
||||
|
|
|
@ -9967,6 +9967,13 @@ export interface ElementHandle<T=Node> extends JSHandle<T> {
|
|||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements
|
||||
* invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces the
|
||||
* Shadow DOM and applies to the inner frames.
|
||||
*/
|
||||
style?: string;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to `0` - no timeout. The default value can be changed via `actionTimeout`
|
||||
* option in the config, or by using the
|
||||
|
@ -20037,6 +20044,13 @@ export interface LocatorScreenshotOptions {
|
|||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements
|
||||
* invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces the
|
||||
* Shadow DOM and applies to the inner frames.
|
||||
*/
|
||||
style?: string;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to `0` - no timeout. The default value can be changed via `actionTimeout`
|
||||
* option in the config, or by using the
|
||||
|
@ -20230,6 +20244,13 @@ export interface PageScreenshotOptions {
|
|||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements
|
||||
* invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces the
|
||||
* Shadow DOM and applies to the inner frames.
|
||||
*/
|
||||
style?: string;
|
||||
|
||||
/**
|
||||
* Maximum time in milliseconds. Defaults to `0` - no timeout. The default value can be changed via `actionTimeout`
|
||||
* option in the config, or by using the
|
||||
|
|
|
@ -356,6 +356,7 @@ export async function toHaveScreenshot(
|
|||
animations: config?.animations ?? 'disabled',
|
||||
scale: config?.scale ?? 'css',
|
||||
caret: config?.caret ?? 'hide',
|
||||
style: config?.style ?? '',
|
||||
...helper.allOptions,
|
||||
mask: (helper.allOptions.mask || []) as LocatorEx[],
|
||||
maskColor: helper.allOptions.maskColor,
|
||||
|
|
|
@ -662,6 +662,11 @@ interface TestConfig {
|
|||
* to `"css"`.
|
||||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* See `style` in [page.screenshot([options])](https://playwright.dev/docs/api/class-page#page-screenshot).
|
||||
*/
|
||||
style?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -5951,6 +5956,13 @@ interface LocatorAssertions {
|
|||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements
|
||||
* invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces the
|
||||
* Shadow DOM and applies to the inner frames.
|
||||
*/
|
||||
style?: string;
|
||||
|
||||
/**
|
||||
* An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the
|
||||
* same pixel in compared images, between zero (strict) and one (lax), default is configurable with
|
||||
|
@ -6034,6 +6046,13 @@ interface LocatorAssertions {
|
|||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements
|
||||
* invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces the
|
||||
* Shadow DOM and applies to the inner frames.
|
||||
*/
|
||||
style?: string;
|
||||
|
||||
/**
|
||||
* An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the
|
||||
* same pixel in compared images, between zero (strict) and one (lax), default is configurable with
|
||||
|
@ -6298,6 +6317,13 @@ interface PageAssertions {
|
|||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements
|
||||
* invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces the
|
||||
* Shadow DOM and applies to the inner frames.
|
||||
*/
|
||||
style?: string;
|
||||
|
||||
/**
|
||||
* An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the
|
||||
* same pixel in compared images, between zero (strict) and one (lax), default is configurable with
|
||||
|
@ -6411,6 +6437,13 @@ interface PageAssertions {
|
|||
*/
|
||||
scale?: "css"|"device";
|
||||
|
||||
/**
|
||||
* Stylesheet to apply while making the screenshot. This is where you can hide dynamic elements, make elements
|
||||
* invisible or change their properties to help you creating repeatable screenshots. This stylesheet pierces the
|
||||
* Shadow DOM and applies to the inner frames.
|
||||
*/
|
||||
style?: string;
|
||||
|
||||
/**
|
||||
* An acceptable perceived color difference in the [YIQ color space](https://en.wikipedia.org/wiki/YIQ) between the
|
||||
* same pixel in compared images, between zero (strict) and one (lax), default is configurable with
|
||||
|
|
|
@ -1944,6 +1944,7 @@ export type PageExpectScreenshotParams = {
|
|||
selector: string,
|
||||
}[],
|
||||
maskColor?: string,
|
||||
style?: string,
|
||||
},
|
||||
};
|
||||
export type PageExpectScreenshotOptions = {
|
||||
|
@ -1971,6 +1972,7 @@ export type PageExpectScreenshotOptions = {
|
|||
selector: string,
|
||||
}[],
|
||||
maskColor?: string,
|
||||
style?: string,
|
||||
},
|
||||
};
|
||||
export type PageExpectScreenshotResult = {
|
||||
|
@ -1995,6 +1997,7 @@ export type PageScreenshotParams = {
|
|||
selector: string,
|
||||
}[],
|
||||
maskColor?: string,
|
||||
style?: string,
|
||||
};
|
||||
export type PageScreenshotOptions = {
|
||||
timeout?: number,
|
||||
|
@ -2011,6 +2014,7 @@ export type PageScreenshotOptions = {
|
|||
selector: string,
|
||||
}[],
|
||||
maskColor?: string,
|
||||
style?: string,
|
||||
};
|
||||
export type PageScreenshotResult = {
|
||||
binary: Binary,
|
||||
|
@ -3355,6 +3359,7 @@ export type ElementHandleScreenshotParams = {
|
|||
selector: string,
|
||||
}[],
|
||||
maskColor?: string,
|
||||
style?: string,
|
||||
};
|
||||
export type ElementHandleScreenshotOptions = {
|
||||
timeout?: number,
|
||||
|
@ -3369,6 +3374,7 @@ export type ElementHandleScreenshotOptions = {
|
|||
selector: string,
|
||||
}[],
|
||||
maskColor?: string,
|
||||
style?: string,
|
||||
};
|
||||
export type ElementHandleScreenshotResult = {
|
||||
binary: Binary,
|
||||
|
|
|
@ -379,6 +379,7 @@ CommonScreenshotOptions:
|
|||
frame: Frame
|
||||
selector: string
|
||||
maskColor: string?
|
||||
style: string?
|
||||
|
||||
LaunchOptions:
|
||||
type: mixin
|
||||
|
|
|
@ -543,6 +543,36 @@ it.describe('page screenshot', () => {
|
|||
maskColor: '#00FF00',
|
||||
})).toMatchSnapshot('mask-color-should-work.png');
|
||||
});
|
||||
|
||||
it('should hide elements based on attr', async ({ page, server }) => {
|
||||
await page.setViewportSize({ width: 500, height: 500 });
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.locator('div').nth(5).evaluate(element => {
|
||||
element.setAttribute('data-test-screenshot', 'hide');
|
||||
});
|
||||
expect(await page.screenshot({
|
||||
style: `[data-test-screenshot="hide"] {
|
||||
visibility: hidden;
|
||||
}`
|
||||
})).toMatchSnapshot('hide-should-work.png');
|
||||
const visibility = await page.locator('div').nth(5).evaluate(element => element.style.visibility);
|
||||
expect(visibility).toBe('');
|
||||
});
|
||||
|
||||
it('should remove elements based on attr', async ({ page, server }) => {
|
||||
await page.setViewportSize({ width: 500, height: 500 });
|
||||
await page.goto(server.PREFIX + '/grid.html');
|
||||
await page.locator('div').nth(5).evaluate(element => {
|
||||
element.setAttribute('data-test-screenshot', 'remove');
|
||||
});
|
||||
expect(await page.screenshot({
|
||||
style: `[data-test-screenshot="remove"] {
|
||||
display: none;
|
||||
}`
|
||||
})).toMatchSnapshot('remove-should-work.png');
|
||||
const display = await page.locator('div').nth(5).evaluate(element => element.style.display);
|
||||
expect(display).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/hide-should-work-chromium.png
Normal file
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/hide-should-work-chromium.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 35 KiB |
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/hide-should-work-firefox.png
Normal file
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/hide-should-work-firefox.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 45 KiB |
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/hide-should-work-webkit.png
Normal file
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/hide-should-work-webkit.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 39 KiB |
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/remove-should-work-chromium.png
Normal file
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/remove-should-work-chromium.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 35 KiB |
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/remove-should-work-firefox.png
Normal file
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/remove-should-work-firefox.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 45 KiB |
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/remove-should-work-webkit.png
Normal file
Двоичные данные
tests/page/page-screenshot.spec.ts-snapshots/remove-should-work-webkit.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 39 KiB |
|
@ -1216,6 +1216,47 @@ test('should support maskColor option', async ({ runInlineTest }) => {
|
|||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should support style option', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
...playwrightConfig({
|
||||
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
||||
}),
|
||||
'__screenshots__/a.spec.js/snapshot.png': createImage(IMG_WIDTH, IMG_HEIGHT, 0, 255, 0),
|
||||
'a.spec.js': `
|
||||
const { test, expect } = require('@playwright/test');
|
||||
test('png', async ({ page }) => {
|
||||
await page.setContent('<style> html,body { padding: 0; margin: 0; }</style>');
|
||||
await expect(page).toHaveScreenshot('snapshot.png', {
|
||||
style: 'body { background: #00FF00; }',
|
||||
});
|
||||
});
|
||||
`,
|
||||
});
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
test('should support style option in config', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
...playwrightConfig({
|
||||
snapshotPathTemplate: '__screenshots__/{testFilePath}/{arg}{ext}',
|
||||
expect: {
|
||||
toHaveScreenshot: {
|
||||
style: 'body { background: #00FF00; }',
|
||||
},
|
||||
},
|
||||
}),
|
||||
'__screenshots__/a.spec.js/snapshot.png': createImage(IMG_WIDTH, IMG_HEIGHT, 0, 255, 0),
|
||||
'a.spec.js': `
|
||||
const { test, expect } = require('@playwright/test');
|
||||
test('png', async ({ page }) => {
|
||||
await page.setContent('<style> html,body { padding: 0; margin: 0; }</style>');
|
||||
await expect(page).toHaveScreenshot('snapshot.png');
|
||||
});
|
||||
`,
|
||||
});
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
function playwrightConfig(obj: any) {
|
||||
return {
|
||||
'playwright.config.js': `
|
||||
|
|
Загрузка…
Ссылка в новой задаче