Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/browser-env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ jobs:
- name: "Prepare browser-env tests: Pull browser docker image"
run: |
mkdir -p ~/.docker/cache
if [ -f ~/.docker/cache/image.tar ]; then
docker load -i ~/.docker/cache/image.tar
if [ -f ~/.docker/cache/image-ghcr-chromium-126.tar ]; then
docker load -i ~/.docker/cache/image-ghcr-chromium-126.tar
else
docker pull yinfra/html-reporter-browsers
docker save yinfra/html-reporter-browsers -o ~/.docker/cache/image.tar
docker pull ghcr.io/gemini-testing/browsers/chromium:126.0
docker save ghcr.io/gemini-testing/browsers/chromium:126.0 -o ~/.docker/cache/image-ghcr-chromium-126.tar
fi

- name: "Prepare browser-env tests: Run browser docker image"
run: docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -it --rm --network=host $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) yinfra/html-reporter-browsers
run: docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -it --rm --network=host $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) ghcr.io/gemini-testing/browsers/chromium:126.0

- name: "browser-env: Run Testplane"
id: "testplane"
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ jobs:
- name: "Prepare e2e tests: Pull browser docker image"
run: |
mkdir -p ~/.docker/cache
if [ -f ~/.docker/cache/image.tar ]; then
docker load -i ~/.docker/cache/image.tar
if [ -f ~/.docker/cache/image-ghcr-chromium-126.tar ]; then
docker load -i ~/.docker/cache/image-ghcr-chromium-126.tar
else
docker pull yinfra/html-reporter-browsers
docker save yinfra/html-reporter-browsers -o ~/.docker/cache/image.tar
docker pull ghcr.io/gemini-testing/browsers/chromium:126.0
docker save ghcr.io/gemini-testing/browsers/chromium:126.0 -o ~/.docker/cache/image-ghcr-chromium-126.tar
fi

- name: "Prepare e2e tests: Run browser docker image"
run: docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -it --rm --network=host $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) yinfra/html-reporter-browsers
run: docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -it --rm --network=host $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) ghcr.io/gemini-testing/browsers/chromium:126.0

# - name: 'Prepare e2e tests: Setup env'
# run: |
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/standalone-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ jobs:
if: ${{ matrix.browser == 'chrome' }}
run: |
mkdir -p ~/.docker/cache
if [ -f ~/.docker/cache/image.tar ]; then
docker load -i ~/.docker/cache/image.tar
if [ -f ~/.docker/cache/image-ghcr-chromium-126.tar ]; then
docker load -i ~/.docker/cache/image-ghcr-chromium-126.tar
else
docker pull yinfra/html-reporter-browsers
docker save yinfra/html-reporter-browsers -o ~/.docker/cache/image.tar
docker pull ghcr.io/gemini-testing/browsers/chromium:126.0
Comment thread
shadowusr marked this conversation as resolved.
docker save ghcr.io/gemini-testing/browsers/chromium:126.0 -o ~/.docker/cache/image-ghcr-chromium-126.tar
fi

- name: "Prepare screenshot tests: Run browser docker image"
if: ${{ matrix.browser == 'chrome' }}
run: docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -it --rm --network=host $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) yinfra/html-reporter-browsers
run: docker run -d --name ${{ env.DOCKER_IMAGE_NAME }} -it --rm --network=host $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) ghcr.io/gemini-testing/browsers/chromium:126.0

- name: Run integration tests for ${{ matrix.browser }}
env:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
}
},
"scripts": {
"browsers:launch": "docker run -it --rm --network=host $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) yinfra/html-reporter-browsers",
"browsers:launch": "docker run -it --rm --network=host --shm-size=2g $(which colima >/dev/null || echo --add-host=host.docker.internal:0.0.0.0) ghcr.io/gemini-testing/browsers/chromium:126.0",
"build": "tsc --build && npm run build-bundles && npm run copy-static",
"copy-static": "copyfiles 'src/browser/client-scripts/**/*.js' 'src/**/[!cache]*/autogenerated/**/*.json' build",
"build-node-bundle": "esbuild ./src/bundle/cjs/index.ts --outdir=./build/src/bundle/cjs --bundle --format=cjs --platform=node --target=ES2021",
Expand Down
170 changes: 94 additions & 76 deletions src/browser/client-scripts/screen-shooter/implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ import {
ScrollResult,
GetCaptureStateResult,
TrackedElementData,
ElementPositionsProbe
ElementPositionsProbe,
CaptureState,
ViewportState
} from "./types";
import { createDebugLogger } from "../shared/logger";
import {
Expand Down Expand Up @@ -181,15 +183,21 @@ export function prepareElementsScreenshot(
return safeCall(prepareElementsScreenshotUnsafe, targetsToCapture, opts);
}

export function getCurrentPixelRatio(): number {
return computePixelRatio();
}

export function scrollBy(
targetsToCapture: ElementTarget[],
scrollDelta: Length<"device", "y"> | Coord<"page", "device", "y">,
targetToScroll?: ElementTarget | null,
usePixelRatio?: boolean,
pixelRatioOverride?: number,
debug?: string[]
): ScrollResult {
return safeCall((): ScrollResult => {
const logger = createDebugLogger({ debug }, "scrollBy");
const pixelRatio = computePixelRatio();
const pixelRatio = computePixelRatio(usePixelRatio, pixelRatioOverride);
const scrollTarget = targetToScroll ? lib.queryFirst(targetToScroll) : null;
const scrollElement = scrollTarget ?? getCommonScrollParent(targetsToCapture);

Expand All @@ -214,6 +222,8 @@ export function scrollTo(
targetsToCapture: ElementTarget[],
scrollOffset: Length<"device", "y"> | Coord<"page", "device", "y">,
targetToScroll?: ElementTarget | null,
usePixelRatio?: boolean,
pixelRatioOverride?: number,
debug?: string[]
): ScrollResult {
return safeCall((): ScrollResult => {
Expand All @@ -226,7 +236,7 @@ export function scrollTo(
"targetToScroll:",
targetToScroll
);
const pixelRatio = computePixelRatio();
const pixelRatio = computePixelRatio(usePixelRatio, pixelRatioOverride);
const scrollTarget = targetToScroll ? lib.queryFirst(targetToScroll) : null;
const scrollElement = scrollTarget ?? getCommonScrollParent(targetsToCapture);

Expand All @@ -250,48 +260,79 @@ export function scrollTo(
});
}

function getViewportState(usePixelRatio?: boolean, pixelRatioOverride?: number): ViewportState {
const pixelRatio = computePixelRatio(usePixelRatio, pixelRatioOverride);

return {
viewportSize: fromCssToDevice(computeViewportSize(), pixelRatio),
viewportOffset: fromCssToDevice(floorCoords(computeViewportOffset()), pixelRatio),
documentSize: ceilCoords(fromCssToDevice(computeDocumentSize(), pixelRatio)),
pixelRatio
};
}

function getCaptureStateUnsafe(
targetsToCapture: ElementTarget[],
targetsToIgnore: ElementTarget[],
targetToScroll: ElementTarget | null | undefined,
usePixelRatio: boolean | undefined,
pixelRatioOverride: number | undefined,
logger: ReturnType<typeof createDebugLogger>
): CaptureState & { readableSelectorToScrollDescr: string } {
const viewportState = getViewportState(usePixelRatio, pixelRatioOverride);
const scrollTarget = targetToScroll ? lib.queryFirst(targetToScroll) : null;
const scrollElement = scrollTarget ?? getCommonScrollParent(targetsToCapture);
const readableAutoScrollElementDescr = getReadableElementDescriptor(scrollElement);
const readableSelectorToScrollDescr = targetToScroll
? scrollTarget
? `${targetToScroll} (${readableAutoScrollElementDescr})`
: `${targetToScroll} (not found, auto-detected ${readableAutoScrollElementDescr})`
: `auto-detected ${readableAutoScrollElementDescr}`;
const ignoreAreas = computeIgnoreAreas(targetsToIgnore);
const safeArea = computeSafeArea(targetsToCapture, scrollElement, logger);
const captureSpecs = computeCaptureSpecs(targetsToCapture, logger);
const scrollOffset = computeScrollOffset(scrollElement);
const anchorShift = computeActualShift();

logger("scrollOffset:", scrollOffset);

return {
...viewportState,
captureSpecs: captureSpecs.map(spec => ({
full: fromCssToDevice(roundCoords(spec.full), viewportState.pixelRatio),
clip: fromCssToDevice(roundCoords(spec.clip), viewportState.pixelRatio),
visible: fromCssToDevice(roundCoords(spec.visible), viewportState.pixelRatio)
})),
ignoreAreas: ignoreAreas.map(area => fromCssToDevice(roundCoords(area), viewportState.pixelRatio)),
safeArea: fromCssToDevice(roundCoords(safeArea), viewportState.pixelRatio),
scrollOffset: fromCssToDeviceNumber(scrollOffset, viewportState.pixelRatio),
anchorShift: anchorShift === null ? null : fromCssToDeviceNumber(anchorShift, viewportState.pixelRatio),
readableSelectorToScrollDescr
};
}

/** Returns current state: positions of elements to capture, ignore areas, safe area, scroll offset */
export function getCaptureState(
targetsToCapture: ElementTarget[],
targetsToIgnore: ElementTarget[],
targetToScroll?: ElementTarget | null,
usePixelRatio?: boolean,
pixelRatioOverride?: number,
debug?: string[]
): GetCaptureStateResult {
return safeCall((): GetCaptureStateResult => {
const logger = createDebugLogger({ debug }, "getCaptureState");
const pixelRatio = computePixelRatio();
const scrollTarget = targetToScroll ? lib.queryFirst(targetToScroll) : null;
const scrollElement = scrollTarget ?? getCommonScrollParent(targetsToCapture);
const readableAutoScrollElementDescr = getReadableElementDescriptor(scrollElement);
const readableSelectorToScrollDescr = targetToScroll
? scrollTarget
? `${targetToScroll} (${readableAutoScrollElementDescr})`
: `${targetToScroll} (not found, auto-detected ${readableAutoScrollElementDescr})`
: `auto-detected ${readableAutoScrollElementDescr}`;
const ignoreAreas = computeIgnoreAreas(targetsToIgnore);
const safeArea = computeSafeArea(targetsToCapture, scrollElement, logger);
const captureSpecsAfterCss = computeCaptureSpecs(targetsToCapture, logger);
const captureSpecs = captureSpecsAfterCss.map(spec => ({
full: fromCssToDevice(roundCoords(spec.full), pixelRatio),
clip: fromCssToDevice(roundCoords(spec.clip), pixelRatio),
visible: fromCssToDevice(roundCoords(spec.visible), pixelRatio)
}));
const scrollOffset = computeScrollOffset(scrollElement);
const viewportOffset = computeViewportOffset();

const anchorShift = computeActualShift();
const anchorShiftDevice = anchorShift === null ? null : fromCssToDeviceNumber(anchorShift, pixelRatio);

logger("scrollOffset:", scrollOffset);
const state = getCaptureStateUnsafe(
targetsToCapture,
targetsToIgnore,
targetToScroll,
usePixelRatio,
pixelRatioOverride,
logger
);

return {
captureSpecs,
ignoreAreas: ignoreAreas.map(area => fromCssToDevice(roundCoords(area), pixelRatio)),
safeArea: fromCssToDevice(roundCoords(safeArea), pixelRatio),
scrollOffset: fromCssToDeviceNumber(scrollOffset, pixelRatio),
viewportOffset: fromCssToDevice(floorCoords(viewportOffset), pixelRatio),
anchorShift: anchorShiftDevice,
readableSelectorToScrollDescr,
...state,
debugLog: logger()
};
});
Expand Down Expand Up @@ -376,19 +417,16 @@ export function prepareViewportScreenshot(
disableAnimation?: boolean;
disableHover?: DisableHoverMode;
ignoreSelectors?: ElementTarget[];
pixelRatioOverride?: number;
} = {}
): PrepareViewportScreenshotResult {
return safeCall((): PrepareViewportScreenshotResult => {
const pixelRatio = computePixelRatio(opts.usePixelRatio);
const viewportSize = computeViewportSize();
const viewportOffset = computeViewportOffset();
const documentSize = computeDocumentSize();
const canHaveCaret = computeCanHaveCaret();

if (opts.disableAnimation) {
disableAnimations();
}

const viewportState = getViewportState(opts.usePixelRatio, opts.pixelRatioOverride);
const canHaveCaret = computeCanHaveCaret();
const ignoreAreas = computeIgnoreAreas(opts.ignoreSelectors);

let pointerEventsDisabled = false;
Expand All @@ -398,12 +436,9 @@ export function prepareViewportScreenshot(
}

return {
viewportSize: fromCssToDevice(viewportSize, pixelRatio),
viewportOffset: fromCssToDevice(floorCoords(viewportOffset), pixelRatio),
documentSize: ceilCoords(fromCssToDevice(documentSize, pixelRatio)),
ignoreAreas: ignoreAreas.map(area => fromCssToDevice(roundCoords(area), pixelRatio)),
...viewportState,
ignoreAreas: ignoreAreas.map(area => fromCssToDevice(roundCoords(area), viewportState.pixelRatio)),
canHaveCaret,
pixelRatio,
pointerEventsDisabled
};
});
Expand Down Expand Up @@ -482,7 +517,7 @@ export function captureAnchorBaseline(targetsToCapture: ElementTarget[]): void |
function prepareElementsScreenshotUnsafe(
targetsToCapture: ElementTarget[],
opts: PrepareScreenshotOptions
): PrepareScreenshotResult {
): PrepareScreenshotSuccess {
const logger = createDebugLogger(opts, "prepareElementsScreenshot");

saveScrollPositions(targetsToCapture, opts.selectorToScroll);
Expand All @@ -499,58 +534,41 @@ function prepareElementsScreenshotUnsafe(
disableAnimations();
}

const pixelRatio = computePixelRatio(opts.usePixelRatio);
const scrollTarget = opts.selectorToScroll ? lib.queryFirst(opts.selectorToScroll) : null;
const scrollElement = scrollTarget ?? getCommonScrollParent(targetsToCapture);

const ignoreAreas = computeIgnoreAreas(opts.ignoreSelectors);
const captureSpecs = computeCaptureSpecs(targetsToCapture, logger);
const viewportSize = computeViewportSize();
const viewportOffset = computeViewportOffset();
const safeArea = computeSafeArea(targetsToCapture, scrollElement, logger);
const scrollOffset = computeScrollOffset(scrollElement);

const documentSize = computeDocumentSize();
const state = getCaptureStateUnsafe(
targetsToCapture,
opts.ignoreSelectors ?? [],
opts.selectorToScroll,
opts.usePixelRatio,
opts.pixelRatioOverride,
logger
);
const canHaveCaret = computeCanHaveCaret();

let pointerEventsDisabled = false;
if (opts.disableHover === DisableHoverMode.Always) {
disablePointerEventsUnsafe();
pointerEventsDisabled = true;
} else if (opts.disableHover === DisableHoverMode.WhenScrollingNeeded && opts.compositeImage) {
const captureArea = getCoveringRect(captureSpecs.map(s => s.full));
const needsScrolling = getBottom(captureArea) > getBottom(safeArea);
const captureArea = getCoveringRect(state.captureSpecs.map(s => s.full));
const needsScrolling = getBottom(captureArea) > getBottom(state.safeArea);

if (needsScrolling) {
logger(
"adding stylesheet with pointer-events: none on all elements (composite capture needs scrolling). captureArea:",
captureArea,
"safeArea:",
safeArea
state.safeArea
);
disablePointerEventsUnsafe();
pointerEventsDisabled = true;
}
}

logger("scrollOffset:", scrollOffset);

return {
ignoreAreas: ignoreAreas.map(area => fromCssToDevice(roundCoords(area), pixelRatio)),
captureSpecs: captureSpecs.map(s => ({
full: fromCssToDevice(roundCoords(s.full), pixelRatio),
clip: fromCssToDevice(roundCoords(s.clip), pixelRatio),
visible: fromCssToDevice(roundCoords(s.visible), pixelRatio)
})),
viewportSize: fromCssToDevice(viewportSize, pixelRatio),
viewportOffset: fromCssToDevice(floorCoords(viewportOffset), pixelRatio),
safeArea: fromCssToDevice(roundCoords(safeArea), pixelRatio),
documentSize: ceilCoords(fromCssToDevice(documentSize, pixelRatio)),
...state,
canHaveCaret,
pixelRatio: pixelRatio,
pointerEventsDisabled: pointerEventsDisabled,
debugLog: logger(),
readableSelectorToScrollDescr,
scrollOffset: fromCssToDeviceNumber(scrollOffset, pixelRatio)
debugLog: logger()
} satisfies PrepareScreenshotSuccess;
}
6 changes: 5 additions & 1 deletion src/browser/client-scripts/screen-shooter/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,15 @@ export function computeCanHaveCaret(): boolean {
return canHaveCaret;
}

export function computePixelRatio(usePixelRatio: boolean = true): number {
export function computePixelRatio(usePixelRatio: boolean = true, pixelRatioOverride?: number): number {
if (usePixelRatio === false) {
return 1;
}

if (pixelRatioOverride) {
return pixelRatioOverride;
}

if (window.devicePixelRatio) {
return window.devicePixelRatio;
}
Expand Down
Loading
Loading