import { describe, it, expect, beforeEach } from "vitest"; import { AppReduced, type AppType } from "ui/client/utils/AppReduced"; import type { BkndAdminOptions } from "ui/client/BkndProvider"; // Import the normalizeAdminPath function for testing // Note: This assumes the function is exported or we need to test it indirectly through public methods describe("AppReduced", () => { let mockAppJson: AppType; let appReduced: AppReduced; beforeEach(() => { mockAppJson = { data: { entities: {}, relations: {}, }, flows: { flows: {}, }, auth: {}, } as AppType; }); describe("getSettingsPath", () => { it("should return settings path with admin_basepath", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(); expect(result).toBe("~/admin/settings"); }); it("should return settings path with empty admin_basepath", () => { const options: BkndAdminOptions = { admin_basepath: "", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(); expect(result).toBe("~/settings"); }); it("should append additional path segments", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(["user", "profile"]); expect(result).toBe("~/admin/settings/user/profile"); }); it("should normalize multiple slashes", () => { const options: BkndAdminOptions = { admin_basepath: "//admin//", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(["//user//"]); expect(result).toBe("~/admin/settings/user"); }); it("should handle admin_basepath without leading slash", () => { const options: BkndAdminOptions = { admin_basepath: "admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(); expect(result).toBe("~/admin/settings"); }); }); describe("getAbsolutePath", () => { it("should return absolute path with admin_basepath", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getAbsolutePath("dashboard"); expect(result).toBe("~/admin/dashboard"); }); it("should return base path when no path provided", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getAbsolutePath(); expect(result).toBe("~/admin"); }); it("should normalize paths correctly", () => { const options: BkndAdminOptions = { admin_basepath: "//admin//", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getAbsolutePath("//dashboard//"); expect(result).toBe("~/admin/dashboard"); }); }); describe("options getter", () => { it("should return merged options with defaults", () => { const customOptions: BkndAdminOptions = { admin_basepath: "/custom-admin", logo_return_path: "/custom-home", }; appReduced = new AppReduced(mockAppJson, customOptions); const options = appReduced.options; expect(options).toEqual({ basepath: "/", logo_return_path: "/custom-home", admin_basepath: "/custom-admin", }); }); it("should use default logo_return_path when not provided", () => { const customOptions: BkndAdminOptions = { admin_basepath: "/admin", }; appReduced = new AppReduced(mockAppJson, customOptions); const options = appReduced.options; expect(options.logo_return_path).toBe("/"); expect(options.admin_basepath).toBe("/admin"); }); }); describe("path normalization behavior", () => { it("should normalize duplicate slashes in settings path", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(["//nested//path//"]); expect(result).toBe("~/admin/settings/nested/path"); }); it("should handle root path normalization", () => { const options: BkndAdminOptions = { admin_basepath: "/", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getAbsolutePath(); // The normalizeAdminPath function removes trailing slashes except for root "/" // When admin_basepath is "/", the result is "~/" which becomes "~" after normalization expect(result).toBe("~"); }); it("should preserve entity paths ending with slash", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getAbsolutePath("entity/"); expect(result).toBe("~/admin/entity"); }); it("should remove trailing slashes from non-entity paths", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getAbsolutePath("dashboard/"); expect(result).toBe("~/admin/dashboard"); }); }); describe("edge cases", () => { it("should handle undefined admin_basepath", () => { const options: BkndAdminOptions = { logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(); // When admin_basepath is undefined, it defaults to empty string expect(result).toBe("~/settings"); }); it("should handle null path segments", () => { const options: BkndAdminOptions = { admin_basepath: "/admin", logo_return_path: "/", }; appReduced = new AppReduced(mockAppJson, options); const result = appReduced.getSettingsPath(["", "valid", ""]); expect(result).toBe("~/admin/settings/valid"); }); }); });