


























@@ -149,6 +149,49 @@ function createIndex(
149149};
150150}
151151152+function requireRecord(value: unknown, label: string): Record<string, unknown> {
153+expect(typeof value, label).toBe("object");
154+expect(value, label).not.toBeNull();
155+return value as Record<string, unknown>;
156+}
157+158+function requireArray(value: unknown, label: string): unknown[] {
159+expect(Array.isArray(value), label).toBe(true);
160+return value as unknown[];
161+}
162+163+function expectFields(record: Record<string, unknown>, expected: Record<string, unknown>) {
164+for (const [key, value] of Object.entries(expected)) {
165+expect(record[key], key).toEqual(value);
166+}
167+}
168+169+function expectPluginRecordFields(record: unknown, expected: Record<string, unknown>) {
170+expectFields(requireRecord(record, "plugin record"), expected);
171+}
172+173+function expectDiagnosticCodes(diagnostics: unknown, expectedCodes: string[]) {
174+const codes = requireArray(diagnostics, "diagnostics").map(
175+(diagnostic) => requireRecord(diagnostic, "diagnostic").code,
176+);
177+expect(codes).toEqual(expectedCodes);
178+}
179+180+function expectInstallRecord(
181+installRecords: unknown,
182+pluginId: string,
183+expected: Record<string, unknown>,
184+) {
185+const records = requireRecord(installRecords, "install records");
186+expectFields(requireRecord(records[pluginId], `${pluginId} install record`), expected);
187+}
188+189+function expectSnapshotPluginIds(snapshot: InstalledPluginIndex, expectedPluginIds: string[]) {
190+expect(listPluginRecords({ index: snapshot }).map((plugin) => plugin.pluginId)).toEqual(
191+expectedPluginIds,
192+);
193+}
194+152195describe("plugin registry facade", () => {
153196it("resolves relative plugin API paths against the plugin root", () => {
154197const pluginRoot = path.join(makeTempDir(), "plugins", "demo");
@@ -181,7 +224,7 @@ describe("plugin registry facade", () => {
181224});
182225183226expect(listPluginRecords({ index }).map((plugin) => plugin.pluginId)).toEqual(["demo"]);
184-expect(getPluginRecord({ index, pluginId: "demo" })).toMatchObject({
227+expectPluginRecordFields(getPluginRecord({ index, pluginId: "demo" }), {
185228pluginId: "demo",
186229enabled: true,
187230});
@@ -246,7 +289,7 @@ describe("plugin registry facade", () => {
246289preferPersisted: false,
247290});
248291249-expect(getPluginRecord({ index, pluginId: "demo" })).toMatchObject({
292+expectPluginRecordFields(getPluginRecord({ index, pluginId: "demo" }), {
250293pluginId: "demo",
251294enabled: false,
252295});
@@ -344,26 +387,19 @@ describe("plugin registry facade", () => {
344387expect(normalizePluginId("openai-chat")).toBe("openai");
345388expect(normalizePluginId("unknown-plugin")).toBe("unknown-plugin");
346389347-expect(
348-normalizePluginsConfigWithRegistry(
349-{
350-allow: ["openai-chat"],
351-entries: {
352-"OpenAI-Codex": {
353-enabled: false,
354-},
390+const normalizedConfig = normalizePluginsConfigWithRegistry(
391+{
392+allow: ["openai-chat"],
393+entries: {
394+"OpenAI-Codex": {
395+enabled: false,
355396},
356397},
357-index,
358-),
359-).toMatchObject({
360-allow: ["openai"],
361-entries: {
362-openai: {
363-enabled: false,
364-},
365398},
366-});
399+index,
400+);
401+expect(normalizedConfig.allow).toEqual(["openai"]);
402+expect(normalizedConfig.entries?.openai?.enabled).toBe(false);
367403});
368404369405it("normalizes plugin config ids from a provided manifest registry without rereading manifests", () => {
@@ -387,17 +423,14 @@ describe("plugin registry facade", () => {
387423});
388424389425expect(normalizePluginId("demo-chat")).toBe("demo");
390-expect(
391-normalizePluginsConfigWithRegistry(
392-{
393-allow: ["demo-chat"],
394-},
395-index,
396-{ manifestRegistry: lookUpTable.manifestRegistry },
397-),
398-).toMatchObject({
399-allow: ["demo"],
400-});
426+const normalizedConfig = normalizePluginsConfigWithRegistry(
427+{
428+allow: ["demo-chat"],
429+},
430+index,
431+{ manifestRegistry: lookUpTable.manifestRegistry },
432+);
433+expect(normalizedConfig.allow).toEqual(["demo"]);
401434});
402435403436it("reads the persisted registry before deriving from discovered candidates", async () => {
@@ -462,12 +495,8 @@ describe("plugin registry facade", () => {
462495});
463496464497expect(result.source).toBe("derived");
465-expect(result.diagnostics).toEqual([
466-expect.objectContaining({ code: "persisted-registry-stale-source" }),
467-]);
468-expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
469-"demo",
470-]);
498+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
499+expectSnapshotPluginIds(result.snapshot, ["demo"]);
471500});
472501473502it("falls back to the derived registry when persisted manifest metadata is stale", async () => {
@@ -501,9 +530,7 @@ describe("plugin registry facade", () => {
501530});
502531503532expect(result.source).toBe("derived");
504-expect(result.diagnostics).toEqual([
505-expect.objectContaining({ code: "persisted-registry-stale-source" }),
506-]);
533+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
507534expect(result.snapshot.plugins[0]?.manifestHash).not.toBe(persisted.plugins[0]?.manifestHash);
508535});
509536@@ -543,9 +570,7 @@ describe("plugin registry facade", () => {
543570});
544571545572expect(result.source).toBe("derived");
546-expect(result.diagnostics).toEqual([
547-expect.objectContaining({ code: "persisted-registry-stale-source" }),
548-]);
573+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
549574expect(result.snapshot.plugins[0]?.packageJson?.hash).not.toBe(
550575persisted.plugins[0]?.packageJson?.hash,
551576);
@@ -583,9 +608,7 @@ describe("plugin registry facade", () => {
583608});
584609585610expect(result.source).toBe("derived");
586-expect(result.diagnostics).toEqual([
587-expect.objectContaining({ code: "persisted-registry-stale-source" }),
588-]);
611+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
589612expect(result.snapshot.plugins[0]?.packageJson).toBeUndefined();
590613});
591614@@ -617,12 +640,8 @@ describe("plugin registry facade", () => {
617640});
618641619642expect(result.source).toBe("derived");
620-expect(result.diagnostics).toEqual([
621-expect.objectContaining({ code: "persisted-registry-stale-source" }),
622-]);
623-expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
624-"demo",
625-]);
643+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-source"]);
644+expectSnapshotPluginIds(result.snapshot, ["demo"]);
626645});
627646628647it("falls back to the derived registry when persisted policy is stale", async () => {
@@ -655,17 +674,11 @@ describe("plugin registry facade", () => {
655674});
656675657676expect(result.source).toBe("derived");
658-expect(result.diagnostics).toEqual([
659-expect.objectContaining({ code: "persisted-registry-stale-policy" }),
660-]);
661-expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
662-"demo",
663-]);
664-expect(result.snapshot.installRecords).toMatchObject({
665-persisted: {
666-source: "npm",
667-spec: "persisted-plugin@1.0.0",
668-},
677+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-stale-policy"]);
678+expectSnapshotPluginIds(result.snapshot, ["demo"]);
679+expectInstallRecord(result.snapshot.installRecords, "persisted", {
680+source: "npm",
681+spec: "persisted-plugin@1.0.0",
669682});
670683});
671684@@ -681,12 +694,8 @@ describe("plugin registry facade", () => {
681694});
682695683696expect(result.source).toBe("derived");
684-expect(result.diagnostics).toEqual([
685-expect.objectContaining({ code: "persisted-registry-missing" }),
686-]);
687-expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
688-"demo",
689-]);
697+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-missing"]);
698+expectSnapshotPluginIds(result.snapshot, ["demo"]);
690699});
691700692701it("derives fresh config-scoped registries when the persisted registry is missing", () => {
@@ -740,15 +749,11 @@ describe("plugin registry facade", () => {
740749});
741750742751expect(result.source).toBe("derived");
743-expect(result.diagnostics).toEqual([
744-expect.objectContaining({
745-code: "persisted-registry-disabled",
746-message: expect.stringContaining("deprecated break-glass compatibility switch"),
747-}),
748-]);
749-expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
750-"demo",
751-]);
752+expectDiagnosticCodes(result.diagnostics, ["persisted-registry-disabled"]);
753+expect(String(requireRecord(result.diagnostics[0], "diagnostic").message)).toContain(
754+"deprecated break-glass compatibility switch",
755+);
756+expectSnapshotPluginIds(result.snapshot, ["demo"]);
752757});
753758754759it("derives a fresh registry without dropping persisted install records", async () => {
@@ -776,14 +781,10 @@ describe("plugin registry facade", () => {
776781});
777782778783expect(result.source).toBe("derived");
779-expect(listPluginRecords({ index: result.snapshot }).map((plugin) => plugin.pluginId)).toEqual([
780-"demo",
781-]);
782-expect(result.snapshot.installRecords).toMatchObject({
783-persisted: {
784-source: "npm",
785-spec: "persisted-plugin@1.0.0",
786-},
784+expectSnapshotPluginIds(result.snapshot, ["demo"]);
785+expectInstallRecord(result.snapshot.installRecords, "persisted", {
786+source: "npm",
787+spec: "persisted-plugin@1.0.0",
787788});
788789});
789790@@ -794,16 +795,11 @@ describe("plugin registry facade", () => {
794795const candidate = createCandidate(pluginDir);
795796const env = hermeticEnv();
796797797-await expect(
798-inspectPluginRegistry({ stateDir, candidates: [candidate], env }),
799-).resolves.toMatchObject({
800-state: "missing",
801-refreshReasons: ["missing"],
802-persisted: null,
803-current: {
804-plugins: [expect.objectContaining({ pluginId: "demo" })],
805-},
806-});
798+const missingInspect = await inspectPluginRegistry({ stateDir, candidates: [candidate], env });
799+expect(missingInspect.state).toBe("missing");
800+expect(missingInspect.refreshReasons).toEqual(["missing"]);
801+expect(missingInspect.persisted).toBeNull();
802+expect(missingInspect.current.plugins.map((plugin) => plugin.pluginId)).toEqual(["demo"]);
807803808804await refreshPluginRegistry({
809805reason: "manual",
@@ -812,15 +808,10 @@ describe("plugin registry facade", () => {
812808 env,
813809});
814810815-await expect(
816-inspectPluginRegistry({ stateDir, candidates: [candidate], env }),
817-).resolves.toMatchObject({
818-state: "fresh",
819-refreshReasons: [],
820-persisted: {
821-plugins: [expect.objectContaining({ pluginId: "demo" })],
822-},
823-});
811+const freshInspect = await inspectPluginRegistry({ stateDir, candidates: [candidate], env });
812+expect(freshInspect.state).toBe("fresh");
813+expect(freshInspect.refreshReasons).toEqual([]);
814+expect(freshInspect.persisted?.plugins.map((plugin) => plugin.pluginId)).toEqual(["demo"]);
824815});
825816826817it("preserves install records when refreshing the persisted registry", async () => {
@@ -846,15 +837,16 @@ describe("plugin registry facade", () => {
846837env: hermeticEnv(),
847838});
848839849-await expect(readPersistedInstalledPluginIndex({ stateDir })).resolves.toMatchObject({
850- installRecords: {
851- missing: {
852- source: "npm",
853- spec: "missing-plugin@1.0.0",
854- installPath: path.join(stateDir, "plugins", "missing"),
855- },
856-},
857-plugins: [],
840+const persisted = await readPersistedInstalledPluginIndex({ stateDir });
841+expect(persisted).not.toBeNull();
842+if (!persisted) {
843+throw new Error("Expected persisted plugin index");
844+}
845+expectInstallRecord(persisted.installRecords, "missing", {
846+source: "npm",
847+spec: "missing-plugin@1.0.0",
848+installPath: path.join(stateDir, "plugins", "missing"),
858849});
850+expect(persisted.plugins).toEqual([]);
859851});
860852});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。