@khanacademy/wonder-blocks-tooltip 2.4.2 → 2.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,64 +0,0 @@
1
- import * as React from "react";
2
- import {render, screen} from "@testing-library/react";
3
-
4
- import {View} from "@khanacademy/wonder-blocks-core";
5
-
6
- import TooltipBubble from "../tooltip-bubble";
7
- import TooltipContent from "../tooltip-content";
8
-
9
- describe("TooltipBubble", () => {
10
- // A little helper method to make the actual test more readable.
11
- const makePopperProps = () =>
12
- ({
13
- placement: "top",
14
- tailOffset: {
15
- top: "0",
16
- left: "50",
17
- bottom: undefined,
18
- right: undefined,
19
- transform: "translate3d(50, 0, 0)",
20
- },
21
- } as const);
22
-
23
- test("updates reference to bubble container", async () => {
24
- // Arrange
25
- // Get some props and set the ref to our assert, that way we assert
26
- // when the bubble component is mounted.
27
- const props = makePopperProps();
28
-
29
- // Do some casting to pretend this is `TooltipContent`. That way we are
30
- // isolating behaviors a bit more.
31
- const fakeContent = (
32
- <View id="content">Some content</View>
33
- ) as React.ReactElement<React.ComponentProps<typeof TooltipContent>>;
34
-
35
- // Act
36
- render(
37
- <View>
38
- <TooltipBubble
39
- id="bubble"
40
- placement={props.placement}
41
- tailOffset={props.tailOffset}
42
- updateBubbleRef={jest.fn()}
43
- onActiveChanged={() => {}}
44
- >
45
- {fakeContent}
46
- </TooltipBubble>
47
- </View>,
48
- );
49
-
50
- // Is the node a mounted element?
51
- const tooltip = await screen.findByRole("tooltip");
52
-
53
- /**
54
- * All we're doing is making sure we got called and verifying that we
55
- * got called with an element we expect.
56
- */
57
- // Assert
58
- // Did we apply our data attribute?
59
- expect(tooltip.getAttribute("data-placement")).toBe("top");
60
-
61
- // Did we render our content?
62
- expect(screen.getByText("Some content")).toBeInTheDocument();
63
- });
64
- });
@@ -1,72 +0,0 @@
1
- import * as React from "react";
2
- import * as ReactDOM from "react-dom";
3
- import {render} from "@testing-library/react";
4
-
5
- import {View} from "@khanacademy/wonder-blocks-core";
6
-
7
- import TooltipBubble from "../tooltip-bubble";
8
- import TooltipPopper from "../tooltip-popper";
9
-
10
- type State = {
11
- ref?: HTMLElement;
12
- };
13
- /**
14
- * A little wrapper for the TooltipPopper so that we can provide an anchor
15
- * element reference and test that the children get rendered.
16
- */
17
- class TestHarness extends React.Component<any, State> {
18
- state: State = {};
19
-
20
- updateRef(ref: any) {
21
- const actualRef = ref && ReactDOM.findDOMNode(ref);
22
- if (actualRef && this.state.ref !== actualRef) {
23
- this.setState({ref: actualRef as HTMLElement});
24
- }
25
- }
26
-
27
- render(): React.ReactElement {
28
- const fakeBubble = (
29
- <View ref={(ref: any) => this.props.resultRef(ref)}>
30
- Fake bubble
31
- </View>
32
- ) as React.ReactElement<React.ComponentProps<typeof TooltipBubble>>;
33
- return (
34
- <View>
35
- <View ref={(ref: any) => this.updateRef(ref)}>Anchor</View>
36
- <TooltipPopper
37
- placement={this.props.placement}
38
- anchorElement={this.state.ref}
39
- >
40
- {(props: any) => fakeBubble}
41
- </TooltipPopper>
42
- </View>
43
- );
44
- }
45
- }
46
-
47
- describe("TooltipPopper", () => {
48
- // The TooltipPopper component is just a wrapper around react-popper.
49
- // PopperJS requires full visual rendering and we don't do that here as
50
- // we're not in a browser.
51
- // So, let's do a test that we at least render the content how we expect
52
- // and use other things to test the overall placement things.
53
- test("ensure component renders", async () => {
54
- // Arrange
55
- const ref = await new Promise((resolve: any, reject: any) => {
56
- const nodes = (
57
- <View>
58
- <TestHarness placement="bottom" resultRef={resolve} />
59
- </View>
60
- );
61
- render(nodes);
62
- });
63
-
64
- if (!ref) {
65
- return;
66
- }
67
-
68
- // Act
69
- // Assert
70
- expect(ref).toBeDefined();
71
- });
72
- });
@@ -1,135 +0,0 @@
1
- import * as React from "react";
2
- import {render} from "@testing-library/react";
3
-
4
- import TooltipTail from "../tooltip-tail";
5
-
6
- import type {Placement} from "../../util/types";
7
-
8
- describe("TooltipTail", () => {
9
- describe("#render", () => {
10
- test("unknown placement, throws", () => {
11
- // Arrange
12
- const fakePlacement = "notaplacement" as Placement;
13
- const nodes = <TooltipTail placement={fakePlacement} />;
14
-
15
- // Act
16
- const underTest = () => render(nodes);
17
-
18
- // Assert
19
- expect(underTest).toThrowErrorMatchingInlineSnapshot(
20
- `"Unknown placement: notaplacement"`,
21
- );
22
- });
23
-
24
- test("known placement, does not throw", () => {
25
- // Arrange
26
- const testPoints = ["top", "right", "bottom", "left"];
27
- const makeNode = (p: any) => <TooltipTail placement={p} />;
28
-
29
- // Act
30
- const testees = testPoints.map(
31
- (tp: any) => () => render(makeNode(tp)),
32
- );
33
-
34
- // Assert
35
- for (const testee of testees) {
36
- expect(testee).not.toThrowError();
37
- }
38
- });
39
-
40
- it("should render a visible tail", () => {
41
- // Arrange
42
- const nodes = <TooltipTail placement="top" />;
43
-
44
- // Act
45
- const {container} = render(nodes);
46
-
47
- // Assert
48
- expect(container).toMatchInlineSnapshot(`
49
- <div>
50
- <div
51
- class=""
52
- data-placement="top"
53
- style="align-items: stretch; border-width: 0px; border-style: solid; box-sizing: border-box; display: flex; flex-direction: column; margin: 0px; padding: 0px; position: relative; z-index: 0; min-height: 0; min-width: 0; pointer-events: none; top: -1px; width: 40px; height: 20px;"
54
- >
55
- <svg
56
- aria-hidden="true"
57
- class="arrow_oo4scr"
58
- height="12"
59
- style="margin-left: 8px; margin-right: 8px; padding-bottom: 8px;"
60
- width="24"
61
- >
62
- <filter
63
- height="200%"
64
- id="tooltip-dropshadow-top-3"
65
- width="200%"
66
- x="-50%"
67
- y="-50%"
68
- >
69
- <fegaussianblur
70
- in="SourceAlpha"
71
- stdDeviation="3"
72
- />
73
- <fecomponenttransfer>
74
- <fefunca
75
- slope="0.3"
76
- type="linear"
77
- />
78
- </fecomponenttransfer>
79
- </filter>
80
- <g
81
- transform="translate(0,5.5)"
82
- >
83
- <polyline
84
- fill="rgba(33,36,44,0.16)"
85
- filter="url(#tooltip-dropshadow-top-3)"
86
- points="0,0 12,12 24,0"
87
- stroke="rgba(33,36,44,0.32)"
88
- />
89
- </g>
90
- <polyline
91
- fill="#ffffff"
92
- points="0,0 12,12 24,0"
93
- stroke="#ffffff"
94
- />
95
- <polyline
96
- fill="#ffffff"
97
- points="0,0 12,12 24,0"
98
- stroke="rgba(33,36,44,0.16)"
99
- />
100
- <polyline
101
- points="0,-0.5 24,-0.5"
102
- stroke="#ffffff"
103
- />
104
- </svg>
105
- </div>
106
- </div>
107
- `);
108
- });
109
-
110
- it("should render a spacer when show is false", () => {
111
- // Arrange
112
- const nodes = <TooltipTail placement="top" show={false} />;
113
-
114
- // Act
115
- const {container} = render(nodes);
116
-
117
- // Assert
118
- expect(container).toMatchInlineSnapshot(`
119
- <div>
120
- <div
121
- class=""
122
- data-placement="top"
123
- style="align-items: stretch; border-width: 0px; border-style: solid; box-sizing: border-box; display: flex; flex-direction: column; margin: 0px; padding: 0px; position: relative; z-index: 0; min-height: 0; min-width: 0; pointer-events: none; top: -1px; width: 40px; height: 20px;"
124
- >
125
- <div
126
- aria-hidden="true"
127
- class=""
128
- style="align-items: stretch; border-width: 0px; border-style: solid; box-sizing: border-box; display: flex; flex-direction: column; margin: 0px; padding: 0px; position: relative; z-index: 0; min-height: 0; min-width: 0; width: 12px; flex-basis: 12px; flex-shrink: 0;"
129
- />
130
- </div>
131
- </div>
132
- `);
133
- });
134
- });
135
- });
@@ -1,116 +0,0 @@
1
- import * as React from "react";
2
-
3
- import {render, screen, fireEvent} from "@testing-library/react";
4
- import {userEvent} from "@testing-library/user-event";
5
-
6
- import Tooltip from "../tooltip";
7
-
8
- describe("tooltip integration tests", () => {
9
- beforeEach(() => {
10
- jest.useFakeTimers();
11
- });
12
-
13
- it("should set timeoutId be null when TooltipBubble is active", async () => {
14
- // Arrange
15
- const ue = userEvent.setup({
16
- advanceTimers: jest.advanceTimersByTime,
17
- });
18
- render(<Tooltip content="hello, world">an anchor</Tooltip>);
19
- const anchor = await screen.findByText("an anchor");
20
-
21
- // Act
22
- await ue.hover(anchor);
23
- // There's a 100ms delay before TooltipAnchor calls _setActiveState with
24
- // instant set to true. This second call is what actually triggers the
25
- // call to this.props.onActiveChanged() which updates Tooltip's active
26
- // state.
27
- jest.runAllTimers();
28
-
29
- // Assert
30
- expect(await screen.findByRole("tooltip")).toBeInTheDocument();
31
- });
32
-
33
- it("should hide the bubble on mouseleave on TooltipAnchor", async () => {
34
- // Arrange
35
- const ue = userEvent.setup({
36
- advanceTimers: jest.advanceTimersByTime,
37
- });
38
- render(<Tooltip content="hello, world">an anchor</Tooltip>);
39
-
40
- const anchor = await screen.findByText("an anchor");
41
- await ue.hover(anchor);
42
-
43
- // Act
44
- await ue.unhover(anchor);
45
- // There's a 100ms delay before TooltipAnchor calls _setActiveState with
46
- // instant set to true. This second call is what actually triggers the
47
- // call to this.props.onActiveChanged() which updates Tooltip's active
48
- // state.
49
- jest.runAllTimers();
50
-
51
- // Assert
52
- expect(screen.queryByRole("tooltip")).toBeNull();
53
- });
54
-
55
- it("should close TooltipBubble on mouseleave on TooltipBubble", async () => {
56
- // Arrange
57
- const ue = userEvent.setup({
58
- advanceTimers: jest.advanceTimersByTime,
59
- });
60
- render(<Tooltip content="hello, world">an anchor</Tooltip>);
61
-
62
- const anchor = await screen.findByText("an anchor");
63
- await ue.hover(anchor);
64
- // hover on bubble to keep it active
65
- // Need to run the timers or we won't get the bubble wrapper to show.
66
- jest.runAllTimers();
67
- const bubbleWrapper = await screen.findByRole("tooltip");
68
- await ue.unhover(anchor);
69
-
70
- // Used because RTL complains about the bubble containing a child
71
- // element with pointerEvents: none
72
- // eslint-disable-next-line testing-library/prefer-user-event
73
- fireEvent.mouseEnter(bubbleWrapper);
74
-
75
- // Act
76
- // eslint-disable-next-line testing-library/prefer-user-event
77
- fireEvent.mouseLeave(bubbleWrapper);
78
- // There's a 100ms delay before TooltipAnchor calls _setActiveState with
79
- // instant set to true. This second call is what actually triggers the
80
- // call to this.props.onActiveChanged() which updates Tooltip's active
81
- // state.
82
- jest.runAllTimers();
83
-
84
- // Assert
85
- expect(screen.queryByRole("tooltip")).not.toBeInTheDocument();
86
- });
87
-
88
- it("should have an opened tooltip when subsequent mouseenter, mouseleave, and mouseenter events occur", async () => {
89
- // This a test case that simulates a bug in Firefox where a tooltip will
90
- // sometimes flicker and not stay opened due to the browser triggering
91
- // subsequent mouseenter, mouseleave, and mouseenter events
92
-
93
- // Arrange
94
- const ue = userEvent.setup({
95
- advanceTimers: jest.advanceTimersByTime,
96
- });
97
- render(<Tooltip content="hello, world">an anchor</Tooltip>);
98
-
99
- // Act
100
- const anchor = await screen.findByText("an anchor");
101
- // Trigger initial mouseenter event on anchor and let the timeout complete
102
- // to activate the tooltip
103
- await ue.hover(anchor);
104
- await jest.runAllTimers();
105
- expect(screen.getByRole("tooltip")).toBeInTheDocument();
106
- // Trigger mouseleave and mouseenter event and run timers only after
107
- // both have been triggered. This simulates the mouseenter event being
108
- // triggered before the tooltip is closed from the mouseleave event
109
- await ue.unhover(anchor);
110
- await ue.hover(anchor);
111
- await jest.runAllTimers();
112
-
113
- // Assert
114
- expect(screen.getByRole("tooltip")).toBeInTheDocument();
115
- });
116
- });