Files
obsidian-mcp-server/tests/__mocks__/obsidian.ts
Bill 2e30b81f01 test: comprehensive coverage for NoteTools
Add extensive test suite for note-tools.ts covering all major operations
and error paths. Improves statement coverage from 13.94% to 96.01%.

Tests added:
- readNote: success, errors, frontmatter parsing
- createNote: success, conflict strategies (error/overwrite/rename), parent folder creation
- updateNote: success, errors, waypoint protection
- deleteNote: soft/permanent delete, dry run, version checking
- renameFile: success, errors, version checking, parent folder creation
- readExcalidraw: success, non-Excalidraw files, errors
- updateFrontmatter: success, field removal, version checking
- updateSections: success, invalid ranges, version checking
- Path validation for all methods
- Empty path validation for all methods

Mock enhancements:
- Added modify, delete, trash methods to VaultAdapter mock
- Added parseYaml function to Obsidian mock for frontmatter testing

Coverage improvements for note-tools.ts:
- Statements: 13.94% -> 96.01% (+82.07%)
- Branches: 5.1% -> 88.44% (+83.34%)
- Functions: 27.27% -> 90.9% (+63.63%)
- Lines: 13.94% -> 96.4% (+82.46%)
2025-10-20 00:13:03 -04:00

100 lines
2.2 KiB
TypeScript

/**
* Mock Obsidian API for testing
* This provides minimal mocks for the Obsidian types used in tests
*/
export class TFile {
path: string;
basename: string;
extension: string;
constructor(path: string) {
this.path = path;
const parts = path.split('/');
const filename = parts[parts.length - 1];
const dotIndex = filename.lastIndexOf('.');
this.basename = dotIndex > 0 ? filename.substring(0, dotIndex) : filename;
this.extension = dotIndex > 0 ? filename.substring(dotIndex + 1) : '';
}
}
export class TFolder {
path: string;
name: string;
constructor(path: string) {
this.path = path;
const parts = path.split('/');
this.name = parts[parts.length - 1];
}
}
export class TAbstractFile {
path: string;
name: string;
constructor(path: string) {
this.path = path;
const parts = path.split('/');
this.name = parts[parts.length - 1];
}
}
export class Vault {
private files: Map<string, TFile | TFolder> = new Map();
getAbstractFileByPath(path: string): TFile | TFolder | null {
return this.files.get(path) || null;
}
// Helper method for tests to add mock files
_addMockFile(path: string, isFolder = false) {
this.files.set(path, isFolder ? new TFolder(path) : new TFile(path));
}
// Helper method for tests to clear mock files
_clearMockFiles() {
this.files.clear();
}
}
export class App {
vault: Vault;
constructor() {
this.vault = new Vault();
}
}
// Export other commonly used types as empty classes/interfaces
export class Plugin {}
export class Notice {}
export class PluginSettingTab {}
export class Setting {}
// Mock parseYaml function
export function parseYaml(yaml: string): any {
// Simple YAML parser mock for testing
const result: any = {};
const lines = yaml.split('\n');
for (const line of lines) {
if (line.trim() && !line.startsWith('#')) {
const colonIndex = line.indexOf(':');
if (colonIndex > 0) {
const key = line.substring(0, colonIndex).trim();
let value = line.substring(colonIndex + 1).trim();
// Handle arrays
if (value.startsWith('[') && value.endsWith(']')) {
value = value.slice(1, -1).split(',').map(v => v.trim());
}
result[key] = value;
}
}
}
return result;
}