The Big Picture
We've been refactoring the codebase to be more testable and maintainable using functional decomposition - extracting pure functions from monolithic classes so we can test real behavior with simple input/output assertions.
Status: ✅ Complete
All services have been refactored or deleted:
| Service |
Status |
Notes |
TddService |
✅ |
Refactored to src/tdd/ (PR #125) |
ApiService |
✅ |
Refactored to src/api/ (PR #127) |
build-manager.js |
✅ |
Kept pure functions, deleted class (PR #134) |
auth-service.js |
✅ |
Refactored to src/auth/ (PR #129) |
config-service.js |
✅ |
Deleted - was thin wrapper (PR #134) |
project-service.js |
✅ |
Deleted - was thin wrapper (PR #134) |
api-service.js |
✅ |
Deleted - was thin wrapper (PR #134) |
server-manager.js |
✅ |
Refactored to src/server-manager/ (PR #133, #134) |
test-runner.js |
✅ |
Refactored to src/test-runner/ (PR #133) |
screenshot-server.js |
✅ |
Refactored to src/screenshot-server/ (PR #133) |
uploader.js |
✅ |
Refactored to functional with DI (PR #133) |
html-report-generator.js |
✅ |
Refactored to src/report-generator/ (PR #134) |
static-report-generator.js |
✅ |
Uses report-generator module (PR #134) |
Key PRs
The Pattern We Used
For each service:
- Create a new module (e.g.,
src/auth/ or src/server-manager/)
- Extract pure functions into
core.js - these need zero mocks to test
- Create operations with dependency injection in
operations.js
- Write tests with dependency injection - pass stubs as params, not
vi.mock
- Delete thin class wrappers that only forwarded calls
- Delete mock-heavy tests - replaced with proper unit tests
Results
- ✅ No
vi.mock in new tests
- ✅ Pure functions tested with input/output assertions
- ✅ Dependency injection for anything with I/O
- ✅ Net reduction in test code (less mocking boilerplate)
- ✅ Commands use functional modules directly
- ✅
createServices() simplified to only what plugins need
What's Left in src/services/
Only services that provide plugin API or need EventEmitter:
ServerManager class - plugins use EventEmitter interface
TestRunner class - plugins use EventEmitter interface
- Pure functions in
build-manager.js, uploader.js
These are documented as the public plugin API.
The Big Picture
We've been refactoring the codebase to be more testable and maintainable using functional decomposition - extracting pure functions from monolithic classes so we can test real behavior with simple input/output assertions.
Status: ✅ Complete
All services have been refactored or deleted:
TddServicesrc/tdd/(PR #125)ApiServicesrc/api/(PR #127)build-manager.jsauth-service.jssrc/auth/(PR #129)config-service.jsproject-service.jsapi-service.jsserver-manager.jssrc/server-manager/(PR #133, #134)test-runner.jssrc/test-runner/(PR #133)screenshot-server.jssrc/screenshot-server/(PR #133)uploader.jshtml-report-generator.jssrc/report-generator/(PR #134)static-report-generator.jsKey PRs
The Pattern We Used
For each service:
src/auth/orsrc/server-manager/)core.js- these need zero mocks to testoperations.jsvi.mockResults
vi.mockin new testscreateServices()simplified to only what plugins needWhat's Left in
src/services/Only services that provide plugin API or need EventEmitter:
ServerManagerclass - plugins use EventEmitter interfaceTestRunnerclass - plugins use EventEmitter interfacebuild-manager.js,uploader.jsThese are documented as the public plugin API.