




















@@ -735,6 +735,138 @@ describe("uninstallPlugin", () => {
735735expect(runCommandWithTimeoutMock).not.toHaveBeenCalled();
736736});
737737738+it.each([
739+{
740+name: "enabled entry only, no installed code",
741+pluginId: "missing-entry-plugin",
742+config: createPluginConfig({
743+entries: {
744+"missing-entry-plugin": { enabled: true },
745+},
746+}),
747+expectedActions: {
748+entry: true,
749+install: false,
750+allowlist: false,
751+denylist: false,
752+loadPath: false,
753+memorySlot: false,
754+contextEngineSlot: false,
755+channelConfig: false,
756+directory: false,
757+},
758+expectedConfig: {},
759+},
760+{
761+name: "install record and channel config, no runtime plugin",
762+pluginId: "missing-channel-plugin",
763+config: createPluginConfig({
764+installs: {
765+"missing-channel-plugin": createNpmInstallRecord("missing-channel-plugin"),
766+},
767+channels: {
768+"missing-channel-plugin": { enabled: true, token: "stale" },
769+discord: { enabled: true },
770+},
771+}),
772+expectedActions: {
773+entry: false,
774+install: true,
775+allowlist: false,
776+denylist: false,
777+loadPath: false,
778+memorySlot: false,
779+contextEngineSlot: false,
780+channelConfig: true,
781+directory: false,
782+},
783+expectedConfig: {
784+channels: {
785+discord: { enabled: true },
786+},
787+},
788+},
789+{
790+name: "linked path record, missing source directory",
791+pluginId: "missing-linked-plugin",
792+config: createPluginConfig({
793+installs: {
794+"missing-linked-plugin": createPathInstallRecord(
795+"/missing/openclaw/plugin",
796+"/missing/openclaw/plugin",
797+),
798+},
799+loadPaths: ["/missing/openclaw/plugin", "/keep/this/plugin"],
800+}),
801+expectedActions: {
802+entry: false,
803+install: true,
804+allowlist: false,
805+denylist: false,
806+loadPath: true,
807+memorySlot: false,
808+contextEngineSlot: false,
809+channelConfig: false,
810+directory: false,
811+},
812+expectedConfig: {
813+plugins: {
814+load: {
815+paths: ["/keep/this/plugin"],
816+},
817+},
818+},
819+},
820+{
821+name: "policy and slots only, no entry or install record",
822+pluginId: "missing-policy-plugin",
823+config: createPluginConfig({
824+allow: ["missing-policy-plugin", "other-plugin"],
825+deny: ["missing-policy-plugin"],
826+slots: {
827+memory: "missing-policy-plugin",
828+contextEngine: "missing-policy-plugin",
829+},
830+}),
831+expectedActions: {
832+entry: false,
833+install: false,
834+allowlist: true,
835+denylist: true,
836+loadPath: false,
837+memorySlot: true,
838+contextEngineSlot: true,
839+channelConfig: false,
840+directory: false,
841+},
842+expectedConfig: {
843+plugins: {
844+allow: ["other-plugin"],
845+slots: {
846+memory: "memory-core",
847+contextEngine: "legacy",
848+},
849+},
850+},
851+},
852+] as const)(
853+"uninstall teardown matrix: $name",
854+async ({ pluginId, config, expectedActions, expectedConfig }) => {
855+const result = await uninstallPlugin({
856+ config,
857+ pluginId,
858+deleteFiles: true,
859+extensionsDir: path.join(tempDir, "extensions"),
860+});
861+862+const successfulResult = expectSuccessfulUninstall(result);
863+expect(successfulResult.actions).toEqual(expectedActions);
864+expect(successfulResult.config).toEqual(expectedConfig);
865+expect(successfulResult.warnings).toEqual([]);
866+expect(runCommandWithTimeoutMock).not.toHaveBeenCalled();
867+},
868+);
869+738870it("removes config entries", async () => {
739871const config = createPluginConfig({
740872entries: createSinglePluginEntries(),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。