дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 03:05:40 +02:00
A plugin can set `icon` (and `icon-dark`) in plugin.toml. The SVGs go through the existing sanitiser (16 KiB each), ship with the package, and show in Settings › Plugins (list rows and detail header) and the marketplace, whose index entries carry them; the IDE sanitises index icons again and drops unsafe ones. IDEs before plugin API 1.2 refuse a manifest with `icon`, so Manifest::needs_api refuses one whose engines.openidea still admits them (check and install), keeping the index from offering such a package to older IDEs. Closes #1732 Co-authored-by: arnaud-ritti <[email protected]>
65 рядки
2.9 KiB
TypeScript
65 рядки
2.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { render } from "@testing-library/react";
|
|
import { Icon } from "@/ui/icons";
|
|
import { pluginIconName } from "../pluginIcon";
|
|
|
|
const svg = (shape: string, root = "") => `<svg viewBox="0 0 16 16"${root}>${shape}</svg>`;
|
|
const rendered = (name: string) => render(<Icon name={name} size={20} />).container;
|
|
const markup = (name: string) => rendered(name).innerHTML;
|
|
|
|
describe("pluginIconName", () => {
|
|
it("gives plugins without an icon the generic one", () => {
|
|
expect(pluginIconName("a.b", null)).toBe("plugin");
|
|
expect(pluginIconName("a.b", undefined)).toBe("plugin");
|
|
});
|
|
|
|
it("renders a plugin's icon under a name of its own", () => {
|
|
const name = pluginIconName("a.b", { light: svg('<rect width="16" height="16"/>'), dark: null });
|
|
expect(name).toMatch(/^ext:pluginIcon\/a\.b\//);
|
|
expect(markup(name)).toContain("<rect");
|
|
});
|
|
|
|
it("keeps two icons of the same plugin id apart (a marketplace and a local copy)", () => {
|
|
const published = pluginIconName("a.b", { light: svg('<rect width="16" height="16"/>'), dark: null });
|
|
const local = pluginIconName("a.b", { light: svg('<circle cx="8" cy="8" r="8"/>'), dark: null });
|
|
expect(local).not.toBe(published);
|
|
expect(markup(published)).toContain("<rect");
|
|
expect(markup(local)).toContain("<circle");
|
|
});
|
|
|
|
it("registers the dark variant with it", () => {
|
|
const name = pluginIconName("c.d", {
|
|
light: svg('<rect width="16" height="16"/>'),
|
|
dark: svg('<circle cx="8" cy="8" r="8"/>'),
|
|
});
|
|
expect(markup(name)).toContain("<circle");
|
|
});
|
|
|
|
it("keeps the icons of plugins whose ids differ by _dark apart", () => {
|
|
const plain = pluginIconName("g", { light: svg('<rect width="16" height="16"/>'), dark: null });
|
|
const other = pluginIconName("g_dark", { light: svg('<circle cx="8" cy="8" r="8"/>'), dark: null });
|
|
expect(markup(plain)).not.toContain("<circle");
|
|
expect(markup(other)).toContain("<circle");
|
|
});
|
|
|
|
it("gives a changed icon without a dark variant none", () => {
|
|
pluginIconName("e.f", { light: svg('<rect width="16" height="16"/>'), dark: svg('<circle cx="8" cy="8" r="8"/>') });
|
|
const name = pluginIconName("e.f", { light: svg('<rect width="16" height="16"/>'), dark: null });
|
|
expect(markup(name)).not.toContain("<circle");
|
|
});
|
|
|
|
it("keeps the root's fill and stroke, and SVG's default black fill", () => {
|
|
const filled = rendered(
|
|
pluginIconName("h.i", {
|
|
light: svg('<circle cx="8" cy="8" r="7"/>', ' fill="#E5A50A" stroke="#FFFFFF"'),
|
|
dark: null,
|
|
}),
|
|
);
|
|
const group = filled.querySelector("circle")?.closest("g");
|
|
expect(group?.getAttribute("fill")).toBe("#E5A50A");
|
|
expect(group?.getAttribute("stroke")).toBe("#FFFFFF");
|
|
const plain = rendered(pluginIconName("j.k", { light: svg('<circle cx="8" cy="8" r="7"/>'), dark: null }));
|
|
expect(plain.querySelector("circle")?.closest("g")?.getAttribute("fill")).toBe("#000");
|
|
});
|
|
});
|