121 lines
4.7 KiB
TypeScript
121 lines
4.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { readFileSync } from "node:fs";
|
|
import { ScopedCommandAction } from "~/services/command-registry/commandRegistry";
|
|
import { filterCommandActions } from "./commandSearch";
|
|
|
|
function rootData(options?: { tenantApiKeys?: boolean; admin?: boolean }) {
|
|
return {
|
|
user: { id: "user_1", admin: options?.admin ?? false },
|
|
appConfiguration: {
|
|
app: { features: { tenantApiKeys: options?.tenantApiKeys ?? true } },
|
|
},
|
|
} as any;
|
|
}
|
|
|
|
function appData(options?: { admin?: boolean; permissions?: string[]; tenantSlug?: string }) {
|
|
return {
|
|
currentTenant: { id: "tenant_1", slug: options?.tenantSlug ?? "acme" },
|
|
permissions: options?.permissions ?? ["app.settings.members.view"],
|
|
isSuperAdmin: false,
|
|
user: { id: "user_1", admin: options?.admin ?? false },
|
|
} as any;
|
|
}
|
|
|
|
const actions = [
|
|
action({ id: "dashboard", name: "Dashboard", keywords: "home overview" }),
|
|
action({ id: "members", name: "Members", subtitle: "Settings", permission: "app.settings.members.view" }),
|
|
action({ id: "billing", name: "Billing", permission: "app.settings.subscription.view" }),
|
|
action({ id: "switch-to-admin", name: "Switch to admin", adminOnly: true }),
|
|
action({ id: "other-tenant", name: "Other tenant", tenantSlug: "globex" }),
|
|
action({ id: "apiKeys", name: "API Keys", featureFlag: "tenantApiKeys" }),
|
|
action({ id: "unknown-feature", name: "Unknown feature", featureFlag: "newFlag" }),
|
|
action({ id: "admin-dashboard", name: "Admin dashboard", layout: "admin", adminOnly: true }),
|
|
] satisfies ScopedCommandAction[];
|
|
|
|
function action(options: {
|
|
id: string;
|
|
name: string;
|
|
subtitle?: string;
|
|
keywords?: string;
|
|
layout?: "app" | "admin" | "docs";
|
|
tenantSlug?: string;
|
|
adminOnly?: boolean;
|
|
featureFlag?: string;
|
|
permission?: string;
|
|
}): ScopedCommandAction {
|
|
return {
|
|
id: options.id,
|
|
name: options.name,
|
|
subtitle: options.subtitle,
|
|
keywords: options.keywords,
|
|
shortcut: [],
|
|
scope: {
|
|
layout: options.layout ?? "app",
|
|
tenantSlug: options.tenantSlug ?? "acme",
|
|
adminOnly: options.adminOnly,
|
|
featureFlag: options.featureFlag,
|
|
permission: options.permission,
|
|
},
|
|
};
|
|
}
|
|
|
|
function search(query: string, options?: Parameters<typeof appData>[0] & { tenantApiKeys?: boolean; tenantSlug?: string }) {
|
|
return filterCommandActions({
|
|
actions,
|
|
query,
|
|
layout: "app",
|
|
tenantSlug: options?.tenantSlug ?? "acme",
|
|
appData: appData(options),
|
|
rootData: rootData({ tenantApiKeys: options?.tenantApiKeys, admin: options?.admin }),
|
|
}).map((result) => result.id);
|
|
}
|
|
|
|
describe("command search", () => {
|
|
it("returns all scope-allowed actions for a blank query", () => {
|
|
expect(search(" ", { admin: true, permissions: ["app.settings.members.view", "app.settings.subscription.view"] })).toEqual([
|
|
"dashboard",
|
|
"members",
|
|
"billing",
|
|
"switch-to-admin",
|
|
"apiKeys",
|
|
]);
|
|
});
|
|
|
|
it("matches query text case-insensitively across id, name, subtitle, and keywords", () => {
|
|
expect(search("dash")).toEqual(["dashboard"]);
|
|
expect(search("SETTINGS")).toEqual(["members"]);
|
|
expect(search("overview")).toEqual(["dashboard"]);
|
|
expect(search("apikeys")).toEqual(["apiKeys"]);
|
|
});
|
|
|
|
it("keeps search normalization independent from host locale", () => {
|
|
const source = readFileSync(`${__dirname}/commandSearch.ts`, "utf8");
|
|
expect(source).not.toContain("toLocaleLowerCase");
|
|
});
|
|
|
|
it("returns no results for unmatched query text", () => {
|
|
expect(search("does-not-exist", { admin: true, permissions: ["app.settings.members.view", "app.settings.subscription.view"] })).toEqual([]);
|
|
});
|
|
|
|
it("denies permission-scoped actions without the required permission", () => {
|
|
expect(search("", { permissions: [] })).not.toContain("members");
|
|
expect(search("", { permissions: [] })).not.toContain("billing");
|
|
});
|
|
|
|
it("denies admin-only actions for non-admin users and missing app context", () => {
|
|
expect(search("")).not.toContain("switch-to-admin");
|
|
expect(filterCommandActions({ actions, query: "", layout: "app", tenantSlug: "acme", rootData: rootData({ admin: true }) }).map((result) => result.id)).not.toContain("switch-to-admin");
|
|
});
|
|
|
|
it("denies tenant-scoped actions for the wrong tenant", () => {
|
|
expect(search("", { tenantSlug: "globex", admin: true, permissions: ["app.settings.members.view", "app.settings.subscription.view"] })).toEqual(["other-tenant"]);
|
|
});
|
|
|
|
it("denies disabled and unknown feature flags", () => {
|
|
const results = search("", { tenantApiKeys: false, admin: true, permissions: ["app.settings.members.view", "app.settings.subscription.view"] });
|
|
|
|
expect(results).not.toContain("apiKeys");
|
|
expect(results).not.toContain("unknown-feature");
|
|
});
|
|
});
|