test: add comprehensive tests for AppReduced utility and path normalization

This commit is contained in:
cameronapak
2025-07-22 08:52:32 -05:00
parent 75c29ae5e2
commit 12ef72d595
3 changed files with 236 additions and 2 deletions

View File

@@ -0,0 +1,231 @@
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({
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');
});
});
});

View File

@@ -8,7 +8,9 @@ import { Message } from "ui/components/display/Message";
import { useNavigate } from "ui/lib/routes"; import { useNavigate } from "ui/lib/routes";
import type { AdminBkndWindowContext } from "modules/server/AdminController"; import type { AdminBkndWindowContext } from "modules/server/AdminController";
export type BkndAdminOptions = Omit<AdminBkndWindowContext, "user" | "logout_route"> export type BkndAdminOptions = Omit<AdminBkndWindowContext, "user" | "logout_route" | "admin_basepath"> & {
admin_basepath?: string;
}
type BkndContext = { type BkndContext = {
version: number; version: number;
schema: ModuleSchemas; schema: ModuleSchemas;

View File

@@ -88,7 +88,8 @@ export class AppReduced {
get options() { get options() {
return { return {
logo_return_path: "/", admin_basepath: '',
logo_return_path: '/',
...this._options, ...this._options,
}; };
} }