All checks were successful
CI / build (push) Successful in 16s
Introduces opt-in pending/total task count frontmatter fields and a "count root tasks only" mode. Root tasks are detected structurally by walking the list tree, so tasks nested under non-task bullets (e.g. "- **Action items**:") are correctly classified as root. Also updates the manifest author metadata.
223 lines
6.9 KiB
TypeScript
223 lines
6.9 KiB
TypeScript
import AutoStatusPlugin from '../src/main';
|
|
import { App } from 'obsidian';
|
|
|
|
// Default settings constant that matches the plugin
|
|
const DEFAULT_SETTINGS = {
|
|
propertyName: 'Pending tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [] as string[],
|
|
includeFolders: [] as string[],
|
|
debounceDelay: 500,
|
|
enableTaskCounts: false,
|
|
pendingTasksCountProperty: 'Pending tasks count',
|
|
totalTasksCountProperty: 'Total tasks count',
|
|
countRootTasksOnly: false,
|
|
};
|
|
|
|
describe('Settings Management', () => {
|
|
let plugin: AutoStatusPlugin;
|
|
let mockApp: App;
|
|
|
|
beforeEach(() => {
|
|
mockApp = new App();
|
|
plugin = new AutoStatusPlugin(mockApp, {} as any);
|
|
// Initialize settings to prevent undefined errors
|
|
plugin.settings = { ...DEFAULT_SETTINGS };
|
|
});
|
|
|
|
describe('loadSettings', () => {
|
|
test('should load default settings when no saved data exists', async () => {
|
|
plugin.loadData = jest.fn().mockResolvedValue(undefined);
|
|
|
|
await plugin.loadSettings();
|
|
|
|
expect(plugin.settings).toEqual(DEFAULT_SETTINGS);
|
|
});
|
|
|
|
test('should merge saved settings with defaults', async () => {
|
|
const savedSettings = {
|
|
propertyName: 'Custom Tasks',
|
|
enableAutoProcessing: false,
|
|
excludeFolders: ['Templates'],
|
|
};
|
|
|
|
plugin.loadData = jest.fn().mockResolvedValue(savedSettings);
|
|
|
|
await plugin.loadSettings();
|
|
|
|
expect(plugin.settings).toEqual({
|
|
...DEFAULT_SETTINGS,
|
|
propertyName: 'Custom Tasks',
|
|
enableAutoProcessing: false,
|
|
excludeFolders: ['Templates'],
|
|
});
|
|
});
|
|
|
|
test('should fill in new task-count fields when loading legacy data', async () => {
|
|
const legacySettings = {
|
|
propertyName: 'Pending tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [],
|
|
includeFolders: [],
|
|
debounceDelay: 500,
|
|
};
|
|
|
|
plugin.loadData = jest.fn().mockResolvedValue(legacySettings);
|
|
|
|
await plugin.loadSettings();
|
|
|
|
expect(plugin.settings.enableTaskCounts).toBe(false);
|
|
expect(plugin.settings.pendingTasksCountProperty).toBe('Pending tasks count');
|
|
expect(plugin.settings.totalTasksCountProperty).toBe('Total tasks count');
|
|
expect(plugin.settings.countRootTasksOnly).toBe(false);
|
|
});
|
|
|
|
test('should handle invalid saved data gracefully', async () => {
|
|
plugin.loadData = jest.fn().mockResolvedValue(null);
|
|
|
|
await plugin.loadSettings();
|
|
|
|
expect(plugin.settings).toEqual(DEFAULT_SETTINGS);
|
|
});
|
|
});
|
|
|
|
describe('saveSettings', () => {
|
|
test('should save current settings', async () => {
|
|
plugin.saveData = jest.fn().mockResolvedValue(undefined);
|
|
plugin.settings = {
|
|
...DEFAULT_SETTINGS,
|
|
propertyName: 'My Tasks',
|
|
enableAutoProcessing: false,
|
|
excludeFolders: ['Archive'],
|
|
includeFolders: ['Work'],
|
|
debounceDelay: 1000,
|
|
};
|
|
|
|
await plugin.saveSettings();
|
|
|
|
expect(plugin.saveData).toHaveBeenCalledWith(plugin.settings);
|
|
});
|
|
|
|
test('should recreate debounced function after saving', async () => {
|
|
plugin.saveData = jest.fn().mockResolvedValue(undefined);
|
|
plugin.debouncedProcessFile = jest.fn();
|
|
// Ensure settings are properly initialized
|
|
plugin.settings = { ...DEFAULT_SETTINGS };
|
|
|
|
const originalDebouncedFn = plugin.debouncedProcessFile;
|
|
|
|
await plugin.saveSettings();
|
|
|
|
// The debounced function should be recreated
|
|
expect(plugin.debouncedProcessFile).toBeDefined();
|
|
expect(plugin.debouncedProcessFile).not.toBe(originalDebouncedFn);
|
|
});
|
|
});
|
|
|
|
describe('default settings validation', () => {
|
|
test('should have valid default property name', () => {
|
|
const defaults = {
|
|
propertyName: 'Pending tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [] as string[],
|
|
includeFolders: [] as string[],
|
|
debounceDelay: 500,
|
|
};
|
|
|
|
expect(defaults.propertyName).toBeTruthy();
|
|
expect(typeof defaults.propertyName).toBe('string');
|
|
});
|
|
|
|
test('should have valid default processing state', () => {
|
|
const defaults = {
|
|
propertyName: 'Pending tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [] as string[],
|
|
includeFolders: [] as string[],
|
|
debounceDelay: 500,
|
|
};
|
|
|
|
expect(typeof defaults.enableAutoProcessing).toBe('boolean');
|
|
expect(defaults.enableAutoProcessing).toBe(true);
|
|
});
|
|
|
|
test('should have valid default folder arrays', () => {
|
|
const defaults = {
|
|
propertyName: 'Pending tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [] as string[],
|
|
includeFolders: [] as string[],
|
|
debounceDelay: 500,
|
|
};
|
|
|
|
expect(Array.isArray(defaults.excludeFolders)).toBe(true);
|
|
expect(Array.isArray(defaults.includeFolders)).toBe(true);
|
|
expect(defaults.excludeFolders.length).toBe(0);
|
|
expect(defaults.includeFolders.length).toBe(0);
|
|
});
|
|
|
|
test('should have valid default debounce delay', () => {
|
|
const defaults = {
|
|
propertyName: 'Pending tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [] as string[],
|
|
includeFolders: [] as string[],
|
|
debounceDelay: 500,
|
|
};
|
|
|
|
expect(typeof defaults.debounceDelay).toBe('number');
|
|
expect(defaults.debounceDelay).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('settings validation edge cases', () => {
|
|
test('should handle empty string property name', async () => {
|
|
const savedSettings = {
|
|
propertyName: '',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [] as string[],
|
|
includeFolders: [] as string[],
|
|
debounceDelay: 500,
|
|
};
|
|
|
|
plugin.loadData = jest.fn().mockResolvedValue(savedSettings);
|
|
await plugin.loadSettings();
|
|
|
|
// Should accept empty string if provided
|
|
expect(plugin.settings.propertyName).toBe('');
|
|
});
|
|
|
|
test('should handle negative debounce delay', async () => {
|
|
const savedSettings = {
|
|
propertyName: 'Tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: [] as string[],
|
|
includeFolders: [] as string[],
|
|
debounceDelay: -100,
|
|
};
|
|
|
|
plugin.loadData = jest.fn().mockResolvedValue(savedSettings);
|
|
await plugin.loadSettings();
|
|
|
|
// Should accept negative value if provided (validation happens in UI)
|
|
expect(plugin.settings.debounceDelay).toBe(-100);
|
|
});
|
|
|
|
test('should handle non-array folder settings', async () => {
|
|
const savedSettings = {
|
|
propertyName: 'Tasks',
|
|
enableAutoProcessing: true,
|
|
excludeFolders: 'Templates', // Should be array
|
|
includeFolders: null as any, // Should be array
|
|
debounceDelay: 500,
|
|
};
|
|
|
|
plugin.loadData = jest.fn().mockResolvedValue(savedSettings);
|
|
await plugin.loadSettings();
|
|
|
|
// Object.assign will overwrite with non-array values
|
|
expect(plugin.settings.excludeFolders).toBe('Templates');
|
|
expect(plugin.settings.includeFolders).toBe(null);
|
|
});
|
|
});
|
|
});
|