refactor: app category metadata to use Record<AppCategories, AppCategoryEntry> for exhaustive type safety (#29558)
* refactor: derive category metadata from single Record source of truth * test: add test for category order and entries sync * fix: check for duplicates
This commit is contained in:
1 parent
b97cd6203d
commit
5d6d4d30cc
3 files changed
+70
-76
No files matched your search
@@ -0,0 +1,18 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { APP_CATEGORY_ENTRIES, CATEGORY_ORDER } from "./getAppCategories";
|
||||
|
||||
import type { ActiveAppCategoryKeys } from "./getAppCategories"
|
||||
|
||||
describe("getAppCategories", () => {
|
||||
it("should have CATEGORY_ORDER that includes all ActiveAppCategoryKeys", () => {
|
||||
const categoryEntriesKeys = Object.keys(APP_CATEGORY_ENTRIES) as ActiveAppCategoryKeys[]
|
||||
const categoryOrderKeys = CATEGORY_ORDER
|
||||
|
||||
const missingInOrder = categoryEntriesKeys.filter((key) => !categoryOrderKeys.includes(key))
|
||||
const missingInEntries = categoryOrderKeys.filter((key) => !categoryEntriesKeys.includes(key))
|
||||
|
||||
expect(categoryOrderKeys).toHaveLength(categoryEntriesKeys.length)
|
||||
expect(missingInEntries).toHaveLength(0)
|
||||
expect(missingInOrder).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
@@ -8,6 +8,8 @@ function getHref(baseURL: string, category: string, useQueryParam: boolean) {
|
||||
return useQueryParam ? `${baseUrlParsed.toString()}` : `${baseURL}/${category}`;
|
||||
}
|
||||
|
||||
export type ActiveAppCategoryKeys = Exclude<AppCategories, "video" | "web3">;
|
||||
|
||||
type AppCategoryEntry = {
|
||||
name: AppCategories;
|
||||
href: string;
|
||||
@@ -15,59 +17,34 @@ type AppCategoryEntry = {
|
||||
"data-testid": string;
|
||||
};
|
||||
|
||||
const getAppCategories = (baseURL: string, useQueryParam: boolean): AppCategoryEntry[] => {
|
||||
// Manually sorted alphabetically, but leaving "Other" at the end
|
||||
// TODO: Refactor and type with Record<AppCategories, AppCategoryEntry> to enforce consistency
|
||||
return [
|
||||
{
|
||||
name: "analytics",
|
||||
href: getHref(baseURL, "analytics", useQueryParam),
|
||||
icon: "chart-bar",
|
||||
"data-testid": "analytics",
|
||||
},
|
||||
{
|
||||
name: "automation",
|
||||
href: getHref(baseURL, "automation", useQueryParam),
|
||||
icon: "share-2",
|
||||
"data-testid": "automation",
|
||||
},
|
||||
{
|
||||
name: "calendar",
|
||||
href: getHref(baseURL, "calendar", useQueryParam),
|
||||
icon: "calendar",
|
||||
"data-testid": "calendar",
|
||||
},
|
||||
{
|
||||
name: "conferencing",
|
||||
href: getHref(baseURL, "conferencing", useQueryParam),
|
||||
icon: "video",
|
||||
"data-testid": "conferencing",
|
||||
},
|
||||
{
|
||||
name: "crm",
|
||||
href: getHref(baseURL, "crm", useQueryParam),
|
||||
icon: "contact",
|
||||
"data-testid": "crm",
|
||||
},
|
||||
{
|
||||
name: "messaging",
|
||||
href: getHref(baseURL, "messaging", useQueryParam),
|
||||
icon: "mail",
|
||||
"data-testid": "messaging",
|
||||
},
|
||||
{
|
||||
name: "payment",
|
||||
href: getHref(baseURL, "payment", useQueryParam),
|
||||
icon: "credit-card",
|
||||
"data-testid": "payment",
|
||||
},
|
||||
{
|
||||
name: "other",
|
||||
href: getHref(baseURL, "other", useQueryParam),
|
||||
icon: "grid-3x3",
|
||||
"data-testid": "other",
|
||||
},
|
||||
];
|
||||
export const APP_CATEGORY_ENTRIES: Record<ActiveAppCategoryKeys, Omit<AppCategoryEntry, "name">> = {
|
||||
analytics: { href: "", icon: "chart-bar", "data-testid": "analytics" },
|
||||
automation: { href: "", icon: "share-2", "data-testid": "automation" },
|
||||
calendar: { href: "", icon: "calendar", "data-testid": "calendar" },
|
||||
conferencing: { href: "", icon: "video", "data-testid": "conferencing" },
|
||||
crm: { href: "", icon: "contact", "data-testid": "crm" },
|
||||
messaging: { href: "", icon: "mail", "data-testid": "messaging" },
|
||||
payment: { href: "", icon: "credit-card", "data-testid": "payment" },
|
||||
other: { href: "", icon: "grid-3x3", "data-testid": "other" },
|
||||
};
|
||||
|
||||
export default getAppCategories;
|
||||
export const CATEGORY_ORDER = [
|
||||
"analytics",
|
||||
"automation",
|
||||
"calendar",
|
||||
"conferencing",
|
||||
"crm",
|
||||
"messaging",
|
||||
"payment",
|
||||
"other",
|
||||
] as const satisfies readonly ActiveAppCategoryKeys[];
|
||||
|
||||
|
||||
const getAppCategories = (baseURL: string, useQueryParam: boolean): AppCategoryEntry[] =>
|
||||
CATEGORY_ORDER.map((name): AppCategoryEntry => ({
|
||||
name,
|
||||
...APP_CATEGORY_ENTRIES[name],
|
||||
href: getHref(baseURL, name, useQueryParam),
|
||||
}));
|
||||
|
||||
export default getAppCategories;
|
||||
Reference in new issue
Block a user