Repository: laboratoriobridge/bold
Pull request #470 (2019-09-24 17:40:04)

Aria fixes for tooltip


Patch:
diff --git a/src/components/InfoLabel/InfoLabel.stories.tsx b/src/components/InfoLabel/InfoLabel.stories.tsx
index 3545715b6..94082b440 100644
--- a/src/components/InfoLabel/InfoLabel.stories.tsx
+++ b/src/components/InfoLabel/InfoLabel.stories.tsx
@@ -2,13 +2,19 @@ import { text } from '@storybook/addon-knobs'
 import { storiesOf } from '@storybook/react'
 import React from 'react'
 
+import { VFlow } from '../VFlow'
+
 import { InfoLabel } from './InfoLabel'
 
 storiesOf('Components|InfoLabel', module).add('default', () => (
-  <>
-    <InfoLabel title={text('title', 'Nome')} placeholder={text('placeholder', '-')}>
+  <VFlow vSpacing={0.5}>
+    <InfoLabel title={text('title', 'Name')} placeholder={text('placeholder', '-')}>
       João da Silva
     </InfoLabel>
-    <InfoLabel title={text('title', 'Nome')} placeholder={text('placeholder', '-')} />
-  </>
+    <InfoLabel title={text('title', 'Text')} placeholder={text('placeholder', '-')}>
+      Lorem ipsum dolor, sit amet consectetur adipisicing elit. Explicabo quasi ullam eos, fuga earum molestiae cum
+      odit, modi exercitationem quis hic quae. Excepturi quia neque expedita explicabo facere corporis dolore?
+    </InfoLabel>
+    <InfoLabel title={text('title', 'Name')} placeholder={text('placeholder', '-')} />
+  </VFlow>
 ))
diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx
index ae93404fa..a0fc6f9b8 100644
--- a/src/components/Tooltip/Tooltip.tsx
+++ b/src/components/Tooltip/Tooltip.tsx
@@ -1,6 +1,7 @@
-import React from 'react'
-import { Manager, Popper, PopperProps, Reference } from 'react-popper'
+import React, { useEffect, useRef, useState } from 'react'
+import { PopperProps } from 'react-popper'
 
+import usePopper from '../../hooks/usePopper'
 import { ExternalStyles, useTheme } from '../../styles'
 import { Omit } from '../../util'
 import { randomStr } from '../../util/string'
@@ -27,21 +28,49 @@ export function Tooltip(props: TooltipProps) {
   const child = React.Children.only(children)
 
   const theme = useTheme()
+  const [visible, setVisible] = useState<boolean>(false)
 
-  const tooltipIdRef = React.useRef<string>(null)
-  React.useEffect(() => {
-    tooltipIdRef.current = `tooltip-${randomStr()}`
-  }, [])
+  const tooltipIdRef = useRef<string>(`tooltip-${randomStr()}`)
+  const anchorRef = useRef<HTMLElement>()
+  const tooltipRef = useRef()
 
-  const [visible, setVisible] = React.useState<boolean>(false)
-  const handleMouseEnter = e => {
+  const { style: popperStyle, placement } = usePopper(
+    {
+      anchorRef,
+      popperRef: tooltipRef,
+      modifiers: {
+        offset: { offset: `0, ${theme.typography.sizes.html * offset}` },
+        preventOverflow: {
+          boundariesElement: 'window',
+        },
+      },
+      ...rest,
+    },
+    [visible]
+  )
+
+  useEffect(() => {
+    if (!anchorRef.current) {
+      return
+    }
+
+    const handleWindowMouseOver = (e: MouseEvent) => {
+      // This is implemented using mouseover since mouseleave does not trigger
+      // for disabled elements due to browser/react bugs (https://github.com/facebook/react/issues/4251)
+      const target = e.target as Node
+      if (!anchorRef.current.contains(target)) {
+        setVisible(false)
+      }
+    }
+
+    window.addEventListener('mouseover', handleWindowMouseOver)
+    return () => window.removeEventListener('mouseover', handleWindowMouseOver)
+  }, [anchorRef.current])
+
+  const handleMouseEnter = (e: React.MouseEvent<HTMLElement>) => {
     setVisible(true)
     child.props.onMouseEnter && child.props.onMouseEnter(e)
   }
-  const handleMouseLeave = e => {
-    setVisible(false)
-    child.props.onMouseLeave && child.props.onMouseLeave(e)
-  }
   const handleFocus = e => {
     setVisible(true)
     child.props.onFocus && child.props.onFocus(e)
@@ -56,54 +85,34 @@ export function Tooltip(props: TooltipProps) {
   }
 
   return (
-    <Manager>
-      <Reference>
-        {({ ref }) => (
-          <RootRef rootRef={ref}>
-            {React.cloneElement(child, {
-              'aria-describedby': visible ? tooltipIdRef.current : undefined,
-              onMouseEnter: handleMouseEnter,
-              onMouseLeave: handleMouseLeave,
-              onFocus: handleFocus,
-              onBlur: handleBlur,
-            })}
-          </RootRef>
-        )}
-      </Reference>
+    <>
+      <RootRef rootRef={anchorRef}>
+        {React.cloneElement(child, {
+          'aria-describedby': tooltipIdRef.current,
+          onMouseEnter: handleMouseEnter,
+          onFocus: handleFocus,
+          onBlur: handleBlur,
+        })}
+      </RootRef>
+
       <FadeTransition in={visible}>
-        {({ className }) =>
-          visible && (
-            <Portal container={container}>
-              <Popper
-                modifiers={{
-                  offset: { offset: `0, ${theme.typography.sizes.html * offset}` },
-                  preventOverflow: {
-                    boundariesElement: 'window',
-                  },
-                }}
-                {...rest}
-              >
-                {({ ref, style, placement }) => (
-                  <div
-                    id={tooltipIdRef.current}
-                    ref={ref}
-                    className={className}
-                    role='tooltip'
-                    style={{
-                      ...style,
-                      zIndex: theme.zIndex.tooltip,
-                    }}
-                    data-placement={placement}
-                  >
-                    <TooltipPopper text={text} style={externalStyle} />
-                  </div>
-                )}
-              </Popper>
-            </Portal>
-          )
-        }
+        {({ className }) => (
+          <Portal container={container}>
+            <div
+              id={tooltipIdRef.current}
+              ref={tooltipRef}
+              className={className}
+              role='tooltip'
+              aria-hidden={!visible ? 'true' : 'false'}
+              style={{ ...popperStyle, zIndex: theme.zIndex.tooltip }}
+              data-placement={placement}
+            >
+              <TooltipPopper text={text} style={externalStyle} />
+            </div>
+          </Portal>
+        )}
       </FadeTransition>
-    </Manager>
+    </>
   )
 }
 
diff --git a/src/util/__mocks__/string.ts b/src/util/__mocks__/string.ts
new file mode 100644
index 000000000..922f23089
--- /dev/null
+++ b/src/util/__mocks__/string.ts
@@ -0,0 +1,3 @@
+export const randomStr = jest.fn(() => {
+  return 'abc'
+})


Test patch:
diff --git a/src/components/Alert/Alert.test.tsx b/src/components/Alert/Alert.test.tsx
index e481f7947..475923a57 100644
--- a/src/components/Alert/Alert.test.tsx
+++ b/src/components/Alert/Alert.test.tsx
@@ -6,6 +6,8 @@ import ptBr from '../../i18n/locales/pt-BR'
 
 import { Alert } from './Alert'
 
+jest.mock('../../util/string')
+
 const click = jest.fn()
 const enter = jest.fn()
 const leave = jest.fn()
diff --git a/src/components/Alert/__snapshots__/Alert.test.tsx.snap b/src/components/Alert/__snapshots__/Alert.test.tsx.snap
index 4eaa6b25f..d705a0631 100644
--- a/src/components/Alert/__snapshots__/Alert.test.tsx.snap
+++ b/src/components/Alert/__snapshots__/Alert.test.tsx.snap
@@ -317,6 +317,7 @@ exports[`should render correctly 1`] = `
           class="emotion-4"
         >
           <button
+            aria-describedby="tooltip-abc"
             aria-label="Close"
             class="emotion-3"
             type="button"
@@ -373,6 +374,7 @@ exports[`should render correctly 1`] = `
           class="emotion-4"
         >
           <button
+            aria-describedby="tooltip-abc"
             aria-label="Close"
             class="emotion-3"
             type="button"
@@ -429,6 +431,7 @@ exports[`should render correctly 1`] = `
           class="emotion-4"
         >
           <button
+            aria-describedby="tooltip-abc"
             aria-label="Close"
             class="emotion-3"
             type="button"
@@ -485,6 +488,7 @@ exports[`should render correctly 1`] = `
           class="emotion-4"
         >
           <button
+            aria-describedby="tooltip-abc"
             aria-label="Close"
             class="emotion-3"
             type="button"
diff --git a/src/components/Dropdown/Dropdown.test.tsx b/src/components/Dropdown/Dropdown.test.tsx
index bd1c44b0a..91f8e3f21 100644
--- a/src/components/Dropdown/Dropdown.test.tsx
+++ b/src/components/Dropdown/Dropdown.test.tsx
@@ -1,13 +1,10 @@
 import { fireEvent, render, wait } from '@testing-library/react'
 import React, { createRef } from 'react'
 
-import * as stringUtils from '../../util/string'
-
 import { Dropdown, DropdownProps } from './Dropdown'
 import { DropdownItem } from './DropdownItem'
 
-const stringUtilsModule = stringUtils as any
-stringUtilsModule.randomStr = jest.fn(() => 'abc')
+jest.mock('../../util/string')
 
 // tslint:disable jsx-no-lambda
 
diff --git a/src/components/MaskedTextField/MaskedTextField.test.tsx b/src/components/MaskedTextField/MaskedTextField.test.tsx
index 70c0467a4..2dfac0095 100644
--- a/src/components/MaskedTextField/MaskedTextField.test.tsx
+++ b/src/components/MaskedTextField/MaskedTextField.test.tsx
@@ -1,12 +1,9 @@
 import { fireEvent, render } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../util/string'
-
 import { MaskedTextField } from './MaskedTextField'
 
-const stringUtilsModule = stringUtils as any
-stringUtilsModule.randomStr = jest.fn(() => 'abc')
+jest.mock('../../util/string')
 
 it('should render correctly', () => {
   const { container } = render(<MaskedTextField label='Masked' mask={['(', /\d/, ')']} />)
diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx
index 713327f8e..14b029d94 100644
--- a/src/components/Modal/Modal.test.tsx
+++ b/src/components/Modal/Modal.test.tsx
@@ -1,10 +1,9 @@
 import { fireEvent, render, wait } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../util/string'
-
 import { Modal, ModalProps } from './Modal'
-;(stringUtils as any).randomStr = jest.fn(() => 'abc')
+
+jest.mock('../../util/string')
 
 describe('Modal', () => {
   it('should render correctly when closed', () => {
diff --git a/src/components/Modal/ModalContainer.test.tsx b/src/components/Modal/ModalContainer.test.tsx
index d6bd9eeaa..5dba90140 100644
--- a/src/components/Modal/ModalContainer.test.tsx
+++ b/src/components/Modal/ModalContainer.test.tsx
@@ -3,10 +3,10 @@ import * as React from 'react'
 
 import { LocaleContext } from '../../i18n'
 import ptBr from '../../i18n/locales/pt-BR'
-import * as stringUtils from '../../util/string'
 
 import { ModalContainer } from './ModalContainer'
-;(stringUtils as any).randomStr = jest.fn(() => 'abc')
+
+jest.mock('../../util/string')
 
 it('should render correctly', () => {
   const { container } = render(<ModalContainer>Container</ModalContainer>)
diff --git a/src/components/Modal/__snapshots__/Modal.test.tsx.snap b/src/components/Modal/__snapshots__/Modal.test.tsx.snap
index 3d2ab8ce1..37e7cd579 100644
--- a/src/components/Modal/__snapshots__/Modal.test.tsx.snap
+++ b/src/components/Modal/__snapshots__/Modal.test.tsx.snap
@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`Modal should accept "style" prop and pass down to ModalContainer 1`] = `
-.emotion-3 {
+.emotion-5 {
   position: fixed;
   left: 50%;
   top: 50%;
@@ -22,18 +22,24 @@ exports[`Modal should accept "style" prop and pass down to ModalContainer 1`] =
   padding: 2rem;
 }
 
-.emotion-6 {
+.emotion-8 {
   overflow: hidden;
 }
 
-.emotion-5 {
+.emotion-1 {
+  -webkit-transition: opacity 200ms ease-in-out;
+  transition: opacity 200ms ease-in-out;
+  opacity: 0;
+}
+
+.emotion-7 {
   -webkit-transition: opacity 200ms ease-in-out;
   transition: opacity 200ms ease-in-out;
   opacity: 0;
   opacity: 1;
 }
 
-.emotion-1 {
+.emotion-3 {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
@@ -63,7 +69,7 @@ exports[`Modal should accept "style" prop and pass down to ModalContainer 1`] =
   margin-right: 0.5rem;
 }
 
-.emotion-1 > span {
+.emotion-3 > span {
   -webkit-align-items: center;
   -webkit-box-align: center;
   -ms-flex-align: center;
@@ -74,25 +80,37 @@ exports[`Modal should accept "style" prop and pass down to ModalContainer 1`] =
   display: inline-flex;
 }
 
-.emotion-1:not(:disabled):active {
+.emotion-3:not(:disabled):active {
   box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
 }
 
-.emotion-1:focus {
+.emotion-3:focus {
   outline: none;
   box-shadow: 0 0 0 2px #0069D0;
 }
 
-.emotion-1:not(:disabled):hover {
+.emotion-3:not(:disabled):hover {
   background-color: rgba(58,58,71,0.1);
 }
 
-.emotion-0 {
+.emotion-2 {
   fill: currentColor;
   font-size: 1.5rem;
 }
 
-.emotion-4 {
+.emotion-0 {
+  border-radius: 2px;
+  max-width: 1280px;
+  background: #3A3A47;
+  color: #FFFFFF;
+  font-size: 0.875rem;
+  font-weight: bold;
+  line-height: 1.5;
+  text-align: center;
+  padding: 0.5rem;
+}
+
+.emotion-6 {
   position: fixed;
   z-index: 1050;
   top: 0;
@@ -102,7 +120,7 @@ exports[`Modal should accept "style" prop and pass down to ModalContainer 1`] =
   background: rgba(211,212,221,0.7);
 }
 
-.emotion-2 {
+.emotion-4 {
   border: 1px solid #D3D4DD;
   box-shadow: 0 8px 10px -5px rgba(0,0,0,0.2),0 6px 30px 5px rgba(0,0,0,0.12),0 16px 24px 2px rgba(0,0,0,0.14);
   border-radius: 4px;
@@ -116,29 +134,43 @@ exports[`Modal should accept "style" prop and pass down to ModalContainer 1`] =
 }
 
 <body
-  class="emotion-6"
+  class="emotion-8"
 >
   <div />
   <div
-    class="emotion-5"
+    aria-hidden="true"
+    class="emotion-1"
+    id="tooltip-abc"
+    role="tooltip"
+    style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none; z-index: 1400;"
+  >
+    <div
+      class="emotion-0"
+    >
+      Close
+    </div>
+  </div>
+  <div
+    class="emotion-7"
   >
     <div
-      class="emotion-3"
+      class="emotion-5"
     >
       <div
         aria-modal="true"
-        class="emotion-2"
+        class="emotion-4"
         role="dialog"
       >
         <button
+          aria-describedby="tooltip-abc"
           aria-label="Close"
-          class="emotion-1"
+          class="emotion-3"
           type="button"
         >
           <span>
             <svg
               aria-hidden="true"
-              class="emotion-0"
+              class="emotion-2"
               height="1em"
               role="img"
               viewBox="0 0 24 24"
@@ -154,7 +186,7 @@ exports[`Modal should accept "style" prop and pass down to ModalContainer 1`] =
       </div>
     </div>
     <div
-      class="emotion-4"
+      class="emotion-6"
       data-testid="backdrop"
     />
   </div>
@@ -168,7 +200,7 @@ exports[`Modal should render correctly when closed 1`] = `
 `;
 
 exports[`Modal should render correctly when opened 1`] = `
-.emotion-3 {
+.emotion-5 {
   position: fixed;
   left: 50%;
   top: 50%;
@@ -189,18 +221,24 @@ exports[`Modal should render correctly when opened 1`] = `
   padding: 2rem;
 }
 
-.emotion-6 {
+.emotion-8 {
   overflow: hidden;
 }
 
-.emotion-5 {
+.emotion-1 {
+  -webkit-transition: opacity 200ms ease-in-out;
+  transition: opacity 200ms ease-in-out;
+  opacity: 0;
+}
+
+.emotion-7 {
   -webkit-transition: opacity 200ms ease-in-out;
   transition: opacity 200ms ease-in-out;
   opacity: 0;
   opacity: 1;
 }
 
-.emotion-2 {
+.emotion-4 {
   border: 1px solid #D3D4DD;
   box-shadow: 0 8px 10px -5px rgba(0,0,0,0.2),0 6px 30px 5px rgba(0,0,0,0.12),0 16px 24px 2px rgba(0,0,0,0.14);
   border-radius: 4px;
@@ -212,7 +250,7 @@ exports[`Modal should render correctly when opened 1`] = `
   width: 900px;
 }
 
-.emotion-1 {
+.emotion-3 {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
@@ -242,7 +280,7 @@ exports[`Modal should render correctly when opened 1`] = `
   margin-right: 0.5rem;
 }
 
-.emotion-1 > span {
+.emotion-3 > span {
   -webkit-align-items: center;
   -webkit-box-align: center;
   -ms-flex-align: center;
@@ -253,25 +291,37 @@ exports[`Modal should render correctly when opened 1`] = `
   display: inline-flex;
 }
 
-.emotion-1:not(:disabled):active {
+.emotion-3:not(:disabled):active {
   box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
 }
 
-.emotion-1:focus {
+.emotion-3:focus {
   outline: none;
   box-shadow: 0 0 0 2px #0069D0;
 }
 
-.emotion-1:not(:disabled):hover {
+.emotion-3:not(:disabled):hover {
   background-color: rgba(58,58,71,0.1);
 }
 
-.emotion-0 {
+.emotion-2 {
   fill: currentColor;
   font-size: 1.5rem;
 }
 
-.emotion-4 {
+.emotion-0 {
+  border-radius: 2px;
+  max-width: 1280px;
+  background: #3A3A47;
+  color: #FFFFFF;
+  font-size: 0.875rem;
+  font-weight: bold;
+  line-height: 1.5;
+  text-align: center;
+  padding: 0.5rem;
+}
+
+.emotion-6 {
   position: fixed;
   z-index: 1050;
   top: 0;
@@ -282,29 +332,43 @@ exports[`Modal should render correctly when opened 1`] = `
 }
 
 <body
-  class="emotion-6"
+  class="emotion-8"
 >
   <div />
   <div
-    class="emotion-5"
+    aria-hidden="true"
+    class="emotion-1"
+    id="tooltip-abc"
+    role="tooltip"
+    style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none; z-index: 1400;"
+  >
+    <div
+      class="emotion-0"
+    >
+      Close
+    </div>
+  </div>
+  <div
+    class="emotion-7"
   >
     <div
-      class="emotion-3"
+      class="emotion-5"
     >
       <div
         aria-modal="true"
-        class="emotion-2"
+        class="emotion-4"
         role="dialog"
       >
         <button
+          aria-describedby="tooltip-abc"
           aria-label="Close"
-          class="emotion-1"
+          class="emotion-3"
           type="button"
         >
           <span>
             <svg
               aria-hidden="true"
-              class="emotion-0"
+              class="emotion-2"
               height="1em"
               role="img"
               viewBox="0 0 24 24"
@@ -320,7 +384,7 @@ exports[`Modal should render correctly when opened 1`] = `
       </div>
     </div>
     <div
-      class="emotion-4"
+      class="emotion-6"
       data-testid="backdrop"
     />
   </div>
@@ -328,7 +392,7 @@ exports[`Modal should render correctly when opened 1`] = `
 `;
 
 exports[`Modal sizes should accept the "auto" size and render accordingly 1`] = `
-.emotion-3 {
+.emotion-5 {
   position: fixed;
   left: 50%;
   top: 50%;
@@ -349,18 +413,24 @@ exports[`Modal sizes should accept the "auto" size and render accordingly 1`] =
   padding: 2rem;
 }
 
-.emotion-6 {
+.emotion-8 {
   overflow: hidden;
 }
 
-.emotion-5 {
+.emotion-1 {
+  -webkit-transition: opacity 200ms ease-in-out;
+  transition: opacity 200ms ease-in-out;
+  opacity: 0;
+}
+
+.emotion-7 {
   -webkit-transition: opacity 200ms ease-in-out;
   transition: opacity 200ms ease-in-out;
   opacity: 0;
   opacity: 1;
 }
 
-.emotion-1 {
+.emotion-3 {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
@@ -390,7 +460,7 @@ exports[`Modal sizes should accept the "auto" size and render accordingly 1`] =
   margin-right: 0.5rem;
 }
 
-.emotion-1 > span {
+.emotion-3 > span {
   -webkit-align-items: center;
   -webkit-box-align: center;
   -ms-flex-align: center;
@@ -401,25 +471,37 @@ exports[`Modal sizes should accept the "auto" size and render accordingly 1`] =
   display: inline-flex;
 }
 
-.emotion-1:not(:disabled):active {
+.emotion-3:not(:disabled):active {
   box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
 }
 
-.emotion-1:focus {
+.emotion-3:focus {
   outline: none;
   box-shadow: 0 0 0 2px #0069D0;
 }
 
-.emotion-1:not(:disabled):hover {
+.emotion-3:not(:disabled):hover {
   background-color: rgba(58,58,71,0.1);
 }
 
-.emotion-0 {
+.emotion-2 {
   fill: currentColor;
   font-size: 1.5rem;
 }
 
-.emotion-4 {
+.emotion-0 {
+  border-radius: 2px;
+  max-width: 1280px;
+  background: #3A3A47;
+  color: #FFFFFF;
+  font-size: 0.875rem;
+  font-weight: bold;
+  line-height: 1.5;
+  text-align: center;
+  padding: 0.5rem;
+}
+
+.emotion-6 {
   position: fixed;
   z-index: 1050;
   top: 0;
@@ -429,7 +511,7 @@ exports[`Modal sizes should accept the "auto" size and render accordingly 1`] =
   background: rgba(211,212,221,0.7);
 }
 
-.emotion-2 {
+.emotion-4 {
   border: 1px solid #D3D4DD;
   box-shadow: 0 8px 10px -5px rgba(0,0,0,0.2),0 6px 30px 5px rgba(0,0,0,0.12),0 16px 24px 2px rgba(0,0,0,0.14);
   border-radius: 4px;
@@ -442,29 +524,43 @@ exports[`Modal sizes should accept the "auto" size and render accordingly 1`] =
 }
 
 <body
-  class="emotion-6"
+  class="emotion-8"
 >
   <div />
   <div
-    class="emotion-5"
+    aria-hidden="true"
+    class="emotion-1"
+    id="tooltip-abc"
+    role="tooltip"
+    style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none; z-index: 1400;"
+  >
+    <div
+      class="emotion-0"
+    >
+      Close
+    </div>
+  </div>
+  <div
+    class="emotion-7"
   >
     <div
-      class="emotion-3"
+      class="emotion-5"
     >
       <div
         aria-modal="true"
-        class="emotion-2"
+        class="emotion-4"
         role="dialog"
       >
         <button
+          aria-describedby="tooltip-abc"
           aria-label="Close"
-          class="emotion-1"
+          class="emotion-3"
           type="button"
         >
           <span>
             <svg
               aria-hidden="true"
-              class="emotion-0"
+              class="emotion-2"
               height="1em"
               role="img"
               viewBox="0 0 24 24"
@@ -480,7 +576,7 @@ exports[`Modal sizes should accept the "auto" size and render accordingly 1`] =
       </div>
     </div>
     <div
-      class="emotion-4"
+      class="emotion-6"
       data-testid="backdrop"
     />
   </div>
@@ -488,7 +584,7 @@ exports[`Modal sizes should accept the "auto" size and render accordingly 1`] =
 `;
 
 exports[`Modal sizes should accept the "large" size and render accordingly 1`] = `
-.emotion-3 {
+.emotion-5 {
   position: fixed;
   left: 50%;
   top: 50%;
@@ -509,18 +605,24 @@ exports[`Modal sizes should accept the "large" size and render accordingly 1`] =
   padding: 2rem;
 }
 
-.emotion-6 {
+.emotion-8 {
   overflow: hidden;
 }
 
-.emotion-5 {
+.emotion-1 {
+  -webkit-transition: opacity 200ms ease-in-out;
+  transition: opacity 200ms ease-in-out;
+  opacity: 0;
+}
+
+.emotion-7 {
   -webkit-transition: opacity 200ms ease-in-out;
   transition: opacity 200ms ease-in-out;
   opacity: 0;
   opacity: 1;
 }
 
-.emotion-2 {
+.emotion-4 {
   border: 1px solid #D3D4DD;
   box-shadow: 0 8px 10px -5px rgba(0,0,0,0.2),0 6px 30px 5px rgba(0,0,0,0.12),0 16px 24px 2px rgba(0,0,0,0.14);
   border-radius: 4px;
@@ -532,7 +634,7 @@ exports[`Modal sizes should accept the "large" size and render accordingly 1`] =
   width: 900px;
 }
 
-.emotion-1 {
+.emotion-3 {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
@@ -562,7 +664,7 @@ exports[`Modal sizes should accept the "large" size and render accordingly 1`] =
   margin-right: 0.5rem;
 }
 
-.emotion-1 > span {
+.emotion-3 > span {
   -webkit-align-items: center;
   -webkit-box-align: center;
   -ms-flex-align: center;
@@ -573,25 +675,37 @@ exports[`Modal sizes should accept the "large" size and render accordingly 1`] =
   display: inline-flex;
 }
 
-.emotion-1:not(:disabled):active {
+.emotion-3:not(:disabled):active {
   box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
 }
 
-.emotion-1:focus {
+.emotion-3:focus {
   outline: none;
   box-shadow: 0 0 0 2px #0069D0;
 }
 
-.emotion-1:not(:disabled):hover {
+.emotion-3:not(:disabled):hover {
   background-color: rgba(58,58,71,0.1);
 }
 
-.emotion-0 {
+.emotion-2 {
   fill: currentColor;
   font-size: 1.5rem;
 }
 
-.emotion-4 {
+.emotion-0 {
+  border-radius: 2px;
+  max-width: 1280px;
+  background: #3A3A47;
+  color: #FFFFFF;
+  font-size: 0.875rem;
+  font-weight: bold;
+  line-height: 1.5;
+  text-align: center;
+  padding: 0.5rem;
+}
+
+.emotion-6 {
   position: fixed;
   z-index: 1050;
   top: 0;
@@ -602,29 +716,43 @@ exports[`Modal sizes should accept the "large" size and render accordingly 1`] =
 }
 
 <body
-  class="emotion-6"
+  class="emotion-8"
 >
   <div />
   <div
-    class="emotion-5"
+    aria-hidden="true"
+    class="emotion-1"
+    id="tooltip-abc"
+    role="tooltip"
+    style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none; z-index: 1400;"
   >
     <div
-      class="emotion-3"
+      class="emotion-0"
+    >
+      Close
+    </div>
+  </div>
+  <div
+    class="emotion-7"
+  >
+    <div
+      class="emotion-5"
     >
       <div
         aria-modal="true"
-        class="emotion-2"
+        class="emotion-4"
         role="dialog"
       >
         <button
+          aria-describedby="tooltip-abc"
           aria-label="Close"
-          class="emotion-1"
+          class="emotion-3"
           type="button"
         >
           <span>
             <svg
               aria-hidden="true"
-              class="emotion-0"
+              class="emotion-2"
               height="1em"
               role="img"
               viewBox="0 0 24 24"
@@ -640,7 +768,7 @@ exports[`Modal sizes should accept the "large" size and render accordingly 1`] =
       </div>
     </div>
     <div
-      class="emotion-4"
+      class="emotion-6"
       data-testid="backdrop"
     />
   </div>
@@ -648,7 +776,7 @@ exports[`Modal sizes should accept the "large" size and render accordingly 1`] =
 `;
 
 exports[`Modal sizes should accept the "small" size and render accordingly 1`] = `
-.emotion-3 {
+.emotion-5 {
   position: fixed;
   left: 50%;
   top: 50%;
@@ -669,18 +797,24 @@ exports[`Modal sizes should accept the "small" size and render accordingly 1`] =
   padding: 2rem;
 }
 
-.emotion-6 {
+.emotion-8 {
   overflow: hidden;
 }
 
-.emotion-5 {
+.emotion-1 {
+  -webkit-transition: opacity 200ms ease-in-out;
+  transition: opacity 200ms ease-in-out;
+  opacity: 0;
+}
+
+.emotion-7 {
   -webkit-transition: opacity 200ms ease-in-out;
   transition: opacity 200ms ease-in-out;
   opacity: 0;
   opacity: 1;
 }
 
-.emotion-1 {
+.emotion-3 {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
@@ -710,7 +844,7 @@ exports[`Modal sizes should accept the "small" size and render accordingly 1`] =
   margin-right: 0.5rem;
 }
 
-.emotion-1 > span {
+.emotion-3 > span {
   -webkit-align-items: center;
   -webkit-box-align: center;
   -ms-flex-align: center;
@@ -721,25 +855,37 @@ exports[`Modal sizes should accept the "small" size and render accordingly 1`] =
   display: inline-flex;
 }
 
-.emotion-1:not(:disabled):active {
+.emotion-3:not(:disabled):active {
   box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
 }
 
-.emotion-1:focus {
+.emotion-3:focus {
   outline: none;
   box-shadow: 0 0 0 2px #0069D0;
 }
 
-.emotion-1:not(:disabled):hover {
+.emotion-3:not(:disabled):hover {
   background-color: rgba(58,58,71,0.1);
 }
 
-.emotion-0 {
+.emotion-2 {
   fill: currentColor;
   font-size: 1.5rem;
 }
 
-.emotion-4 {
+.emotion-0 {
+  border-radius: 2px;
+  max-width: 1280px;
+  background: #3A3A47;
+  color: #FFFFFF;
+  font-size: 0.875rem;
+  font-weight: bold;
+  line-height: 1.5;
+  text-align: center;
+  padding: 0.5rem;
+}
+
+.emotion-6 {
   position: fixed;
   z-index: 1050;
   top: 0;
@@ -749,7 +895,7 @@ exports[`Modal sizes should accept the "small" size and render accordingly 1`] =
   background: rgba(211,212,221,0.7);
 }
 
-.emotion-2 {
+.emotion-4 {
   border: 1px solid #D3D4DD;
   box-shadow: 0 8px 10px -5px rgba(0,0,0,0.2),0 6px 30px 5px rgba(0,0,0,0.12),0 16px 24px 2px rgba(0,0,0,0.14);
   border-radius: 4px;
@@ -762,29 +908,43 @@ exports[`Modal sizes should accept the "small" size and render accordingly 1`] =
 }
 
 <body
-  class="emotion-6"
+  class="emotion-8"
 >
   <div />
   <div
-    class="emotion-5"
+    aria-hidden="true"
+    class="emotion-1"
+    id="tooltip-abc"
+    role="tooltip"
+    style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none; z-index: 1400;"
+  >
+    <div
+      class="emotion-0"
+    >
+      Close
+    </div>
+  </div>
+  <div
+    class="emotion-7"
   >
     <div
-      class="emotion-3"
+      class="emotion-5"
     >
       <div
         aria-modal="true"
-        class="emotion-2"
+        class="emotion-4"
         role="dialog"
       >
         <button
+          aria-describedby="tooltip-abc"
           aria-label="Close"
-          class="emotion-1"
+          class="emotion-3"
           type="button"
         >
           <span>
             <svg
               aria-hidden="true"
-              class="emotion-0"
+              class="emotion-2"
               height="1em"
               role="img"
               viewBox="0 0 24 24"
@@ -800,7 +960,7 @@ exports[`Modal sizes should accept the "small" size and render accordingly 1`] =
       </div>
     </div>
     <div
-      class="emotion-4"
+      class="emotion-6"
       data-testid="backdrop"
     />
   </div>
diff --git a/src/components/Modal/__snapshots__/ModalContainer.test.tsx.snap b/src/components/Modal/__snapshots__/ModalContainer.test.tsx.snap
index 5b0ae7975..2628e49c8 100644
--- a/src/components/Modal/__snapshots__/ModalContainer.test.tsx.snap
+++ b/src/components/Modal/__snapshots__/ModalContainer.test.tsx.snap
@@ -77,6 +77,7 @@ exports[`should accept the "style" prop 1`] = `
     role="dialog"
   >
     <button
+      aria-describedby="tooltip-abc"
       aria-label="Close"
       class="emotion-1"
       type="button"
@@ -177,6 +178,7 @@ exports[`should render correctly 1`] = `
     role="dialog"
   >
     <button
+      aria-describedby="tooltip-abc"
       aria-label="Close"
       class="emotion-1"
       type="button"
diff --git a/src/components/Modal/auto/ModalAuto.test.tsx b/src/components/Modal/auto/ModalAuto.test.tsx
index 7a4991c51..9fddaa220 100644
--- a/src/components/Modal/auto/ModalAuto.test.tsx
+++ b/src/components/Modal/auto/ModalAuto.test.tsx
@@ -1,10 +1,9 @@
 import { fireEvent, render } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../../util/string'
-
 import { ModalAuto } from './ModalAuto'
-;(stringUtils as any).randomStr = jest.fn(() => 'abc')
+
+jest.mock('../../../util/string')
 
 // tslint:disable jsx-no-lambda
 
diff --git a/src/components/Modal/auto/__snapshots__/ModalAuto.test.tsx.snap b/src/components/Modal/auto/__snapshots__/ModalAuto.test.tsx.snap
index ff3967231..a6ffdc52d 100644
--- a/src/components/Modal/auto/__snapshots__/ModalAuto.test.tsx.snap
+++ b/src/components/Modal/auto/__snapshots__/ModalAuto.test.tsx.snap
@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render correctly 1`] = `
-.emotion-7 {
+.emotion-9 {
   position: fixed;
   left: 50%;
   top: 50%;
@@ -22,11 +22,17 @@ exports[`should render correctly 1`] = `
   padding: 2rem;
 }
 
-.emotion-10 {
+.emotion-12 {
   overflow: hidden;
 }
 
-.emotion-6 {
+.emotion-1 {
+  -webkit-transition: opacity 200ms ease-in-out;
+  transition: opacity 200ms ease-in-out;
+  opacity: 0;
+}
+
+.emotion-8 {
   border: 1px solid #D3D4DD;
   box-shadow: 0 8px 10px -5px rgba(0,0,0,0.2),0 6px 30px 5px rgba(0,0,0,0.12),0 16px 24px 2px rgba(0,0,0,0.14);
   border-radius: 4px;
@@ -38,7 +44,7 @@ exports[`should render correctly 1`] = `
   width: 520px;
 }
 
-.emotion-1 {
+.emotion-3 {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
@@ -68,7 +74,7 @@ exports[`should render correctly 1`] = `
   margin-right: 0.5rem;
 }
 
-.emotion-1 > span {
+.emotion-3 > span {
   -webkit-align-items: center;
   -webkit-box-align: center;
   -ms-flex-align: center;
@@ -79,36 +85,48 @@ exports[`should render correctly 1`] = `
   display: inline-flex;
 }
 
-.emotion-1:not(:disabled):active {
+.emotion-3:not(:disabled):active {
   box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
 }
 
-.emotion-1:focus {
+.emotion-3:focus {
   outline: none;
   box-shadow: 0 0 0 2px #0069D0;
 }
 
-.emotion-1:not(:disabled):hover {
+.emotion-3:not(:disabled):hover {
   background-color: rgba(58,58,71,0.1);
 }
 
-.emotion-0 {
+.emotion-2 {
   fill: currentColor;
   font-size: 1.5rem;
 }
 
-.emotion-2 {
+.emotion-0 {
+  border-radius: 2px;
+  max-width: 1280px;
+  background: #3A3A47;
+  color: #FFFFFF;
+  font-size: 0.875rem;
+  font-weight: bold;
+  line-height: 1.5;
+  text-align: center;
+  padding: 0.5rem;
+}
+
+.emotion-4 {
   padding: 2.5rem;
 }
 
-.emotion-5 {
+.emotion-7 {
   background-color: #F0F0F5;
   padding: 1rem;
   border-bottom-left-radius: 4px;
   border-bottom-right-radius: 4px;
 }
 
-.emotion-4 {
+.emotion-6 {
   display: grid;
   grid-auto-flow: column;
   grid-auto-columns: minmax(min-content,max-content);
@@ -119,7 +137,7 @@ exports[`should render correctly 1`] = `
   justify-content: flex-end;
 }
 
-.emotion-3 {
+.emotion-5 {
   display: -webkit-inline-box;
   display: -webkit-inline-flex;
   display: -ms-inline-flexbox;
@@ -147,7 +165,7 @@ exports[`should render correctly 1`] = `
   min-width: 144px;
 }
 
-.emotion-3 > span {
+.emotion-5 > span {
   -webkit-align-items: center;
   -webkit-box-align: center;
   -ms-flex-align: center;
@@ -158,20 +176,20 @@ exports[`should render correctly 1`] = `
   display: inline-flex;
 }
 
-.emotion-3:not(:disabled):active {
+.emotion-5:not(:disabled):active {
   box-shadow: inset 0 2px 8px 0 rgba(0,0,0,0.1);
 }
 
-.emotion-3:focus {
+.emotion-5:focus {
   outline: none;
   box-shadow: 0 0 0 2px #F0F0F5,0 0 0 4px #0069D0;
 }
 
-.emotion-3:not(:disabled):hover {
+.emotion-5:not(:disabled):hover {
   background-color: #F0F0F5;
 }
 
-.emotion-8 {
+.emotion-10 {
   position: fixed;
   z-index: 1050;
   top: 0;
@@ -181,7 +199,7 @@ exports[`should render correctly 1`] = `
   background: rgba(211,212,221,0.7);
 }
 
-.emotion-9 {
+.emotion-11 {
   -webkit-transition: opacity 200ms ease-in-out;
   transition: opacity 200ms ease-in-out;
   opacity: 0;
@@ -189,29 +207,43 @@ exports[`should render correctly 1`] = `
 }
 
 <body
-  class="emotion-10"
+  class="emotion-12"
 >
   <div />
   <div
-    class="emotion-9"
+    aria-hidden="true"
+    class="emotion-1"
+    id="tooltip-abc"
+    role="tooltip"
+    style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none; z-index: 1400;"
+  >
+    <div
+      class="emotion-0"
+    >
+      Close
+    </div>
+  </div>
+  <div
+    class="emotion-11"
   >
     <div
-      class="emotion-7"
+      class="emotion-9"
     >
       <div
         aria-modal="true"
-        class="emotion-6"
+        class="emotion-8"
         role="dialog"
       >
         <button
+          aria-describedby="tooltip-abc"
           aria-label="Close"
-          class="emotion-1"
+          class="emotion-3"
           type="button"
         >
           <span>
             <svg
               aria-hidden="true"
-              class="emotion-0"
+              class="emotion-2"
               height="1em"
               role="img"
               viewBox="0 0 24 24"
@@ -224,20 +256,20 @@ exports[`should render correctly 1`] = `
           </span>
         </button>
         <div
-          class="emotion-2"
+          class="emotion-4"
         >
           <span>
             Body
           </span>
         </div>
         <div
-          class="emotion-5"
+          class="emotion-7"
         >
           <div
-            class="emotion-4"
+            class="emotion-6"
           >
             <button
-              class="emotion-3"
+              class="emotion-5"
               type="button"
             >
               <span>
@@ -249,7 +281,7 @@ exports[`should render correctly 1`] = `
       </div>
     </div>
     <div
-      class="emotion-8"
+      class="emotion-10"
       data-testid="backdrop"
     />
   </div>
diff --git a/src/components/Select/SelectMulti/SelectMulti.test.tsx b/src/components/Select/SelectMulti/SelectMulti.test.tsx
index 63dfaa0fd..714d0c5a7 100644
--- a/src/components/Select/SelectMulti/SelectMulti.test.tsx
+++ b/src/components/Select/SelectMulti/SelectMulti.test.tsx
@@ -1,13 +1,11 @@
 import { fireEvent, render } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../../util/string'
 import { DefaultItemType } from '../SelectSingle'
 
 import { SelectMulti, SelectMultiProps } from './SelectMulti'
 
-const stringUtilsModule = stringUtils as any
-stringUtilsModule.randomStr = jest.fn(() => 'abc')
+jest.mock('../../../util/string')
 
 const items: DefaultItemType[] = [
   { value: 1, label: 'Apple' },
diff --git a/src/components/Select/SelectSingle/SelectSingle.test.tsx b/src/components/Select/SelectSingle/SelectSingle.test.tsx
index 302864315..4ca6a4702 100644
--- a/src/components/Select/SelectSingle/SelectSingle.test.tsx
+++ b/src/components/Select/SelectSingle/SelectSingle.test.tsx
@@ -1,12 +1,9 @@
 import { fireEvent, render } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../../util/string'
-
 import { DefaultItemType, SelectSingle, SelectSingleProps } from './SelectSingle'
 
-const stringUtilsModule = stringUtils as any
-stringUtilsModule.randomStr = jest.fn(() => 'abc')
+jest.mock('../../../util/string')
 
 const items: DefaultItemType[] = [
   { value: 1, label: 'Apple' },
diff --git a/src/components/TextArea/TextArea.test.tsx b/src/components/TextArea/TextArea.test.tsx
index 6c10cd4d1..cc9deeb5f 100644
--- a/src/components/TextArea/TextArea.test.tsx
+++ b/src/components/TextArea/TextArea.test.tsx
@@ -1,12 +1,9 @@
 import { render } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../util/string'
-
 import { TextArea } from './TextArea'
 
-const stringUtilsModule = stringUtils as any
-stringUtilsModule.randomStr = jest.fn(() => 'abc')
+jest.mock('../../util/string')
 
 it('should render correctly', () => {
   const { container } = render(<TextArea name='input' label='Label' placeholder='Test' defaultValue='Value' />)
diff --git a/src/components/TextField/TextField.test.tsx b/src/components/TextField/TextField.test.tsx
index e0d75fd27..1bfb23049 100644
--- a/src/components/TextField/TextField.test.tsx
+++ b/src/components/TextField/TextField.test.tsx
@@ -1,12 +1,9 @@
 import { render } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../util/string'
-
 import { TextField } from './TextField'
 
-const stringUtilsModule = stringUtils as any
-stringUtilsModule.randomStr = jest.fn(() => 'abc')
+jest.mock('../../util/string')
 
 it('should render correctly', () => {
   const { container } = render(<TextField label='Label' error='Some error' />)
diff --git a/src/components/Tooltip/Tooltip.test.tsx b/src/components/Tooltip/Tooltip.test.tsx
index abcf95cc4..1ecb0e30a 100644
--- a/src/components/Tooltip/Tooltip.test.tsx
+++ b/src/components/Tooltip/Tooltip.test.tsx
@@ -1,12 +1,9 @@
 import { fireEvent, render } from '@testing-library/react'
 import React from 'react'
 
-import * as stringUtils from '../../util/string'
-
 import { Tooltip, TooltipProps } from './Tooltip'
 
-const stringUtilsMock = stringUtils as any
-stringUtilsMock.randomStr = jest.fn(() => 'abc')
+jest.mock('../../util/string')
 
 beforeEach(() => render(<div id='portal-root' />))
 
@@ -44,61 +41,56 @@ it('should not render tooltip if text if null or empty', () => {
 
 it('should show tooltip when mouse enters component', () => {
   const { getByText } = render(createComponent())
-  expect(document.body.querySelector('[role="tooltip"]')).toBeFalsy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('true')
   fireEvent.mouseEnter(getByText('Testing'))
-  expect(document.body.querySelector('[role="tooltip"]')).toBeTruthy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('false')
 })
 
 it('should show tooltip when focus component', () => {
   const { getByText } = render(createComponent())
-  expect(document.body.querySelector('[role="tooltip"]')).toBeFalsy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('true')
   fireEvent.focus(getByText('Testing'))
-  expect(document.body.querySelector('[role="tooltip"]')).toBeTruthy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('false')
 })
 
 it('should hide tooltip when mouse leaves component', () => {
   const { getByText } = render(createComponent())
   fireEvent.mouseEnter(getByText('Testing'))
-  fireEvent.mouseLeave(getByText('Testing'))
-  expect(document.body.querySelector('[role="tooltip"]')).toBeFalsy()
+  fireEvent.mouseOver(document)
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('true')
 })
 
 it('should hide tooltip when blur component', () => {
   const { getByText } = render(createComponent())
   fireEvent.focus(getByText('Testing'))
   fireEvent.blur(getByText('Testing'))
-  expect(document.body.querySelector('[role="tooltip"]')).toBeFalsy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('true')
 })
 
 it('should compose onMouseEnter, onMouseLeave, onFocus and onBlur functions', () => {
   const focus = jest.fn()
   const blur = jest.fn()
   const mouseEnter = jest.fn()
-  const mouseLeave = jest.fn()
   const { getByText } = render(
     <Tooltip text='Tooltip text' offset={2} placement='bottom-start'>
-      <button onFocus={focus} onBlur={blur} onMouseEnter={mouseEnter} onMouseLeave={mouseLeave}>
+      <button onFocus={focus} onBlur={blur} onMouseEnter={mouseEnter}>
         Testing
       </button>
     </Tooltip>
   )
 
   const target = getByText('Testing')
-  expect(document.body.querySelector('[role="tooltip"]')).toBeFalsy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('true')
 
   fireEvent.focus(target)
   expect(focus).toHaveBeenCalledTimes(1)
-  expect(document.body.querySelector('[role="tooltip"]')).toBeTruthy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('false')
 
   fireEvent.blur(target)
   expect(blur).toHaveBeenCalledTimes(1)
-  expect(document.body.querySelector('[role="tooltip"]')).toBeFalsy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('true')
 
   fireEvent.mouseEnter(target)
   expect(mouseEnter).toHaveBeenCalledTimes(1)
-  expect(document.body.querySelector('[role="tooltip"]')).toBeTruthy()
-
-  fireEvent.mouseLeave(target)
-  expect(mouseLeave).toHaveBeenCalledTimes(1)
-  expect(document.body.querySelector('[role="tooltip"]')).toBeFalsy()
+  expect(document.body.querySelector('[role="tooltip"]').getAttribute('aria-hidden')).toEqual('false')
 })
diff --git a/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap b/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap
index a4875a72f..8be85b529 100644
--- a/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap
+++ b/src/components/Tooltip/__snapshots__/Tooltip.test.tsx.snap
@@ -1,6 +1,24 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should render correctly 1`] = `
+.emotion-1 {
+  -webkit-transition: opacity 200ms ease-in-out;
+  transition: opacity 200ms ease-in-out;
+  opacity: 0;
+}
+
+.emotion-0 {
+  border-radius: 2px;
+  max-width: 1280px;
+  background: #3A3A47;
+  color: #FFFFFF;
+  font-size: 0.875rem;
+  font-weight: bold;
+  line-height: 1.5;
+  text-align: center;
+  padding: 0.5rem;
+}
+
 <body>
   <div>
     <div
@@ -8,10 +26,25 @@ exports[`should render correctly 1`] = `
     />
   </div>
   <div>
-    <span>
+    <span
+      aria-describedby="tooltip-abc"
+    >
       Testing
     </span>
   </div>
+  <div
+    aria-hidden="true"
+    class="emotion-1"
+    id="tooltip-abc"
+    role="tooltip"
+    style="position: absolute; top: 0px; left: 0px; opacity: 0; pointer-events: none; z-index: 1400;"
+  >
+    <div
+      class="emotion-0"
+    >
+      Tooltip text
+    </div>
+  </div>
 </body>
 `;
 
@@ -41,6 +74,7 @@ exports[`should render correctly 2`] = `
       id="portal-root"
     >
       <div
+        aria-hidden="false"
         class="emotion-1"
         id="tooltip-abc"
         role="tooltip"