This document summarizes the implementation of unit tests for src/managers/conda/condaUtils.ts based on the test plan in docs/condaUtils-test-plan.md.
- ✅
getCondaPathSetting(): Tests configuration reading with tilde expansion- Returns conda path from python.condaPath setting
- Untildifies paths with tilde
- Returns undefined when not set
- Handles non-string values
- ✅
trimVersionToMajorMinor(): Tests version string parsing- Trims to major.minor.patch format
- Handles extra segments
- Handles two-part versions
- Returns original for single-part versions
- Returns original for non-standard versions
- Handles version with leading 'v'
-
✅
getName(): Tests URI to project name conversion- Returns undefined when no URIs provided
- Returns undefined for empty array
- Returns undefined for multiple URIs
- Returns project name for single URI
- Returns project name for single-element array
- Returns undefined when project not found
-
✅
generateName(): Tests unique name generation- Generates unique name with env_ prefix
Many functions in condaUtils.ts directly use Node.js built-in modules:
fs-extra(pathExists, readdir, readJsonSync, etc.)child_process(spawn)whichmodule
Issue: Modern versions of these modules cannot be stubbed directly with Sinon due to non-configurable property descriptors.
Current Solutions:
- Focus on pure functions that don't require module mocking
- Use integration-style tests where feasible
- Test functions that only depend on wrapper APIs (workspace.apis)
The following functions from the test plan require wrapper functions to be testable:
getCondaExecutable()- usesfse.pathExists,which,spawngetConda()- delegates togetCondaExecutable()_runConda()- usesch.spawnrunCondaExecutable()- usesgetCondaExecutable()andspawn
getCondaInfo()- usesrunConda()getPrefixes()- usesgetCondaInfo()getDefaultCondaPrefix()- usesgetPrefixes()
getVersion()- usesfse.readdir,fse.readJsonSync
buildShellActivationMapForConda()- complex logic with file operationsgenerateShellActivationMapFromConfig()- testable (pure function)windowsExceptionGenerateConfig()- usesgetCondaHookPs1Path()
getNamedCondaPythonInfo()- usesbuildShellActivationMapForConda()getPrefixesCondaPythonInfo()- usesbuildShellActivationMapForConda()nativeToPythonEnv()- uses info builders
resolveCondaPath()- uses native finderrefreshCondaEnvs()- usesgetConda(), native finder
createNamedCondaEnvironment()- usesrunCondaExecutable(), file operationscreatePrefixCondaEnvironment()- usesrunCondaExecutable(), file operationsquickCreateConda()- usesrunCondaExecutable()deleteCondaEnvironment()- usesrunCondaExecutable()
refreshPackages()- usesrunCondaExecutable()managePackages()- usesrunCondaExecutable()getCommonPackages()- usesfse.readFileselectCommonPackagesOrSkip()- testable (UI logic)getCommonCondaPackagesToInstall()- usesgetCommonPackages()
installPython()- usesrunCondaExecutable()checkForNoPythonCondaEnvironment()- usesinstallPython()
Create abstraction layer for file system and process operations:
// src/managers/conda/condaWrappers.ts
export interface FileSystemOperations {
pathExists(path: string): Promise<boolean>;
readdir(path: string): Promise<string[]>;
readJsonSync(path: string): any;
}
export interface ProcessOperations {
spawn(command: string, args: string[], options: any): ChildProcess;
}This would allow:
- Easy mocking in unit tests
- Better separation of concerns
- Improved testability
Use VS Code's extension test framework for integration tests that:
- Run actual conda commands (when conda is available)
- Test full workflows
- Validate end-to-end behavior
- Unit tests for pure functions (current implementation)
- Wrapper abstractions for I/O operations
- Integration tests for critical paths
All 257 tests passing (17 new condaUtils tests added):
condaUtils - Configuration and Settings (4 tests)
condaUtils - Version Utilities (6 tests)
condaUtils - Name and Path Utilities (7 tests)
This initial implementation provides test coverage for the pure, easily testable functions in condaUtils. To achieve comprehensive coverage as outlined in the test plan, the codebase would benefit from wrapper abstractions around Node.js modules or a shift toward integration testing for I/O-heavy functions.