chore: run format
This commit is contained in:
@@ -18,7 +18,10 @@ export const testConfig = {
|
|||||||
logDir: join(projectRoot, 'tests/e2e/log'),
|
logDir: join(projectRoot, 'tests/e2e/log'),
|
||||||
samplePrdSource: join(projectRoot, 'tests/fixtures/sample-prd.txt'),
|
samplePrdSource: join(projectRoot, 'tests/fixtures/sample-prd.txt'),
|
||||||
mainEnvFile: join(projectRoot, '.env'),
|
mainEnvFile: join(projectRoot, '.env'),
|
||||||
supportedModelsFile: join(projectRoot, 'scripts/modules/supported-models.json')
|
supportedModelsFile: join(
|
||||||
|
projectRoot,
|
||||||
|
'scripts/modules/supported-models.json'
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
// Test settings
|
// Test settings
|
||||||
@@ -41,10 +44,14 @@ export const testConfig = {
|
|||||||
|
|
||||||
// Test prompts
|
// Test prompts
|
||||||
prompts: {
|
prompts: {
|
||||||
addTask: 'Create a task to implement user authentication using OAuth 2.0 with Google as the provider. Include steps for registering the app, handling the callback, and storing user sessions.',
|
addTask:
|
||||||
updateTask: 'Update backend server setup: Ensure CORS is configured to allow requests from the frontend origin.',
|
'Create a task to implement user authentication using OAuth 2.0 with Google as the provider. Include steps for registering the app, handling the callback, and storing user sessions.',
|
||||||
updateFromTask: 'Refactor the backend storage module to use a simple JSON file (storage.json) instead of an in-memory object for persistence. Update relevant tasks.',
|
updateTask:
|
||||||
updateSubtask: 'Implementation note: Remember to handle potential API errors and display a user-friendly message.'
|
'Update backend server setup: Ensure CORS is configured to allow requests from the frontend origin.',
|
||||||
|
updateFromTask:
|
||||||
|
'Refactor the backend storage module to use a simple JSON file (storage.json) instead of an in-memory object for persistence. Update relevant tasks.',
|
||||||
|
updateSubtask:
|
||||||
|
'Implementation note: Remember to handle potential API errors and display a user-friendly message.'
|
||||||
},
|
},
|
||||||
|
|
||||||
// LLM Analysis settings
|
// LLM Analysis settings
|
||||||
|
|||||||
@@ -237,7 +237,8 @@ async function runTests(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if we need to run setup (either explicitly requested or needed for other tests)
|
// Check if we need to run setup (either explicitly requested or needed for other tests)
|
||||||
const needsSetup = testsToRun.setup || (!testDir && Object.keys(testsToRun).length > 0);
|
const needsSetup =
|
||||||
|
testsToRun.setup || (!testDir && Object.keys(testsToRun).length > 0);
|
||||||
|
|
||||||
if (needsSetup) {
|
if (needsSetup) {
|
||||||
// Always run setup if we need a test directory
|
// Always run setup if we need a test directory
|
||||||
|
|||||||
@@ -24,10 +24,16 @@ export class ParallelTestRunner extends EventEmitter {
|
|||||||
const groupNames = Object.keys(testGroups);
|
const groupNames = Object.keys(testGroups);
|
||||||
const workerPromises = [];
|
const workerPromises = [];
|
||||||
|
|
||||||
this.logger.info(`Starting parallel execution of ${groupNames.length} test groups`);
|
this.logger.info(
|
||||||
|
`Starting parallel execution of ${groupNames.length} test groups`
|
||||||
|
);
|
||||||
|
|
||||||
for (const groupName of groupNames) {
|
for (const groupName of groupNames) {
|
||||||
const workerPromise = this.runTestGroup(groupName, testGroups[groupName], sharedContext);
|
const workerPromise = this.runTestGroup(
|
||||||
|
groupName,
|
||||||
|
testGroups[groupName],
|
||||||
|
sharedContext
|
||||||
|
);
|
||||||
workerPromises.push(workerPromise);
|
workerPromises.push(workerPromise);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,21 +120,24 @@ export class ParallelTestRunner extends EventEmitter {
|
|||||||
|
|
||||||
// Handle worker completion
|
// Handle worker completion
|
||||||
worker.on('exit', (code) => {
|
worker.on('exit', (code) => {
|
||||||
this.workers = this.workers.filter(w => w !== worker);
|
this.workers = this.workers.filter((w) => w !== worker);
|
||||||
|
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
resolve(this.results[groupName] || { status: 'passed', group: groupName });
|
resolve(
|
||||||
|
this.results[groupName] || { status: 'passed', group: groupName }
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
reject(new Error(`Worker for group ${groupName} exited with code ${code}`));
|
reject(
|
||||||
|
new Error(`Worker for group ${groupName} exited with code ${code}`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle worker errors
|
// Handle worker errors
|
||||||
worker.on('error', (error) => {
|
worker.on('error', (error) => {
|
||||||
this.workers = this.workers.filter(w => w !== worker);
|
this.workers = this.workers.filter((w) => w !== worker);
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +145,10 @@ export class ParallelTestRunner extends EventEmitter {
|
|||||||
* Terminate all running workers
|
* Terminate all running workers
|
||||||
*/
|
*/
|
||||||
async terminate() {
|
async terminate() {
|
||||||
const terminationPromises = this.workers.map(worker =>
|
const terminationPromises = this.workers.map((worker) =>
|
||||||
worker.terminate().catch(err =>
|
worker
|
||||||
|
.terminate()
|
||||||
|
.catch((err) =>
|
||||||
this.logger.warning(`Failed to terminate worker: ${err.message}`)
|
this.logger.warning(`Failed to terminate worker: ${err.message}`)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -176,7 +187,11 @@ export class SequentialTestRunner {
|
|||||||
this.logger.step(`Running ${testModule} tests`);
|
this.logger.step(`Running ${testModule} tests`);
|
||||||
|
|
||||||
// Dynamic import of test module
|
// Dynamic import of test module
|
||||||
const testPath = join(dirname(__dirname), 'tests', `${testModule}.test.js`);
|
const testPath = join(
|
||||||
|
dirname(__dirname),
|
||||||
|
'tests',
|
||||||
|
`${testModule}.test.js`
|
||||||
|
);
|
||||||
const { default: testFn } = await import(testPath);
|
const { default: testFn } = await import(testPath);
|
||||||
|
|
||||||
// Run the test
|
// Run the test
|
||||||
@@ -190,7 +205,6 @@ export class SequentialTestRunner {
|
|||||||
results.summary.failedTests++;
|
results.summary.failedTests++;
|
||||||
results.overall = 'failed';
|
results.overall = 'failed';
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`Failed to run ${testModule}: ${error.message}`);
|
this.logger.error(`Failed to run ${testModule}: ${error.message}`);
|
||||||
results.tests[testModule] = {
|
results.tests[testModule] = {
|
||||||
|
|||||||
@@ -46,7 +46,8 @@ class WorkerLogger extends TestLogger {
|
|||||||
|
|
||||||
// Main worker execution
|
// Main worker execution
|
||||||
async function runTestGroup() {
|
async function runTestGroup() {
|
||||||
const { groupName, testModules, sharedContext, logDir, testRunId } = workerData;
|
const { groupName, testModules, sharedContext, logDir, testRunId } =
|
||||||
|
workerData;
|
||||||
|
|
||||||
const logger = new WorkerLogger(logDir, testRunId, groupName);
|
const logger = new WorkerLogger(logDir, testRunId, groupName);
|
||||||
const helpers = new TestHelpers(logger);
|
const helpers = new TestHelpers(logger);
|
||||||
@@ -68,7 +69,11 @@ async function runTestGroup() {
|
|||||||
logger.info(`Running test: ${testModule}`);
|
logger.info(`Running test: ${testModule}`);
|
||||||
|
|
||||||
// Dynamic import of test module
|
// Dynamic import of test module
|
||||||
const testPath = join(dirname(__dirname), 'tests', `${testModule}.test.js`);
|
const testPath = join(
|
||||||
|
dirname(__dirname),
|
||||||
|
'tests',
|
||||||
|
`${testModule}.test.js`
|
||||||
|
);
|
||||||
const { default: testFn } = await import(testPath);
|
const { default: testFn } = await import(testPath);
|
||||||
|
|
||||||
// Run the test with shared context
|
// Run the test with shared context
|
||||||
@@ -82,7 +87,6 @@ async function runTestGroup() {
|
|||||||
results.errors.push(...testResults.errors);
|
results.errors.push(...testResults.errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Test ${testModule} failed: ${error.message}`);
|
logger.error(`Test ${testModule} failed: ${error.message}`);
|
||||||
results.tests[testModule] = {
|
results.tests[testModule] = {
|
||||||
@@ -97,7 +101,6 @@ async function runTestGroup() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Worker error: ${error.message}`);
|
logger.error(`Worker error: ${error.message}`);
|
||||||
results.status = 'failed';
|
results.status = 'failed';
|
||||||
@@ -126,7 +129,7 @@ async function runTestGroup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run the test group
|
// Run the test group
|
||||||
runTestGroup().catch(error => {
|
runTestGroup().catch((error) => {
|
||||||
console.error('Worker fatal error:', error);
|
console.error('Worker fatal error:', error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
@@ -8,14 +8,22 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
logger.info('Testing tag context management...');
|
logger.info('Testing tag context management...');
|
||||||
|
|
||||||
// Create new tag contexts
|
// Create new tag contexts
|
||||||
const tag1Result = await helpers.taskMaster('add-tag', ['feature-auth', '--description', 'Authentication feature'], { cwd: testDir });
|
const tag1Result = await helpers.taskMaster(
|
||||||
|
'add-tag',
|
||||||
|
['feature-auth', '--description', 'Authentication feature'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Create tag context - feature-auth',
|
test: 'Create tag context - feature-auth',
|
||||||
passed: tag1Result.exitCode === 0,
|
passed: tag1Result.exitCode === 0,
|
||||||
output: tag1Result.stdout
|
output: tag1Result.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
const tag2Result = await helpers.taskMaster('add-tag', ['feature-api', '--description', 'API development'], { cwd: testDir });
|
const tag2Result = await helpers.taskMaster(
|
||||||
|
'add-tag',
|
||||||
|
['feature-api', '--description', 'API development'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Create tag context - feature-api',
|
test: 'Create tag context - feature-api',
|
||||||
passed: tag2Result.exitCode === 0,
|
passed: tag2Result.exitCode === 0,
|
||||||
@@ -23,7 +31,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add task to feature-auth tag
|
// Add task to feature-auth tag
|
||||||
const task1Result = await helpers.taskMaster('add-task', ['--tag=feature-auth', '--prompt', 'Implement user authentication'], { cwd: testDir });
|
const task1Result = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
['--tag=feature-auth', '--prompt', 'Implement user authentication'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Add task to feature-auth tag',
|
test: 'Add task to feature-auth tag',
|
||||||
passed: task1Result.exitCode === 0,
|
passed: task1Result.exitCode === 0,
|
||||||
@@ -31,7 +43,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add task to feature-api tag
|
// Add task to feature-api tag
|
||||||
const task2Result = await helpers.taskMaster('add-task', ['--tag=feature-api', '--prompt', 'Create REST API endpoints'], { cwd: testDir });
|
const task2Result = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
['--tag=feature-api', '--prompt', 'Create REST API endpoints'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Add task to feature-api tag',
|
test: 'Add task to feature-api tag',
|
||||||
passed: task2Result.exitCode === 0,
|
passed: task2Result.exitCode === 0,
|
||||||
@@ -39,20 +55,28 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// List all tag contexts
|
// List all tag contexts
|
||||||
const listTagsResult = await helpers.taskMaster('tags', [], { cwd: testDir });
|
const listTagsResult = await helpers.taskMaster('tags', [], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
results.push({
|
results.push({
|
||||||
test: 'List all tag contexts',
|
test: 'List all tag contexts',
|
||||||
passed: listTagsResult.exitCode === 0 &&
|
passed:
|
||||||
|
listTagsResult.exitCode === 0 &&
|
||||||
listTagsResult.stdout.includes('feature-auth') &&
|
listTagsResult.stdout.includes('feature-auth') &&
|
||||||
listTagsResult.stdout.includes('feature-api'),
|
listTagsResult.stdout.includes('feature-api'),
|
||||||
output: listTagsResult.stdout
|
output: listTagsResult.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
// List tasks in feature-auth tag
|
// List tasks in feature-auth tag
|
||||||
const taggedTasksResult = await helpers.taskMaster('list', ['--tag=feature-auth'], { cwd: testDir });
|
const taggedTasksResult = await helpers.taskMaster(
|
||||||
|
'list',
|
||||||
|
['--tag=feature-auth'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'List tasks in feature-auth tag',
|
test: 'List tasks in feature-auth tag',
|
||||||
passed: taggedTasksResult.exitCode === 0 &&
|
passed:
|
||||||
|
taggedTasksResult.exitCode === 0 &&
|
||||||
taggedTasksResult.stdout.includes('Implement user authentication'),
|
taggedTasksResult.stdout.includes('Implement user authentication'),
|
||||||
output: taggedTasksResult.stdout
|
output: taggedTasksResult.stdout
|
||||||
});
|
});
|
||||||
@@ -61,7 +85,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
logger.info('Testing model configuration...');
|
logger.info('Testing model configuration...');
|
||||||
|
|
||||||
// Set main model
|
// Set main model
|
||||||
const setMainModelResult = await helpers.taskMaster('models', ['--set-main', 'gpt-4'], { cwd: testDir });
|
const setMainModelResult = await helpers.taskMaster(
|
||||||
|
'models',
|
||||||
|
['--set-main', 'gpt-4'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Set main model',
|
test: 'Set main model',
|
||||||
passed: setMainModelResult.exitCode === 0,
|
passed: setMainModelResult.exitCode === 0,
|
||||||
@@ -69,7 +97,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Set research model
|
// Set research model
|
||||||
const setResearchModelResult = await helpers.taskMaster('models', ['--set-research', 'claude-3-sonnet'], { cwd: testDir });
|
const setResearchModelResult = await helpers.taskMaster(
|
||||||
|
'models',
|
||||||
|
['--set-research', 'claude-3-sonnet'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Set research model',
|
test: 'Set research model',
|
||||||
passed: setResearchModelResult.exitCode === 0,
|
passed: setResearchModelResult.exitCode === 0,
|
||||||
@@ -77,7 +109,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Set fallback model
|
// Set fallback model
|
||||||
const setFallbackModelResult = await helpers.taskMaster('models', ['--set-fallback', 'gpt-3.5-turbo'], { cwd: testDir });
|
const setFallbackModelResult = await helpers.taskMaster(
|
||||||
|
'models',
|
||||||
|
['--set-fallback', 'gpt-3.5-turbo'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Set fallback model',
|
test: 'Set fallback model',
|
||||||
passed: setFallbackModelResult.exitCode === 0,
|
passed: setFallbackModelResult.exitCode === 0,
|
||||||
@@ -85,10 +121,13 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Verify model configuration
|
// Verify model configuration
|
||||||
const showModelsResult = await helpers.taskMaster('models', [], { cwd: testDir });
|
const showModelsResult = await helpers.taskMaster('models', [], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Show model configuration',
|
test: 'Show model configuration',
|
||||||
passed: showModelsResult.exitCode === 0 &&
|
passed:
|
||||||
|
showModelsResult.exitCode === 0 &&
|
||||||
showModelsResult.stdout.includes('gpt-4') &&
|
showModelsResult.stdout.includes('gpt-4') &&
|
||||||
showModelsResult.stdout.includes('claude-3-sonnet') &&
|
showModelsResult.stdout.includes('claude-3-sonnet') &&
|
||||||
showModelsResult.stdout.includes('gpt-3.5-turbo'),
|
showModelsResult.stdout.includes('gpt-3.5-turbo'),
|
||||||
@@ -99,7 +138,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
logger.info('Testing task expansion...');
|
logger.info('Testing task expansion...');
|
||||||
|
|
||||||
// Add task for expansion
|
// Add task for expansion
|
||||||
const expandTaskResult = await helpers.taskMaster('add-task', ['--prompt', 'Build REST API'], { cwd: testDir });
|
const expandTaskResult = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
['--prompt', 'Build REST API'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
const expandTaskMatch = expandTaskResult.stdout.match(/#(\d+)/);
|
const expandTaskMatch = expandTaskResult.stdout.match(/#(\d+)/);
|
||||||
const expandTaskId = expandTaskMatch ? expandTaskMatch[1] : null;
|
const expandTaskId = expandTaskMatch ? expandTaskMatch[1] : null;
|
||||||
|
|
||||||
@@ -111,23 +154,37 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
|
|
||||||
if (expandTaskId) {
|
if (expandTaskId) {
|
||||||
// Single task expansion
|
// Single task expansion
|
||||||
const expandResult = await helpers.taskMaster('expand', [expandTaskId], { cwd: testDir });
|
const expandResult = await helpers.taskMaster('expand', [expandTaskId], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Expand single task',
|
test: 'Expand single task',
|
||||||
passed: expandResult.exitCode === 0 && expandResult.stdout.includes('subtasks'),
|
passed:
|
||||||
|
expandResult.exitCode === 0 &&
|
||||||
|
expandResult.stdout.includes('subtasks'),
|
||||||
output: expandResult.stdout
|
output: expandResult.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify expand worked
|
// Verify expand worked
|
||||||
const afterExpandResult = await helpers.taskMaster('show', [expandTaskId], { cwd: testDir });
|
const afterExpandResult = await helpers.taskMaster(
|
||||||
|
'show',
|
||||||
|
[expandTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Verify task expansion',
|
test: 'Verify task expansion',
|
||||||
passed: afterExpandResult.exitCode === 0 && afterExpandResult.stdout.includes('subtasks'),
|
passed:
|
||||||
|
afterExpandResult.exitCode === 0 &&
|
||||||
|
afterExpandResult.stdout.includes('subtasks'),
|
||||||
output: afterExpandResult.stdout
|
output: afterExpandResult.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
// Force expand (re-expand)
|
// Force expand (re-expand)
|
||||||
const forceExpandResult = await helpers.taskMaster('expand', [expandTaskId, '--force'], { cwd: testDir });
|
const forceExpandResult = await helpers.taskMaster(
|
||||||
|
'expand',
|
||||||
|
[expandTaskId, '--force'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Force expand task',
|
test: 'Force expand task',
|
||||||
passed: forceExpandResult.exitCode === 0,
|
passed: forceExpandResult.exitCode === 0,
|
||||||
@@ -139,20 +196,32 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
logger.info('Testing subtask management...');
|
logger.info('Testing subtask management...');
|
||||||
|
|
||||||
// Add task for subtask testing
|
// Add task for subtask testing
|
||||||
const subtaskParentResult = await helpers.taskMaster('add-task', ['--prompt', 'Create user interface'], { cwd: testDir });
|
const subtaskParentResult = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
['--prompt', 'Create user interface'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
const parentMatch = subtaskParentResult.stdout.match(/#(\d+)/);
|
const parentMatch = subtaskParentResult.stdout.match(/#(\d+)/);
|
||||||
const parentTaskId = parentMatch ? parentMatch[1] : null;
|
const parentTaskId = parentMatch ? parentMatch[1] : null;
|
||||||
|
|
||||||
if (parentTaskId) {
|
if (parentTaskId) {
|
||||||
// Add subtasks manually
|
// Add subtasks manually
|
||||||
const addSubtask1Result = await helpers.taskMaster('add-subtask', ['--parent', parentTaskId, '--title', 'Design mockups'], { cwd: testDir });
|
const addSubtask1Result = await helpers.taskMaster(
|
||||||
|
'add-subtask',
|
||||||
|
['--parent', parentTaskId, '--title', 'Design mockups'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Add subtask - Design mockups',
|
test: 'Add subtask - Design mockups',
|
||||||
passed: addSubtask1Result.exitCode === 0,
|
passed: addSubtask1Result.exitCode === 0,
|
||||||
output: addSubtask1Result.stdout
|
output: addSubtask1Result.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
const addSubtask2Result = await helpers.taskMaster('add-subtask', ['--parent', parentTaskId, '--title', 'Implement components'], { cwd: testDir });
|
const addSubtask2Result = await helpers.taskMaster(
|
||||||
|
'add-subtask',
|
||||||
|
['--parent', parentTaskId, '--title', 'Implement components'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Add subtask - Implement components',
|
test: 'Add subtask - Implement components',
|
||||||
passed: addSubtask2Result.exitCode === 0,
|
passed: addSubtask2Result.exitCode === 0,
|
||||||
@@ -160,10 +229,15 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// List subtasks (use show command to see subtasks)
|
// List subtasks (use show command to see subtasks)
|
||||||
const listSubtasksResult = await helpers.taskMaster('show', [parentTaskId], { cwd: testDir });
|
const listSubtasksResult = await helpers.taskMaster(
|
||||||
|
'show',
|
||||||
|
[parentTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'List subtasks',
|
test: 'List subtasks',
|
||||||
passed: listSubtasksResult.exitCode === 0 &&
|
passed:
|
||||||
|
listSubtasksResult.exitCode === 0 &&
|
||||||
listSubtasksResult.stdout.includes('Design mockups') &&
|
listSubtasksResult.stdout.includes('Design mockups') &&
|
||||||
listSubtasksResult.stdout.includes('Implement components'),
|
listSubtasksResult.stdout.includes('Implement components'),
|
||||||
output: listSubtasksResult.stdout
|
output: listSubtasksResult.stdout
|
||||||
@@ -171,7 +245,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
|
|
||||||
// Update subtask
|
// Update subtask
|
||||||
const subtaskId = `${parentTaskId}.1`;
|
const subtaskId = `${parentTaskId}.1`;
|
||||||
const updateSubtaskResult = await helpers.taskMaster('update-subtask', ['--id', subtaskId, '--prompt', 'Create detailed mockups'], { cwd: testDir });
|
const updateSubtaskResult = await helpers.taskMaster(
|
||||||
|
'update-subtask',
|
||||||
|
['--id', subtaskId, '--prompt', 'Create detailed mockups'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Update subtask',
|
test: 'Update subtask',
|
||||||
passed: updateSubtaskResult.exitCode === 0,
|
passed: updateSubtaskResult.exitCode === 0,
|
||||||
@@ -180,7 +258,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
|
|
||||||
// Remove subtask
|
// Remove subtask
|
||||||
const removeSubtaskId = `${parentTaskId}.2`;
|
const removeSubtaskId = `${parentTaskId}.2`;
|
||||||
const removeSubtaskResult = await helpers.taskMaster('remove-subtask', ['--id', removeSubtaskId], { cwd: testDir });
|
const removeSubtaskResult = await helpers.taskMaster(
|
||||||
|
'remove-subtask',
|
||||||
|
['--id', removeSubtaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Remove subtask',
|
test: 'Remove subtask',
|
||||||
passed: removeSubtaskResult.exitCode === 0,
|
passed: removeSubtaskResult.exitCode === 0,
|
||||||
@@ -188,17 +270,26 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Verify subtask changes
|
// Verify subtask changes
|
||||||
const verifySubtasksResult = await helpers.taskMaster('show', [parentTaskId], { cwd: testDir });
|
const verifySubtasksResult = await helpers.taskMaster(
|
||||||
|
'show',
|
||||||
|
[parentTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Verify subtask changes',
|
test: 'Verify subtask changes',
|
||||||
passed: verifySubtasksResult.exitCode === 0 &&
|
passed:
|
||||||
|
verifySubtasksResult.exitCode === 0 &&
|
||||||
verifySubtasksResult.stdout.includes('Create detailed mockups') &&
|
verifySubtasksResult.stdout.includes('Create detailed mockups') &&
|
||||||
!verifySubtasksResult.stdout.includes('Implement components'),
|
!verifySubtasksResult.stdout.includes('Implement components'),
|
||||||
output: verifySubtasksResult.stdout
|
output: verifySubtasksResult.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear all subtasks
|
// Clear all subtasks
|
||||||
const clearSubtasksResult = await helpers.taskMaster('clear-subtasks', ['--id', parentTaskId], { cwd: testDir });
|
const clearSubtasksResult = await helpers.taskMaster(
|
||||||
|
'clear-subtasks',
|
||||||
|
['--id', parentTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Clear all subtasks',
|
test: 'Clear all subtasks',
|
||||||
passed: clearSubtasksResult.exitCode === 0,
|
passed: clearSubtasksResult.exitCode === 0,
|
||||||
@@ -206,12 +297,17 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Verify subtasks cleared
|
// Verify subtasks cleared
|
||||||
const verifyClearResult = await helpers.taskMaster('show', [parentTaskId], { cwd: testDir });
|
const verifyClearResult = await helpers.taskMaster(
|
||||||
|
'show',
|
||||||
|
[parentTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Verify subtasks cleared',
|
test: 'Verify subtasks cleared',
|
||||||
passed: verifyClearResult.exitCode === 0 &&
|
passed:
|
||||||
(!verifyClearResult.stdout.includes('Design mockups') &&
|
verifyClearResult.exitCode === 0 &&
|
||||||
!verifyClearResult.stdout.includes('Create detailed mockups')),
|
!verifyClearResult.stdout.includes('Design mockups') &&
|
||||||
|
!verifyClearResult.stdout.includes('Create detailed mockups'),
|
||||||
output: verifyClearResult.stdout
|
output: verifyClearResult.stdout
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -220,10 +316,20 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
logger.info('Testing expand all...');
|
logger.info('Testing expand all...');
|
||||||
|
|
||||||
// Add multiple tasks
|
// Add multiple tasks
|
||||||
await helpers.taskMaster('add-task', ['--prompt', 'Task A for expand all'], { cwd: testDir });
|
await helpers.taskMaster(
|
||||||
await helpers.taskMaster('add-task', ['--prompt', 'Task B for expand all'], { cwd: testDir });
|
'add-task',
|
||||||
|
['--prompt', 'Task A for expand all'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
|
await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
['--prompt', 'Task B for expand all'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
|
|
||||||
const expandAllResult = await helpers.taskMaster('expand', ['--all'], { cwd: testDir });
|
const expandAllResult = await helpers.taskMaster('expand', ['--all'], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Expand all tasks',
|
test: 'Expand all tasks',
|
||||||
passed: expandAllResult.exitCode === 0,
|
passed: expandAllResult.exitCode === 0,
|
||||||
@@ -235,7 +341,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
|
|
||||||
// Generate files for a specific task
|
// Generate files for a specific task
|
||||||
if (expandTaskId) {
|
if (expandTaskId) {
|
||||||
const generateResult = await helpers.taskMaster('generate', [expandTaskId], { cwd: testDir });
|
const generateResult = await helpers.taskMaster(
|
||||||
|
'generate',
|
||||||
|
[expandTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Generate task files',
|
test: 'Generate task files',
|
||||||
passed: generateResult.exitCode === 0,
|
passed: generateResult.exitCode === 0,
|
||||||
@@ -249,7 +359,9 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
results.push({
|
results.push({
|
||||||
test: 'Verify generated task file exists',
|
test: 'Verify generated task file exists',
|
||||||
passed: fileExists,
|
passed: fileExists,
|
||||||
output: fileExists ? `Task file created at ${taskFilePath}` : 'Task file not found'
|
output: fileExists
|
||||||
|
? `Task file created at ${taskFilePath}`
|
||||||
|
: 'Task file not found'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,20 +369,28 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
logger.info('Testing tag context integrity after operations...');
|
logger.info('Testing tag context integrity after operations...');
|
||||||
|
|
||||||
// Verify tag contexts still exist
|
// Verify tag contexts still exist
|
||||||
const finalTagListResult = await helpers.taskMaster('tags', [], { cwd: testDir });
|
const finalTagListResult = await helpers.taskMaster('tags', [], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Final tag context list verification',
|
test: 'Final tag context list verification',
|
||||||
passed: finalTagListResult.exitCode === 0 &&
|
passed:
|
||||||
|
finalTagListResult.exitCode === 0 &&
|
||||||
finalTagListResult.stdout.includes('feature-auth') &&
|
finalTagListResult.stdout.includes('feature-auth') &&
|
||||||
finalTagListResult.stdout.includes('feature-api'),
|
finalTagListResult.stdout.includes('feature-api'),
|
||||||
output: finalTagListResult.stdout
|
output: finalTagListResult.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verify tasks are still in their respective tag contexts
|
// Verify tasks are still in their respective tag contexts
|
||||||
const finalTaggedTasksResult = await helpers.taskMaster('list', ['--tag=feature-api'], { cwd: testDir });
|
const finalTaggedTasksResult = await helpers.taskMaster(
|
||||||
|
'list',
|
||||||
|
['--tag=feature-api'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Final tasks in tag context verification',
|
test: 'Final tasks in tag context verification',
|
||||||
passed: finalTaggedTasksResult.exitCode === 0 &&
|
passed:
|
||||||
|
finalTaggedTasksResult.exitCode === 0 &&
|
||||||
finalTaggedTasksResult.stdout.includes('Create REST API endpoints'),
|
finalTaggedTasksResult.stdout.includes('Create REST API endpoints'),
|
||||||
output: finalTaggedTasksResult.stdout
|
output: finalTaggedTasksResult.stdout
|
||||||
});
|
});
|
||||||
@@ -279,7 +399,11 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
logger.info('Testing additional advanced features...');
|
logger.info('Testing additional advanced features...');
|
||||||
|
|
||||||
// Test priority task
|
// Test priority task
|
||||||
const priorityTagResult = await helpers.taskMaster('add-task', ['--prompt', 'High priority task', '--priority', 'high'], { cwd: testDir });
|
const priorityTagResult = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
['--prompt', 'High priority task', '--priority', 'high'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Add task with high priority',
|
test: 'Add task with high priority',
|
||||||
passed: priorityTagResult.exitCode === 0,
|
passed: priorityTagResult.exitCode === 0,
|
||||||
@@ -287,13 +411,16 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Test filtering by status
|
// Test filtering by status
|
||||||
const statusFilterResult = await helpers.taskMaster('list', ['--status', 'pending'], { cwd: testDir });
|
const statusFilterResult = await helpers.taskMaster(
|
||||||
|
'list',
|
||||||
|
['--status', 'pending'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
results.push({
|
results.push({
|
||||||
test: 'Filter by status',
|
test: 'Filter by status',
|
||||||
passed: statusFilterResult.exitCode === 0,
|
passed: statusFilterResult.exitCode === 0,
|
||||||
output: statusFilterResult.stdout
|
output: statusFilterResult.stdout
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error in advanced features tests:', error);
|
logger.error('Error in advanced features tests:', error);
|
||||||
results.push({
|
results.push({
|
||||||
@@ -303,7 +430,7 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const passed = results.filter(r => r.passed).length;
|
const passed = results.filter((r) => r.passed).length;
|
||||||
const total = results.length;
|
const total = results.length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -313,4 +440,4 @@ export default async function testAdvanced(logger, helpers, context) {
|
|||||||
results,
|
results,
|
||||||
summary: `Advanced features tests: ${passed}/${total} passed`
|
summary: `Advanced features tests: ${passed}/${total} passed`
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
throw new Error(`List command failed: ${listResult1.stderr}`);
|
throw new Error(`List command failed: ${listResult1.stderr}`);
|
||||||
}
|
}
|
||||||
// Check for expected output patterns - either empty or with tasks
|
// Check for expected output patterns - either empty or with tasks
|
||||||
const hasValidOutput = listResult1.stdout.includes('No tasks found') ||
|
const hasValidOutput =
|
||||||
|
listResult1.stdout.includes('No tasks found') ||
|
||||||
listResult1.stdout.includes('Task List') ||
|
listResult1.stdout.includes('Task List') ||
|
||||||
listResult1.stdout.includes('Project Dashboard') ||
|
listResult1.stdout.includes('Project Dashboard') ||
|
||||||
listResult1.stdout.includes('Listing tasks from');
|
listResult1.stdout.includes('Listing tasks from');
|
||||||
@@ -31,7 +32,16 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 2: Add manual task
|
// Test 2: Add manual task
|
||||||
logger.info('\nTest 2: Add manual task');
|
logger.info('\nTest 2: Add manual task');
|
||||||
const addResult1 = await helpers.taskMaster('add-task', ['--title', 'Write unit tests', '--description', 'Create comprehensive unit tests for the application'], { cwd: testDir });
|
const addResult1 = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
[
|
||||||
|
'--title',
|
||||||
|
'Write unit tests',
|
||||||
|
'--description',
|
||||||
|
'Create comprehensive unit tests for the application'
|
||||||
|
],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (addResult1.exitCode !== 0) {
|
if (addResult1.exitCode !== 0) {
|
||||||
throw new Error(`Failed to add manual task: ${addResult1.stderr}`);
|
throw new Error(`Failed to add manual task: ${addResult1.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -43,7 +53,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 3: Add AI task
|
// Test 3: Add AI task
|
||||||
logger.info('\nTest 3: Add AI task');
|
logger.info('\nTest 3: Add AI task');
|
||||||
const addResult2 = await helpers.taskMaster('add-task', ['--prompt', 'Implement authentication system'], { cwd: testDir });
|
const addResult2 = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
['--prompt', 'Implement authentication system'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (addResult2.exitCode !== 0) {
|
if (addResult2.exitCode !== 0) {
|
||||||
throw new Error(`Failed to add AI task: ${addResult2.stderr}`);
|
throw new Error(`Failed to add AI task: ${addResult2.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -55,7 +69,16 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 4: Add another task for dependency testing
|
// Test 4: Add another task for dependency testing
|
||||||
logger.info('\nTest 4: Add task for dependency testing');
|
logger.info('\nTest 4: Add task for dependency testing');
|
||||||
const addResult3 = await helpers.taskMaster('add-task', ['--title', 'Create database schema', '--description', 'Design and implement the database schema'], { cwd: testDir });
|
const addResult3 = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
[
|
||||||
|
'--title',
|
||||||
|
'Create database schema',
|
||||||
|
'--description',
|
||||||
|
'Design and implement the database schema'
|
||||||
|
],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (addResult3.exitCode !== 0) {
|
if (addResult3.exitCode !== 0) {
|
||||||
throw new Error(`Failed to add database task: ${addResult3.stderr}`);
|
throw new Error(`Failed to add database task: ${addResult3.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -81,7 +104,8 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Also check for partial matches (list may truncate titles)
|
// Also check for partial matches (list may truncate titles)
|
||||||
const hasOurTasks = listResult2.stdout.includes('Write') ||
|
const hasOurTasks =
|
||||||
|
listResult2.stdout.includes('Write') ||
|
||||||
listResult2.stdout.includes('Create');
|
listResult2.stdout.includes('Create');
|
||||||
if (hasOurTasks) {
|
if (hasOurTasks) {
|
||||||
logger.success('✓ List tasks shows our added tasks');
|
logger.success('✓ List tasks shows our added tasks');
|
||||||
@@ -99,22 +123,34 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 7: Show task details
|
// Test 7: Show task details
|
||||||
logger.info('\nTest 7: Show task details');
|
logger.info('\nTest 7: Show task details');
|
||||||
const showResult = await helpers.taskMaster('show', [aiTaskId], { cwd: testDir });
|
const showResult = await helpers.taskMaster('show', [aiTaskId], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
if (showResult.exitCode !== 0) {
|
if (showResult.exitCode !== 0) {
|
||||||
throw new Error(`Show task details failed: ${showResult.stderr}`);
|
throw new Error(`Show task details failed: ${showResult.stderr}`);
|
||||||
}
|
}
|
||||||
// Check that the task ID is shown and basic structure is present
|
// Check that the task ID is shown and basic structure is present
|
||||||
if (!showResult.stdout.includes(`Task: #${aiTaskId}`) && !showResult.stdout.includes(`ID: │ ${aiTaskId}`)) {
|
if (
|
||||||
|
!showResult.stdout.includes(`Task: #${aiTaskId}`) &&
|
||||||
|
!showResult.stdout.includes(`ID: │ ${aiTaskId}`)
|
||||||
|
) {
|
||||||
throw new Error('Task ID not found in show output');
|
throw new Error('Task ID not found in show output');
|
||||||
}
|
}
|
||||||
if (!showResult.stdout.includes('Status:') || !showResult.stdout.includes('Priority:')) {
|
if (
|
||||||
|
!showResult.stdout.includes('Status:') ||
|
||||||
|
!showResult.stdout.includes('Priority:')
|
||||||
|
) {
|
||||||
throw new Error('Task details missing expected fields');
|
throw new Error('Task details missing expected fields');
|
||||||
}
|
}
|
||||||
logger.success('✓ Show task details successful');
|
logger.success('✓ Show task details successful');
|
||||||
|
|
||||||
// Test 8: Add dependencies
|
// Test 8: Add dependencies
|
||||||
logger.info('\nTest 8: Add dependencies');
|
logger.info('\nTest 8: Add dependencies');
|
||||||
const addDepResult = await helpers.taskMaster('add-dependency', ['--id', aiTaskId, '--depends-on', dbTaskId], { cwd: testDir });
|
const addDepResult = await helpers.taskMaster(
|
||||||
|
'add-dependency',
|
||||||
|
['--id', aiTaskId, '--depends-on', dbTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (addDepResult.exitCode !== 0) {
|
if (addDepResult.exitCode !== 0) {
|
||||||
throw new Error(`Failed to add dependency: ${addDepResult.stderr}`);
|
throw new Error(`Failed to add dependency: ${addDepResult.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -122,21 +158,30 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 9: Verify dependency was added
|
// Test 9: Verify dependency was added
|
||||||
logger.info('\nTest 9: Verify dependency');
|
logger.info('\nTest 9: Verify dependency');
|
||||||
const showResult2 = await helpers.taskMaster('show', [aiTaskId], { cwd: testDir });
|
const showResult2 = await helpers.taskMaster('show', [aiTaskId], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
if (showResult2.exitCode !== 0) {
|
if (showResult2.exitCode !== 0) {
|
||||||
throw new Error(`Show task failed: ${showResult2.stderr}`);
|
throw new Error(`Show task failed: ${showResult2.stderr}`);
|
||||||
}
|
}
|
||||||
if (!showResult2.stdout.includes('Dependencies:') || !showResult2.stdout.includes(dbTaskId)) {
|
if (
|
||||||
|
!showResult2.stdout.includes('Dependencies:') ||
|
||||||
|
!showResult2.stdout.includes(dbTaskId)
|
||||||
|
) {
|
||||||
throw new Error('Dependency not shown in task details');
|
throw new Error('Dependency not shown in task details');
|
||||||
}
|
}
|
||||||
logger.success('✓ Dependency verified in task details');
|
logger.success('✓ Dependency verified in task details');
|
||||||
|
|
||||||
// Test 10: Test circular dependency (should fail)
|
// Test 10: Test circular dependency (should fail)
|
||||||
logger.info('\nTest 10: Test circular dependency prevention');
|
logger.info('\nTest 10: Test circular dependency prevention');
|
||||||
const circularResult = await helpers.taskMaster('add-dependency', ['--id', dbTaskId, '--depends-on', aiTaskId], {
|
const circularResult = await helpers.taskMaster(
|
||||||
|
'add-dependency',
|
||||||
|
['--id', dbTaskId, '--depends-on', aiTaskId],
|
||||||
|
{
|
||||||
cwd: testDir,
|
cwd: testDir,
|
||||||
allowFailure: true
|
allowFailure: true
|
||||||
});
|
}
|
||||||
|
);
|
||||||
if (circularResult.exitCode === 0) {
|
if (circularResult.exitCode === 0) {
|
||||||
throw new Error('Circular dependency was not prevented');
|
throw new Error('Circular dependency was not prevented');
|
||||||
}
|
}
|
||||||
@@ -147,10 +192,14 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 11: Test non-existent dependency
|
// Test 11: Test non-existent dependency
|
||||||
logger.info('\nTest 11: Test non-existent dependency');
|
logger.info('\nTest 11: Test non-existent dependency');
|
||||||
const nonExistResult = await helpers.taskMaster('add-dependency', ['--id', '99999', '--depends-on', '88888'], {
|
const nonExistResult = await helpers.taskMaster(
|
||||||
|
'add-dependency',
|
||||||
|
['--id', '99999', '--depends-on', '88888'],
|
||||||
|
{
|
||||||
cwd: testDir,
|
cwd: testDir,
|
||||||
allowFailure: true
|
allowFailure: true
|
||||||
});
|
}
|
||||||
|
);
|
||||||
if (nonExistResult.exitCode === 0) {
|
if (nonExistResult.exitCode === 0) {
|
||||||
throw new Error('Non-existent dependency was incorrectly allowed');
|
throw new Error('Non-existent dependency was incorrectly allowed');
|
||||||
}
|
}
|
||||||
@@ -158,7 +207,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 12: Remove dependency
|
// Test 12: Remove dependency
|
||||||
logger.info('\nTest 12: Remove dependency');
|
logger.info('\nTest 12: Remove dependency');
|
||||||
const removeDepResult = await helpers.taskMaster('remove-dependency', ['--id', aiTaskId, '--depends-on', dbTaskId], { cwd: testDir });
|
const removeDepResult = await helpers.taskMaster(
|
||||||
|
'remove-dependency',
|
||||||
|
['--id', aiTaskId, '--depends-on', dbTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (removeDepResult.exitCode !== 0) {
|
if (removeDepResult.exitCode !== 0) {
|
||||||
throw new Error(`Failed to remove dependency: ${removeDepResult.stderr}`);
|
throw new Error(`Failed to remove dependency: ${removeDepResult.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -166,7 +219,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 13: Validate dependencies
|
// Test 13: Validate dependencies
|
||||||
logger.info('\nTest 13: Validate dependencies');
|
logger.info('\nTest 13: Validate dependencies');
|
||||||
const validateResult = await helpers.taskMaster('validate-dependencies', [], { cwd: testDir });
|
const validateResult = await helpers.taskMaster(
|
||||||
|
'validate-dependencies',
|
||||||
|
[],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (validateResult.exitCode !== 0) {
|
if (validateResult.exitCode !== 0) {
|
||||||
throw new Error(`Dependency validation failed: ${validateResult.stderr}`);
|
throw new Error(`Dependency validation failed: ${validateResult.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -174,7 +231,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 14: Update task description
|
// Test 14: Update task description
|
||||||
logger.info('\nTest 14: Update task description');
|
logger.info('\nTest 14: Update task description');
|
||||||
const updateResult = await helpers.taskMaster('update-task', [manualTaskId, '--description', 'Write comprehensive unit tests'], { cwd: testDir });
|
const updateResult = await helpers.taskMaster(
|
||||||
|
'update-task',
|
||||||
|
[manualTaskId, '--description', 'Write comprehensive unit tests'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (updateResult.exitCode !== 0) {
|
if (updateResult.exitCode !== 0) {
|
||||||
throw new Error(`Failed to update task: ${updateResult.stderr}`);
|
throw new Error(`Failed to update task: ${updateResult.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -182,7 +243,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 15: Add subtask
|
// Test 15: Add subtask
|
||||||
logger.info('\nTest 15: Add subtask');
|
logger.info('\nTest 15: Add subtask');
|
||||||
const subtaskResult = await helpers.taskMaster('add-subtask', [manualTaskId, 'Write test for login'], { cwd: testDir });
|
const subtaskResult = await helpers.taskMaster(
|
||||||
|
'add-subtask',
|
||||||
|
[manualTaskId, 'Write test for login'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (subtaskResult.exitCode !== 0) {
|
if (subtaskResult.exitCode !== 0) {
|
||||||
throw new Error(`Failed to add subtask: ${subtaskResult.stderr}`);
|
throw new Error(`Failed to add subtask: ${subtaskResult.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -191,7 +256,9 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 16: Verify subtask relationship
|
// Test 16: Verify subtask relationship
|
||||||
logger.info('\nTest 16: Verify subtask relationship');
|
logger.info('\nTest 16: Verify subtask relationship');
|
||||||
const showResult3 = await helpers.taskMaster('show', [manualTaskId], { cwd: testDir });
|
const showResult3 = await helpers.taskMaster('show', [manualTaskId], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
if (showResult3.exitCode !== 0) {
|
if (showResult3.exitCode !== 0) {
|
||||||
throw new Error(`Show task failed: ${showResult3.stderr}`);
|
throw new Error(`Show task failed: ${showResult3.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -202,7 +269,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 17: Set task status to in_progress
|
// Test 17: Set task status to in_progress
|
||||||
logger.info('\nTest 17: Set task status to in_progress');
|
logger.info('\nTest 17: Set task status to in_progress');
|
||||||
const statusResult1 = await helpers.taskMaster('set-status', [manualTaskId, 'in_progress'], { cwd: testDir });
|
const statusResult1 = await helpers.taskMaster(
|
||||||
|
'set-status',
|
||||||
|
[manualTaskId, 'in_progress'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (statusResult1.exitCode !== 0) {
|
if (statusResult1.exitCode !== 0) {
|
||||||
throw new Error(`Failed to update task status: ${statusResult1.stderr}`);
|
throw new Error(`Failed to update task status: ${statusResult1.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -210,7 +281,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 18: Set task status to completed
|
// Test 18: Set task status to completed
|
||||||
logger.info('\nTest 18: Set task status to completed');
|
logger.info('\nTest 18: Set task status to completed');
|
||||||
const statusResult2 = await helpers.taskMaster('set-status', [dbTaskId, 'completed'], { cwd: testDir });
|
const statusResult2 = await helpers.taskMaster(
|
||||||
|
'set-status',
|
||||||
|
[dbTaskId, 'completed'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (statusResult2.exitCode !== 0) {
|
if (statusResult2.exitCode !== 0) {
|
||||||
throw new Error(`Failed to complete task: ${statusResult2.stderr}`);
|
throw new Error(`Failed to complete task: ${statusResult2.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -218,7 +293,11 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 19: List tasks with status filter
|
// Test 19: List tasks with status filter
|
||||||
logger.info('\nTest 19: List tasks by status');
|
logger.info('\nTest 19: List tasks by status');
|
||||||
const listStatusResult = await helpers.taskMaster('list', ['--status', 'completed'], { cwd: testDir });
|
const listStatusResult = await helpers.taskMaster(
|
||||||
|
'list',
|
||||||
|
['--status', 'completed'],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (listStatusResult.exitCode !== 0) {
|
if (listStatusResult.exitCode !== 0) {
|
||||||
throw new Error(`List by status failed: ${listStatusResult.stderr}`);
|
throw new Error(`List by status failed: ${listStatusResult.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -229,7 +308,9 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 20: Remove single task
|
// Test 20: Remove single task
|
||||||
logger.info('\nTest 20: Remove single task');
|
logger.info('\nTest 20: Remove single task');
|
||||||
const removeResult1 = await helpers.taskMaster('remove-task', [dbTaskId], { cwd: testDir });
|
const removeResult1 = await helpers.taskMaster('remove-task', [dbTaskId], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
if (removeResult1.exitCode !== 0) {
|
if (removeResult1.exitCode !== 0) {
|
||||||
throw new Error(`Failed to remove task: ${removeResult1.stderr}`);
|
throw new Error(`Failed to remove task: ${removeResult1.stderr}`);
|
||||||
}
|
}
|
||||||
@@ -237,9 +318,15 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 21: Remove multiple tasks
|
// Test 21: Remove multiple tasks
|
||||||
logger.info('\nTest 21: Remove multiple tasks');
|
logger.info('\nTest 21: Remove multiple tasks');
|
||||||
const removeResult2 = await helpers.taskMaster('remove-task', [manualTaskId, aiTaskId], { cwd: testDir });
|
const removeResult2 = await helpers.taskMaster(
|
||||||
|
'remove-task',
|
||||||
|
[manualTaskId, aiTaskId],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (removeResult2.exitCode !== 0) {
|
if (removeResult2.exitCode !== 0) {
|
||||||
throw new Error(`Failed to remove multiple tasks: ${removeResult2.stderr}`);
|
throw new Error(
|
||||||
|
`Failed to remove multiple tasks: ${removeResult2.stderr}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
logger.success('✓ Removed multiple tasks successfully');
|
logger.success('✓ Removed multiple tasks successfully');
|
||||||
|
|
||||||
@@ -250,9 +337,15 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
throw new Error(`List command failed: ${listResult3.stderr}`);
|
throw new Error(`List command failed: ${listResult3.stderr}`);
|
||||||
}
|
}
|
||||||
// Check that our specific task IDs are no longer in the list
|
// Check that our specific task IDs are no longer in the list
|
||||||
const stillHasTask11 = new RegExp(`\\b${manualTaskId}\\b`).test(listResult3.stdout);
|
const stillHasTask11 = new RegExp(`\\b${manualTaskId}\\b`).test(
|
||||||
const stillHasTask12 = new RegExp(`\\b${aiTaskId}\\b`).test(listResult3.stdout);
|
listResult3.stdout
|
||||||
const stillHasTask13 = new RegExp(`\\b${dbTaskId}\\b`).test(listResult3.stdout);
|
);
|
||||||
|
const stillHasTask12 = new RegExp(`\\b${aiTaskId}\\b`).test(
|
||||||
|
listResult3.stdout
|
||||||
|
);
|
||||||
|
const stillHasTask13 = new RegExp(`\\b${dbTaskId}\\b`).test(
|
||||||
|
listResult3.stdout
|
||||||
|
);
|
||||||
|
|
||||||
if (stillHasTask11 || stillHasTask12 || stillHasTask13) {
|
if (stillHasTask11 || stillHasTask12 || stillHasTask13) {
|
||||||
throw new Error('Removed task IDs still appear in list');
|
throw new Error('Removed task IDs still appear in list');
|
||||||
@@ -261,7 +354,9 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
|
|
||||||
// Test 23: Fix dependencies (cleanup)
|
// Test 23: Fix dependencies (cleanup)
|
||||||
logger.info('\nTest 23: Fix dependencies');
|
logger.info('\nTest 23: Fix dependencies');
|
||||||
const fixDepsResult = await helpers.taskMaster('fix-dependencies', [], { cwd: testDir });
|
const fixDepsResult = await helpers.taskMaster('fix-dependencies', [], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
if (fixDepsResult.exitCode !== 0) {
|
if (fixDepsResult.exitCode !== 0) {
|
||||||
// Non-critical, just log
|
// Non-critical, just log
|
||||||
logger.warning(`Fix dependencies had issues: ${fixDepsResult.stderr}`);
|
logger.warning(`Fix dependencies had issues: ${fixDepsResult.stderr}`);
|
||||||
@@ -270,7 +365,6 @@ export default async function testCoreOperations(logger, helpers, context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info('\n✅ All core task operations tests passed!');
|
logger.info('\n✅ All core task operations tests passed!');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
results.status = 'failed';
|
results.status = 'failed';
|
||||||
results.errors.push({
|
results.errors.push({
|
||||||
|
|||||||
@@ -51,13 +51,21 @@ export default async function testProviders(logger, helpers, context) {
|
|||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.info(`\nTesting provider: ${provider.name} with model: ${provider.model}`);
|
logger.info(
|
||||||
|
`\nTesting provider: ${provider.name} with model: ${provider.model}`
|
||||||
|
);
|
||||||
|
|
||||||
// Step 1: Set the main model for this provider
|
// Step 1: Set the main model for this provider
|
||||||
logger.info(`Setting model to ${provider.model}...`);
|
logger.info(`Setting model to ${provider.model}...`);
|
||||||
const setModelResult = await helpers.taskMaster('models', ['--set-main', provider.model], { cwd: testDir });
|
const setModelResult = await helpers.taskMaster(
|
||||||
|
'models',
|
||||||
|
['--set-main', provider.model],
|
||||||
|
{ cwd: testDir }
|
||||||
|
);
|
||||||
if (setModelResult.exitCode !== 0) {
|
if (setModelResult.exitCode !== 0) {
|
||||||
throw new Error(`Failed to set model for ${provider.name}: ${setModelResult.stderr}`);
|
throw new Error(
|
||||||
|
`Failed to set model for ${provider.name}: ${setModelResult.stderr}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Execute add-task with standard prompt
|
// Step 2: Execute add-task with standard prompt
|
||||||
@@ -67,10 +75,14 @@ export default async function testProviders(logger, helpers, context) {
|
|||||||
addTaskArgs.push(...provider.flags);
|
addTaskArgs.push(...provider.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
const addTaskResult = await helpers.taskMaster('add-task', addTaskArgs, {
|
const addTaskResult = await helpers.taskMaster(
|
||||||
|
'add-task',
|
||||||
|
addTaskArgs,
|
||||||
|
{
|
||||||
cwd: testDir,
|
cwd: testDir,
|
||||||
timeout: 120000 // 2 minutes timeout for AI tasks
|
timeout: 120000 // 2 minutes timeout for AI tasks
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (addTaskResult.exitCode !== 0) {
|
if (addTaskResult.exitCode !== 0) {
|
||||||
throw new Error(`Add-task failed: ${addTaskResult.stderr}`);
|
throw new Error(`Add-task failed: ${addTaskResult.stderr}`);
|
||||||
@@ -85,25 +97,32 @@ export default async function testProviders(logger, helpers, context) {
|
|||||||
logger.success(`✓ Created task ${taskId} with ${provider.name}`);
|
logger.success(`✓ Created task ${taskId} with ${provider.name}`);
|
||||||
|
|
||||||
// Step 4: Get task details
|
// Step 4: Get task details
|
||||||
const showResult = await helpers.taskMaster('show', [taskId], { cwd: testDir });
|
const showResult = await helpers.taskMaster('show', [taskId], {
|
||||||
|
cwd: testDir
|
||||||
|
});
|
||||||
if (showResult.exitCode === 0) {
|
if (showResult.exitCode === 0) {
|
||||||
providerResult.taskDetails = showResult.stdout;
|
providerResult.taskDetails = showResult.stdout;
|
||||||
|
|
||||||
// Analyze task features
|
// Analyze task features
|
||||||
providerResult.features.hasTitle = showResult.stdout.includes('Title:') ||
|
providerResult.features.hasTitle =
|
||||||
|
showResult.stdout.includes('Title:') ||
|
||||||
showResult.stdout.includes('Task:');
|
showResult.stdout.includes('Task:');
|
||||||
providerResult.features.hasDescription = showResult.stdout.includes('Description:');
|
providerResult.features.hasDescription =
|
||||||
providerResult.features.hasSubtasks = showResult.stdout.includes('Subtasks:');
|
showResult.stdout.includes('Description:');
|
||||||
providerResult.features.hasDependencies = showResult.stdout.includes('Dependencies:');
|
providerResult.features.hasSubtasks =
|
||||||
|
showResult.stdout.includes('Subtasks:');
|
||||||
|
providerResult.features.hasDependencies =
|
||||||
|
showResult.stdout.includes('Dependencies:');
|
||||||
|
|
||||||
// Count subtasks
|
// Count subtasks
|
||||||
const subtaskMatches = showResult.stdout.match(/\d+\.\d+/g);
|
const subtaskMatches = showResult.stdout.match(/\d+\.\d+/g);
|
||||||
providerResult.subtaskCount = subtaskMatches ? subtaskMatches.length : 0;
|
providerResult.subtaskCount = subtaskMatches
|
||||||
|
? subtaskMatches.length
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
providerResult.status = 'success';
|
providerResult.status = 'success';
|
||||||
results.summary.successfulProviders++;
|
results.summary.successfulProviders++;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
providerResult.status = 'failed';
|
providerResult.status = 'failed';
|
||||||
providerResult.error = error.message;
|
providerResult.error = error.message;
|
||||||
@@ -128,7 +147,9 @@ export default async function testProviders(logger, helpers, context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate summary statistics
|
// Calculate summary statistics
|
||||||
results.summary.averageExecutionTime = Math.round(totalExecutionTime / providers.length);
|
results.summary.averageExecutionTime = Math.round(
|
||||||
|
totalExecutionTime / providers.length
|
||||||
|
);
|
||||||
results.summary.successRate = `${Math.round((results.summary.successfulProviders / results.summary.totalProviders) * 100)}%`;
|
results.summary.successRate = `${Math.round((results.summary.successfulProviders / results.summary.totalProviders) * 100)}%`;
|
||||||
|
|
||||||
// Log summary
|
// Log summary
|
||||||
@@ -137,7 +158,9 @@ export default async function testProviders(logger, helpers, context) {
|
|||||||
logger.info(`Successful: ${results.summary.successfulProviders}`);
|
logger.info(`Successful: ${results.summary.successfulProviders}`);
|
||||||
logger.info(`Failed: ${results.summary.failedProviders}`);
|
logger.info(`Failed: ${results.summary.failedProviders}`);
|
||||||
logger.info(`Success rate: ${results.summary.successRate}`);
|
logger.info(`Success rate: ${results.summary.successRate}`);
|
||||||
logger.info(`Average execution time: ${results.summary.averageExecutionTime}ms`);
|
logger.info(
|
||||||
|
`Average execution time: ${results.summary.averageExecutionTime}ms`
|
||||||
|
);
|
||||||
|
|
||||||
// Determine overall status
|
// Determine overall status
|
||||||
if (results.summary.failedProviders === 0) {
|
if (results.summary.failedProviders === 0) {
|
||||||
@@ -149,7 +172,6 @@ export default async function testProviders(logger, helpers, context) {
|
|||||||
results.status = 'failed';
|
results.status = 'failed';
|
||||||
logger.error('❌ All provider tests failed');
|
logger.error('❌ All provider tests failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
results.status = 'failed';
|
results.status = 'failed';
|
||||||
results.errors.push({
|
results.errors.push({
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ export async function runSetupTest(logger, helpers) {
|
|||||||
try {
|
try {
|
||||||
// Step 1: Create test directory with timestamp
|
// Step 1: Create test directory with timestamp
|
||||||
logger.step('Creating test directory');
|
logger.step('Creating test directory');
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '').replace('T', '_').slice(0, -1);
|
const timestamp = new Date()
|
||||||
|
.toISOString()
|
||||||
|
.replace(/[:.]/g, '')
|
||||||
|
.replace('T', '_')
|
||||||
|
.slice(0, -1);
|
||||||
const testDir = join(testConfig.paths.baseTestDir, `run_${timestamp}`);
|
const testDir = join(testConfig.paths.baseTestDir, `run_${timestamp}`);
|
||||||
|
|
||||||
if (!existsSync(testDir)) {
|
if (!existsSync(testDir)) {
|
||||||
@@ -72,14 +76,18 @@ export async function runSetupTest(logger, helpers) {
|
|||||||
|
|
||||||
// Step 4: Initialize project with task-master init
|
// Step 4: Initialize project with task-master init
|
||||||
logger.step('Initializing project with task-master');
|
logger.step('Initializing project with task-master');
|
||||||
const initResult = await helpers.taskMaster('init', [
|
const initResult = await helpers.taskMaster(
|
||||||
|
'init',
|
||||||
|
[
|
||||||
'-y',
|
'-y',
|
||||||
'--name="E2E Test ' + testDir.split('/').pop() + '"',
|
'--name="E2E Test ' + testDir.split('/').pop() + '"',
|
||||||
'--description="Automated E2E test run"'
|
'--description="Automated E2E test run"'
|
||||||
], {
|
],
|
||||||
|
{
|
||||||
cwd: testDir,
|
cwd: testDir,
|
||||||
timeout: 120000
|
timeout: 120000
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (initResult.exitCode === 0) {
|
if (initResult.exitCode === 0) {
|
||||||
testResults.steps.initialize = true;
|
testResults.steps.initialize = true;
|
||||||
@@ -104,7 +112,10 @@ export async function runSetupTest(logger, helpers) {
|
|||||||
|
|
||||||
if (!helpers.fileExists(prdSourcePath)) {
|
if (!helpers.fileExists(prdSourcePath)) {
|
||||||
// If sample PRD doesn't exist in fixtures, use the example PRD
|
// If sample PRD doesn't exist in fixtures, use the example PRD
|
||||||
const examplePrdPath = join(testConfig.paths.projectRoot, 'assets/example_prd.txt');
|
const examplePrdPath = join(
|
||||||
|
testConfig.paths.projectRoot,
|
||||||
|
'assets/example_prd.txt'
|
||||||
|
);
|
||||||
if (helpers.fileExists(examplePrdPath)) {
|
if (helpers.fileExists(examplePrdPath)) {
|
||||||
helpers.copyFile(examplePrdPath, prdDestPath);
|
helpers.copyFile(examplePrdPath, prdDestPath);
|
||||||
logger.info('Using example PRD file');
|
logger.info('Using example PRD file');
|
||||||
@@ -164,7 +175,8 @@ Phase 2: Enhanced features
|
|||||||
logger.success('PRD parsed successfully');
|
logger.success('PRD parsed successfully');
|
||||||
|
|
||||||
// Extract task count from output
|
// Extract task count from output
|
||||||
const taskCountMatch = parsePrdResult.stdout.match(/(\d+) tasks? created/i);
|
const taskCountMatch =
|
||||||
|
parsePrdResult.stdout.match(/(\d+) tasks? created/i);
|
||||||
if (taskCountMatch) {
|
if (taskCountMatch) {
|
||||||
logger.info(`Created ${taskCountMatch[1]} tasks from PRD`);
|
logger.info(`Created ${taskCountMatch[1]} tasks from PRD`);
|
||||||
}
|
}
|
||||||
@@ -179,17 +191,27 @@ Phase 2: Enhanced features
|
|||||||
if (!existsSync(reportsDir)) {
|
if (!existsSync(reportsDir)) {
|
||||||
mkdirSync(reportsDir, { recursive: true });
|
mkdirSync(reportsDir, { recursive: true });
|
||||||
}
|
}
|
||||||
const analyzeResult = await helpers.taskMaster('analyze-complexity', ['--research', '--output', '.taskmaster/reports/task-complexity-report.json'], {
|
const analyzeResult = await helpers.taskMaster(
|
||||||
|
'analyze-complexity',
|
||||||
|
[
|
||||||
|
'--research',
|
||||||
|
'--output',
|
||||||
|
'.taskmaster/reports/task-complexity-report.json'
|
||||||
|
],
|
||||||
|
{
|
||||||
cwd: testDir,
|
cwd: testDir,
|
||||||
timeout: 240000
|
timeout: 240000
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (analyzeResult.exitCode === 0) {
|
if (analyzeResult.exitCode === 0) {
|
||||||
testResults.steps.analyzeComplexity = true;
|
testResults.steps.analyzeComplexity = true;
|
||||||
logger.success('Complexity analysis completed');
|
logger.success('Complexity analysis completed');
|
||||||
|
|
||||||
// Extract complexity information from output
|
// Extract complexity information from output
|
||||||
const complexityMatch = analyzeResult.stdout.match(/Total Complexity Score: ([\d.]+)/);
|
const complexityMatch = analyzeResult.stdout.match(
|
||||||
|
/Total Complexity Score: ([\d.]+)/
|
||||||
|
);
|
||||||
if (complexityMatch) {
|
if (complexityMatch) {
|
||||||
logger.info(`Total complexity score: ${complexityMatch[1]}`);
|
logger.info(`Total complexity score: ${complexityMatch[1]}`);
|
||||||
}
|
}
|
||||||
@@ -209,20 +231,28 @@ Phase 2: Enhanced features
|
|||||||
logger.success('Complexity report generated');
|
logger.success('Complexity report generated');
|
||||||
|
|
||||||
// Check if complexity report file was created (not needed since complexity-report reads from the standard location)
|
// Check if complexity report file was created (not needed since complexity-report reads from the standard location)
|
||||||
const reportPath = join(testDir, '.taskmaster/reports/task-complexity-report.json');
|
const reportPath = join(
|
||||||
|
testDir,
|
||||||
|
'.taskmaster/reports/task-complexity-report.json'
|
||||||
|
);
|
||||||
if (helpers.fileExists(reportPath)) {
|
if (helpers.fileExists(reportPath)) {
|
||||||
testResults.complexityReport = helpers.readJson(reportPath);
|
testResults.complexityReport = helpers.readJson(reportPath);
|
||||||
logger.info('Complexity report saved to task-complexity-report.json');
|
logger.info('Complexity report saved to task-complexity-report.json');
|
||||||
|
|
||||||
// Log summary if available
|
// Log summary if available
|
||||||
if (testResults.complexityReport && testResults.complexityReport.summary) {
|
if (
|
||||||
|
testResults.complexityReport &&
|
||||||
|
testResults.complexityReport.summary
|
||||||
|
) {
|
||||||
const summary = testResults.complexityReport.summary;
|
const summary = testResults.complexityReport.summary;
|
||||||
logger.info(`Tasks analyzed: ${summary.totalTasks || 0}`);
|
logger.info(`Tasks analyzed: ${summary.totalTasks || 0}`);
|
||||||
logger.info(`Average complexity: ${summary.averageComplexity || 0}`);
|
logger.info(`Average complexity: ${summary.averageComplexity || 0}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warning(`Complexity report generation had issues: ${reportResult.stderr}`);
|
logger.warning(
|
||||||
|
`Complexity report generation had issues: ${reportResult.stderr}`
|
||||||
|
);
|
||||||
// Don't fail the test for report generation issues
|
// Don't fail the test for report generation issues
|
||||||
testResults.steps.generateReport = true;
|
testResults.steps.generateReport = true;
|
||||||
}
|
}
|
||||||
@@ -239,7 +269,6 @@ Phase 2: Enhanced features
|
|||||||
// All steps completed successfully
|
// All steps completed successfully
|
||||||
testResults.status = 'success';
|
testResults.status = 'success';
|
||||||
logger.success('Setup test completed successfully');
|
logger.success('Setup test completed successfully');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
testResults.status = 'failed';
|
testResults.status = 'failed';
|
||||||
testResults.errors.push(error.message);
|
testResults.errors.push(error.message);
|
||||||
|
|||||||
@@ -51,7 +51,10 @@ export class ErrorHandler {
|
|||||||
categorizeError(error) {
|
categorizeError(error) {
|
||||||
const message = error.message.toLowerCase();
|
const message = error.message.toLowerCase();
|
||||||
|
|
||||||
if (message.includes('command not found') || message.includes('not found')) {
|
if (
|
||||||
|
message.includes('command not found') ||
|
||||||
|
message.includes('not found')
|
||||||
|
) {
|
||||||
return 'DEPENDENCY_ERROR';
|
return 'DEPENDENCY_ERROR';
|
||||||
}
|
}
|
||||||
if (message.includes('permission') || message.includes('access denied')) {
|
if (message.includes('permission') || message.includes('access denied')) {
|
||||||
@@ -79,7 +82,7 @@ export class ErrorHandler {
|
|||||||
getSummary() {
|
getSummary() {
|
||||||
const errorsByType = {};
|
const errorsByType = {};
|
||||||
|
|
||||||
this.errors.forEach(error => {
|
this.errors.forEach((error) => {
|
||||||
if (!errorsByType[error.type]) {
|
if (!errorsByType[error.type]) {
|
||||||
errorsByType[error.type] = [];
|
errorsByType[error.type] = [];
|
||||||
}
|
}
|
||||||
@@ -90,7 +93,7 @@ export class ErrorHandler {
|
|||||||
totalErrors: this.errors.length,
|
totalErrors: this.errors.length,
|
||||||
totalWarnings: this.warnings.length,
|
totalWarnings: this.warnings.length,
|
||||||
errorsByType,
|
errorsByType,
|
||||||
criticalErrors: this.errors.filter(e => e.context.critical),
|
criticalErrors: this.errors.filter((e) => e.context.critical),
|
||||||
recentErrors: this.errors.slice(-5)
|
recentErrors: this.errors.slice(-5)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -149,7 +152,8 @@ export class ErrorHandler {
|
|||||||
if (summary.errorsByType.TIMEOUT_ERROR) {
|
if (summary.errorsByType.TIMEOUT_ERROR) {
|
||||||
recommendations.push({
|
recommendations.push({
|
||||||
type: 'TIMEOUT',
|
type: 'TIMEOUT',
|
||||||
message: 'Consider increasing timeout values or optimizing slow operations',
|
message:
|
||||||
|
'Consider increasing timeout values or optimizing slow operations',
|
||||||
errors: summary.errorsByType.TIMEOUT_ERROR.length
|
errors: summary.errorsByType.TIMEOUT_ERROR.length
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -179,8 +183,12 @@ export class ErrorHandler {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (summary.criticalErrors.length > 0) {
|
if (summary.criticalErrors.length > 0) {
|
||||||
console.log(chalk.red.bold(`\n ⚠️ Critical Errors: ${summary.criticalErrors.length}`));
|
console.log(
|
||||||
summary.criticalErrors.forEach(error => {
|
chalk.red.bold(
|
||||||
|
`\n ⚠️ Critical Errors: ${summary.criticalErrors.length}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
summary.criticalErrors.forEach((error) => {
|
||||||
console.log(chalk.red(` - ${error.message}`));
|
console.log(chalk.red(` - ${error.message}`));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -189,7 +197,7 @@ export class ErrorHandler {
|
|||||||
const recommendations = this.generateRecommendations(summary);
|
const recommendations = this.generateRecommendations(summary);
|
||||||
if (recommendations.length > 0) {
|
if (recommendations.length > 0) {
|
||||||
console.log(chalk.yellow.bold('\n💡 Recommendations:'));
|
console.log(chalk.yellow.bold('\n💡 Recommendations:'));
|
||||||
recommendations.forEach(rec => {
|
recommendations.forEach((rec) => {
|
||||||
console.log(chalk.yellow(` - ${rec.message}`));
|
console.log(chalk.yellow(` - ${rec.message}`));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -210,7 +218,10 @@ export class ErrorHandler {
|
|||||||
export function setupGlobalErrorHandlers(errorHandler, logger) {
|
export function setupGlobalErrorHandlers(errorHandler, logger) {
|
||||||
process.on('uncaughtException', (error) => {
|
process.on('uncaughtException', (error) => {
|
||||||
logger.error(`Uncaught Exception: ${error.message}`);
|
logger.error(`Uncaught Exception: ${error.message}`);
|
||||||
errorHandler.handleError(error, { critical: true, source: 'uncaughtException' });
|
errorHandler.handleError(error, {
|
||||||
|
critical: true,
|
||||||
|
source: 'uncaughtException'
|
||||||
|
});
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ export class LLMAnalyzer {
|
|||||||
try {
|
try {
|
||||||
providerSummary = readFileSync(providerSummaryFile, 'utf8');
|
providerSummary = readFileSync(providerSummaryFile, 'utf8');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.warning(`Could not read provider summary file: ${error.message}`);
|
this.logger.warning(
|
||||||
|
`Could not read provider summary file: ${error.message}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,9 +96,7 @@ ${logContent}`;
|
|||||||
const payload = {
|
const payload = {
|
||||||
model: this.config.llmAnalysis.model,
|
model: this.config.llmAnalysis.model,
|
||||||
max_tokens: this.config.llmAnalysis.maxTokens,
|
max_tokens: this.config.llmAnalysis.maxTokens,
|
||||||
messages: [
|
messages: [{ role: 'user', content: prompt }]
|
||||||
{ role: 'user', content: prompt }
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch(this.apiEndpoint, {
|
const response = await fetch(this.apiEndpoint, {
|
||||||
@@ -138,12 +138,15 @@ ${logContent}`;
|
|||||||
calculateCost(usage) {
|
calculateCost(usage) {
|
||||||
const modelCosts = {
|
const modelCosts = {
|
||||||
'claude-3-7-sonnet-20250219': {
|
'claude-3-7-sonnet-20250219': {
|
||||||
input: 3.00, // per 1M tokens
|
input: 3.0, // per 1M tokens
|
||||||
output: 15.00 // per 1M tokens
|
output: 15.0 // per 1M tokens
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const costs = modelCosts[this.config.llmAnalysis.model] || { input: 0, output: 0 };
|
const costs = modelCosts[this.config.llmAnalysis.model] || {
|
||||||
|
input: 0,
|
||||||
|
output: 0
|
||||||
|
};
|
||||||
const inputCost = (usage.input_tokens / 1000000) * costs.input;
|
const inputCost = (usage.input_tokens / 1000000) * costs.input;
|
||||||
const outputCost = (usage.output_tokens / 1000000) * costs.output;
|
const outputCost = (usage.output_tokens / 1000000) * costs.output;
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,10 @@ export class TestLogger {
|
|||||||
step(message) {
|
step(message) {
|
||||||
this.stepCount++;
|
this.stepCount++;
|
||||||
const separator = '='.repeat(45);
|
const separator = '='.repeat(45);
|
||||||
this.log('STEP', `\n${separator}\n STEP ${this.stepCount}: ${message}\n${separator}`);
|
this.log(
|
||||||
|
'STEP',
|
||||||
|
`\n${separator}\n STEP ${this.stepCount}: ${message}\n${separator}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
addCost(cost) {
|
addCost(cost) {
|
||||||
@@ -109,8 +112,12 @@ export class TestLogger {
|
|||||||
|
|
||||||
getSummary() {
|
getSummary() {
|
||||||
const duration = this.formatDuration(Date.now() - this.startTime);
|
const duration = this.formatDuration(Date.now() - this.startTime);
|
||||||
const successCount = this.logBuffer.filter(line => line.includes('[SUCCESS]')).length;
|
const successCount = this.logBuffer.filter((line) =>
|
||||||
const errorCount = this.logBuffer.filter(line => line.includes('[ERROR]')).length;
|
line.includes('[SUCCESS]')
|
||||||
|
).length;
|
||||||
|
const errorCount = this.logBuffer.filter((line) =>
|
||||||
|
line.includes('[ERROR]')
|
||||||
|
).length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
duration,
|
duration,
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ export class TestHelpers {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// When using shell: true, pass the full command as a single string
|
// When using shell: true, pass the full command as a single string
|
||||||
const fullCommand = args.length > 0 ? `${command} ${args.join(' ')}` : command;
|
const fullCommand =
|
||||||
|
args.length > 0 ? `${command} ${args.join(' ')}` : command;
|
||||||
const child = spawn(fullCommand, [], spawnOptions);
|
const child = spawn(fullCommand, [], spawnOptions);
|
||||||
let stdout = '';
|
let stdout = '';
|
||||||
let stderr = '';
|
let stderr = '';
|
||||||
@@ -89,7 +90,9 @@ export class TestHelpers {
|
|||||||
const content = readFileSync(filePath, 'utf8');
|
const content = readFileSync(filePath, 'utf8');
|
||||||
return JSON.parse(content);
|
return JSON.parse(content);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`Failed to read JSON file ${filePath}: ${error.message}`);
|
this.logger.error(
|
||||||
|
`Failed to read JSON file ${filePath}: ${error.message}`
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,7 +105,9 @@ export class TestHelpers {
|
|||||||
copyFileSync(source, destination);
|
copyFileSync(source, destination);
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`Failed to copy file from ${source} to ${destination}: ${error.message}`);
|
this.logger.error(
|
||||||
|
`Failed to copy file from ${source} to ${destination}: ${error.message}`
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +116,7 @@ export class TestHelpers {
|
|||||||
* Wait for a specified duration
|
* Wait for a specified duration
|
||||||
*/
|
*/
|
||||||
async wait(milliseconds) {
|
async wait(milliseconds) {
|
||||||
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,7 +126,7 @@ export class TestHelpers {
|
|||||||
const tasks = this.readJson(tasksFile);
|
const tasks = this.readJson(tasksFile);
|
||||||
if (!tasks || !tasks[tagName]) return false;
|
if (!tasks || !tasks[tagName]) return false;
|
||||||
|
|
||||||
return tasks[tagName].tasks.some(task => task.id === taskId);
|
return tasks[tagName].tasks.some((task) => task.id === taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -169,7 +174,7 @@ export class TestHelpers {
|
|||||||
const executing = [];
|
const executing = [];
|
||||||
|
|
||||||
for (const operation of operations) {
|
for (const operation of operations) {
|
||||||
const promise = operation().then(result => {
|
const promise = operation().then((result) => {
|
||||||
executing.splice(executing.indexOf(promise), 1);
|
executing.splice(executing.indexOf(promise), 1);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user