Files
Termix/packages/plugin-sdk/src/testing/setup.ts
T
a89ccc6b07 v26.10.3 (#1692)
* feat: shell controller, TabStage, layout and theme plugins with repair view

* feat: move the classic layout into its own bundled plugin

* feat: move color themes into a bundled themes plugin

* fix: plugin tests and type checks work with a linked sdk

* fix: home tab, layout switch and missing layout fallbacks for looks

* chore: add classic layout and themes to the readme

* chore: drop example plugin links from the plugin guide

* feat: plugin filters by type, paged browse, hide plugins needing newer termix

* feat: move desktop, status, import, audit and branding features into plugins

* feat: host lock api so a plugin can load hosts from a config file (#1581)

* chore: add hosts config to the plugin table

* feat: login policy hook for plugins and optional https redirect (#1584)

* chore: add login security to the plugin table

* feat: api key socket tickets so a master can open remote sessions (#1654)

* feat: sync moves to a plugin, desktop gets multiple accounts (#1580, #1654)

* chore: add sync to the plugin table

* feat: move the sync screens and wizard out of core into the plugin (#1580)

* fix: add a neutral linked desktop hook for plugins (#1580)

* fix: show the linked account's name and admin flag in the app (#1580)

* feat: ssh transport providers, core ssh relay and plugin folders api

* feat: support FIDO2 security keys through ssh agent

* feat: add companion panels beside host tabs

* feat: mTLS client certificates for desktop server links

* feat: native web view for plugins in the desktop app

* fix: detect the desktop link window by Electron's default user agent

Fixes #1675

* fix: changelog for desktop link fix

* fix: keep text primary keys in the plugin data export

* fix: ship sharp binaries for Windows arm64 builds

* feat: client cert on the sync link types (sdk 1.0.18)

* chore: update translations

* feat: themed title bar for the desktop app (#1690)

* chore: changelog for the themed title bar

* fix: draw the title bar in the sidebar color

* feat: per host layout for the terminal panel bar

* chore: sdk 1.0.19 for the panel bar layout

* chore: bundle all 43 plugins for 26.10.3

* chore: update translations

---------

Co-authored-by: SirHephaistos <60616553+SirHephaistos@users.noreply.github.com>
Co-authored-by: Giovanny Aranda <garanda21@gmail.com>
2026-10-20 16:03:29 -05:00

167 lines
4.9 KiB
TypeScript

/**
* Shared vitest setup for core and for every plugin suite.
*
* The root vitest.setup.ts re-exports this so there is one copy of the
* polyfills rather than two that drift apart.
*/
import { afterEach, vi } from "vitest";
import { installSafePorts } from "./safe-ports.js";
installSafePorts();
// Radix measures some controls (Checkbox, Switch) and jsdom has no observer.
if (typeof globalThis.ResizeObserver === "undefined") {
globalThis.ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
} as unknown as typeof ResizeObserver;
}
if (typeof window !== "undefined" && !window.matchMedia) {
window.matchMedia = vi.fn().mockImplementation((query: string) => ({
matches: false,
media: query,
onchange: null,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
addListener: vi.fn(),
removeListener: vi.fn(),
dispatchEvent: vi.fn(),
}));
}
/**
* jsdom in this project ships without a `localStorage` global, and Node only
* provides one when started with --localstorage-file (which persists to disk
* and is shared across test files -- both wrong for tests). Suites that touch
* storage therefore threw `Cannot read properties of undefined`, taking out
* every test in the file rather than just the ones that used it.
*
* A per-process in-memory implementation is enough: it satisfies the Storage
* interface the app uses and keeps nothing on disk.
*/
if (typeof globalThis.localStorage === "undefined") {
const createMemoryStorage = (): Storage => {
const store = new Map<string, string>();
return {
get length() {
return store.size;
},
key: (index: number) => Array.from(store.keys())[index] ?? null,
getItem: (key: string) => (store.has(key) ? store.get(key)! : null),
setItem: (key: string, value: string) => {
store.set(key, String(value));
},
removeItem: (key: string) => {
store.delete(key);
},
clear: () => {
store.clear();
},
} as Storage;
};
Object.defineProperty(globalThis, "localStorage", {
value: createMemoryStorage(),
configurable: true,
writable: true,
});
Object.defineProperty(globalThis, "sessionStorage", {
value: createMemoryStorage(),
configurable: true,
writable: true,
});
}
/**
* A plain plugin host for components a test renders on its own: keys come
* back as text, every permission is held, and nothing reaches a server.
* renderWithApp installs Termix's real host instead, which takes precedence.
*/
const noop = () => {};
const offline = () =>
Promise.reject(new Error("No plugin API in a unit test; mock it"));
(globalThis as Record<string, unknown>).__termixTestPluginHost = {
usePluginId: () => "test-plugin",
useDocsUrl: () => null,
useTranslation: () => ({
t: (key: string) => key,
language: "en",
}),
usePermission: () => true,
useSettings: () => ({ values: {}, loaded: true, save: async () => {} }),
useHost: () => null,
useHosts: () => ({ hosts: [], loaded: true }),
useHostStatus: () => null,
useCurrentUser: () => null,
useTheme: () => ({ theme: "dark" }),
useShell: () => null,
toast: { success: noop, error: noop, info: noop, warning: noop },
getApi: () => ({
get: offline,
delete: offline,
post: offline,
put: offline,
patch: offline,
}),
useTabs: () => ({
openTab: noop,
openSingletonTab: noop,
connectHost: noop,
closeTab: noop,
getLayout: () => null,
applyLayout: async () => ({ skipped: [] }),
onChange: () => noop,
onReady: () => noop,
}),
invokeAction: async () => undefined,
useSshAuthTypes: () => ({
types: ["password", "key", "credential", "agent", "none"].map((type) => ({
type,
labelKey: type,
pluginId: "core",
credentialType: type === "password" || type === "key",
supportsBackground: type !== "none",
quickConnect: true,
})),
loaded: true,
}),
useSlotContributions: () => [],
usePluginComponent: () => undefined,
getApiFor: () => ({
get: offline,
delete: offline,
post: offline,
put: offline,
patch: offline,
}),
hostProtocols: () => ["ssh"],
useHostActions: () => [],
useCompanions: () => [],
useActivityTypes: () => [],
activityTarget: () => undefined,
useExtensions: () => [],
getExtension: () => undefined,
usePluginUiPreferences: () => ({ values: {}, set: noop }),
core: {
logActivity: async () => {},
getHostPassword: async () => null,
patchOpenTab: async () => {},
getCustomKeybindings: async () => [],
runKeybindingAction: () => false,
getClientPreference: () => undefined,
setClientPreference: () => {},
listHosts: async () => [],
listCredentials: async () => [],
notifyHostsChanged: () => {},
getHostStatusColorScheme: () => "accent",
getLocalAuthToken: () => null,
},
};
afterEach(() => {
vi.restoreAllMocks();
});