This guide provides technical information for developers working on or contributing to the File Content Aggregator project.
- Introduction
- Getting Started
- Project Structure
- Architecture
- Code Organization
- Key Technologies
- Core Logic Areas
- Building for Distribution
- Security Considerations
- Code Style & Linting
- Testing
- Contributing
File Content Aggregator is a desktop application built using Electron, React (with Vite), and TypeScript. It allows users to search for files across specified directories based on various criteria, including filename patterns, metadata (date, size), and complex content queries using boolean logic and proximity search.
- Node.js (LTS version recommended)
- npm (usually included with Node.js)
- Git
- Clone the repository:
git clone <https://github.com/12Mosch/File-Content-Aggregator/> cd file-content-aggregator
- Install dependencies:
npm install
To run the application locally with hot-reloading for the UI:
npm run devThis command concurrently:
- Starts the Vite development server (typically on
http://localhost:5123) to serve the React UI. - Transpiles the Electron main and preload scripts.
- Starts the Electron application, loading the UI from the Vite dev server. The main process terminal output will appear in your console, and the renderer process console (and React DevTools) can be accessed via Electron's developer tools (usually opened automatically in dev mode).
file-content-aggregator/
├── docs/ # Documentation files (like this one)
│ ├── assets/ # Images for documentation
│ ├── user-guide.md
│ └── developer-guide.md
├── public/ # Static assets served by Vite / copied to build
│ ├── locales/ # i18n translation JSON files
│ └── vite.svg # Example static asset
├── release/ # Output directory for packaged application (from electron-builder)
├── src/
│ ├── components/ # React UI components (especially shadcn/ui)
│ │ └── ui/ # shadcn/ui components live here
│ ├── electron/ # Electron Main process & related code
│ │ ├── main.ts # Main process entry point
│ │ ├── fileSearchService.ts # Core file searching logic
│ │ ├── preload.cts # Preload script (CommonJS for Electron compatibility)
│ │ ├── pathResolver.ts # Helper for resolving paths (e.g., preload)
│ │ ├── util.ts # Utility functions for main process (e.g., isDev)
│ │ └── tsconfig.json # TypeScript config specific to main process
│ ├── hooks/ # Custom React hooks (e.g., useDebounce)
│ ├── lib/ # Shared utility functions (e.g., cn for Tailwind)
│ │ └── utils.ts
│ ├── ui/ # Electron Renderer process code (React UI)
│ │ ├── App.tsx # Root React component
│ │ ├── main.tsx # Renderer process entry point (React root render)
│ │ ├── SearchForm.tsx # Component for search inputs
│ │ ├── ResultsDisplay.tsx # Component for displaying results
│ │ ├── QueryBuilder.tsx # Structured query builder UI
│ │ ├── QueryGroup.tsx # Query builder sub-component
│ │ ├── QueryCondition.tsx # Query builder sub-component
│ │ ├── SettingsModal.tsx # Settings UI
│ │ ├── HistoryModal.tsx # History UI
│ │ ├── ThemeManager.tsx # Theme application logic and listener component
│ │ ├── highlight.worker.ts # Web worker for syntax highlighting
│ │ ├── utils/ # UI utility functions
│ │ │ ├── fileTypeIcons.tsx # File type icon mapping utility
│ │ ├── i18n.ts # i18next configuration for UI
│ │ ├── index.css # Main CSS entry point (Tailwind directives)
│ │ ├── queryBuilderUtils.ts # Utilities for query builder (ID gen, type guard)
│ │ └── vite-env.d.ts # TypeScript definitions for Vite env & Electron API
│ └── queryBuilderTypes.ts # Shared types for the query builder structure
├── index.html # HTML entry point for Vite/React UI
├── package.json # Project dependencies and scripts
├── vite.config.ts # Vite configuration
├── tsconfig.json # Root TypeScript configuration
├── tsconfig.app.json # TypeScript config for React app (checked by Vite)
├── tsconfig.node.json # TypeScript config for Vite config file itself
├── tailwind.config.js # Tailwind CSS configuration
├── components.json # shadcn/ui configuration
├── electron-builder.json # electron-builder configuration for packaging
├── README.md # Project overview
├── LICENSE # Project license
└── CONTRIBUTING.md # Contribution guidelines
- Main Process (
src/electron/main.ts): Runs in a Node.js environment. Has access to all Node.js APIs and Electron APIs for managing windows, menus, dialogs, system events, etc. It orchestrates the application lifecycle and performs backend tasks like file searching, exporting results, reading individual file contents on demand, and generating formatted content for copying. - Renderer Process (
src/ui/main.tsx& components): Runs the web page (index.html) inside a Chromium window. This is where the React UI lives. It does not have direct access to Node.js or most Electron APIs for security reasons.
- Startup: The application starts with
npm run devwhich runs both the Vite development server and the Electron application in parallel using a custom Node.js script (scripts/dev.js). - Window Management: The main window is created in
createWindow()inmain.ts. When this window is closed, theclosedevent is triggered, and themainWindowreference is set to null. - Shutdown:
- When all windows are closed, the
window-all-closedevent is triggered. On non-macOS platforms,app.quit()is called. - On Windows specifically, we use
process.exit(0)to ensure all processes terminate properly when the window is closed. - In development mode, we also handle the
before-quitevent to ensure the application fully terminates when quitting. - The
will-quitevent is used for cleanup tasks before the application exits, such as saving profiling data. - The custom development script (
scripts/dev.js) monitors the Electron process and terminates all child processes (including the Vite server) when the Electron application exits, ensuring a clean shutdown without requiring manual intervention (Ctrl+C).
- When all windows are closed, the
- Preload Script (
src/electron/preload.cts): A special script that runs in the renderer's context before the web page loads, but with access to Node.js globals likerequireand Electron'sipcRenderer. - Context Isolation: This is enabled (default and recommended). It ensures the preload script and the renderer's main world JavaScript do not share the same
windowobject, preventing prototype pollution and enhancing security. contextBridge: Used in the preload script to securely expose specific functions from the Node.js/Electron world to the renderer process viawindow.electronAPI. This is the only way the renderer should interact with the main process's capabilities.- Sandbox: Enabled for the renderer process, further restricting its capabilities.
Communication between the Main and Renderer processes happens via IPC messages:
- Renderer -> Main (Invoke/Response): Used for actions where the renderer needs data or confirmation from the main process.
- Renderer calls
window.electronAPI.invokeSomething(args). - Preload script uses
ipcRenderer.invoke('channel', args). - Main process listens with
ipcMain.handle('channel', async (event, args) => { ... return result; }). - Examples:
search-files,export-results,get-initial-language,get-theme-preference, history handlers,copy-to-clipboard,get-file-content,generate-export-content, settings handlers.
- Renderer calls
- Main -> Renderer (Send): Used for updates or events initiated by the main process.
- Main process uses
mainWindow.webContents.send('channel', data). - Preload script sets up a listener using
ipcRenderer.on('channel', listener)and exposes a handler function viacontextBridge(e.g.,onSearchProgress,onThemePreferenceChanged). - Renderer calls
window.electronAPI.onSomething(callback)to register its handler. - Examples:
search-progress,theme-preference-changed.
- Main process uses
- Renderer -> Main (Send): Used for fire-and-forget notifications from the renderer.
- Renderer calls
window.electronAPI.notifySomething(args). - Preload script uses
ipcRenderer.send('channel', args). - Main process listens with
ipcMain.on('channel', (event, args) => { ... }). - Examples:
language-changed,cancel-search.
- Renderer calls
- Security:
main.tsusesvalidateSenderto ensure IPC messages originate from the expected main window frame.
- Development: Vite serves the React UI on a local development server. Electron loads the UI from this server (
mainWindow.loadURL("http://localhost:5123")). Vite provides Hot Module Replacement (HMR) for fast UI updates. - Production:
vite buildbundles the React UI into static files indist-react/. Electron loads the UI directly from the filesystem using a custom protocol (app://) registered inmain.ts(mainWindow.loadURL("app://index.html")). The custom protocol handler serves files fromdist-react/.
The application follows a structured approach to code organization to ensure maintainability, scalability, and readability.
The application uses a comprehensive error handling system with multiple components:
-
AppError Class: Base error class that provides:
- Consistent error types with error codes
- Detailed error information
- Factory methods for common error types
- Proper error propagation
Example usage:
try { // Some operation that might fail } catch (error) { throw AppError.fileNotFound(filePath); }
-
ErrorHandlingService: Centralized service for handling errors:
- Standardized error logging and reporting
- Error severity levels (LOW, MEDIUM, HIGH, CRITICAL)
- Error context tracking (component, operation, data)
- Error listener registration for UI notifications
- Error statistics collection
Example usage:
const errorHandler = getErrorHandler(); errorHandler.handleError(error, { severity: ErrorSeverity.MEDIUM, context: { component: "FileProcessor", operation: "readFile", data: { filePath }, }, showToUser: true, });
-
Error Boundaries: React components that catch JavaScript errors in their child component tree:
- Prevent the entire application from crashing
- Display fallback UI when errors occur
- Log errors to the ErrorHandlingService
- Allow component recovery through reset functionality
Example usage:
<ErrorBoundary component="SearchResults"> <SearchResultsComponent /> </ErrorBoundary>
-
IPC Error Handling: Utilities for handling errors in IPC communication:
- Standardized error responses
- Sender validation
- Error context tracking
- Error wrapping for IPC handlers
Example usage:
ipcMain.handle( "get-file-content", wrapIpcHandler(async (event, filePath) => { // Handler implementation }, "FileContentHandler") );
-
i18n Error Messages: Internationalized error messages for user-facing errors:
- Error message templates in multiple languages
- Error code to message mapping
- Error severity labels
- Component error messages
The error handling system ensures that errors are:
- Properly caught and logged
- Reported to the user when appropriate
- Contextualized with relevant information
- Handled consistently throughout the application
- Recoverable when possible
The application has a set of utility modules that provide common functionality:
common.ts: General utility functionsstring.ts: String manipulation utilitiesfile.ts: File system utilitiessearch.ts: Search-related utilities
These utilities are designed to be reusable across the application and provide consistent behavior.
The application uses a service-oriented architecture with the following key services:
Logger: Provides standardized logging functionalityConfigService: Manages application configurationCacheManager: Manages application cachesOptimizedFileSearchService: Provides file search functionalityFileDiscoveryService: Discovers files based on search criteriaContentMatchingService: Matches content against search termsSearchResultProcessor: Processes search results
Services are implemented as singletons to ensure a single instance is used throughout the application:
export class SomeService {
private static instance: SomeService;
public static getInstance(): SomeService {
if (!SomeService.instance) {
SomeService.instance = new SomeService();
}
return SomeService.instance;
}
private constructor() {
// Initialize the service
}
}The FileSearchService acts as a facade for the more complex OptimizedFileSearchService, providing a simpler interface and maintaining backward compatibility.
The AppError class uses factory methods to create specific error types:
static fileNotFound(path: string): AppError {
return new AppError(`File not found: ${path}`, "FILE_NOT_FOUND", { path });
}- Classes: PascalCase (e.g.,
AppError,Logger) - Interfaces: PascalCase (e.g.,
SearchOptions,LoggerConfig) - Methods and Functions: camelCase (e.g.,
searchFiles,updateSettings) - Variables: camelCase (e.g.,
fileContent,searchResult) - Constants: UPPER_SNAKE_CASE (e.g.,
FILE_OPERATION_CONCURRENCY_LIMIT) - Private Properties: camelCase with underscore prefix (e.g.,
_cache,_config)
All public APIs should be documented with JSDoc comments:
/**
* Updates the search settings
* @param booleanEnabled Whether fuzzy search is enabled for boolean queries
* @param nearEnabled Whether fuzzy search is enabled for NEAR operator
* @param wholeWordEnabled Whether whole word matching is enabled
*/
export function updateSearchSettings(
booleanEnabled: boolean,
nearEnabled: boolean,
wholeWordEnabled: boolean
): void {
// Implementation
}All functions that can fail should use proper error handling:
- Use try/catch blocks to handle errors
- Use the
AppErrorclass for consistent error reporting - Propagate errors with appropriate context
- Log errors with the
Loggerservice
Asynchronous code should use async/await for better readability:
async function processFile(filePath: string): Promise<r> {
try {
const content = await readFile(filePath);
return processContent(content);
} catch (error) {
throw AppError.fileAccessError(filePath, error);
}
}Each module should have a single responsibility:
- Services: Provide business logic
- Utilities: Provide reusable functions
- Components: Provide UI elements
- Workers: Handle CPU-intensive tasks
Services should be designed to accept dependencies through their constructor or methods:
class SearchService {
constructor(
private fileDiscoveryService: FileDiscoveryService,
private contentMatchingService: ContentMatchingService
) {}
// Methods that use the injected services
}Prefer immutable data structures to avoid unexpected side effects:
// Good
const newArray = [...oldArray, newItem];
// Avoid
oldArray.push(newItem);Prefer pure functions that don't have side effects:
// Good
function add(a: number, b: number): number {
return a + b;
}
// Avoid
let sum = 0;
function addToSum(value: number): void {
sum += value;
}- Electron: Framework for building cross-platform desktop apps with web technologies.
- React 19: UI library for building the user interface.
- Vite: Fast build tool and development server for the React UI.
- TypeScript: Provides static typing for improved code quality and maintainability.
- Tailwind CSS: Utility-first CSS framework for styling.
- shadcn/ui: Re-usable UI components built on Radix UI and Tailwind CSS. Components like Accordion, Dialog, Popover, and Select are used throughout the application to create a consistent and accessible UI.
- Lucide React: Icon library used for UI elements, including file type icons in the results display.
- i18next / react-i18next: Framework for internationalization (handling multiple languages). Locales stored in
public/locales. - react-window / react-virtualized-auto-sizer: Libraries for efficiently rendering long lists (search results) by only rendering visible items (virtualization).
- fast-glob: Efficient library for finding files matching glob patterns. Used for initial file discovery.
- picomatch: Performant glob pattern matcher. Used for file/folder exclusion filtering.
- jsep: JavaScript Expression Parser. Used to parse the boolean content query string into an Abstract Syntax Tree (AST).
- p-limit: Limits asynchronous operation concurrency (used to limit simultaneous file reads/stats).
- highlight.js: Library for syntax highlighting. Executed in a Web Worker (
highlight.worker.ts) to avoid blocking the main UI thread. - date-fns: Modern utility library for date parsing, formatting, and manipulation.
- electron-store: Simple data persistence library for Electron apps. Used for storing settings and search history.
- Fuse.js: Lightweight fuzzy-search library. Used for filtering the results list in the UI.
- File Search (
fileSearchService.ts): Contains the main search orchestration logic.- Uses
fast-globwithsuppressErrors: truefor initial discovery. - Error Handling: Initial
fs.statchecks on top-level paths. Traversal errors suppressed byfast-glob. Errors during laterfs.statorfs.readFileare caught and reported per-file. - Error Relevance Filtering: Filters path errors based on
excludeFoldersrules. - Metadata Fetching: Now performs
fs.statfor all files passing exclusion filters to gathersizeandmtimefor sorting, even if size/date filters are not active. - Applies filters (extension, excludes, date, size) sequentially.
- Uses
p-limitto manage concurrency for file stats and reads. - Parses boolean queries using
jsepand evaluates the AST against file content. - Handles proximity search (
NEAR) logic. - Fuzzy Search: Integrated into Boolean queries and NEAR function, with settings to enable/disable each independently.
- Accepts and checks a
checkCancellationfunction. - Sends progress updates via
progressCallback. - Memory Optimization: Does not read/return full content in the main result set.
- Output: Returns
StructuredItem[]containingfilePath,matched,readError,size, andmtime.
- Uses
- Internationalization (i18n):
- UI: Configured in
src/ui/i18n.ts, usesHttpApibackend. The i18n instance is configured ini18n.tsbut only initialized once inmain.tsxto prevent duplicate initialization warnings.useTranslationhook used throughout components. Language preference synced via IPC. - Main: Separate
i18nextinstance inmain.ts, usesi18next-fs-backend.
- UI: Configured in
- UI State Management: Primarily uses standard React hooks. Global state (original results, progress, errors, history, settings, sort state, raw filter term) managed in
App.tsxand passed down. Filtered results are derived withinResultsDisplay.tsx. Content for individual files fetched on demand and managed withinResultsDisplay.tsx. - Theming:
- Initialization: Initial theme fetched via IPC in
src/ui/main.tsxbefore render.applyThemecalled immediately. - Updates:
ThemeHandlercomponent listens for IPC changes and OS changes, callsapplyTheme. - Storage: Preference read/written via IPC to
electron-store. - Styling: Uses Tailwind CSS dark mode variant (
dark:) and CSS variables.
- Initialization: Initial theme fetched via IPC in
- Settings:
- Stored in
electron-storewith schema validation. - Includes language preference, theme, default export format, and fuzzy search settings.
- Managed through IPC handlers in
main.ts. - UI in
SettingsModal.tsxwith checkboxes, radio buttons, and dropdowns. - Fuzzy search settings are passed to
fileSearchService.tsvia theupdateFuzzySearchSettingsfunction.
- Stored in
- Search History:
- IPC handlers in
main.tsmanage CRUD usingelectron-store. - De-duplication:
add-search-history-entryupdates existing entries with identical params. - UI handled by
HistoryModal.tsxandHistoryListItem.tsx. - Loading:
isQueryStructuretype guard used when loading history.
- IPC handlers in
- Exporting Results:
export-resultsIPC handler inmain.tstakesStructuredItem[](without content) and format.- Calls
fetchContentForExportto read content of matched files. - Uses helper functions (
generateTxt,generateCsv, etc.) to format data including fetched content. - Prompts user for save location using
dialog.showSaveDialog. - Writes the generated content to file.
- Batch Operations: Allows users to perform various operations on selected files or all search results.
- Uses a checkbox in each tree item to select/deselect files.
- Selection state is managed using a reducer pattern with a Set of file paths.
- "Select All" and "Deselect All" buttons for bulk operations.
- The "Export Results" dropdown menu provides access to multiple batch operations:
- Export All Results/Export Selected: Exports all search results or only selected files based on selection state.
- Copy All Paths/Copy Selected Paths: Copies the file paths of all search results or only selected files to the clipboard.
- Copy All Files to Folder/Copy Selected Files to Folder: Copies all search results or only selected files to a destination folder.
- Move All Files to Folder/Move Selected Files to Folder: Moves all search results or only selected files to a destination folder.
- When no files are selected, operations apply to all search results.
- The menu item text dynamically changes based on selection state to indicate whether the operation will apply to selected files or all results.
- On-Demand Content Loading:
get-file-contentIPC channel handled inmain.ts.- Renderer (
ResultsDisplay.tsx) callswindow.electronAPI.invokeGetFileContent(filePath)on item expansion. - Main process reads and returns content or error key.
ResultsDisplay.tsxusescontentCacheRef(Map) to store fetched content and manage loading states.
- File System Operations:
open-fileIPC channel handled inmain.tsuses Electron'sshell.openPath()to open files with the default system application.open-file-locationIPC channel handled inmain.tsuses Electron'sshell.showItemInFolder()to open the file's containing folder in the system's file explorer.show-directory-dialogIPC channel handled inmain.tsuses Electron'sdialog.showOpenDialog()to allow users to select directories visually.copy-file-pathsIPC channel handled inmain.tscopies selected file paths to the clipboard.copy-files-to-folderIPC channel handled inmain.tscopies selected files to a destination folder.move-files-to-folderIPC channel handled inmain.tsmoves selected files to a destination folder.- Renderer (
SearchForm.tsx) provides a "Browse..." button next to the Search Paths input that uses the directory selection dialog. - Renderer (
ResultsDisplay.tsx) provides buttons for file operations in each file's header. - Batch operations on selected files are handled through the dropdown menu in the results area.
- All operations include proper error handling and validation, including handling file conflicts when copying or moving files.
- Content Highlighting:
- Plain text files use
HighlightMatchescomponent to highlight search terms. - Syntax-highlighted code (via highlight.js in a Web Worker) uses
highlightTermsInHtmlutility to post-process the HTML and highlight search terms within the syntax-highlighted content. - Search terms are extracted from both the raw content query string and the structured query.
- When loading a search from history, the search terms are extracted and used for highlighting.
- The
highlightHtmlUtils.tsfile contains the logic for highlighting search terms within HTML content.
- Plain text files use
- Copying Results:
- Copy Results: Button triggers
handleCopyResultsinResultsDisplay.tsx.- Calls
generate-export-contentIPC handler. - Handler calls
fetchContentForExportfor matched files. - Generates content string (including content) and returns it.
- Renderer uses
copy-to-clipboardIPC handler. - Warning shown for large result sets.
- Calls
- Export Results Dropdown: Combines the functionality of the previous "Save Results As..." button and "Batch Operations" dropdown.
- Uses a single dropdown menu for all export and batch operations.
- The button text shows "Export Results" instead of "Save Results As...".
- Menu items dynamically change based on selection state.
- When no files are selected, operations apply to all search results.
- Copy Individual File Content: Icon triggers
handleCopyFileContentinResultsDisplay.tsx.- Uses content already loaded in
contentCache. - Calls
copy-to-clipboardIPC handler.
- Uses content already loaded in
- Copy Results: Button triggers
- Results Sorting:
- Implemented in
ResultsDisplay.tsx. - State variables
sortKeyandsortDirectionmanage the current sort order. - UI controls (Select dropdowns) allow user selection.
useMemohook calculatessortedItemsbased on the currentfilteredItems(which are derived fromstructuredItemsand the fuzzy filter) and sort state.- The sorting function handles comparisons for
filePath(string),size(number),mtime(number), andmatched(boolean), including handlingundefinedmetadata values. VariableSizeListis updated to usesortedItems.resetAfterIndexis called when sort state or filtered items change to ensure the list re-renders correctly.
- Implemented in
- Results Filtering (Fuzzy):
- Implemented in
ResultsDisplay.tsx. - Uses
Fuse.jslibrary for fuzzy matching. - A
Fuseinstance is created within auseMemohook whenever the sourcestructuredItemsorfilterCaseSensitiveprop changes. The instance is configured to search thefilePathandreadErrorkeys. - The debounced
filterTermprop (originating fromApp.tsx) is used withfuse.search(). - The
filteredItemsmemoized value holds the results of the fuzzy search. - The
Case-Sensitivecheckbox inApp.tsxcontrols thefilterCaseSensitiveprop passed toResultsDisplay. - The
VariableSizeListrenders thefilteredItems(after sorting).
- Implemented in
- Build UI & Transpile Electron Code:
This runs
npm run build
vite build(output todist-react/) andtscfor the main/preload processes (output todist-electron/). - Package Application: Use the
dist:*scripts or the maindistscript:npm run dist # Build for current OS and default arch npm run dist:win # Build for Windows x64 npm run dist:mac # Build for macOS arm64 npm run dist:linux # Build for Linux x64
electron-builderreads configuration fromelectron-builder.jsonand creates installers/packages in therelease/directory.
Security is paramount in Electron applications. Key measures taken:
- Context Isolation: Enabled (
contextIsolation: true). - Sandbox: Enabled (
sandbox: true). - Preload Script (
contextBridge): Only necessary functions exposed viawindow.electronAPI. - Content Security Policy (CSP): Strict CSP applied via
session.defaultSession.webRequest.onHeadersReceivedwith different policies for development and production environments. The production policy eliminates unsafe directives likeunsafe-evaland restricts resource loading to trusted sources. - IPC Sender Validation: All
ipcMain.handleandipcMain.onlisteners usevalidateSender. - No Node Integration in Renderer:
nodeIntegration: false. - External Links: Use
shell.openExternal(if needed). - Input Validation: Basic validation exists; further sanitization could be added if necessary.
Refer to the official Electron Security Documentation for more details.
- TypeScript: Used throughout.
- ESLint: Configured for code quality. Run
npm run lint. - Prettier: Used for automatic code formatting.
- TSDoc: Used for documenting functions, classes, and interfaces.
The application uses Jest for testing. Tests are organized in a dedicated tests/ directory that mirrors the source code structure.
# Run all tests
npm test
# Run only unit tests
npm run test:unit
# Run only integration tests
npm run test:integration
# Run tests with coverage reporting
npm run test:coverage- Unit Tests: Test individual functions and components in isolation.
- Boundary Tests: Test edge cases and boundary conditions.
- Performance Tests: Test performance with large inputs or many operations.
- Integration Tests: Test how multiple components work together.
Unit tests should focus on testing a single unit of code in isolation:
describe("AppError", () => {
it("should create a file not found error", () => {
const error = AppError.fileNotFound("/path/to/file");
expect(error.code).toBe("FILE_NOT_FOUND");
expect(error.message).toBe("File not found: /path/to/file");
});
});Integration tests should focus on testing the interaction between multiple units:
describe("FileSearchService", () => {
it("should search files and return results", async () => {
const service = OptimizedFileSearchService.getInstance();
const results = await service.searchFiles(
params,
progressCallback,
checkCancellation
);
expect(results.filesFound).toBeGreaterThan(0);
});
});Use mocks to isolate the code being tested:
jest.mock("./services/FileDiscoveryService");
const mockDiscoveryService = FileDiscoveryService as jest.MockedClass<
typeof FileDiscoveryService
>;
mockDiscoveryService.getInstance.mockReturnValue({
discoverFiles: jest.fn().mockResolvedValue({
files: [{ filePath: "/path/to/file", stats: null }],
errors: [],
wasCancelled: false,
}),
});For detailed information about testing, see the Testing Guide.
Contributions are welcome! Please see CONTRIBUTING.md for detailed guidelines.