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
1 change: 1 addition & 0 deletions src/browser-scripts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
export * from './scroll';
export * from './sizes';
export * from './events-spy';
export * from './permutations';
38 changes: 38 additions & 0 deletions src/browser-scripts/permutations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { ElementOffset, ElementSize } from '../page-objects/types';

export interface PermutationInfo extends ElementSize {
id: string;
offset: ElementOffset;
}

export interface PageDimensions {
pageHeight: number;
viewportHeight: number;
}

export function getPermutationSizes(): PermutationInfo[] {
var pixelRatio = window.devicePixelRatio || 1;
return Array.prototype.slice
.call(document.querySelectorAll('[data-permutation]'))
.map(function (element: HTMLElement) {
var rect = element.getBoundingClientRect();
return {
id: element.getAttribute('data-permutation') || '',
width: rect.width * pixelRatio,
height: rect.height * pixelRatio,
offset: {
top: rect.top * pixelRatio,
left: rect.left * pixelRatio,
},
};
});
}

export function getPageDimensions(): PageDimensions {
return {
pageHeight: document.documentElement.scrollHeight,
viewportHeight: window.innerHeight,
};
}
2 changes: 1 addition & 1 deletion src/page-objects/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
export { default as BasePageObject } from './base';
export { default as ScreenshotPageObject } from './screenshot';
export { default as ScreenshotPageObject, PermutationScreenshot } from './screenshot';
export { default as EventsSpy } from './events-spy';
export { ScreenshotWithOffset, ElementSize, ElementRect, ElementOffset } from './types';
54 changes: 53 additions & 1 deletion src/page-objects/screenshot.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { ScrollAction, scrollAction } from '../browser-scripts';
import {
ScrollAction,
scrollAction,
getPermutationSizes,
getPageDimensions,
PermutationInfo,
} from '../browser-scripts';
import { parsePng } from '../image-utils';
import BasePageObject from './base';
import { ElementOffset, ScreenshotCapturingOptions, ScreenshotWithOffset } from './types';
import fullPageScreenshot from './full-page-screenshot';

export interface PermutationScreenshot extends ScreenshotWithOffset {
id: string;
}

export default class ScreenshotPageObject extends BasePageObject {
constructor(browser: WebdriverIO.Browser, public readonly forceScrollAndMerge: boolean = false) {
super(browser);
Expand Down Expand Up @@ -65,4 +75,46 @@ export default class ScreenshotPageObject extends BasePageObject {
const image = await parsePng(screenshot);
return { image, offset, height, width };
}

async capturePermutations(): Promise<PermutationScreenshot[]> {
await this.windowScrollTo({ top: 0, left: 0 });

// Adapt viewport height to fit all elements before taking a screenshot
const originalWindowSize = await this.fitWindowHeightToContent();

const permutations = await this.browser.execute(getPermutationSizes);
Comment thread
NathanZlion marked this conversation as resolved.

// Restore window size after taking the screenshot
await this.safeSetWindowSize(originalWindowSize.width, originalWindowSize.height);

if (permutations.length === 0) {
throw new Error('No permutations found on current page.');
}

const screenshot = await this.fullPageScreenshot();
const image = await parsePng(screenshot);

return permutations.map((permutation: PermutationInfo) => ({ ...permutation, image }));
Comment thread
NathanZlion marked this conversation as resolved.
}

private async fitWindowHeightToContent(): Promise<{ width: number; height: number }> {
const originalWindowSize = await this.browser.getWindowSize();
const { viewportHeight, pageHeight } = await this.browser.execute(getPageDimensions);
const windowUIHeight = originalWindowSize.height - viewportHeight;
await this.safeSetWindowSize(originalWindowSize.width, pageHeight + windowUIHeight);
return originalWindowSize;
}

/* istanbul ignore next -- setWindowSize is unsupported on some mobile browsers, not testable in CI */
private async safeSetWindowSize(width: number, height: number): Promise<void> {
try {
await this.browser.setWindowSize(width, height);
} catch (error) {
if (error instanceof Error && error.message.includes('Method has not yet been implemented')) {
console.log('setWindowSize is not supported on this device');
} else {
throw error;
}
}
}
}
26 changes: 26 additions & 0 deletions test/fixtures/test-permutations.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Permutations test page</title>
<style>
body,
html {
margin: 0;
padding: 0;
}
.permutation {
width: 100px;
height: 50px;
background: #eee;
margin: 10px;
}
</style>
</head>
<body>
<div class="permutation" data-permutation="perm-1">Permutation 1</div>
<div class="permutation" data-permutation="perm-2">Permutation 2</div>
<div class="permutation" data-permutation="perm-3">Permutation 3</div>
</body>
</html>
35 changes: 33 additions & 2 deletions test/page-object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import useBrowser from '../src/use-browser';
import './utils/setup-local-driver';

type TestFn = (page: ScreenshotPageObject) => Promise<void>;
function setupTest(testFn: TestFn) {
function setupTest(testFn: TestFn, url = './test-page-object.html') {
return useBrowser(async browser => {
await browser.url('./test-page-object.html');
await browser.url(url);
await testFn(new ScreenshotPageObject(browser));
});
}
Expand Down Expand Up @@ -362,3 +362,34 @@ test(
});
})
);

describe('capturePermutations', () => {
test(
'captures all permutations with correct ids and dimensions',
setupTest(async page => {
const permutations = await page.capturePermutations();

expect(permutations).toHaveLength(3);
expect(permutations.map(p => p.id)).toEqual(['perm-1', 'perm-2', 'perm-3']);

permutations.forEach(perm => {
expect(perm.image).toBeDefined();
expect(perm.width).toBeGreaterThan(0);
expect(perm.height).toBeGreaterThan(0);
expect(perm.offset.top).toBeGreaterThanOrEqual(0);
expect(perm.offset.left).toBeGreaterThanOrEqual(0);
});

// Verify permutations are in order (top to bottom)
expect(permutations[0].offset.top).toBeLessThan(permutations[1].offset.top);
expect(permutations[1].offset.top).toBeLessThan(permutations[2].offset.top);
}, './test-permutations.html')
);

test(
'throws error when no permutations found',
setupTest(async page => {
await expect(page.capturePermutations()).rejects.toThrowError('No permutations found on current page.');
})
);
});
Loading