Skip to content

Commit

Permalink
add more unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
abvthecity committed Oct 4, 2024
1 parent 520edee commit 6397cc6
Show file tree
Hide file tree
Showing 6 changed files with 322 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,215 @@ describe("pruneNavigationTree", () => {

expect(result).toBeUndefined();
});

it("should not prune section children even if section itself is pruned", () => {
const root: FernNavigation.NavigationNode = {
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
title: "Root",
overviewPageId: FernNavigation.PageId("overview.mdx"), // this is a visitable page
children: [
{
type: "page",
id: FernNavigation.NodeId("page"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
pointsTo: undefined,
};

const result = pruneNavigationTree(root, (node) => node.id !== "root");

// structuredClone should duplicate the object
expect(result === root).toBe(false);

expect(result).toStrictEqual({
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
overviewPageId: undefined, // this should be deleted
title: "Root",
children: [
{
type: "page",
id: FernNavigation.NodeId("page"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
pointsTo: undefined,
});
});

it("should not prune non-leaf nodes", () => {
const root: FernNavigation.NavigationNode = {
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
title: "Root",
overviewPageId: undefined,
children: [
{
type: "page",
id: FernNavigation.NodeId("page"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
pointsTo: undefined,
};

const result = pruneNavigationTree(root, (node) => node.id !== "root");

// structuredClone should duplicate the object
expect(result === root).toBe(false);

expect(result).toStrictEqual({
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
overviewPageId: undefined, // this should be deleted
title: "Root",
children: [
{
type: "page",
id: FernNavigation.NodeId("page"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
pointsTo: undefined,
});
});

it("should delete leaf node and its parent if no siblings left", () => {
const root: FernNavigation.NavigationNode = {
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
title: "Root",
overviewPageId: undefined,
children: [
{
type: "section",
id: FernNavigation.NodeId("section2"),
slug: FernNavigation.Slug("root/section2"),
title: "Section 2",
overviewPageId: undefined,
children: [
{
type: "page",
id: FernNavigation.NodeId("page1"),
slug: FernNavigation.Slug("root/section2/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
pointsTo: undefined,
},
{
type: "page",
id: FernNavigation.NodeId("page2"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
pointsTo: undefined,
};

const result = pruneNavigationTree(root, (node) => node.id !== "page1");

// structuredClone should duplicate the object
expect(result === root).toBe(false);

expect(result).toStrictEqual({
type: "section",
id: FernNavigation.NodeId("root"),
slug: FernNavigation.Slug("root"),
overviewPageId: undefined, // this should be deleted
title: "Root",
children: [
{
type: "page",
id: FernNavigation.NodeId("page2"),
slug: FernNavigation.Slug("root/page"),
title: "Page",
pageId: FernNavigation.PageId("page.mdx"),
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,
},
],
collapsed: undefined,
canonicalSlug: undefined,
icon: undefined,
hidden: undefined,
noindex: undefined,

// NOTE: points to is updated!
pointsTo: "root/page",
});
});
});
75 changes: 53 additions & 22 deletions packages/fdr-sdk/src/navigation/utils/deleteChild.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,102 @@
import { UnreachableCaseError } from "ts-essentials";
import { MarkOptional, UnreachableCaseError } from "ts-essentials";
import { FernNavigation } from "../..";
import { DeleterAction } from "../../utils/traversers/types";

/**
* @param parent delete node from this parent (mutable)
* @param node node to delete
* @returns the id of the deleted node or null if the node was not deletable from the parent
*/
export function mutableDeleteChild(
parent: FernNavigation.NavigationNodeParent,
parent: FernNavigation.NavigationNodeParent | undefined,
node: FernNavigation.NavigationNode,
): FernNavigation.NodeId | null {
): DeleterAction {
/**
* The idea here is we should only delete leaf nodes (we're treating changelogs here like a leaf node)
*
* In the case that we have sections that have content, deleting it from its parent would delete all its children as well.
* Instead, we'll just remove the overviewPageId, which will make the section a non-visitable node, yet still retain its children.
*/
if (
!FernNavigation.isLeaf(node) &&
FernNavigation.isPage(node) &&
FernNavigation.getChildren(node).length > 0 &&
node.type !== "changelog"
) {
// if the node to be deleted is a section, remove the overviewPageId
if (FernNavigation.isSectionOverview(node)) {
(node as MarkOptional<typeof node, "overviewPageId">).overviewPageId = undefined;
return "noop";
} else {
throw new UnreachableCaseError(node);
}
}

// if the node is not a leaf node, don't delete it from the parent unless it has no children
if (!FernNavigation.isLeaf(node) && FernNavigation.getChildren(node).length > 0) {
return "noop";
}

if (parent == null) {
return "deleted";
}

switch (parent.type) {
case "apiPackage":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "apiReference":
parent.children = parent.children.filter((child) => child.id !== node.id);
parent.changelog = parent.changelog?.id === node.id ? undefined : parent.changelog;
return node.id;
return "deleted";
case "changelog":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "changelogYear":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "changelogMonth":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "endpointPair":
return null;
return "should-delete-parent";
case "productgroup":
parent.children = parent.children.filter((child) => child.id !== node.id);
parent.landingPage = parent.landingPage?.id === node.id ? undefined : parent.landingPage;
return node.id;
return "deleted";
case "product":
return null;
return "should-delete-parent";
case "root":
return null;
return "should-delete-parent";
case "unversioned":
if (node.id === parent.landingPage?.id) {
parent.landingPage = undefined;
return node.id;
return "deleted";
}
return null;
return "should-delete-parent";
case "section":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "sidebarGroup":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "tab":
return null;
return "should-delete-parent";
case "sidebarRoot":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "tabbed":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
case "version":
if (node.id === parent.landingPage?.id) {
parent.landingPage = undefined;
return node.id;
return "deleted";
}
return null;
return "should-delete-parent";
case "versioned":
parent.children = parent.children.filter((child) => child.id !== node.id);
return node.id;
return "deleted";
default:
throw new UnreachableCaseError(parent);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import type { ChangelogMonthNode, ChangelogNode, ChangelogYearNode } from ".";
import type { ChangelogNode } from ".";
import type { NavigationNode } from "./NavigationNode";
import { isApiLeaf, type NavigationNodeApiLeaf } from "./NavigationNodeApiLeaf";
import { hasMarkdown, type NavigationNodeWithMarkdown } from "./NavigationNodeMarkdown";

/**
* A navigation node that represents a visitable page in the documentation
*/
export type NavigationNodePage =
| NavigationNodeWithMarkdown
| NavigationNodeApiLeaf
| ChangelogNode
| ChangelogYearNode
| ChangelogMonthNode;
export type NavigationNodePage = NavigationNodeWithMarkdown | NavigationNodeApiLeaf | ChangelogNode;
// | ChangelogYearNode
// | ChangelogMonthNode;

export function isPage(node: NavigationNode): node is NavigationNodePage {
export function isPage<N extends NavigationNode>(node: N): node is N & NavigationNodePage {
return (
isApiLeaf(node) ||
node.type === "changelog" ||
Expand Down
Loading

0 comments on commit 6397cc6

Please sign in to comment.