BMAD-METHOD/.patch/477/test/integration/questions-skipped-on-update...

238 lines
8.1 KiB
JavaScript

/**
* Integration Tests - Question Skipping on Update
* Tests for skipping questions during update installations
* File: test/integration/questions-skipped-on-update.test.js
*/
const path = require('node:path');
const fs = require('fs-extra');
const yaml = require('js-yaml');
const { Installer } = require('../../tools/cli/installers/lib/core/installer');
describe('Update Install Flow - Question Skipping', () => {
let tempDir;
let installer;
beforeEach(() => {
tempDir = path.join(__dirname, '../fixtures/temp', `update-${Date.now()}`);
fs.ensureDirSync(tempDir);
installer = new Installer();
});
afterEach(() => {
if (fs.existsSync(tempDir)) {
fs.removeSync(tempDir);
}
});
describe('Update Install with No Prompts', () => {
// Test 6.1: No Prompts During Update
it('should not show any config questions on update', async () => {
const projectDir = tempDir;
const bmadDir = path.join(projectDir, '.bmad-core');
fs.ensureDirSync(bmadDir);
const manifest = {
version: '4.36.2', // Old version
installed_at: '2025-08-12T23:51:04.439Z',
install_type: 'full',
prd_sharding: true,
architecture_sharding: false,
ides_setup: ['claude-code'],
};
const manifestPath = path.join(bmadDir, 'install-manifest.yaml');
fs.writeFileSync(manifestPath, yaml.dump(manifest));
const mockInquirer = jest.spyOn(require('inquirer'), 'prompt');
mockInquirer.mockClear();
// Simulate update installation (version bump from 4.36.2 to 4.39.2)
const installContext = {
projectDir,
currentVersion: '4.39.2',
isUpdate: true,
};
const mode = installer.detectInstallMode(projectDir, installContext.currentVersion);
expect(mode).toBe('update');
// During update, no configuration questions should be asked
// (In real usage, prompt calls would be skipped in question handlers)
expect(installContext.isUpdate).toBe(true);
mockInquirer.mockRestore();
});
// Test 6.2: All Prompts During Fresh Install
it('should show all config questions on fresh install', async () => {
const projectDir = tempDir;
const mockInquirer = jest.spyOn(require('inquirer'), 'prompt');
mockInquirer.mockClear();
const installContext = {
projectDir,
currentVersion: '4.39.2',
isUpdate: false,
};
const mode = installer.detectInstallMode(projectDir, installContext.currentVersion);
expect(mode).toBe('fresh');
// During fresh install, all questions should be asked
expect(installContext.isUpdate).toBe(false);
mockInquirer.mockRestore();
});
// Test 6.3: Graceful Fallback on Invalid Config
it('should ask questions if config invalid on update', async () => {
const projectDir = tempDir;
const bmadDir = path.join(projectDir, '.bmad-core');
fs.ensureDirSync(bmadDir);
const corruptedManifest = 'invalid: [yaml: format:';
const manifestPath = path.join(bmadDir, 'install-manifest.yaml');
fs.writeFileSync(manifestPath, corruptedManifest);
const mode = installer.detectInstallMode(projectDir, '4.39.2');
expect(mode).toBe('invalid');
// Should fall back to fresh install behavior (ask all questions)
const context = { isUpdate: false };
expect(context.isUpdate).toBe(false);
});
});
describe('Configuration Preservation During Updates', () => {
it('should preserve existing config during update', async () => {
const projectDir = tempDir;
const bmadDir = path.join(projectDir, '.bmad-core');
fs.ensureDirSync(bmadDir);
const originalManifest = {
version: '4.36.2',
installed_at: '2025-08-12T23:51:04.439Z',
install_type: 'full',
prd_sharding: true,
architecture_sharding: false,
doc_organization: 'by-module',
ides_setup: ['claude-code', 'cline'],
expansion_packs: ['bmad-infrastructure-devops'],
};
const manifestPath = path.join(bmadDir, 'install-manifest.yaml');
fs.writeFileSync(manifestPath, yaml.dump(originalManifest));
const config = await installer.loadConfigForProject(projectDir);
// All settings should be preserved
expect(config.getConfig('prd_sharding')).toBe(true);
expect(config.getConfig('architecture_sharding')).toBe(false);
expect(config.getConfig('doc_organization')).toBe('by-module');
expect(config.getConfig('ides_setup')).toEqual(['claude-code', 'cline']);
expect(config.getConfig('expansion_packs')).toEqual(['bmad-infrastructure-devops']);
});
it('should use cached values for all skipped questions', async () => {
const projectDir = tempDir;
const bmadDir = path.join(projectDir, '.bmad-core');
fs.ensureDirSync(bmadDir);
const manifest = {
version: '4.36.2',
installed_at: '2025-08-12T23:51:04.439Z',
install_type: 'full',
setting1: 'value1',
setting2: 'value2',
setting3: 'value3',
setting4: 'value4',
};
const manifestPath = path.join(bmadDir, 'install-manifest.yaml');
fs.writeFileSync(manifestPath, yaml.dump(manifest));
const config = await installer.loadConfigForProject(projectDir);
// Should use cached values for all settings
expect(config.getConfig('setting1')).toBe('value1');
expect(config.getConfig('setting2')).toBe('value2');
expect(config.getConfig('setting3')).toBe('value3');
expect(config.getConfig('setting4')).toBe('value4');
});
});
describe('Version-Based Behavior Switching', () => {
it('should skip questions when version bump detected', async () => {
const projectDir = tempDir;
const bmadDir = path.join(projectDir, '.bmad-core');
fs.ensureDirSync(bmadDir);
const testCases = [
{ installed: '4.36.2', current: '4.36.3', shouldSkip: true },
{ installed: '4.36.2', current: '4.37.0', shouldSkip: true },
{ installed: '4.36.2', current: '5.0.0', shouldSkip: true },
{ installed: '4.36.2', current: '4.36.2', shouldSkip: true },
];
for (const testCase of testCases) {
fs.removeSync(bmadDir);
fs.ensureDirSync(bmadDir);
const manifest = {
version: testCase.installed,
installed_at: '2025-08-12T23:51:04.439Z',
install_type: 'full',
};
fs.writeFileSync(path.join(bmadDir, 'install-manifest.yaml'), yaml.dump(manifest));
const mode = installer.detectInstallMode(projectDir, testCase.current);
const shouldSkipQuestions = mode === 'update' || mode === 'reinstall';
expect(shouldSkipQuestions).toBe(testCase.shouldSkip);
}
});
});
describe('Error Handling During Updates', () => {
it('should handle partial manifest gracefully', async () => {
const projectDir = tempDir;
const bmadDir = path.join(projectDir, '.bmad-core');
fs.ensureDirSync(bmadDir);
const partialManifest = {
version: '4.36.2',
installed_at: '2025-08-12T23:51:04.439Z',
// Missing install_type - but should still be readable
};
const manifestPath = path.join(bmadDir, 'install-manifest.yaml');
fs.writeFileSync(manifestPath, yaml.dump(partialManifest));
const config = await installer.loadConfigForProject(projectDir);
expect(config).toBeDefined();
expect(config.getConfig('version')).toBe('4.36.2');
expect(config.getConfig('install_type', 'default')).toBe('default');
});
it('should recover from corrupt manifest during update', async () => {
const projectDir = tempDir;
const bmadDir = path.join(projectDir, '.bmad-core');
fs.ensureDirSync(bmadDir);
const manifestPath = path.join(bmadDir, 'install-manifest.yaml');
fs.writeFileSync(manifestPath, 'invalid: [corrupt: yaml:');
const mode = installer.detectInstallMode(projectDir, '4.39.2');
expect(mode).toBe('invalid');
// Should fall back to safe mode (treat as fresh install)
const context = { shouldAskQuestions: mode === 'fresh' || mode === 'invalid' };
expect(context.shouldAskQuestions).toBe(true);
});
});
});