Repository: mui/material-ui (TypeScript)
Date: 2019-10-21 09:00:52+00:00
Task type: Bug Fix

Issue:
Selects in Gatsby allow scrolling
<!-- Provide a general summary of the issue in the Title above -->
Using the selects component in on a Gatsby site allows you scroll. The selects box will stay with you as you scroll down the page

<!--
  Thank you very much for contributing to Material-UI by creating an issue! ❤️
  To avoid duplicate issues we ask you to check off the following list.
-->

<!-- Checked checkbox should look like this: [x] -->

- [x] The issue is present in the latest release.
- [x] I have searched the [issues](https://github.com/mui-org/material-ui/issues) of this repository and believe that this is not a duplicate.

## Current Behavior 😯
On a Gatsby site the select box when opened does not lock scrolling. When you scroll the selects box scrolls with you down the page disconnecting from its base
<!-- Describe what happens instead of the expected behavior. -->

## Expected Behavior 🤔
When the selects box is open scroll is locked except in the box itself
<!-- Describe what should happen. -->

## Steps to Reproduce 🕹
1. Launch a gatsby dev site.
2. Add material ui as a dependency
3. Add the selects component to a page

Example below
https://codesandbox.io/s/gatsby-starter-default-4v42v?fontsize=14
<!--
  Provide a link to a live example (you can use codesandbox.io) and an unambiguous set of steps to reproduce this bug.
  Include code to reproduce, if relevant (which it most likely is).

  This codesandbox.io template _may_ be a good starting point:
  https://codesandbox.io/s/github/mui-org/material-ui/tree/master/examples/create-react-app

  If you're using typescript a better starting point would be
  https://codesandbox.io/s/github/mui-org/material-ui/tree/master/examples/create-react-app-with-typescript

  If YOU DO NOT take time to provide a codesandbox.io reproduction, should the COMMUNITY take time to help you?
-->

## Context 🔦
I am trying to use the select component on a Gatsby site
<!--
  What are you trying to accomplish? How has this issue affected you?
  Providing context helps us come up with a solution that is most useful in the real world.
-->

## Your Environment 🌎

<!--
  Include as many relevant details about the environment with which you experienced the bug.
  If you encounter issues with typescript please include version and tsconfig.
-->

| Tech        | Version |
| ----------- | ------- |
| Material-UI | v4.5.0  |
| React       |   ^16.10.2      |
| Browser     |    chrome     |
| TypeScript  |   no      |
| etc.        |         |



Issue discussion:
The problems come from *layout.css*, it's the first time I see such approach:

```css
html {
  overflow-y: scroll;
}
```

Where does this template come from?
Oh boy, it's present with
```sh
npm install -g gatsby-cli
gatsby new gatsby-site
cd gatsby-site
```
Ok, maybe we should apply overflow: hidden to the `<html>` element. Gatsby's owner has provided an interesting answer on why the overflow style on the element is important: https://github.com/gatsbyjs/gatsby/pull/18411#issuecomment-541633814.

I would like to explore a diff that adds overflow hidden to the body and the html element, when required. What do you think of?
```diff
diff --git a/packages/material-ui/src/Modal/ModalManager.js b/packages/material-ui/src/Modal/ModalManager.js
index a0e9dc0a2..d640b34ef 100644
--- a/packages/material-ui/src/Modal/ModalManager.js
+++ b/packages/material-ui/src/Modal/ModalManager.js
@@ -59,35 +59,46 @@ function findIndexOf(containerInfo, callback) {
 }

 function handleContainer(containerInfo, props) {
-  const restoreStyle = {};
-  const style = {};
+  const restoreStyle = [];
   const restorePaddings = [];
+  const container = containerInfo.container;
   let fixedNodes;

-  if (!props.disableScrollLock) {
-    restoreStyle.overflow = containerInfo.container.style.overflow;
-    restoreStyle['padding-right'] = containerInfo.container.style.paddingRight;
-    style.overflow = 'hidden';
+  if (!props.disableScrollLock && isOverflowing(container)) {
+    const parent = container.parentElement;
+    if (parent.nodeName === 'HTML') {
+      restoreStyle.push({
+        value: parent.style.overflow,
+        key: 'overflow',
+        el: parent,
+      });
+      parent.style.overflow = 'hidden';
+    }
+    restoreStyle.push({
+      value: container.style.overflow,
+      key: 'overflow',
+      el: container,
+    });
+    restoreStyle.push({
+      value: container.style.paddingRight,
+      key: 'padding-right',
+      el: container,
+    });
+    container.style.overflow = 'hidden';

-    if (isOverflowing(containerInfo.container)) {
-      const scrollbarSize = getScrollbarSize();
+    const scrollbarSize = getScrollbarSize();

-      // Use computed style, here to get the real padding to add our scrollbar width.
-      style['padding-right'] = `${getPaddingRight(containerInfo.container) + scrollbarSize}px`;
+    // Use computed style, here to get the real padding to add our scrollbar width.
+    container.style['padding-right'] = `${getPaddingRight(container) + scrollbarSize}px`;

-      // .mui-fixed is a global helper.
-      fixedNodes = ownerDocument(containerInfo.container).querySelectorAll('.mui-fixed');
-      [].forEach.call(fixedNodes, node => {
-        restorePaddings.push(node.style.paddingRight);
-        node.style.paddingRight = `${getPaddingRight(node) + scrollbarSize}px`;
-      });
-    }
+    // .mui-fixed is a global helper.
+    fixedNodes = ownerDocument(container).querySelectorAll('.mui-fixed');
+    [].forEach.call(fixedNodes, node => {
+      restorePaddings.push(node.style.paddingRight);
+      node.style.paddingRight = `${getPaddingRight(node) + scrollbarSize}px`;
+    });
   }

-  Object.keys(style).forEach(key => {
-    containerInfo.container.style[key] = style[key];
-  });
-
   const restore = () => {
     if (fixedNodes) {
       [].forEach.call(fixedNodes, (node, i) => {
@@ -99,11 +110,11 @@ function handleContainer(containerInfo, props) {
       });
     }

-    Object.keys(restoreStyle).forEach(key => {
-      if (restoreStyle[key]) {
-        containerInfo.container.style.setProperty(key, restoreStyle[key]);
+    restoreStyle.forEach(({ value, el, key }) => {
+      if (value) {
+        el.style.setProperty(key, value);
       } else {
-        containerInfo.container.style.removeProperty(key);
+        el.style.removeProperty(key);
       }
     });
   };
```
This somewhat relates to my gripe with dislodged scrollbars for modals (scrolle=body vs scroll=paper). My guess was always that this was intended to direct mousewheel scrolling while hovering over the body to the dialog. 

Would it make sense to prevent event defaults in mouse wheel event handlers?
> Would it make sense to prevent event defaults in mouse wheel event handlers?

@eps1lon As an alternative implementation of the scroll lock feature (rather than the overflow: hidden approach)? I don't have all the context on this matter, I believe there is no way to prevent manual interactions with the scrollbar buttons, but maybe there is a better way :). https://github.com/reactjs/react-modal/issues/191
The scroll bar maybe not. Though I think you can prevent mousewheel scroll. I doubt many people actually click on scrollbars. Those are tiny :smile:
Related to: #5098.

Solution patch:
diff --git a/docs/src/pages/components/modal/ServerModal.js b/docs/src/pages/components/modal/ServerModal.js
--- a/docs/src/pages/components/modal/ServerModal.js
+++ b/docs/src/pages/components/modal/ServerModal.js
@@ -4,9 +4,14 @@ import Modal from '@material-ui/core/Modal';
 
 const useStyles = makeStyles(theme => ({
   root: {
-    transform: 'translateZ(0)',
     height: 300,
     flexGrow: 1,
+    transform: 'translateZ(0)',
+    // The position fixed scoping doesn't work in IE 11.
+    // Disable this demo to preserve the others.
+    '@media all and (-ms-high-contrast: none)': {
+      display: 'none',
+    },
   },
   modal: {
     display: 'flex',
diff --git a/docs/src/pages/components/modal/ServerModal.tsx b/docs/src/pages/components/modal/ServerModal.tsx
--- a/docs/src/pages/components/modal/ServerModal.tsx
+++ b/docs/src/pages/components/modal/ServerModal.tsx
@@ -5,9 +5,14 @@ import Modal from '@material-ui/core/Modal';
 const useStyles = makeStyles((theme: Theme) =>
   createStyles({
     root: {
-      transform: 'translateZ(0)',
       height: 300,
       flexGrow: 1,
+      transform: 'translateZ(0)',
+      // The position fixed scoping doesn't work in IE 11.
+      // Disable this demo to preserve the others.
+      '@media all and (-ms-high-contrast: none)': {
+        display: 'none',
+      },
     },
     modal: {
       display: 'flex',
diff --git a/docs/src/pages/components/modal/SpringModal.js b/docs/src/pages/components/modal/SpringModal.js
--- a/docs/src/pages/components/modal/SpringModal.js
+++ b/docs/src/pages/components/modal/SpringModal.js
@@ -3,7 +3,7 @@ import React from 'react';
 import { makeStyles } from '@material-ui/core/styles';
 import Modal from '@material-ui/core/Modal';
 import Backdrop from '@material-ui/core/Backdrop';
-import { useSpring, animated } from 'react-spring';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
 
 const useStyles = makeStyles(theme => ({
   modal: {
diff --git a/docs/src/pages/components/modal/SpringModal.tsx b/docs/src/pages/components/modal/SpringModal.tsx
--- a/docs/src/pages/components/modal/SpringModal.tsx
+++ b/docs/src/pages/components/modal/SpringModal.tsx
@@ -3,7 +3,7 @@ import React from 'react';
 import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
 import Modal from '@material-ui/core/Modal';
 import Backdrop from '@material-ui/core/Backdrop';
-import { useSpring, animated } from 'react-spring';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
 
 const useStyles = makeStyles((theme: Theme) =>
   createStyles({
diff --git a/docs/src/pages/components/popper/SpringPopper.js b/docs/src/pages/components/popper/SpringPopper.js
--- a/docs/src/pages/components/popper/SpringPopper.js
+++ b/docs/src/pages/components/popper/SpringPopper.js
@@ -2,7 +2,7 @@
 import React from 'react';
 import { makeStyles } from '@material-ui/core/styles';
 import Popper from '@material-ui/core/Popper';
-import { useSpring, animated } from 'react-spring';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
 
 const useStyles = makeStyles(theme => ({
   paper: {
diff --git a/docs/src/pages/components/popper/SpringPopper.tsx b/docs/src/pages/components/popper/SpringPopper.tsx
--- a/docs/src/pages/components/popper/SpringPopper.tsx
+++ b/docs/src/pages/components/popper/SpringPopper.tsx
@@ -2,7 +2,7 @@
 import React from 'react';
 import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
 import Popper from '@material-ui/core/Popper';
-import { useSpring, animated } from 'react-spring';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
 
 const useStyles = makeStyles((theme: Theme) =>
   createStyles({
diff --git a/docs/src/pages/components/tree-view/CustomizedTreeView.js b/docs/src/pages/components/tree-view/CustomizedTreeView.js
--- a/docs/src/pages/components/tree-view/CustomizedTreeView.js
+++ b/docs/src/pages/components/tree-view/CustomizedTreeView.js
@@ -5,7 +5,7 @@ import { fade, makeStyles, withStyles } from '@material-ui/core/styles';
 import TreeView from '@material-ui/lab/TreeView';
 import TreeItem from '@material-ui/lab/TreeItem';
 import Collapse from '@material-ui/core/Collapse';
-import { useSpring, animated } from 'react-spring';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
 
 function MinusSquare(props) {
   return (
diff --git a/docs/src/pages/components/tree-view/CustomizedTreeView.tsx b/docs/src/pages/components/tree-view/CustomizedTreeView.tsx
--- a/docs/src/pages/components/tree-view/CustomizedTreeView.tsx
+++ b/docs/src/pages/components/tree-view/CustomizedTreeView.tsx
@@ -4,7 +4,7 @@ import { fade, makeStyles, withStyles, Theme, createStyles } from '@material-ui/
 import TreeView from '@material-ui/lab/TreeView';
 import TreeItem, { TreeItemProps } from '@material-ui/lab/TreeItem';
 import Collapse from '@material-ui/core/Collapse';
-import { useSpring, animated } from 'react-spring';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
 import { TransitionProps } from '@material-ui/core/transitions';
 
 function MinusSquare(props: SvgIconProps) {
diff --git a/packages/material-ui/src/Modal/ModalManager.js b/packages/material-ui/src/Modal/ModalManager.js
--- a/packages/material-ui/src/Modal/ModalManager.js
+++ b/packages/material-ui/src/Modal/ModalManager.js
@@ -2,13 +2,12 @@ import getScrollbarSize from '../utils/getScrollbarSize';
 import ownerDocument from '../utils/ownerDocument';
 import ownerWindow from '../utils/ownerWindow';
 
-// Do we have a vertical scrollbar?
+// Is a vertical scrollbar displayed?
 function isOverflowing(container) {
   const doc = ownerDocument(container);
 
   if (doc.body === container) {
-    const win = ownerWindow(doc);
-    return win.innerWidth > doc.documentElement.clientWidth;
+    return ownerWindow(doc).innerWidth > doc.documentElement.clientWidth;
   }
 
   return container.scrollHeight > container.clientHeight;
@@ -26,26 +25,21 @@ function getPaddingRight(node) {
   return parseInt(window.getComputedStyle(node)['padding-right'], 10) || 0;
 }
 
-const BLACKLIST = ['template', 'script', 'style'];
-
-function isHideable(node) {
-  return node.nodeType === 1 && BLACKLIST.indexOf(node.tagName.toLowerCase()) === -1;
-}
-
-function siblings(container, mount, currentNode, nodesToExclude, callback) {
-  const blacklist = [mount, currentNode, ...nodesToExclude];
+function ariaHiddenSiblings(container, mountNode, currentNode, nodesToExclude = [], show) {
+  const blacklist = [mountNode, currentNode, ...nodesToExclude];
+  const blacklistTagNames = ['TEMPLATE', 'SCRIPT', 'STYLE'];
 
   [].forEach.call(container.children, node => {
-    if (blacklist.indexOf(node) === -1 && isHideable(node)) {
-      callback(node);
+    if (
+      node.nodeType === 1 &&
+      blacklist.indexOf(node) === -1 &&
+      blacklistTagNames.indexOf(node.tagName) === -1
+    ) {
+      ariaHidden(node, show);
     }
   });
 }
 
-function ariaHiddenSiblings(container, mountNode, currentNode, nodesToExclude = [], show) {
-  siblings(container, mountNode, currentNode, nodesToExclude, node => ariaHidden(node, show));
-}
-
 function findIndexOf(containerInfo, callback) {
   let idx = -1;
   containerInfo.some((item, index) => {
@@ -59,24 +53,42 @@ function findIndexOf(containerInfo, callback) {
 }
 
 function handleContainer(containerInfo, props) {
-  const restoreStyle = {};
-  const style = {};
+  const restoreStyle = [];
   const restorePaddings = [];
+  const container = containerInfo.container;
   let fixedNodes;
 
   if (!props.disableScrollLock) {
-    restoreStyle.overflow = containerInfo.container.style.overflow;
-    restoreStyle['padding-right'] = containerInfo.container.style.paddingRight;
-    style.overflow = 'hidden';
+    const overflowing = isOverflowing(container);
 
-    if (isOverflowing(containerInfo.container)) {
+    // Improve Gatsby support
+    // https://css-tricks.com/snippets/css/force-vertical-scrollbar/
+    const parent = container.parentElement;
+    const scrollContainer = parent.nodeName === 'HTML' ? parent : container;
+
+    restoreStyle.push({
+      value: scrollContainer.style.overflow,
+      key: 'overflow',
+      el: scrollContainer,
+    });
+
+    // Block the scroll even if no scrollbar is visible to account for mobile keyboard
+    // screensize shrink.
+    scrollContainer.style.overflow = 'hidden';
+
+    if (overflowing) {
       const scrollbarSize = getScrollbarSize();
 
+      restoreStyle.push({
+        value: container.style.paddingRight,
+        key: 'padding-right',
+        el: container,
+      });
       // Use computed style, here to get the real padding to add our scrollbar width.
-      style['padding-right'] = `${getPaddingRight(containerInfo.container) + scrollbarSize}px`;
+      container.style['padding-right'] = `${getPaddingRight(container) + scrollbarSize}px`;
 
       // .mui-fixed is a global helper.
-      fixedNodes = ownerDocument(containerInfo.container).querySelectorAll('.mui-fixed');
+      fixedNodes = ownerDocument(container).querySelectorAll('.mui-fixed');
       [].forEach.call(fixedNodes, node => {
         restorePaddings.push(node.style.paddingRight);
         node.style.paddingRight = `${getPaddingRight(node) + scrollbarSize}px`;
@@ -84,10 +96,6 @@ function handleContainer(containerInfo, props) {
     }
   }
 
-  Object.keys(style).forEach(key => {
-    containerInfo.container.style[key] = style[key];
-  });
-
   const restore = () => {
     if (fixedNodes) {
       [].forEach.call(fixedNodes, (node, i) => {
@@ -99,11 +107,11 @@ function handleContainer(containerInfo, props) {
       });
     }
 
-    Object.keys(restoreStyle).forEach(key => {
-      if (restoreStyle[key]) {
-        containerInfo.container.style.setProperty(key, restoreStyle[key]);
+    restoreStyle.forEach(({ value, el, key }) => {
+      if (value) {
+        el.style.setProperty(key, value);
       } else {
-        containerInfo.container.style.removeProperty(key);
+        el.style.removeProperty(key);
       }
     });
   };
@@ -230,6 +238,6 @@ export default class ModalManager {
   }
 
   isTopModal(modal) {
-    return !!this.modals.length && this.modals[this.modals.length - 1] === modal;
+    return this.modals.length > 0 && this.modals[this.modals.length - 1] === modal;
   }
 }
diff --git a/packages/material-ui/src/test-utils/createMount.js b/packages/material-ui/src/test-utils/createMount.js
--- a/packages/material-ui/src/test-utils/createMount.js
+++ b/packages/material-ui/src/test-utils/createMount.js
@@ -35,10 +35,10 @@ class Mode extends React.Component {
 export default function createMount(options = {}) {
   const { mount = enzymeMount, strict: globalStrict, ...globalEnzymeOptions } = options;
 
-  const attachTo = window.document.createElement('div');
+  const attachTo = document.createElement('div');
   attachTo.className = 'app';
   attachTo.setAttribute('id', 'app');
-  window.document.body.insertBefore(attachTo, window.document.body.firstChild);
+  document.body.insertBefore(attachTo, document.body.firstChild);
 
   const mountWithContext = function mountWithContext(node, localOptions = {}) {
     const { disableUnnmount = false, strict = globalStrict, ...localEnzymeOptions } = localOptions;


Test patch:
diff --git a/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js b/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js
--- a/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js
+++ b/packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js
@@ -77,13 +77,13 @@ describe('<ClickAwayListener />', () => {
         </ClickAwayListener>,
       );
       const preventDefault = event => event.preventDefault();
-      window.document.body.addEventListener('click', preventDefault);
+      document.body.addEventListener('click', preventDefault);
 
       const event = new window.Event('click', { view: window, bubbles: true, cancelable: true });
-      window.document.body.dispatchEvent(event);
+      document.body.dispatchEvent(event);
       assert.strictEqual(handleClickAway.callCount, 0);
 
-      window.document.body.removeEventListener('click', preventDefault);
+      document.body.removeEventListener('click', preventDefault);
     });
   });
 
diff --git a/packages/material-ui/src/Modal/Modal.test.js b/packages/material-ui/src/Modal/Modal.test.js
--- a/packages/material-ui/src/Modal/Modal.test.js
+++ b/packages/material-ui/src/Modal/Modal.test.js
@@ -49,8 +49,18 @@ describe('<Modal />', () => {
   );
 
   describe('props', () => {
+    let container;
+
+    before(() => {
+      container = document.createElement('div');
+      document.body.appendChild(container);
+    });
+
+    after(() => {
+      document.body.removeChild(container);
+    });
+
     it('should consume theme default props', () => {
-      const container = document.createElement('div');
       const theme = createMuiTheme({ props: { MuiModal: { container } } });
       mount(
         <ThemeProvider theme={theme}>
@@ -620,11 +630,11 @@ describe('<Modal />', () => {
       };
 
       const wrapper = mount(<TestCase open={false} />);
-      assert.strictEqual(document.body.style.overflow, '');
+      assert.strictEqual(document.body.parentNode.style.overflow, '');
       wrapper.setProps({ open: true });
-      assert.strictEqual(document.body.style.overflow, 'hidden');
+      assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
       wrapper.setProps({ open: false });
-      assert.strictEqual(document.body.style.overflow, '');
+      assert.strictEqual(document.body.parentNode.style.overflow, '');
     });
 
     it('should open and close with Transitions', done => {
@@ -649,17 +659,17 @@ describe('<Modal />', () => {
 
       let wrapper;
       const onEntered = () => {
-        assert.strictEqual(document.body.style.overflow, 'hidden');
+        assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
         wrapper.setProps({ open: false });
       };
 
       const onExited = () => {
-        assert.strictEqual(document.body.style.overflow, '');
+        assert.strictEqual(document.body.parentNode.style.overflow, '');
         done();
       };
 
       wrapper = mount(<TestCase onEntered={onEntered} onExited={onExited} open={false} />);
-      assert.strictEqual(document.body.style.overflow, '');
+      assert.strictEqual(document.body.parentNode.style.overflow, '');
       wrapper.setProps({ open: true });
     });
   });
@@ -711,23 +721,23 @@ describe('<Modal />', () => {
 
       let wrapper;
       const onEntered = () => {
-        assert.strictEqual(document.body.style.overflow, 'hidden');
+        assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
         wrapper.setProps({ open: false });
       };
 
       const onExited = () => {
-        assert.strictEqual(document.body.style.overflow, '');
+        assert.strictEqual(document.body.parentNode.style.overflow, '');
         done();
       };
 
       const onExiting = () => {
-        assert.strictEqual(document.body.style.overflow, 'hidden');
+        assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
       };
 
       wrapper = mount(
         <TestCase onEntered={onEntered} onExiting={onExiting} onExited={onExited} open={false} />,
       );
-      assert.strictEqual(document.body.style.overflow, '');
+      assert.strictEqual(document.body.parentNode.style.overflow, '');
       wrapper.setProps({ open: true });
     });
 
@@ -754,23 +764,23 @@ describe('<Modal />', () => {
 
       let wrapper;
       const onEntered = () => {
-        assert.strictEqual(document.body.style.overflow, 'hidden');
+        assert.strictEqual(document.body.parentNode.style.overflow, 'hidden');
         wrapper.setProps({ open: false });
       };
 
       const onExited = () => {
-        assert.strictEqual(document.body.style.overflow, '');
+        assert.strictEqual(document.body.parentNode.style.overflow, '');
         done();
       };
 
       const onExiting = () => {
-        assert.strictEqual(document.body.style.overflow, '');
+        assert.strictEqual(document.body.parentNode.style.overflow, '');
       };
 
       wrapper = mount(
         <TestCase onEntered={onEntered} onExiting={onExiting} onExited={onExited} open={false} />,
       );
-      assert.strictEqual(document.body.style.overflow, '');
+      assert.strictEqual(document.body.parentNode.style.overflow, '');
       wrapper.setProps({ open: true });
     });
   });
diff --git a/packages/material-ui/src/Popover/Popover.test.js b/packages/material-ui/src/Popover/Popover.test.js
--- a/packages/material-ui/src/Popover/Popover.test.js
+++ b/packages/material-ui/src/Popover/Popover.test.js
@@ -336,7 +336,7 @@ describe('<Popover />', () => {
     before(() => {
       openPopover = anchorOrigin => {
         if (!anchorEl) {
-          anchorEl = window.document.createElement('div');
+          anchorEl = document.createElement('div');
         }
 
         const css = (element, styles) => {
@@ -352,7 +352,7 @@ describe('<Popover />', () => {
           top: '100px',
           left: '100px',
         });
-        window.document.body.appendChild(anchorEl);
+        document.body.appendChild(anchorEl);
 
         return new Promise(resolve => {
           const component = (
@@ -362,7 +362,7 @@ describe('<Popover />', () => {
               anchorOrigin={anchorOrigin}
               transitionDuration={0}
               onEntered={() => {
-                popoverEl = window.document.querySelector('[data-mui-test="Popover"]');
+                popoverEl = document.querySelector('[data-mui-test="Popover"]');
                 resolve();
               }}
             >
@@ -392,7 +392,7 @@ describe('<Popover />', () => {
 
     after(() => {
       if (anchorEl) {
-        window.document.body.removeChild(anchorEl);
+        document.body.removeChild(anchorEl);
       }
     });
 
@@ -449,7 +449,7 @@ describe('<Popover />', () => {
 
     it('should pass through container prop if container and anchorEl props are provided', () => {
       const container = document.createElement('div');
-      const wrapper2 = mount(<Popover anchorEl={anchorEl} container={container} open />);
+      const wrapper2 = mount(<Popover anchorEl={anchorEl} container={container} open={false} />);
 
       assert.strictEqual(wrapper2.find(Modal).props().container, container);
     });
@@ -458,7 +458,7 @@ describe('<Popover />', () => {
       await openPopover(undefined);
       assert.strictEqual(
         wrapper.find(Modal).props().container,
-        window.document.body,
+        document.body,
         "should use anchorEl's parent body as Modal container",
       );
     });
@@ -516,7 +516,7 @@ describe('<Popover />', () => {
               anchorOrigin={anchorOrigin}
               transitionDuration={0}
               onEntered={() => {
-                popoverEl = window.document.querySelector('[data-mui-test="Popover"]');
+                popoverEl = document.querySelector('[data-mui-test="Popover"]');
                 resolve();
               }}
             >
@@ -568,7 +568,7 @@ describe('<Popover />', () => {
               anchorReference="none"
               transitionDuration={0}
               onEntered={() => {
-                popoverEl = window.document.querySelector('[data-mui-test="Popover"]');
+                popoverEl = document.querySelector('[data-mui-test="Popover"]');
                 resolve();
               }}
               PaperProps={{
diff --git a/packages/material-ui/src/Popper/Popper.test.js b/packages/material-ui/src/Popper/Popper.test.js
--- a/packages/material-ui/src/Popper/Popper.test.js
+++ b/packages/material-ui/src/Popper/Popper.test.js
@@ -14,7 +14,7 @@ describe('<Popper />', () => {
   let mount;
   const render = createClientRender({ strict: true });
   const defaultProps = {
-    anchorEl: () => window.document.createElement('svg'),
+    anchorEl: () => document.createElement('svg'),
     children: <span>Hello World</span>,
     open: true,
   };
diff --git a/packages/material-ui/src/Snackbar/Snackbar.test.js b/packages/material-ui/src/Snackbar/Snackbar.test.js
--- a/packages/material-ui/src/Snackbar/Snackbar.test.js
+++ b/packages/material-ui/src/Snackbar/Snackbar.test.js
@@ -38,7 +38,7 @@ describe('<Snackbar />', () => {
       mount(<Snackbar open onClose={handleClose} message="message" />);
 
       const event = new window.Event('click', { view: window, bubbles: true, cancelable: true });
-      window.document.body.dispatchEvent(event);
+      document.body.dispatchEvent(event);
 
       assert.strictEqual(handleClose.callCount, 1);
       assert.deepEqual(handleClose.args[0], [event, 'clickaway']);