diff --git a/packages/dnb-eufemia/src/components/tooltip/TooltipPortal.tsx b/packages/dnb-eufemia/src/components/tooltip/TooltipPortal.tsx
index a5f94e621b1..259f25819f5 100644
--- a/packages/dnb-eufemia/src/components/tooltip/TooltipPortal.tsx
+++ b/packages/dnb-eufemia/src/components/tooltip/TooltipPortal.tsx
@@ -83,13 +83,21 @@ export default class TooltipPortal extends React.PureComponent<
}
})
} else if (!active && prevProps.active) {
- tooltipPortal[group].timeout = setTimeout(() => {
+ const run = () => {
this.setState({ isActive: false }, () => {
if (!this.isMainGorup()) {
this.renderPortal()
}
})
- }, parseFloat(String(hide_delay)))
+ }
+ if (this.props.no_animation || globalThis.IS_TEST) {
+ run()
+ } else {
+ tooltipPortal[group].timeout = setTimeout(
+ run,
+ parseFloat(String(hide_delay))
+ )
+ }
}
}
}
diff --git a/packages/dnb-eufemia/src/components/tooltip/TooltipWithEvents.tsx b/packages/dnb-eufemia/src/components/tooltip/TooltipWithEvents.tsx
index 9c1e187cee9..e1bd2ec9d23 100644
--- a/packages/dnb-eufemia/src/components/tooltip/TooltipWithEvents.tsx
+++ b/packages/dnb-eufemia/src/components/tooltip/TooltipWithEvents.tsx
@@ -150,17 +150,19 @@ export default class TooltipWithEvents extends React.PureComponent<
warn(e)
}
- clearTimeout(this._onEnterTimeout)
- this._onEnterTimeout = setTimeout(
- () => {
- this.setState({ isActive: true })
+ const run = () => {
+ this.setState({ isActive: true, clientX: e.clientX })
+ }
- this.setState({ isActive: true, clientX: e.clientX })
- },
- typeof globalThis !== 'undefined' && !globalThis.IS_TEST
- ? parseFloat(String(this.props.show_delay)) || 1
- : 1
- ) // have min 1 to make sure we are after onMouseLeave
+ if (this.props.no_animation || globalThis.IS_TEST) {
+ run()
+ } else {
+ clearTimeout(this._onEnterTimeout)
+ this._onEnterTimeout = setTimeout(
+ run,
+ parseFloat(String(this.props.show_delay)) || 1
+ ) // have min 1 to make sure we are after onMouseLeave
+ }
}
onMouseLeave = (e: MouseEvent) => {
diff --git a/packages/dnb-eufemia/src/components/tooltip/__tests__/Tooltip.test.tsx b/packages/dnb-eufemia/src/components/tooltip/__tests__/Tooltip.test.tsx
index 536a969c4f1..54b44b1e0aa 100644
--- a/packages/dnb-eufemia/src/components/tooltip/__tests__/Tooltip.test.tsx
+++ b/packages/dnb-eufemia/src/components/tooltip/__tests__/Tooltip.test.tsx
@@ -4,14 +4,10 @@
*/
import React from 'react'
-import {
- mount,
- toJson,
- axeComponent,
- loadScss,
- attachToBody,
-} from '../../../core/jest/jestSetup'
-import Tooltip from '../Tooltip'
+import { axeComponent, loadScss } from '../../../core/jest/jestSetup'
+import { fireEvent, render } from '@testing-library/react'
+import { wait } from '@testing-library/user-event/dist/utils'
+import OriginalTooltip from '../Tooltip'
import Anchor from '../../../elements/Anchor'
import { TooltipProps } from '../types'
@@ -41,20 +37,39 @@ beforeEach(() => {
})
describe('Tooltip', () => {
- describe('with target', () => {
- const Component = (props: TooltipProps = {}) => (
+ describe('with target_selector', () => {
+ const Tooltip = (props: TooltipProps = {}) => (
<>
-
+
Text
-
+
>
)
+ it('should validate with ARIA rules as a tooltip', async () => {
+ const Component = render()
+ expect(await axeComponent(Component)).toHaveNoViolations()
+ })
+ })
+
+ describe('with target_element', () => {
+ const Tooltip = (props: TooltipProps = {}) => (
+ Button}
+ >
+ Text
+
+ )
+
it('creates a React Portal', () => {
- mount(, {
- attachTo: attachToBody(),
- })
+ render()
expect(
document.body.querySelectorAll('.dnb-tooltip__portal')
@@ -65,48 +80,21 @@ describe('Tooltip', () => {
})
it('will skip React Portal when skip_portal is true', () => {
- const Comp = mount(, {
- attachTo: attachToBody(),
- })
+ render()
expect(
document.body.querySelectorAll('.dnb-tooltip__portal')
).toHaveLength(0)
-
- expect(toJson(Comp.find('.dnb-tooltip'))).toMatchSnapshot()
})
- it('should validate with ARIA rules as a tooltip', async () => {
- const Comp = mount()
- expect(await axeComponent(Comp)).toHaveNoViolations()
- })
- })
-
- describe('with target_element', () => {
- const Component = (props: TooltipProps = {}) => (
- Button}
- >
- Text
-
- )
-
- it('have to match default tooltip snapshot', () => {
- const Comp = mount()
- expect(toJson(Comp)).toMatchSnapshot()
- })
-
- it('should show when active prop is true', async () => {
- const Component = () => {
+ it('should show when active prop is true', () => {
+ const Tooltip = () => {
const [active, setActive] = React.useState(false)
return (
- {
@@ -121,112 +109,152 @@ describe('Tooltip', () => {
}
>
Tooltip
-
+
)
}
- const Comp = mount()
+ render()
const mainElem = document.body.querySelector('.dnb-tooltip')
+ const buttonElem = document.querySelector('button')
- Comp.find('button').simulate('mouseenter')
+ fireEvent.mouseEnter(buttonElem)
expect(mainElem.classList.contains('dnb-tooltip--active')).toBe(true)
- Comp.find('button').simulate('mouseleave')
- Comp.find('button').simulate('mouseenter')
-
- await wait(2)
+ fireEvent.mouseLeave(buttonElem)
+ fireEvent.mouseEnter(buttonElem)
expect(mainElem.classList.contains('dnb-tooltip--active')).toBe(true)
- Comp.find('button').simulate('mouseleave')
-
- await wait(2)
+ fireEvent.mouseLeave(buttonElem)
expect(mainElem.classList.contains('dnb-tooltip--hide')).toBe(true)
})
- it('should validate with ARIA rules as a tooltip', async () => {
- const Comp = mount()
- expect(await axeComponent(Comp)).toHaveNoViolations()
+ it('should set animate_position class', () => {
+ render()
+
+ const mainElem = document.body.querySelector('.dnb-tooltip')
+
+ expect(Array.from(mainElem.classList)).toEqual(
+ expect.arrayContaining([
+ 'dnb-tooltip',
+ 'dnb-tooltip--active',
+ 'dnb-tooltip--animate_position',
+ ])
+ )
})
- it('should show when active prop is true', async () => {
- const Component = () => {
- const [active, setActive] = React.useState(false)
+ it('should set fixed_position class', () => {
+ render()
+
+ const mainElem = document.body.querySelector('.dnb-tooltip')
+
+ expect(Array.from(mainElem.classList)).toEqual(
+ expect.arrayContaining([
+ 'dnb-tooltip',
+ 'dnb-tooltip--active',
+ 'dnb-tooltip--fixed',
+ ])
+ )
+ })
+
+ describe('and group', () => {
+ const commonProps: TooltipProps = {
+ group: 'unique-name',
+ no_animation: true,
+ }
+ const GroupTooltip = (props) => {
return (
- {
- setActive(true)
- }}
- onMouseLeave={() => {
- setActive(false)
- }}
- >
- Text
-
- }
- >
- Tooltip
-
+ <>
+ Button A}
+ {...commonProps}
+ {...props}
+ >
+ Tooltip A
+
+
+ Button B}
+ {...commonProps}
+ {...props}
+ >
+ Tooltip B
+
+ >
)
}
- const Comp = mount()
+ it('should only have one tooltip', () => {
+ render()
- const mainElem = document.body.querySelector('.dnb-tooltip')
+ const allElements = document.body.querySelectorAll('.dnb-tooltip')
+ const mainElem = allElements[0]
+ const buttonA = document.querySelector('button#a')
+ const buttonB = document.querySelector('button#b')
- Comp.find('button').simulate('mouseenter')
+ expect(allElements).toHaveLength(1)
- expect(mainElem.classList.contains('dnb-tooltip--active')).toBe(true)
+ fireEvent.mouseEnter(buttonA)
- Comp.find('button').simulate('mouseleave')
- Comp.find('button').simulate('mouseenter')
+ expect(mainElem.textContent).toBe('Tooltip A')
+ expect(mainElem.classList.contains('dnb-tooltip--active')).toBe(
+ true
+ )
- await wait(2)
+ fireEvent.mouseEnter(buttonB)
- expect(mainElem.classList.contains('dnb-tooltip--active')).toBe(true)
+ expect(mainElem.textContent).toBe('Tooltip B')
+ expect(mainElem.classList.contains('dnb-tooltip--active')).toBe(
+ true
+ )
- Comp.find('button').simulate('mouseleave')
+ fireEvent.mouseLeave(buttonB)
- await wait(2)
+ expect(mainElem.classList.contains('dnb-tooltip--hide')).toBe(true)
+ })
+ })
- expect(mainElem.classList.contains('dnb-tooltip--hide')).toBe(true)
+ it('should validate with ARIA rules as a tooltip', async () => {
+ const Component = render()
+ expect(await axeComponent(Component)).toHaveNoViolations()
})
})
describe('Anchor with tooltip', () => {
it('has to be in the DOM so aria-describedby is valid', () => {
- const Comp = mount(
+ render(
text
)
- const id = Comp.find('a').instance().getAttribute('aria-describedby')
+ const id = document
+ .querySelector('a')
+ .getAttribute('aria-describedby')
expect(document.body.querySelectorAll('#' + id).length).toBe(1)
})
it('has to be visible on hover', async () => {
- const Comp = mount(
+ render(
text
)
// hover
- Comp.find('a').instance().dispatchEvent(new MouseEvent('mouseenter'))
+ document
+ .querySelector('a')
+ .dispatchEvent(new MouseEvent('mouseenter'))
await wait(100)
- const id = Comp.find('a').instance().getAttribute('aria-describedby')
+ const id = document
+ .querySelector('a')
+ .getAttribute('aria-describedby')
expect(
document.body
.querySelector('#' + id)
@@ -234,7 +262,9 @@ describe('Tooltip', () => {
).toBe(true)
// leave hover
- Comp.find('a').instance().dispatchEvent(new MouseEvent('mouseleave'))
+ document
+ .querySelector('a')
+ .dispatchEvent(new MouseEvent('mouseleave'))
await wait(600)
@@ -246,14 +276,14 @@ describe('Tooltip', () => {
})
it('has to be visible on focus event dispatch', async () => {
- const Comp = mount(
+ render(
text
)
document.documentElement.setAttribute('data-whatintent', 'keyboard')
- const inst = Comp.find('a').instance()
+ const inst = document.querySelector('a')
inst.dispatchEvent(new Event('focus'))
await wait(400) // because of visibility delay
@@ -281,5 +311,3 @@ describe('Tooltip scss', () => {
expect(scss).toMatchSnapshot()
})
})
-
-const wait = (t: number) => new Promise((r) => setTimeout(r, t))
diff --git a/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.tsx.snap b/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.tsx.snap
index 1ade9000ec0..3105299324b 100644
--- a/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.tsx.snap
+++ b/packages/dnb-eufemia/src/components/tooltip/__tests__/__snapshots__/Tooltip.test.tsx.snap
@@ -181,123 +181,3 @@ exports[`Tooltip scss have to match snapshot 1`] = `
visibility: hidden; } }
"
`;
-
-exports[`Tooltip with target will skip React Portal when skip_portal is true 1`] = `
-
-
-
- Text
-
-
-`;
-
-exports[`Tooltip with target_element have to match default tooltip snapshot 1`] = `
-
-
- Button
-
- }
- >
-
- Button
-
- }
- target_element={
-
- }
- target_selector={null}
- tooltip={null}
- >
-
-
- Button
-
- }
- target_element={
-
- }
- target_selector={null}
- tooltip={null}
- />
-
-
-
-`;
diff --git a/packages/dnb-eufemia/src/components/tooltip/stories/Tooltip.stories.tsx b/packages/dnb-eufemia/src/components/tooltip/stories/Tooltip.stories.tsx
index 06d60787e19..ef2cee3e01b 100644
--- a/packages/dnb-eufemia/src/components/tooltip/stories/Tooltip.stories.tsx
+++ b/packages/dnb-eufemia/src/components/tooltip/stories/Tooltip.stories.tsx
@@ -119,7 +119,11 @@ export const TooltipSandbox = () => {
Tooltip
Tooltip for this NumberFormat}
+ tooltip={
+
+ Tooltip for this NumberFormat
+
+ }
>
1234