Skip to content
This repository has been archived by the owner on Dec 24, 2023. It is now read-only.

Commit

Permalink
Merge 1696fc8 into 6eb2c21
Browse files Browse the repository at this point in the history
  • Loading branch information
wswebcreation committed May 26, 2019
2 parents 6eb2c21 + 1696fc8 commit bd18f28
Show file tree
Hide file tree
Showing 12 changed files with 867 additions and 165 deletions.
47 changes: 44 additions & 3 deletions lib/clientSideScripts/getDocumentScrollHeight.spec.ts
@@ -1,9 +1,50 @@
import getDocumentScrollHeight from './getDocumentScrollHeight';

const CONFIGURABLE = {
writable: true,
configurable: true,
};

describe('getDocumentScrollHeight', () => {
it('should check if the document.documentElement.scrollHeight function has been called', () => {
it('should return the bodyScrollHeight', () => {
// For viewPortHeight
Object.defineProperty(document.documentElement, 'clientHeight', {value: 500, ...CONFIGURABLE});
Object.defineProperty(window, 'innerHeight', {value: 500, ...CONFIGURABLE});
// For scrollHeight
Object.defineProperty(document.documentElement, 'scrollHeight', {value: 500, ...CONFIGURABLE});
// For bodyScrollHeight
Object.defineProperty(document.body, 'scrollHeight', {value: 1500, ...CONFIGURABLE});

expect(getDocumentScrollHeight()).toEqual(1500);
});

it('should return the scrollHeight', () => {
// For viewPortHeight
Object.defineProperty(document.documentElement, 'clientHeight', {value: 500, ...CONFIGURABLE});
Object.defineProperty(window, 'innerHeight', {value: 500, ...CONFIGURABLE});
// For scrollHeight
Object.defineProperty(document.documentElement, 'scrollHeight', {value: 2250, ...CONFIGURABLE});
// For bodyScrollHeight
Object.defineProperty(document.body, 'scrollHeight', {value: 1500, ...CONFIGURABLE});

expect(getDocumentScrollHeight()).toEqual(2250);
});

it('should return the height of the largest node', () => {
// For viewPortHeight
Object.defineProperty(document.documentElement, 'clientHeight', {value: 1500, ...CONFIGURABLE});
Object.defineProperty(window, 'innerHeight', {value: 1500, ...CONFIGURABLE});
// For scrollHeight
Object.defineProperty(document.documentElement, 'scrollHeight', {value: 1500, ...CONFIGURABLE});
// For bodyScrollHeight
Object.defineProperty(document.body, 'scrollHeight', {value: 1500, ...CONFIGURABLE});
document.body.innerHTML =
'<div>' +
' <span style="height: 200px;width: 50px"/>' +
' <div style="height: 500px;width: 50px" />' +
'</div>';

// Some lines and the outcome can't be tested because we can't mock `scrollHeight` and `clientHeight`
getDocumentScrollHeight();
// I can't verify the call of the document.documentElement.scrollHeight with Jest, so there is no verification here, sorry :(
// If you know a way, please add it here ;-)
});
});
52 changes: 51 additions & 1 deletion lib/clientSideScripts/getDocumentScrollHeight.ts
Expand Up @@ -2,5 +2,55 @@
* Get the document scroll height, this means the actual height of the page from the top to the bottom of the DOM
*/
export default function getDocumentScrollHeight(): number {
return document.documentElement.scrollHeight;
const viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
const scrollHeight = document.documentElement.scrollHeight;
const bodyScrollHeight = document.body.scrollHeight;

// In some situations the default scrollheight can be equal to the viewport height
// but the body scroll height can be different, then return that one
if ((viewPortHeight === scrollHeight) && (bodyScrollHeight > scrollHeight)) {
return bodyScrollHeight;
}

// In some cases we can have a challenge determining the height of the page
// due to for example a `vh` property on the body element.
// If that is the case we need to walk over all the elements and determine the highest element
// this is a very time consuming thing, so our last hope :(
let pageHeight = 0;
let largestNodeElement = document.querySelector('body');

if (bodyScrollHeight === scrollHeight && bodyScrollHeight === viewPortHeight) {
findHighestNode(document.documentElement.childNodes);

// There could be some elements above this largest element,
// add that on top
/* istanbul ignore next */
return pageHeight + largestNodeElement.getBoundingClientRect().top;
}

// The scrollHeight is good enough
return scrollHeight;

/**
* Find the largest html element on the page
* @param nodesList
*/
function findHighestNode(nodesList: any) {
for (let i = nodesList.length - 1; i >= 0; i--) {
const currentNode = nodesList[i];

/* istanbul ignore next */
if (currentNode.scrollHeight && currentNode.clientHeight) {
const elHeight = Math.max(currentNode.scrollHeight, currentNode.clientHeight);
pageHeight = Math.max(elHeight, pageHeight);
if (elHeight === pageHeight) {
largestNodeElement = currentNode;
}
}

if (currentNode.childNodes.length) {
findHighestNode(currentNode.childNodes);
}
}
}
}
6 changes: 3 additions & 3 deletions lib/clientSideScripts/hideScrollbars.spec.ts
Expand Up @@ -2,14 +2,14 @@ import hideScrollBars from './hideScrollbars';

describe('hideScrollBars', ()=>{
it('should be able to hide and show the scrollbars', ()=>{
expect(document.documentElement.style.overflow).toMatchSnapshot();
expect(document.body.style.overflow).toMatchSnapshot();

hideScrollBars(true);

expect(document.documentElement.style.overflow).toMatchSnapshot();
expect(document.body.style.overflow).toMatchSnapshot();

hideScrollBars(false);

expect(document.documentElement.style.overflow).toMatchSnapshot();
expect(document.body.style.overflow).toMatchSnapshot();
});
});
4 changes: 2 additions & 2 deletions lib/clientSideScripts/hideScrollbars.ts
Expand Up @@ -3,8 +3,8 @@
*/
export default function hideScrollBars(hide: boolean): void {
if (hide) {
document.documentElement.style.overflow = 'hidden';
document.body.style.overflow = 'hidden';
} else {
document.documentElement.style.overflow = '';
document.body.style.overflow = '';
}
}
18 changes: 18 additions & 0 deletions lib/clientSideScripts/scrollToPosition.spec.ts
@@ -1,9 +1,27 @@
import scrollToPosition from './scrollToPosition';

const CONFIGURABLE = {
writable: true,
configurable: true,
};

describe('scrollToPosition', () => {
it('should check if the scrollTo function has been called', () => {
window.scrollTo = jest.fn();
scrollToPosition(150);
expect(window.scrollTo).toBeCalledWith(0, 150);
});

it('should find the largest node if scrollTo does not work on the window', () => {
window.scrollTo = jest.fn();
Object.defineProperty(document.documentElement, 'scrollTop', {value: 150, ...CONFIGURABLE});
document.body.innerHTML =
'<div>' +
' <span style="height: 200px;width: 50px"/>' +
' <div style="height: 500px;width: 50px" />' +
'</div>';

scrollToPosition(150);
// Some lines and the outcome can't be tested because we can't mock `scrollHeight` and `clientHeight`
});
});
55 changes: 53 additions & 2 deletions lib/clientSideScripts/scrollToPosition.ts
@@ -1,6 +1,57 @@
/**
* Scroll to a x = 0 and y = variable position in the screen
* Sometimes a scroll can't be done on the window, so the scroll needs to be done on the largest
* element on the screen
*/
export default function scrollToPosition(yPosition:number):void {
window.scrollTo(0, yPosition);
export default function scrollToPosition(yPosition: number): void {
const initialScroll = document.documentElement.scrollTop;

// If for some reason the scroll didn't work, find the first largest element and use that to scroll on
let largestNode: HTMLElement;

// Scroll with the default way of scrolling
window.scrollTo(0, yPosition);

/* istanbul ignore else */
if (initialScroll === document.documentElement.scrollTop && yPosition > 0) {
largestFirstNode(document.documentElement.childNodes).scrollTo(0, yPosition);
}

/**
* Find the first largest node in the page so it can be used for scrolling
*/
function largestFirstNode(nodesList: any) {
let node: HTMLElement;

// Loop over the nodes
for (let i = nodesList.length - 1; i >= 0; i--) {
node = nodesList[i];

// Stop if the largest node has been found
/* istanbul ignore next */
if (largestNode) {
break;
}

// Check if the element has a scroll / client height
/* istanbul ignore next */
if (node.scrollHeight && node.clientHeight) {
const viewPortHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
const elHeight = Math.max(node.scrollHeight, node.clientHeight);

// If the element is bigger than the viewport, then we got our scroll container
if (elHeight > viewPortHeight) {
largestNode = node;
break;
}
}

if (node.childNodes.length) {
largestFirstNode(node.childNodes);
}
}

// If the largestNode is the body then return the window
return (document.body === largestNode || !largestNode) ? window : largestNode;
}
}
6 changes: 3 additions & 3 deletions lib/commands/saveFullPageScreen.ts
Expand Up @@ -28,9 +28,9 @@ export default async function saveFullPageScreen(
const disableCSSAnimation: boolean = 'disableCSSAnimation' in saveFullPageOptions.method
? saveFullPageOptions.method.disableCSSAnimation
: saveFullPageOptions.wic.disableCSSAnimation;
const hideScrollBars: boolean = 'hideScrollBars' in saveFullPageOptions.method
? saveFullPageOptions.method.hideScrollBars
: saveFullPageOptions.wic.hideScrollBars;
// default this one to false, this will be handled in
// taking the screenshots
const hideScrollBars: boolean = false;
const fullPageScrollTimeout: number = 'fullPageScrollTimeout' in saveFullPageOptions.method
? saveFullPageOptions.method.fullPageScrollTimeout
: saveFullPageOptions.wic.fullPageScrollTimeout;
Expand Down
124 changes: 124 additions & 0 deletions lib/methods/__snapshots__/screenshots.spec.ts.snap

Large diffs are not rendered by default.

0 comments on commit bd18f28

Please sign in to comment.