Skip to content

Commit 3f8c885

Browse files
authored
Overlay improvements (#724)
* Make Overlay more robust. * Fix tests
1 parent 859309e commit 3f8c885

File tree

8 files changed

+156
-111
lines changed

8 files changed

+156
-111
lines changed

.babelrc

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
{
2-
"presets": [
3-
"@babel/preset-env",
4-
"@babel/preset-react"
5-
],
6-
"plugins": [
7-
"@babel/plugin-proposal-object-rest-spread"
8-
],
9-
"env": {
10-
"test": {
11-
"plugins": [
12-
"@babel/plugin-proposal-class-properties"
13-
]
14-
}
2+
"presets": ["@babel/preset-env", "@babel/preset-react"],
3+
"plugins": [
4+
"@babel/plugin-proposal-object-rest-spread",
5+
"@babel/plugin-transform-runtime"
6+
],
7+
"env": {
8+
"test": {
9+
"plugins": ["@babel/plugin-proposal-class-properties"]
1510
}
11+
}
1612
}

package-lock.json

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
"@babel/core": "^7.15.0",
3939
"@babel/plugin-proposal-class-properties": "^7.14.5",
4040
"@babel/plugin-proposal-object-rest-spread": "^7.14.7",
41+
"@babel/plugin-transform-runtime": "^7.15.0",
4142
"@babel/preset-env": "^7.15.0",
4243
"@babel/preset-react": "^7.14.5",
4344
"@testing-library/jest-dom": "^5.14.1",

src/components/tooltip/__tests__/Tooltip.test.js

Lines changed: 0 additions & 68 deletions
This file was deleted.

src/private/Overlay.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ function isInDOMSubtree(element, subtreeRoot) {
99

1010
function useStateRef(initialValue) {
1111
const [value, setValue] = useState(initialValue);
12-
1312
const ref = useRef(value);
1413

1514
useEffect(() => {
@@ -146,9 +145,23 @@ const Overlay = ({
146145
setIsOpen(defaultShow);
147146
}, [defaultShow]);
148147

148+
const wait = ms => new Promise(res => setTimeout(res, ms));
149+
150+
const getTarget = async (target, depth = 0) => {
151+
const targetRef = document.getElementById(target);
152+
if (targetRef === null && depth < 4) {
153+
await wait(2 ** depth * 100);
154+
return getTarget(target, depth + 1);
155+
}
156+
return targetRef;
157+
};
158+
149159
useEffect(() => {
150-
targetRef.current = document.getElementById(targetStr);
151-
addEventListeners(targetRef.current);
160+
const attachListenersToTarget = async () => {
161+
targetRef.current = await getTarget(targetStr);
162+
addEventListeners(targetRef.current);
163+
};
164+
attachListenersToTarget();
152165
}, [targetStr]);
153166

154167
return (

src/private/__tests__/Overlay.test.js

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
*/
44

55
import React from 'react';
6-
import {act, fireEvent, render} from '@testing-library/react';
7-
import userEvent from '@testing-library/user-event';
8-
import Tooltip from '../../components/tooltip/Tooltip';
9-
6+
import {render} from '@testing-library/react';
7+
import Overlay from '../Overlay';
108
jest.useFakeTimers();
119

12-
describe('Tooltip with dict id', () => {
10+
const CustomChild = React.forwardRef((props, ref) => (
11+
<div ref={ref} id="content">
12+
Some test content
13+
</div>
14+
));
15+
16+
describe('Overlay with dict id', () => {
1317
// this is just a little hack to silence a warning that we'll get until we
1418
// upgrade to 16.9. See also: https://github.com/facebook/react/pull/14853
1519
const originalError = console.error;
@@ -34,41 +38,27 @@ describe('Tooltip with dict id', () => {
3438

3539
test('renders nothing by default', () => {
3640
render(
37-
<Tooltip target={{type: 'target', index: 1}}>Test content</Tooltip>,
41+
<Overlay target={{type: 'target', index: 1}}>
42+
<CustomChild />
43+
</Overlay>,
3844
{
3945
container: document.body.appendChild(div)
4046
}
4147
);
4248

43-
expect(document.body.querySelector('.tooltip')).toBe(null);
44-
});
45-
46-
test('renders a div with class "tooltip"', () => {
47-
render(<Tooltip target={{type: 'target', index: 1}} />, {
48-
container: document.body.appendChild(div)
49-
});
50-
51-
fireEvent.mouseOver(div);
52-
act(() => jest.runAllTimers());
53-
expect(document.body.querySelector('.tooltip')).not.toBe(null);
54-
55-
fireEvent.mouseLeave(div);
56-
act(() => jest.runAllTimers());
57-
expect(document.body.querySelector('.tooltip')).toBe(null);
49+
expect(document.body.querySelector('#content')).toBe(null);
5850
});
5951

6052
test('renders its content', () => {
6153
render(
62-
<Tooltip target={{type: 'target', index: 1}}>Tooltip content</Tooltip>,
54+
<Overlay defaultShow target={{type: 'target', index: 1}}>
55+
<CustomChild />
56+
</Overlay>,
6357
{
6458
container: document.body.appendChild(div)
6559
}
6660
);
6761

68-
fireEvent.mouseOver(div);
69-
act(() => jest.runAllTimers());
70-
expect(document.body.querySelector('.tooltip')).toHaveTextContent(
71-
'Tooltip content'
72-
);
62+
expect(document.body.querySelector('#content')).not.toBe(null);
7363
});
7464
});

tests/test_popover.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from dash import Dash, html
2+
from dash_bootstrap_components import (
3+
Popover,
4+
PopoverBody,
5+
PopoverHeader,
6+
themes,
7+
)
8+
from selenium.webdriver.common.action_chains import ActionChains
9+
10+
11+
def test_dbpo001_popover_click(dash_duo):
12+
app = Dash(external_stylesheets=[themes.BOOTSTRAP])
13+
14+
app.layout = html.Div(
15+
[
16+
Popover(
17+
[PopoverHeader("Test Header"), PopoverBody("Test content")],
18+
id="popover",
19+
target="popover-target",
20+
trigger="click",
21+
),
22+
html.Div("Target", id="popover-target"),
23+
],
24+
className="container p-5",
25+
)
26+
27+
dash_duo.start_server(app)
28+
29+
dash_duo.wait_for_element_by_id("popover-target").click()
30+
assert dash_duo.wait_for_element(".popover-body").text == "Test content"
31+
32+
33+
def test_dbpo002_popover_hover(dash_duo):
34+
app = Dash(external_stylesheets=[themes.BOOTSTRAP])
35+
36+
app.layout = html.Div(
37+
[
38+
Popover(
39+
[PopoverHeader("Test Header"), PopoverBody("Test content")],
40+
id="popover",
41+
target="popover-target",
42+
trigger="hover",
43+
),
44+
html.Div("Target", id="popover-target"),
45+
],
46+
className="container p-5",
47+
)
48+
49+
dash_duo.start_server(app)
50+
51+
hover = ActionChains(dash_duo.driver).move_to_element(
52+
dash_duo.wait_for_element_by_id("popover-target")
53+
)
54+
hover.perform()
55+
assert dash_duo.wait_for_element(".popover-body").text == "Test content"

tests/test_tooltip.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from dash import Dash, html
2+
from dash_bootstrap_components import Tooltip, themes
3+
from selenium.webdriver.common.action_chains import ActionChains
4+
5+
6+
def test_dbtt001_tooltip_content(dash_duo):
7+
app = Dash(external_stylesheets=[themes.BOOTSTRAP])
8+
9+
app.layout = html.Div(
10+
[
11+
Tooltip("Test content", id="tooltip", target="tooltip-target"),
12+
html.Div("Target", id="tooltip-target"),
13+
],
14+
className="container p-5",
15+
)
16+
17+
dash_duo.start_server(app)
18+
19+
hover = ActionChains(dash_duo.driver).move_to_element(
20+
dash_duo.wait_for_element_by_id("tooltip-target")
21+
)
22+
hover.perform()
23+
assert dash_duo.wait_for_element(".tooltip-inner").text == "Test content"

0 commit comments

Comments
 (0)