feat: replace CJS require with static imports, add comprehensive layout system tests
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import test, { describe } from "node:test"
|
||||
import assert from "node:assert"
|
||||
import { resolveFrame, frameRegistry } from "./index"
|
||||
import { DefaultFrame } from "./DefaultFrame"
|
||||
import { FullWidthFrame } from "./FullWidthFrame"
|
||||
import type { PageFrame } from "./types"
|
||||
|
||||
const customFrame: PageFrame = {
|
||||
name: "custom-test-frame",
|
||||
render: () => null as any,
|
||||
}
|
||||
|
||||
describe("resolveFrame", () => {
|
||||
test("returns DefaultFrame for undefined", () => {
|
||||
assert.strictEqual(resolveFrame(undefined), DefaultFrame)
|
||||
})
|
||||
|
||||
test("returns DefaultFrame for 'default'", () => {
|
||||
assert.strictEqual(resolveFrame("default"), DefaultFrame)
|
||||
})
|
||||
|
||||
test("returns named built-in frame", () => {
|
||||
assert.strictEqual(resolveFrame("full-width"), FullWidthFrame)
|
||||
})
|
||||
|
||||
test("returns DefaultFrame for unknown frame name", () => {
|
||||
assert.strictEqual(resolveFrame("nonexistent"), DefaultFrame)
|
||||
})
|
||||
|
||||
test("plugin-registered frame takes priority", () => {
|
||||
frameRegistry.register("custom-test-frame", customFrame, "test-plugin")
|
||||
const result = resolveFrame("custom-test-frame")
|
||||
assert.strictEqual(result, customFrame)
|
||||
})
|
||||
|
||||
test("returns DefaultFrame for unknown name even with plugin frames registered", () => {
|
||||
frameRegistry.register("custom-test-frame", customFrame, "test-plugin")
|
||||
const result = resolveFrame("totally-unknown")
|
||||
assert.strictEqual(result, DefaultFrame)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,140 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
@@ -18,7 +18,8 @@ export interface RegisteredComponent {
|
||||
manifest?: ComponentManifest
|
||||
}
|
||||
|
||||
class ComponentRegistry {
|
||||
/** @internal Exported for testing only. */
|
||||
export class ComponentRegistry {
|
||||
private components = new Map<string, RegisteredComponent>()
|
||||
private instanceCache = new Map<string, QuartzComponent>()
|
||||
private optionOverrides = new Map<string, Record<string, unknown>>()
|
||||
@@ -111,6 +112,13 @@ class ComponentRegistry {
|
||||
return results
|
||||
}
|
||||
|
||||
/** @internal For testing only — resets all registry state. */
|
||||
clear(): void {
|
||||
this.components.clear()
|
||||
this.instanceCache.clear()
|
||||
this.optionOverrides.clear()
|
||||
}
|
||||
|
||||
private findCachedInstance(
|
||||
constructor: QuartzComponentConstructor<any>,
|
||||
): QuartzComponent | undefined {
|
||||
|
||||
Reference in New Issue
Block a user