Files

141 lines
4.8 KiB
TypeScript

import test, { describe, afterEach } from "node:test"
import assert from "node:assert"
import { ComponentRegistry } from "./registry"
import { QuartzComponent, QuartzComponentConstructor } from "./types"
const StubA = (() => null) as unknown as QuartzComponent
const StubB = (() => null) as unknown as QuartzComponent
StubA.displayName = "StubA"
StubB.displayName = "StubB"
const StubConstructor = ((opts?: any) => {
const c = (() => null) as unknown as QuartzComponent
c.displayName = opts?.name ?? "stub"
return c
}) as unknown as QuartzComponentConstructor
let registry: ComponentRegistry | null = null
afterEach(() => {
registry?.clear()
registry = null
})
describe("register and get", () => {
test("registers a component and retrieves it by name", () => {
registry = new ComponentRegistry()
registry.register("foo", StubA, "source")
const result = registry.get("foo")
assert.strictEqual(result?.component, StubA)
assert.strictEqual(result?.source, "source")
})
test("returns undefined for unregistered names", () => {
registry = new ComponentRegistry()
const result = registry.get("nonexistent")
assert.strictEqual(result, undefined)
})
test("overwrites component from different source", () => {
registry = new ComponentRegistry()
registry.register("foo", StubA, "src1")
registry.register("foo", StubB, "src2")
const result = registry.get("foo")
assert.strictEqual(result?.component, StubB)
})
})
describe("instantiate", () => {
test("returns a component instance from a constructor", () => {
registry = new ComponentRegistry()
const instance = registry.instantiate(StubConstructor)
assert.ok(instance)
assert.strictEqual(typeof instance, "function")
})
test("caches instances by constructor + options", () => {
registry = new ComponentRegistry()
const first = registry.instantiate(StubConstructor)
const second = registry.instantiate(StubConstructor)
assert.strictEqual(first, second)
})
test("different options produce different instances", () => {
registry = new ComponentRegistry()
const first = registry.instantiate(StubConstructor, { a: 1 })
const second = registry.instantiate(StubConstructor, { a: 2 })
assert.notStrictEqual(first, second)
})
test("undefined options and no-arg call produce same cache key", () => {
registry = new ComponentRegistry()
const first = registry.instantiate(StubConstructor)
const second = registry.instantiate(StubConstructor, undefined)
assert.strictEqual(first, second)
})
})
describe("getAllComponents", () => {
test("deduplicates components registered under multiple names", () => {
registry = new ComponentRegistry()
registry.register("foo", StubConstructor, "source")
registry.register("bar", StubConstructor, "source")
const result = registry.getAllComponents()
assert.strictEqual(result.length, 1)
})
test("reuses cached instance from prior instantiate call", () => {
registry = new ComponentRegistry()
registry.register("x", StubConstructor, "source")
const instance = registry.instantiate(StubConstructor, { opt: 1 })
const result = registry.getAllComponents()
assert.strictEqual(result[0], instance)
})
test("skips components that fail to instantiate", () => {
registry = new ComponentRegistry()
const ThrowingConstructor = (() => {
throw new Error("boom")
}) as unknown as QuartzComponentConstructor
registry.register("bad", ThrowingConstructor, "source")
const result = registry.getAllComponents()
assert.deepStrictEqual(result, [])
})
})
describe("setOptionOverrides and cache invalidation", () => {
test("stores and retrieves option overrides", () => {
registry = new ComponentRegistry()
registry.setOptionOverrides("plugin", { key: "val" })
assert.deepStrictEqual(registry.getOptionOverrides("plugin"), { key: "val" })
})
test("merges with existing overrides", () => {
registry = new ComponentRegistry()
registry.setOptionOverrides("plugin", { a: 1 })
registry.setOptionOverrides("plugin", { b: 2 })
assert.deepStrictEqual(registry.getOptionOverrides("plugin"), { a: 1, b: 2 })
})
test("clears instance cache when overrides change", () => {
registry = new ComponentRegistry()
const first = registry.instantiate(StubConstructor, { name: "cached" })
registry.setOptionOverrides("anything", { trigger: true })
const second = registry.instantiate(StubConstructor, { name: "cached" })
assert.notStrictEqual(first, second)
})
test("ignores empty or undefined overrides", () => {
registry = new ComponentRegistry()
registry.setOptionOverrides("plugin", {})
assert.strictEqual(registry.getOptionOverrides("plugin"), undefined)
registry.setOptionOverrides("plugin", undefined)
assert.strictEqual(registry.getOptionOverrides("plugin"), undefined)
})
})