This commit is contained in:
173
e2e/node/tests/test_plugins.test.ts
generated
Normal file
173
e2e/node/tests/test_plugins.test.ts
generated
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Bridge registry error-path tests for document extractor and renderer plugins.
|
||||
*
|
||||
* These tests cover the observable behaviour of register/unregister/clear at
|
||||
* the TypeScript/Node layer. register_document_extractor and register_renderer
|
||||
* are generated by the alef trait-bridge codegen and present on the native
|
||||
* kreuzberg module at runtime; they do not appear in the curated index.d.ts
|
||||
* re-export because the TypeScript wrapper only surfaces a subset of the API.
|
||||
*
|
||||
* A DocumentExtractor bridge object must expose:
|
||||
* name(): string
|
||||
* extract_bytes(content, mimeType, configJson): string (JSON InternalDocument)
|
||||
* supported_mime_types(): string[]
|
||||
*
|
||||
* A Renderer bridge object must expose:
|
||||
* name(): string
|
||||
* render(docJson): string
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { extractBytesSync, listDocumentExtractors, listRenderers } from "kreuzberg";
|
||||
|
||||
// The register/unregister/clear functions are exported by the native module but
|
||||
// not re-typed in the public TypeScript wrapper. Import the native binding
|
||||
// directly so we can reach the full API surface without 'any' sprawl.
|
||||
import kreuzberg from "kreuzberg";
|
||||
const native = kreuzberg as unknown as Record<string, (...args: unknown[]) => unknown>;
|
||||
|
||||
function registerDocumentExtractor(obj: unknown): void {
|
||||
(native["registerDocumentExtractor"] as (o: unknown) => void)(obj);
|
||||
}
|
||||
function unregisterDocumentExtractor(name: string): void {
|
||||
(native["unregisterDocumentExtractor"] as (n: string) => void)(name);
|
||||
}
|
||||
function clearDocumentExtractors(): void {
|
||||
(native["clearDocumentExtractors"] as () => void)();
|
||||
}
|
||||
function registerRenderer(obj: unknown): void {
|
||||
(native["registerRenderer"] as (o: unknown) => void)(obj);
|
||||
}
|
||||
function unregisterRenderer(name: string): void {
|
||||
(native["unregisterRenderer"] as (n: string) => void)(name);
|
||||
}
|
||||
function clearRenderers(): void {
|
||||
(native["clearRenderers"] as () => void)();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Minimal stub factory helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function makeExtractor(name: string, mimeType = "application/x-test"): object {
|
||||
return {
|
||||
name: (): string => name,
|
||||
version: (): string => "0.0.1",
|
||||
initialize: (): void => {
|
||||
/* no-op */
|
||||
},
|
||||
shutdown: (): void => {
|
||||
/* no-op */
|
||||
},
|
||||
supported_mime_types: (): string[] => [mimeType],
|
||||
extract_bytes: (_content: Uint8Array, _mimeType: string, _configJson: string): string =>
|
||||
JSON.stringify({
|
||||
source_format: "plain",
|
||||
mime_type: "text/plain",
|
||||
elements: [],
|
||||
relationships: [],
|
||||
images: [],
|
||||
tables: [],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function makeRenderer(name: string): object {
|
||||
return {
|
||||
name: (): string => name,
|
||||
version: (): string => "0.0.1",
|
||||
initialize: (): void => {
|
||||
/* no-op */
|
||||
},
|
||||
shutdown: (): void => {
|
||||
/* no-op */
|
||||
},
|
||||
render: (_docJson: string): string => "rendered",
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// DocumentExtractor tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("plugins: document extractor registry", () => {
|
||||
it("register_duplicate_extractor_replaces: second registration silently replaces first", () => {
|
||||
const name = "_test_ts_dup_extractor";
|
||||
try {
|
||||
registerDocumentExtractor(makeExtractor(name, "application/x-ts-dup1"));
|
||||
registerDocumentExtractor(makeExtractor(name, "application/x-ts-dup2"));
|
||||
const listed = listDocumentExtractors();
|
||||
const count = listed.filter((n) => n === name).length;
|
||||
expect(count).toBe(1);
|
||||
} finally {
|
||||
unregisterDocumentExtractor(name);
|
||||
}
|
||||
});
|
||||
|
||||
it("unregister_unknown_extractor_returns_ok: unregistering unknown name is a no-op", () => {
|
||||
// Must not throw
|
||||
expect(() => {
|
||||
unregisterDocumentExtractor("_test_ts_never_registered_extractor_xyz");
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it("clear_then_list_extractor_empty: list is empty after clear", () => {
|
||||
registerDocumentExtractor(makeExtractor("_test_ts_clear_a", "application/x-ts-clear-a"));
|
||||
registerDocumentExtractor(makeExtractor("_test_ts_clear_b", "application/x-ts-clear-b"));
|
||||
clearDocumentExtractors();
|
||||
const listed = listDocumentExtractors();
|
||||
expect(listed).toEqual([]);
|
||||
});
|
||||
|
||||
it("extract_after_unregister_uses_builtin: built-in extractor is used after custom removed", () => {
|
||||
const name = "_test_ts_unreg_plain";
|
||||
registerDocumentExtractor(makeExtractor(name, "text/plain"));
|
||||
unregisterDocumentExtractor(name);
|
||||
|
||||
// Must not throw; falls back to the built-in plain-text extractor.
|
||||
const encoded = new TextEncoder().encode("hello world");
|
||||
const result = extractBytesSync(encoded, "text/plain", undefined);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Renderer tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("plugins: renderer registry", () => {
|
||||
it("register_duplicate_renderer_replaces: second registration silently replaces first", () => {
|
||||
const name = "_test_ts_dup_renderer";
|
||||
try {
|
||||
registerRenderer(makeRenderer(name));
|
||||
registerRenderer(makeRenderer(name));
|
||||
const listed = listRenderers();
|
||||
const count = listed.filter((n) => n === name).length;
|
||||
expect(count).toBe(1);
|
||||
} finally {
|
||||
unregisterRenderer(name);
|
||||
}
|
||||
});
|
||||
|
||||
it("unregister_unknown_renderer_returns_ok: unregistering unknown name is a no-op", () => {
|
||||
expect(() => {
|
||||
unregisterRenderer("_test_ts_never_registered_renderer_xyz");
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it("clear_then_list_renderer_empty: list is empty after clear", () => {
|
||||
registerRenderer(makeRenderer("_test_ts_renderer_clear_a"));
|
||||
registerRenderer(makeRenderer("_test_ts_renderer_clear_b"));
|
||||
clearRenderers();
|
||||
const listed = listRenderers();
|
||||
expect(listed).toEqual([]);
|
||||
});
|
||||
|
||||
it("list_renderers_after_unregister_does_not_include_removed: name absent after unregister", () => {
|
||||
const name = "_test_ts_unregister_renderer_check";
|
||||
registerRenderer(makeRenderer(name));
|
||||
expect(listRenderers()).toContain(name);
|
||||
unregisterRenderer(name);
|
||||
expect(listRenderers()).not.toContain(name);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user