1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

fix scroll-spy.test.tsx

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-04-12 12:07:53 -04:00
parent fa9683a170
commit 49faa2f9b7
3 changed files with 37 additions and 46 deletions

View File

@ -5,7 +5,7 @@
import React from "react";
import "@testing-library/jest-dom/extend-expect";
import { render, waitFor } from "@testing-library/react";
import { render, screen, waitFor } from "@testing-library/react";
import { ScrollSpy } from "../scroll-spy";
import { RecursiveTreeView } from "../../tree-view";
@ -23,7 +23,6 @@ describe("<ScrollSpy/>", () => {
it("renders w/o errors", () => {
const { container } = render((
<ScrollSpy
htmlFor=""
render={() => (
<div>
<section id="application">
@ -40,7 +39,6 @@ describe("<ScrollSpy/>", () => {
it("calls intersection observer", () => {
render((
<ScrollSpy
htmlFor=""
render={() => (
<div>
<section id="application">
@ -55,9 +53,8 @@ describe("<ScrollSpy/>", () => {
});
it("renders dataTree component", async () => {
const { queryByTestId } = render((
render((
<ScrollSpy
htmlFor=""
render={dataTree => (
<div>
<nav>
@ -71,9 +68,7 @@ describe("<ScrollSpy/>", () => {
/>
));
await waitFor(() => {
expect(queryByTestId("TreeView")).toBeInTheDocument();
});
expect(await screen.findByTestId("TreeView")).toBeInTheDocument();
});
it("throws if no sections founded", () => {
@ -84,7 +79,6 @@ describe("<ScrollSpy/>", () => {
expect(() => render((
<ScrollSpy
htmlFor=""
render={() => (
<div>
Content
@ -101,9 +95,8 @@ describe("<ScrollSpy/>", () => {
describe("<TreeView/> dataTree inside <ScrollSpy/>", () => {
it("contains links to all sections", async () => {
const { queryByTitle } = render((
render((
<ScrollSpy
htmlFor=""
render={dataTree => (
<div>
<nav>
@ -124,17 +117,14 @@ describe("<TreeView/> dataTree inside <ScrollSpy/>", () => {
/>
));
await waitFor(() => {
expect(queryByTitle("Application")).toBeInTheDocument();
expect(queryByTitle("Appearance")).toBeInTheDocument();
expect(queryByTitle("Theme")).toBeInTheDocument();
});
expect(await screen.findByTitle("Application")).toBeInTheDocument();
expect(await screen.findByTitle("Appearance")).toBeInTheDocument();
expect(await screen.findByTitle("Theme")).toBeInTheDocument();
});
it("not showing links to sections without id", async () => {
const { queryByTitle } = render((
<ScrollSpy
htmlFor=""
render={dataTree => (
<div>
<nav>
@ -154,17 +144,17 @@ describe("<TreeView/> dataTree inside <ScrollSpy/>", () => {
/>
));
expect(await screen.findByTitle("Application")).toBeInTheDocument();
expect(await screen.findByTitle("Appearance")).toBeInTheDocument();
await waitFor(() => {
expect(queryByTitle("Application")).toBeInTheDocument();
expect(queryByTitle("Appearance")).toBeInTheDocument();
expect(queryByTitle("Kubectl")).not.toBeInTheDocument();
});
});
it("expands parent sections", async () => {
const { queryByTitle } = render((
render((
<ScrollSpy
htmlFor=""
render={dataTree => (
<div>
<nav>
@ -191,16 +181,13 @@ describe("<TreeView/> dataTree inside <ScrollSpy/>", () => {
/>
));
await waitFor(() => {
expect(queryByTitle("Application")).toHaveAttribute("aria-expanded");
expect(queryByTitle("Kubernetes")).toHaveAttribute("aria-expanded");
});
expect(await screen.findByTitle("Application")).toHaveAttribute("aria-expanded");
expect(await screen.findByTitle("Kubernetes")).toHaveAttribute("aria-expanded");
});
it("skips sections without headings", async () => {
const { queryByTitle } = render((
render((
<ScrollSpy
htmlFor=""
render={dataTree => (
<div>
<nav>
@ -220,10 +207,11 @@ describe("<TreeView/> dataTree inside <ScrollSpy/>", () => {
/>
));
expect(await screen.findByTitle("Application")).toBeInTheDocument();
await waitFor(() => {
expect(queryByTitle("Application")).toBeInTheDocument();
expect(queryByTitle("appearance")).not.toBeInTheDocument();
expect(queryByTitle("Appearance")).not.toBeInTheDocument();
expect(screen.queryByTitle("appearance")).not.toBeInTheDocument();
expect(screen.queryByTitle("Appearance")).not.toBeInTheDocument();
});
});
});

View File

@ -10,7 +10,7 @@ import type { NavigationTree } from "../tree-view";
export interface ScrollSpyProps extends React.DOMAttributes<HTMLElement> {
render: (data: NavigationTree[]) => JSX.Element;
htmlFor: string; // Id of the element to put observers on
htmlFor?: string; // Id of the element to put observers on
rootMargin?: string; // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer
}
@ -20,12 +20,14 @@ export const ScrollSpy = observer(({ render, htmlFor, rootMargin = "0px 0px -100
const [tree, setTree] = useState<NavigationTree[]>([]);
const [activeElementId, setActiveElementId] = useState("");
const setSections = () => {
const setSections = (): NodeListOf<HTMLElement> => {
sections.current = parent.current?.querySelectorAll("section");
if (!sections.current?.length) {
throw new Error("No <section/> tag founded! Content should be placed inside <section></section> elements to activate navigation.");
}
return sections.current;
};
const getSectionsParentElement = () => {
@ -33,14 +35,14 @@ export const ScrollSpy = observer(({ render, htmlFor, rootMargin = "0px 0px -100
};
const updateNavigation = () => {
const parentSection = getSectionsParentElement();
if (parentSection) {
setTree(getNavigation(parentSection));
}
setTree(getNavigation(getSectionsParentElement()));
};
const getNavigation = (element: Element) => {
const getNavigation = (element: Element | null | undefined): NavigationTree[] => {
if (!element) {
return [];
}
const sections = element.querySelectorAll(":scope > section"); // Searching only direct children of an element. Impossible without :scope
const children: NavigationTree[] = [];
@ -50,7 +52,7 @@ export const ScrollSpy = observer(({ render, htmlFor, rootMargin = "0px 0px -100
const name = section.querySelector("h1, h2, h3, h4, h5, h6")?.textContent;
const selected = id === activeElementId;
if (!name || !id || !parentId) {
if (!name || !id) {
return;
}
@ -74,13 +76,13 @@ export const ScrollSpy = observer(({ render, htmlFor, rootMargin = "0px 0px -100
}
};
const observeSections = () => {
const observeSections = (list: NodeListOf<HTMLElement>) => {
const options: IntersectionObserverInit = {
root: document.getElementById(htmlFor) || getSectionsParentElement(),
root: (htmlFor && document.getElementById(htmlFor)) || getSectionsParentElement(),
rootMargin,
};
sections.current?.forEach((section) => {
list.forEach((section) => {
const observer = new IntersectionObserver(handleIntersect, options);
const target = section.querySelector("section") || section;
@ -89,9 +91,10 @@ export const ScrollSpy = observer(({ render, htmlFor, rootMargin = "0px 0px -100
};
useEffect(() => {
setSections();
observeSections();
}, []);
const list = setSections();
observeSections(list);
}, [parent.current]);
useEffect(() => {
updateNavigation();

View File

@ -18,7 +18,7 @@ const deepDash = getDeepDash(_);
export interface NavigationTree {
id: string;
parentId: string;
parentId?: string;
name: string;
selected?: boolean;
children?: NavigationTree[];