1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00
lens/packages/ui-components/tooltip/src/tooltip.test.tsx
Sebastian Malton 9656b8c577 chore: Fix unit tests by increasing coverage of tooltip to 100%
Signed-off-by: Sebastian Malton <sebastian@malton.name>
2023-04-19 15:01:02 -04:00

415 lines
10 KiB
TypeScript

/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { render } from "@testing-library/react";
import type { RenderResult } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import assert from "assert";
import React from "react";
import { computeNextPosition, RectangleDimensions } from "./helpers";
import { Tooltip, TooltipPosition } from "./tooltip";
const getRectangle = (
parts: Omit<RectangleDimensions, "width" | "height">,
): RectangleDimensions => {
assert(parts.right >= parts.left);
assert(parts.bottom >= parts.top);
return {
...parts,
width: parts.right - parts.left,
height: parts.bottom - parts.top,
};
};
describe("<Tooltip />", () => {
let requestAnimationFrameSpy: jest.SpyInstance<number, [callback: FrameRequestCallback]>;
beforeEach(() => {
requestAnimationFrameSpy = jest.spyOn(window, "requestAnimationFrame");
requestAnimationFrameSpy.mockImplementation((cb) => {
cb(0);
return 0;
});
});
afterEach(() => {
requestAnimationFrameSpy.mockRestore();
});
it("does not render to DOM if not visible", () => {
const result = render(
<>
<Tooltip targetId="my-target" usePortal={false}>
I am a tooltip
</Tooltip>
<div id="my-target">Target Text</div>
</>,
);
expect(result.baseElement).toMatchSnapshot();
});
it("renders to DOM when hovering over target", () => {
const result = render(
<>
<Tooltip targetId="my-target" data-testid="tooltip" usePortal={false}>
I am a tooltip
</Tooltip>
<div id="my-target">Target Text</div>
</>,
);
const target = result.baseElement.querySelector("#my-target");
assert(target);
userEvent.hover(target);
expect(result.baseElement).toMatchSnapshot();
});
it("renders to DOM when forced to by visible prop", () => {
const result = render(
<>
<Tooltip targetId="my-target" data-testid="tooltip" visible={true} usePortal={false}>
I am a tooltip
</Tooltip>
<div id="my-target">Target Text</div>
</>,
);
expect(result.baseElement).toMatchSnapshot();
});
it("uses a portal if usePortal is specified", () => {
const result = render(
<div>
<Tooltip targetId="my-target" data-testid="tooltip" visible={true} usePortal>
I am a tooltip
</Tooltip>
<div id="my-target">Target Text</div>
</div>,
);
expect(result.baseElement).toMatchSnapshot();
});
describe("when specifying a tooltip for a component", () => {
let result: RenderResult;
beforeEach(() => {
result = render(
<div>
<Tooltip targetId="my-target" data-testid="tooltip">
I am a tooltip
</Tooltip>
<div id="my-target" data-testid="target">
Target Text
</div>
</div>,
);
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("doesn't render the tooltip", () => {
expect(result.queryByTestId("tooltip")).not.toBeInTheDocument();
});
describe("when hovering over the target element", () => {
beforeEach(() => {
userEvent.hover(result.getByTestId("target"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("renders the tooltip", () => {
expect(result.getByTestId("tooltip")).toBeInTheDocument();
});
describe("when no longer hovering the target", () => {
beforeEach(() => {
userEvent.unhover(result.getByTestId("target"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("doesn't render the tooltip", () => {
expect(result.queryByTestId("tooltip")).not.toBeInTheDocument();
});
});
});
});
describe("when specifying a tooltip for a component with show on parent hover", () => {
let result: RenderResult;
beforeEach(() => {
result = render(
<div>
<Tooltip targetId="my-target" data-testid="tooltip" tooltipOnParentHover>
I am a tooltip
</Tooltip>
<div data-testid="target-parent">
<div id="my-target" data-testid="target">
Target Text
</div>
</div>
</div>,
);
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("doesn't render the tooltip", () => {
expect(result.queryByTestId("tooltip")).not.toBeInTheDocument();
});
describe("when hovering over the target element", () => {
beforeEach(() => {
userEvent.hover(result.getByTestId("target"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("renders the tooltip", () => {
expect(result.getByTestId("tooltip")).toBeInTheDocument();
});
describe("when no longer hovering the target", () => {
beforeEach(() => {
userEvent.unhover(result.getByTestId("target"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("doesn't render the tooltip", () => {
expect(result.queryByTestId("tooltip")).not.toBeInTheDocument();
});
});
});
describe("when hovering over the target's parent element", () => {
beforeEach(() => {
userEvent.hover(result.getByTestId("target-parent"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("renders the tooltip", () => {
expect(result.getByTestId("tooltip")).toBeInTheDocument();
});
describe("when no longer hovering the target's parent", () => {
beforeEach(() => {
userEvent.unhover(result.getByTestId("target-parent"));
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("doesn't render the tooltip", () => {
expect(result.queryByTestId("tooltip")).not.toBeInTheDocument();
});
});
});
});
describe("when specifying a tooltip for a component that doesn't exist with show on parent hover", () => {
let result: RenderResult;
beforeEach(() => {
result = render(
<>
<Tooltip targetId="my-target" data-testid="tooltip" tooltipOnParentHover>
I am a tooltip
</Tooltip>
</>,
);
});
it("renders", () => {
expect(result.baseElement).toMatchSnapshot();
});
it("doesn't render the tooltip", () => {
expect(result.queryByTestId("tooltip")).not.toBeInTheDocument();
});
});
});
describe("computeNextPosition technical tests", () => {
describe("given a 1280x720 window", () => {
beforeEach(() => {
window.innerHeight = 720;
window.innerWidth = 1280;
});
[
{
position: "right",
targetRect: {
top: 700,
left: 700,
bottom: 720,
right: 720,
},
},
{
position: "bottom",
targetRect: {
top: 500,
left: 1200,
bottom: 520,
right: 1280,
},
},
{
position: "top",
targetRect: {
top: 700,
left: 1200,
bottom: 720,
right: 1280,
},
},
{
position: "left",
targetRect: {
top: 0,
left: 1200,
bottom: 720,
right: 1280,
},
},
].forEach(({ position, targetRect }) => {
it(`renders to the "${position}" by default if there is enough room`, () => {
expect(
computeNextPosition({
offset: 10,
target: {
getBoundingClientRect: () => getRectangle(targetRect),
},
tooltip: {
getBoundingClientRect: () => ({
height: 20,
width: 20,
}),
},
}),
).toMatchObject({
position,
});
});
});
it("doesn't throw if the preferredPosition is invalid", () => {
expect(
computeNextPosition({
preferredPositions: "some-invalid-data" as any,
offset: 10,
target: {
getBoundingClientRect: () =>
getRectangle({
top: 50,
left: 50,
bottom: 100,
right: 100,
}),
},
tooltip: {
getBoundingClientRect: () => ({
height: 20,
width: 20,
}),
},
}),
).toMatchObject({
position: "right",
});
});
it("defaults to right if no other location works", () => {
expect(
computeNextPosition({
offset: 10,
target: {
getBoundingClientRect: () =>
getRectangle({
top: 0,
left: 0,
bottom: 720,
right: 1280,
}),
},
tooltip: {
getBoundingClientRect: () => ({
height: 20,
width: 20,
}),
},
}),
).toMatchObject({
position: "right",
});
});
it.each([
TooltipPosition.RIGHT,
TooltipPosition.BOTTOM,
TooltipPosition.TOP,
TooltipPosition.LEFT,
TooltipPosition.TOP_RIGHT,
TooltipPosition.TOP_LEFT,
TooltipPosition.BOTTOM_RIGHT,
TooltipPosition.BOTTOM_LEFT,
])(
"computes to the %p if there is space and it is specified as a preferred position",
(position) => {
expect(
computeNextPosition({
preferredPositions: position,
offset: 10,
target: {
getBoundingClientRect: () =>
getRectangle({
top: 50,
left: 50,
bottom: 100,
right: 100,
}),
},
tooltip: {
getBoundingClientRect: () => ({
height: 20,
width: 20,
}),
},
}),
).toMatchObject({
position,
});
},
);
});
});