79e232f1c2
Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
165 lines
5.9 KiB
TypeScript
165 lines
5.9 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { pluginRegistry } from "./registry";
|
|
|
|
const PRIMARY_PLUGIN_ID = "plugin-a";
|
|
const SECONDARY_PLUGIN_ID = "plugin-b";
|
|
const SOURCE_CONTROL_PROVIDER_ID = "source-control";
|
|
const SECOND_SOURCE_CONTROL_PROVIDER_ID = "source-control-secondary";
|
|
const WORKSPACE_ID = "workspace-1";
|
|
const OTHER_WORKSPACE_ID = "workspace-2";
|
|
|
|
const registration = {
|
|
id: SOURCE_CONTROL_PROVIDER_ID,
|
|
label: "Source Control",
|
|
description: "Configure source control.",
|
|
Component: () => null,
|
|
};
|
|
|
|
function setIntegrationEnabled(
|
|
pluginId: string,
|
|
integrationId: string,
|
|
workspaceId: string,
|
|
enabled: boolean,
|
|
): void {
|
|
(
|
|
pluginRegistry.setIntegrationEnabled.bind(pluginRegistry) as unknown as (
|
|
pluginId: string,
|
|
integrationId: string,
|
|
workspaceId: string,
|
|
enabled: boolean,
|
|
) => void
|
|
)(pluginId, integrationId, workspaceId, enabled);
|
|
}
|
|
|
|
function isIntegrationEnabled(integrationId: string, workspaceId: string): boolean {
|
|
return (
|
|
pluginRegistry.isIntegrationEnabled.bind(pluginRegistry) as unknown as (
|
|
integrationId: string,
|
|
workspaceId: string,
|
|
) => boolean
|
|
)(integrationId, workspaceId);
|
|
}
|
|
|
|
describe("pluginRegistry — integration settings", () => {
|
|
afterEach(() => {
|
|
pluginRegistry.unregisterPlugin(PRIMARY_PLUGIN_ID);
|
|
pluginRegistry.unregisterPlugin(SECONDARY_PLUGIN_ID);
|
|
});
|
|
|
|
it("exposes native integration settings registration to scoped plugins", () => {
|
|
const scoped = pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID);
|
|
|
|
expect("registerIntegrationSettings" in scoped).toBe(true);
|
|
});
|
|
|
|
it("keeps a contribution with its active plugin owner", () => {
|
|
function Settings() {
|
|
return null;
|
|
}
|
|
|
|
pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID).registerIntegrationSettings({
|
|
...registration,
|
|
icon: "cloud",
|
|
Component: Settings,
|
|
});
|
|
|
|
expect(pluginRegistry.getIntegrationSetting(SOURCE_CONTROL_PROVIDER_ID)).toEqual({
|
|
pluginId: PRIMARY_PLUGIN_ID,
|
|
...registration,
|
|
icon: "cloud",
|
|
Component: Settings,
|
|
});
|
|
});
|
|
|
|
it("rejects duplicate active ownership without replacing the owner", () => {
|
|
pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID).registerIntegrationSettings(registration);
|
|
|
|
expect(() =>
|
|
pluginRegistry.forPlugin(SECONDARY_PLUGIN_ID).registerIntegrationSettings(registration),
|
|
).toThrow(
|
|
`integration settings "${SOURCE_CONTROL_PROVIDER_ID}" is already owned by "${PRIMARY_PLUGIN_ID}"`,
|
|
);
|
|
expect(pluginRegistry.getIntegrationSetting(SOURCE_CONTROL_PROVIDER_ID)?.pluginId).toBe(
|
|
PRIMARY_PLUGIN_ID,
|
|
);
|
|
});
|
|
|
|
it("rejects core integration IDs and path-unsafe IDs", () => {
|
|
const scoped = pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID);
|
|
|
|
expect(() => scoped.registerIntegrationSettings({ ...registration, id: "github" })).toThrow(
|
|
'integration settings id "github" is reserved by the host',
|
|
);
|
|
expect(() =>
|
|
scoped.registerIntegrationSettings({ ...registration, id: "unsafe/path" }),
|
|
).toThrow('integration settings id "unsafe/path" must be a URL-safe slug');
|
|
});
|
|
|
|
it("revokes on unload and lets a successor claim the id", () => {
|
|
pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID).registerIntegrationSettings(registration);
|
|
|
|
pluginRegistry.unregisterPlugin(PRIMARY_PLUGIN_ID);
|
|
pluginRegistry.forPlugin(SECONDARY_PLUGIN_ID).registerIntegrationSettings(registration);
|
|
|
|
expect(pluginRegistry.getIntegrationSetting(SOURCE_CONTROL_PROVIDER_ID)?.pluginId).toBe(
|
|
SECONDARY_PLUGIN_ID,
|
|
);
|
|
});
|
|
|
|
it("keeps enabled state independent for each registration and workspace", () => {
|
|
pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID).registerIntegrationSettings(registration);
|
|
pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID).registerIntegrationSettings({
|
|
...registration,
|
|
id: SECOND_SOURCE_CONTROL_PROVIDER_ID,
|
|
});
|
|
|
|
setIntegrationEnabled(PRIMARY_PLUGIN_ID, SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID, true);
|
|
setIntegrationEnabled(
|
|
PRIMARY_PLUGIN_ID,
|
|
SECOND_SOURCE_CONTROL_PROVIDER_ID,
|
|
OTHER_WORKSPACE_ID,
|
|
true,
|
|
);
|
|
|
|
expect(isIntegrationEnabled(SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID)).toBe(true);
|
|
expect(isIntegrationEnabled(SOURCE_CONTROL_PROVIDER_ID, OTHER_WORKSPACE_ID)).toBe(false);
|
|
expect(isIntegrationEnabled(SECOND_SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID)).toBe(false);
|
|
expect(isIntegrationEnabled(SECOND_SOURCE_CONTROL_PROVIDER_ID, OTHER_WORKSPACE_ID)).toBe(true);
|
|
});
|
|
|
|
it("rejects state updates for an integration owned by another plugin", () => {
|
|
pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID).registerIntegrationSettings(registration);
|
|
pluginRegistry.forPlugin(SECONDARY_PLUGIN_ID).registerIntegrationSettings({
|
|
...registration,
|
|
id: SECOND_SOURCE_CONTROL_PROVIDER_ID,
|
|
});
|
|
|
|
const listener = vi.fn();
|
|
const unsubscribe = pluginRegistry.subscribe(listener);
|
|
|
|
setIntegrationEnabled(PRIMARY_PLUGIN_ID, SECOND_SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID, true);
|
|
|
|
expect(listener).not.toHaveBeenCalled();
|
|
expect(isIntegrationEnabled(SECOND_SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID)).toBe(false);
|
|
unsubscribe();
|
|
});
|
|
|
|
it("suppresses unchanged notifications and clears state on unload", () => {
|
|
pluginRegistry.forPlugin(PRIMARY_PLUGIN_ID).registerIntegrationSettings(registration);
|
|
const listener = vi.fn();
|
|
const unsubscribe = pluginRegistry.subscribe(listener);
|
|
|
|
setIntegrationEnabled(PRIMARY_PLUGIN_ID, SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID, true);
|
|
setIntegrationEnabled(PRIMARY_PLUGIN_ID, SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID, true);
|
|
|
|
expect(listener).toHaveBeenCalledTimes(1);
|
|
expect(isIntegrationEnabled(SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID)).toBe(true);
|
|
|
|
pluginRegistry.unregisterPlugin(PRIMARY_PLUGIN_ID);
|
|
|
|
expect(isIntegrationEnabled(SOURCE_CONTROL_PROVIDER_ID, WORKSPACE_ID)).toBe(false);
|
|
expect(listener).toHaveBeenCalledTimes(2);
|
|
unsubscribe();
|
|
});
|
|
});
|