Skip to content

Commit

Permalink
Fix position offset computing for window (#920)
Browse files Browse the repository at this point in the history
Fix position offset computing for window
  • Loading branch information
TrySound authored Dec 29, 2017
1 parent f275a57 commit 1936f5b
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 18 deletions.
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"start": "webpack-dev-server --hot --config webpack.config.dev.js",
"test": "npm run test:jest",
"test:jest": "jest --no-watchman --runInBand",
"test:ci": "jest --no-watchman --maxWorkers 2 --coverage && codecov",
"test:ci": "cross-env JEST=ci jest --testPathPattern=jest.js --no-watchman --maxWorkers 2 --coverage && codecov",
"watch": "watch 'clear && npm run test -s' source",
"watch:jest": "jest --no-watchman --watch"
},
Expand Down Expand Up @@ -68,6 +68,8 @@
"url": "https://github.com/bvaughn/react-virtualized/issues"
},
"jest": {
"globalSetup": "./source/jest-global-setup.js",
"globalTeardown": "./source/jest-global-teardown.js",
"setupFiles": [
"./source/jest-setup.js"
],
Expand All @@ -81,11 +83,11 @@
"source/**/*.js",
"!source/vendor/**",
"!source/demo/**",
"!source/jest-setup.js",
"!source/jest-*.js",
"!source/TestUtils.js",
"!**/*.example.js"
],
"testRegex": ".jest.js",
"testRegex": ".(jest|e2e).js",
"verbose": true
},
"devDependencies": {
Expand Down Expand Up @@ -130,10 +132,13 @@
"husky": "^0.14.3",
"immutable": "^3.7.5",
"jest": "^22.0.4",
"jest-environment-node": "^22.0.4",
"make-dir": "^1.1.0",
"postcss": "^6.0.14",
"postcss-cli": "^4.1.1",
"postcss-loader": "^2.0.9",
"prettier": "^1.9.2",
"puppeteer": "^0.13.0",
"react": "^16.0.0",
"react-codemirror": "^1.0.0",
"react-dom": "^16.0.0",
Expand Down
113 changes: 113 additions & 0 deletions source/WindowScroller/WindowScroller.e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* @jest-environment ./source/jest-puppeteer-environment.js
*/

const bootstrap = async () => {
const page = await global.__BROWSER__.newPage();
const scripts = [
'./node_modules/react/umd/react.development.js',
'./node_modules/react-dom/umd/react-dom.development.js',
'./dist/umd/react-virtualized.js',
];

for (const path of scripts) {
await page.addScriptTag({path});
}

return page;
};

const renderWindowScroller = ({scrollElement}) => {
const {render} = window.ReactDOM;
const {createElement} = window.React;
const {WindowScroller} = window.ReactVirtualized;

const container = document.createElement('div');
container.id = 'container';
container.style.margin = '100px';
container.style.padding = '50px';
document.body.appendChild(container);
document.body.style.margin = 0;

if (scrollElement === 'container') {
container.style.width = '100%';
container.style.height = '100%';
container.style.overflow = 'auto';
}

render(
createElement(
WindowScroller,
{
scrollElement: scrollElement === 'container' ? container : window,
onScroll: window.scrollFn,
onResize: window.resizeFn,
},
() => createElement('div', {style: {width: 2000, height: 3000}}),
),
container,
);
};

const delay = time => new Promise(resolve => setTimeout(resolve, time));

test('save position after resize and then scroll in window', async () => {
const page = await bootstrap();
const scrollFn = jest.fn();
const resizeFn = jest.fn();
await page.exposeFunction('scrollFn', scrollFn);
await page.exposeFunction('resizeFn', resizeFn);

await page.setViewport({width: 400, height: 600});
await page.evaluate(renderWindowScroller, {scrollElement: 'window'});

// scroll more than viewport
await page.evaluate(() => window.scrollTo(610, 830));
await delay(100);
// resize a bit container/window
await page.setViewport({width: 300, height: 500});
await delay(100);
// scroll again
await page.evaluate(() => window.scrollTo(620, 840));
await delay(100);

await page.close();

expect(scrollFn.mock.calls).toEqual([
[{scrollLeft: 610 - 150, scrollTop: 830 - 150}],
[{scrollLeft: 620 - 150, scrollTop: 840 - 150}],
]);
expect(resizeFn.mock.calls).toEqual([[{width: 300, height: 500}]]);
});

test('save position after resize and then scroll in container', async () => {
const page = await bootstrap();
const scrollFn = jest.fn();
const resizeFn = jest.fn();
await page.exposeFunction('scrollFn', scrollFn);
await page.exposeFunction('resizeFn', resizeFn);

await page.setViewport({width: 400, height: 600});
await page.evaluate(renderWindowScroller, {scrollElement: 'container'});

// scroll more than viewport
await page.$eval('#container', el => el.scrollTo(610, 830));
await delay(100);
// resize a bit container/window
await page.setViewport({width: 300, height: 500});
await delay(100);
// scroll again
await page.$eval('#container', el => el.scrollTo(620, 840));
await delay(100);

await page.close();

expect(scrollFn.mock.calls).toEqual([
[{scrollLeft: 610 - 50, scrollTop: 830 - 50}],
[{scrollLeft: 620 - 50, scrollTop: 840 - 50}],
]);
expect(resizeFn.mock.calls).toEqual([
[{width: 500, height: 700}],
[{width: 400, height: 600}],
]);
});
32 changes: 20 additions & 12 deletions source/WindowScroller/utils/dimensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type WindowScrollerProps = {

const isWindow = element => element === window;

const getBoundingBox = element => element.getBoundingClientRect();

export function getDimensions(
scrollElement: ?Element,
props: WindowScrollerProps,
Expand All @@ -34,7 +36,7 @@ export function getDimensions(
width: typeof innerWidth === 'number' ? innerWidth : 0,
};
} else {
return scrollElement.getBoundingClientRect();
return getBoundingBox(scrollElement);
}
}

Expand All @@ -45,17 +47,23 @@ export function getDimensions(
* In this case the body’s top or left position will be a negative number and this element’s top or left will be increased (by that amount).
*/
export function getPositionOffset(element: Element, container: Element) {
const scrollOffset = getScrollOffset(container);
const containerElement =
isWindow(container) && document.documentElement
? document.documentElement
: container;
const elementRect = element.getBoundingClientRect();
const containerRect = containerElement.getBoundingClientRect();
return {
top: elementRect.top + scrollOffset.top - containerRect.top,
left: elementRect.left + scrollOffset.left - containerRect.left,
};
if (isWindow(container) && document.documentElement) {
const containerElement = document.documentElement;
const elementRect = getBoundingBox(element);
const containerRect = getBoundingBox(containerElement);
return {
top: elementRect.top - containerRect.top,
left: elementRect.left - containerRect.left,
};
} else {
const scrollOffset = getScrollOffset(container);
const elementRect = getBoundingBox(element);
const containerRect = getBoundingBox(container);
return {
top: elementRect.top + scrollOffset.top - containerRect.top,
left: elementRect.left + scrollOffset.left - containerRect.left,
};
}
}

/**
Expand Down
20 changes: 20 additions & 0 deletions source/jest-global-setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const os = require('os');
const util = require('util');
const fs = require('fs');
const path = require('path');
const makeDir = require('mkdirp');
const puppeteer = require('puppeteer');

const writeFile = util.promisify(fs.writeFile);

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');

module.exports = async function() {
if (process.env.JEST !== 'ci') {
console.log('Setup Puppeteer Environment.');
const browser = await puppeteer.launch({});
global.__BROWSER__ = browser;
await makeDir(DIR);
await writeFile(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint());
}
};
17 changes: 17 additions & 0 deletions source/jest-global-teardown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const os = require('os');
const util = require('util');
const path = require('path');
const puppeteer = require('puppeteer');
const rimraf = require('rimraf');

const del = util.promisify(rimraf);

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');

module.exports = async function() {
if (process.env.JEST !== 'ci') {
console.log('Teardown Puppeteer Environment.');
await global.__BROWSER__.close();
await del(DIR);
}
};
35 changes: 35 additions & 0 deletions source/jest-puppeteer-environment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const os = require('os');
const fs = require('fs');
const path = require('path');
const NodeEnvironment = require('jest-environment-node');
const puppeteer = require('puppeteer');

const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');

class PuppeteerEnvironment extends NodeEnvironment {
constructor(config) {
super(config);
}

async setup() {
console.log('Setup Puppeteer Test Environment.');
await super.setup();
const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf8');
if (!wsEndpoint) {
throw new Error('wsEndpoint not found');
}
this.global.__BROWSER__ = await puppeteer.connect({
browserWSEndpoint: wsEndpoint,
});
}

async teardown() {
await super.teardown();
}

runScript(script) {
return super.runScript(script);
}
}

module.exports = PuppeteerEnvironment;
Loading

0 comments on commit 1936f5b

Please sign in to comment.