✨ Add auto-mode detection and build lifecycle to Storybook plugin#45
✨ Add auto-mode detection and build lifecycle to Storybook plugin#45
Conversation
Code Review: Auto-Mode Detection & Build LifecycleExcellent work on this PR! The auto-mode detection is a significant UX improvement. Here's my detailed feedback: ✅ Strengths1. Architecture & Design
2. Error Handling
3. Test Coverage
4. Developer Experience
🔍 Issues & Concerns1. Critical: Test Code Duplication (src/index.js:72-91)The Issue: Recommendation: // In tests/concurrency.spec.js
import { mapWithConcurrency } from '../src/index.js'; // Import instead of redefineWhy it matters: If the implementation changes, tests won't catch regressions unless they're testing the actual production code. 2. Performance: Fetch Without Timeout (src/index.js:144-146)The health check fetch call has no timeout, which could hang indefinitely. Current code: let response = await fetch(`http://localhost:${serverInfo.port}/health`);
return response.ok;Recommendation: let controller = new AbortController();
let timeoutId = setTimeout(() => controller.abort(), 2000); // 2s timeout
try {
let response = await fetch(
`http://localhost:${serverInfo.port}/health`,
{ signal: controller.signal }
);
return response.ok;
} catch {
return false;
} finally {
clearTimeout(timeoutId);
}3. Resource Leak: Logger Mutation (src/plugin.js:21-22)Logger level is set to 'info' but never restored to original level. Current code: let originalLevel = logger.level; // Stored but never used
logger.level = 'info';Impact: This could affect subsequent commands in the same process. Recommendation: register(program, { config, logger, services }) {
let originalLevel = logger.level;
program
.command('storybook <path>')
// ... options ...
.action(async (path, options) => {
logger.level = 'info'; // Set before execution
try {
// ... existing code ...
} finally {
logger.level = originalLevel; // Restore in finally block
}
});
}4. Code Smell: Complex Git Detection Logic (src/index.js:222-241)The git utils import logic is overly complex with multiple fallback paths. Concerns:
Recommendation: async function loadGitUtils() {
// Try package first
try {
return await import('@vizzly-testing/cli/dist/utils/git.js');
} catch {}
// Try monorepo relative path
try {
return await import('../../../src/utils/git.js');
} catch {}
return null;
}5. Security: Environment Variable Mutation (src/index.js:284-286)The code mutates Current code: process.env.VIZZLY_SERVER_URL = `http://localhost:${runOptions.port}`;
process.env.VIZZLY_BUILD_ID = buildId;
process.env.VIZZLY_ENABLED = 'true';Concerns:
Recommendation: let envBackup = {
url: process.env.VIZZLY_SERVER_URL,
buildId: process.env.VIZZLY_BUILD_ID,
enabled: process.env.VIZZLY_ENABLED,
};
try {
process.env.VIZZLY_SERVER_URL = `http://localhost:${runOptions.port}`;
// ...
} finally {
// Restore original values
if (envBackup.url !== undefined) process.env.VIZZLY_SERVER_URL = envBackup.url;
else delete process.env.VIZZLY_SERVER_URL;
// ... restore others
}6. Race Condition: Build URL Event (src/index.js:215-220)The Current code: testRunner.once('build-created', buildInfo => {
// ...
});
buildId = await testRunner.createBuild(runOptions, false);Why it's a problem: If Recommendation: // Option 1: Register before calling
testRunner.once('build-created', buildInfo => { /* ... */ });
buildId = await testRunner.createBuild(runOptions, false);
// Option 2: Handle in response
let buildResult = await testRunner.createBuild(runOptions, false);
if (buildResult.url) {
buildUrl = buildResult.url;
logger.info(`🔗 ${buildUrl}`);
}💡 Minor Suggestions
🧪 Test Coverage Gaps
Recommended additions: describe('mode detection', () => {
it('should detect TDD mode when server.json exists', async () => { /* ... */ });
it('should detect Run mode when token is present', async () => { /* ... */ });
it('should warn when neither mode is available', async () => { /* ... */ });
});📊 Overall AssessmentRating: ⭐⭐⭐⭐ (4/5) This is a solid PR that significantly improves the developer experience. The architecture is sound and the feature implementation is mostly clean. However, there are some issues that should be addressed: Must Fix:
Should Fix:
Nice to Have:
🚀 Next Steps
Great work overall! The auto-mode detection will make the Storybook plugin much more intuitive to use. 🎉 |
- Add automatic TDD/Run mode detection - Support direct `vizzly storybook` without wrapper command - Display mode indicator (TDD vs Cloud) and build URLs - Clean up log output for better DX - Add test coverage for concurrency control and hooks - Fix logger level override in plugin registration The plugin now automatically detects whether to use TDD server or cloud mode, eliminating the need to wrap commands with `vizzly run`. When VIZZLY_TOKEN is set, it creates builds, manages screenshot server lifecycle, and displays results URLs.
0f6584f to
5c268c9
Compare
## Summary - Add automatic TDD/Run mode detection to Storybook plugin - Enable direct `vizzly storybook` usage without `vizzly run` wrapper - Display mode indicators (📍 TDD / ☁️ Cloud) and build URLs - Clean up log output for better developer experience - Add comprehensive test coverage for concurrency control and hooks - Fix logger level override in plugin registration ## Changes ### Auto-Mode Detection The plugin now automatically detects whether to use TDD server or cloud mode: 1. **TDD mode** - If `.vizzly/server.json` exists and server responds to health check 2. **Run mode** - If `VIZZLY_TOKEN` environment variable is set 3. **Warning** - If neither is available ### Build Lifecycle Management When in Run mode, the plugin now: - Creates builds via test runner service - Starts screenshot server automatically - Listens for `build-created` event to display build URL - Finalizes builds with execution time and success/failure status - Properly cleans up server on completion or error ### Improved Logging - Override logger level from 'warn' to 'info' for progress visibility - Display mode indicator at start (📍 TDD / ☁️ Cloud) - Show build URL at start and end of process - Clean, minimal output with emojis for visual clarity - Remove verbose status messages ### Test Coverage Added 15 new tests across 2 test files: - `tests/concurrency.spec.js` - Concurrency control logic (4 tests) - `tests/hooks.spec.js` - Interaction hooks system (11 tests) Total: **67 tests passing** ## Test Plan - [x] Run `vizzly storybook` with TDD server running - shows TDD mode - [x] Run `VIZZLY_TOKEN=xxx vizzly storybook` - shows Run mode with build URL - [x] Run without TDD server or token - shows warning - [x] All 67 tests pass - [x] Build lifecycle completes successfully in Run mode - [x] Logger outputs progress messages correctly
Summary
vizzly storybookusage withoutvizzly runwrapperChanges
Auto-Mode Detection
The plugin now automatically detects whether to use TDD server or cloud mode:
.vizzly/server.jsonexists and server responds to health checkVIZZLY_TOKENenvironment variable is setBuild Lifecycle Management
When in Run mode, the plugin now:
build-createdevent to display build URLImproved Logging
Test Coverage
Added 15 new tests across 2 test files:
tests/concurrency.spec.js- Concurrency control logic (4 tests)tests/hooks.spec.js- Interaction hooks system (11 tests)Total: 67 tests passing
Test Plan
vizzly storybookwith TDD server running - shows TDD modeVIZZLY_TOKEN=xxx vizzly storybook- shows Run mode with build URL