Files
quartz-website/quartz/plugins/loader/config-loader.test.ts
T

301 lines
9.8 KiB
TypeScript

import test, { describe, afterEach } from "node:test"
import assert from "node:assert"
import { buildLayoutForEntries, resolveGroups } from "./config-loader"
import { componentRegistry } from "../../components/registry"
import type { QuartzComponent, QuartzComponentConstructor } from "../../components/types"
import { PluginJsonEntry, LayoutPosition } from "./types"
const makeComponent = (name: string): QuartzComponent => {
const c = (() => null) as unknown as QuartzComponent
c.displayName = name
return c
}
const makeConstructor = (name: string): QuartzComponentConstructor => {
return () => makeComponent(name)
}
function makeEntry(
source: string,
layout?: { position: LayoutPosition; priority: number },
): PluginJsonEntry {
return {
source,
enabled: true,
options: {},
...(layout ? { layout: { position: layout.position, priority: layout.priority } } : {}),
}
}
afterEach(() => {
componentRegistry.clear()
})
describe("position assignment", () => {
test("places component in correct position from layout.position", () => {
const component = makeComponent("MyPlugin")
componentRegistry.register("my-plugin", component, "test-source")
const result = buildLayoutForEntries([makeEntry("my-plugin", { position: "left", priority: 10 })], {})
assert.deepStrictEqual(result.left, [component])
})
test("places component in footer position", () => {
const component = makeComponent("FooterComp")
componentRegistry.register("footer-comp", component, "test-source")
const result = buildLayoutForEntries(
[makeEntry("footer-comp", { position: "footer", priority: 20 })],
{},
)
assert.deepStrictEqual(result.footer, [component])
})
test("places component in header position", () => {
const component = makeComponent("HeaderComp")
componentRegistry.register("header-comp", component, "test-source")
const result = buildLayoutForEntries(
[makeEntry("header-comp", { position: "header", priority: 5 })],
{},
)
assert.deepStrictEqual(result.header, [component])
})
test("returns empty arrays when no entries have layout", () => {
const component = makeComponent("NoLayout")
componentRegistry.register("no-layout", component, "test-source")
const result = buildLayoutForEntries([makeEntry("no-layout")], {})
assert.deepStrictEqual(result.header, [])
assert.deepStrictEqual(result.left, [])
assert.deepStrictEqual(result.right, [])
assert.deepStrictEqual(result.beforeBody, [])
assert.deepStrictEqual(result.afterBody, [])
assert.deepStrictEqual(result.footer, [])
})
})
describe("defaultPosition fallback", () => {
test("uses manifest defaultPosition when no explicit layout", () => {
const component = makeComponent("F")
componentRegistry.register("f", component, "test-source", {
name: "f",
displayName: "F",
description: "",
version: "1",
defaultPosition: "footer",
defaultPriority: 50,
})
const result = buildLayoutForEntries([makeEntry("f")], {})
assert.deepStrictEqual(result.footer, [component])
})
test("explicit layout takes precedence over defaultPosition", () => {
const component = makeComponent("P")
componentRegistry.register("p", component, "test-source", {
name: "p",
displayName: "P",
description: "",
version: "1",
defaultPosition: "right",
})
const result = buildLayoutForEntries(
[makeEntry("p", { position: "left", priority: 10 })],
{},
)
assert.deepStrictEqual(result.left, [component])
assert.deepStrictEqual(result.right, [])
})
test("silently skips invalid defaultPosition", () => {
const component = makeComponent("Bad")
componentRegistry.register("bad", component, "test-source", {
name: "bad",
displayName: "Bad",
description: "",
version: "1",
defaultPosition: "body",
})
const result = buildLayoutForEntries([makeEntry("bad")], {})
assert.deepStrictEqual(result.header, [])
assert.deepStrictEqual(result.left, [])
assert.deepStrictEqual(result.right, [])
assert.deepStrictEqual(result.beforeBody, [])
assert.deepStrictEqual(result.afterBody, [])
assert.deepStrictEqual(result.footer, [])
})
})
describe("priority sorting", () => {
test("sorts components within a position by priority", () => {
const compA = makeComponent("A")
const compB = makeComponent("B")
const compC = makeComponent("C")
componentRegistry.register("a", compA, "test-source")
componentRegistry.register("b", compB, "test-source")
componentRegistry.register("c", compC, "test-source")
const result = buildLayoutForEntries(
[
makeEntry("a", { position: "left", priority: 30 }),
makeEntry("b", { position: "left", priority: 10 }),
makeEntry("c", { position: "left", priority: 20 }),
],
{},
)
const names = result.left?.map((component) => component.displayName)
assert.deepStrictEqual(names, ["B", "C", "A"])
})
test("defaults to priority 50 for defaultPosition without defaultPriority", () => {
const explicit = makeComponent("Explicit")
const ctor = makeConstructor("Default")
const defaulted = ctor(undefined)
componentRegistry.register("explicit", explicit, "test-source")
componentRegistry.register("defaulted", defaulted, "test-source", {
name: "defaulted",
displayName: "Default",
description: "",
version: "1",
defaultPosition: "left",
})
const result = buildLayoutForEntries(
[makeEntry("explicit", { position: "left", priority: 40 }), makeEntry("defaulted")],
{},
)
const names = result.left?.map((component) => component.displayName)
assert.deepStrictEqual(names, ["Explicit", "Default"])
})
})
describe("resolveGroups", () => {
test("returns ungrouped items in priority order", () => {
const a = makeComponent("A")
const b = makeComponent("B")
const c = makeComponent("C")
const items = [
{ component: a, priority: 30 },
{ component: b, priority: 10 },
{ component: c, priority: 20 },
]
const result = resolveGroups(items, {})
assert.strictEqual(result.length, 3)
assert.strictEqual(result[0], b)
assert.strictEqual(result[1], c)
assert.strictEqual(result[2], a)
})
test("returns ungrouped items unchanged", () => {
const a = makeComponent("A")
const items = [{ component: a, priority: 10 }]
const result = resolveGroups(items, {})
assert.strictEqual(result.length, 1)
assert.strictEqual(result[0], a)
})
test("returns empty array for empty input", () => {
const result = resolveGroups([], {})
assert.deepStrictEqual(result, [])
})
test("wraps grouped items in a Flex component", () => {
const a = makeComponent("A")
const b = makeComponent("B")
const items = [
{ component: a, priority: 10, group: "toolbar" },
{ component: b, priority: 20, group: "toolbar" },
]
const result = resolveGroups(items, {})
assert.strictEqual(result.length, 1)
assert.notStrictEqual(result[0], a)
assert.notStrictEqual(result[0], b)
})
test("uses explicit group priority from config", () => {
const grouped = makeComponent("Grouped")
const ungrouped = makeComponent("Ungrouped")
const items = [
{ component: grouped, priority: 50, group: "nav" },
{ component: ungrouped, priority: 10 },
]
const result = resolveGroups(items, { nav: { priority: 5 } })
assert.strictEqual(result.length, 2)
assert.strictEqual(result[1], ungrouped)
})
test("falls back to first member priority when no group config", () => {
const a = makeComponent("A")
const b = makeComponent("B")
const solo = makeComponent("Solo")
const items = [
{ component: a, priority: 20, group: "nav" },
{ component: b, priority: 40, group: "nav" },
{ component: solo, priority: 30 },
]
const result = resolveGroups(items, {})
assert.strictEqual(result.length, 2)
assert.strictEqual(result[1], solo)
})
test("single-member group still wraps in Flex", () => {
const a = makeComponent("A")
const items = [{ component: a, priority: 10, group: "solo" }]
const result = resolveGroups(items, {})
assert.strictEqual(result.length, 1)
assert.notStrictEqual(result[0], a)
})
})
describe("buildLayoutForEntries with display wrappers", () => {
test("applies display wrapper for mobile-only", () => {
const component = makeComponent("Wrapped")
componentRegistry.register("wrapped-plugin", component, "test-source")
const entry: PluginJsonEntry = {
source: "wrapped-plugin",
enabled: true,
options: {},
layout: { position: "left" as LayoutPosition, priority: 10, display: "mobile-only" },
}
const result = buildLayoutForEntries([entry], {})
assert.strictEqual(result.left?.length, 1)
assert.notStrictEqual(result.left?.[0], component)
})
})
describe("buildLayoutForEntries with constructors", () => {
test("instantiates constructor components via registry", () => {
const ctor = makeConstructor("Instantiated")
componentRegistry.register("ctor-plugin", ctor, "test-source")
const result = buildLayoutForEntries(
[makeEntry("ctor-plugin", { position: "left", priority: 10 })],
{},
)
assert.strictEqual(result.left?.length, 1)
assert.strictEqual(result.left?.[0].displayName, "Instantiated")
})
test("merges entry options with TS overrides for constructors", () => {
const ctor = makeConstructor("Merged")
componentRegistry.register("merge-plugin", ctor, "test-source")
componentRegistry.setOptionOverrides("merge-plugin", { extra: true })
const result = buildLayoutForEntries(
[{ source: "merge-plugin", enabled: true, options: { base: 1 }, layout: { position: "right" as LayoutPosition, priority: 10 } }],
{},
)
assert.strictEqual(result.right?.length, 1)
})
})