Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 18 additions & 16 deletions apps/nx-mcp-e2e/src/nx-project-details-compressed-targets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,10 @@ describe('nx_project_details compressed targets', () => {

const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
'target-nx-executor: @nx/webpack:webpack | cache: true',
expect(targetsBlock).toContain('target-nx-executor: @nx/webpack:webpack');
// Cache is true by default, so it should NOT be shown (token efficiency)
expect(targetsBlock).not.toContain(
'target-nx-executor: @nx/webpack:webpack | cache:',
);
});

Expand All @@ -190,7 +192,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
'target-custom-executor: @my-org/custom:build | cache: true',
'target-custom-executor: @my-org/custom:build',
);
});

Expand All @@ -205,7 +207,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
"target-run-cmd-options: nx:run-commands - 'echo test' | cache: true",
"target-run-cmd-options: nx:run-commands - 'echo test'",
);
});

Expand All @@ -220,7 +222,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
"target-run-cmd-array-single-str: nx:run-commands - 'npm build' | cache: true",
"target-run-cmd-array-single-str: nx:run-commands - 'npm build'",
);
});

Expand All @@ -235,7 +237,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
"target-run-cmd-array-single-obj: nx:run-commands - 'npm test' | cache: true",
"target-run-cmd-array-single-obj: nx:run-commands - 'npm test'",
);
});

Expand All @@ -250,7 +252,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
'target-run-cmd-array-multi: nx:run-commands - 3 commands | cache: true',
'target-run-cmd-array-multi: nx:run-commands - 3 commands',
);
});

Expand All @@ -264,9 +266,7 @@ describe('nx_project_details compressed targets', () => {

const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
"deploy: nx:run-script - 'npm run deploy' | cache: true",
);
expect(targetsBlock).toContain("deploy: nx:run-script - 'npm run deploy'");
});

it('should display nx:run-script target from package.json script - custom-hello', () => {
Expand All @@ -280,7 +280,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
"custom-hello: nx:run-script - 'npm run custom-hello' | cache: true",
"custom-hello: nx:run-script - 'npm run custom-hello'",
);
});

Expand All @@ -295,7 +295,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
'target-with-deps-string: @nx/js:tsc | depends: [build, test] | cache: true',
'target-with-deps-string: @nx/js:tsc | depends: [build, test]',
);
});

Expand All @@ -310,7 +310,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
'target-with-deps-object: @nx/js:tsc | depends: [build, ^build] | cache: true',
'target-with-deps-object: @nx/js:tsc | depends: [build, ^build]',
);
});

Expand Down Expand Up @@ -339,8 +339,10 @@ describe('nx_project_details compressed targets', () => {

const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
'target-with-cache: @nx/js:tsc | cache: true',
// When cache is true (default), it should NOT be displayed (token efficiency)
expect(targetsBlock).toContain('target-with-cache: @nx/js:tsc');
expect(targetsBlock).not.toContain(
'target-with-cache: @nx/js:tsc | cache:',
);
});

Expand Down Expand Up @@ -405,7 +407,7 @@ describe('nx_project_details compressed targets', () => {
const targetsBlock = getCompressedTargetsBlock(result);
expect(targetsBlock).toBeDefined();
expect(targetsBlock).toContain(
'target-empty-cmds: nx:run-commands - 0 commands | cache: true',
'target-empty-cmds: nx:run-commands - 0 commands',
);
});

Expand Down
4 changes: 3 additions & 1 deletion apps/nx-mcp-e2e/src/nx-project-details-select.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ describe('nx_project_details select', () => {
expect(result.content[1]?.text).toContain(
'To see full configuration for a specific target',
);
expect(result.content[1]?.text).toContain('cache:');
// Cache should only appear when it's false (token efficiency)
// So we should see "cache: false" somewhere, but not "cache: true"
expect(result.content[1]?.text).not.toContain('cache: true');

// Third block should be External Dependencies
expect(result.content[2]?.text).toContain('External Dependencies:');
Expand Down
167 changes: 157 additions & 10 deletions libs/nx-mcp/nx-mcp-server/src/lib/tools/nx-workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
getTokenOptimizedToolResult,
chunkContent,
registerNxWorkspaceTools,
__testing__,
} from './nx-workspace';
import { NxWorkspace, NxError } from '@nx-console/shared-types';
import {
Expand All @@ -12,16 +13,15 @@ import {
NX_PROJECT_DETAILS,
} from '@nx-console/shared-llm-context';

jest.mock('@nx-console/shared-llm-context', () => ({
getNxJsonPrompt: jest.fn(),
getProjectGraphPrompt: jest.fn(),
getProjectGraphErrorsPrompt: jest.fn(),
NX_WORKSPACE: 'nx_workspace',
NX_PROJECT_DETAILS: 'nx_project_details',
NX_GENERATORS: 'nx_generators',
NX_GENERATOR_SCHEMA: 'nx_generator_schema',
NX_WORKSPACE_PATH: 'nx_workspace_path',
}));
jest.mock('@nx-console/shared-llm-context', () => {
const actual = jest.requireActual('@nx-console/shared-llm-context');
return {
...actual,
getNxJsonPrompt: jest.fn(),
getProjectGraphPrompt: jest.fn(),
getProjectGraphErrorsPrompt: jest.fn(),
};
});

// Mock shared-npm module - don't import to avoid lazy-load conflict
jest.mock('@nx-console/shared-npm', () => ({
Expand Down Expand Up @@ -512,3 +512,150 @@ describe('registerNxWorkspaceTools', () => {
});
});
});

describe('compressTargetForDisplay', () => {
const { compressTargetForDisplay } = __testing__;

it('should omit cache status when true', () => {
const config = {
executor: 'nx:run-commands',
command: 'echo test',
cache: true,
};

const result = compressTargetForDisplay('build', config);

expect(result).toBe("build: nx:run-commands - 'echo test'");
expect(result).not.toContain('cache');
});

it('should show cache status when false', () => {
const config = {
executor: 'nx:run-commands',
command: 'echo test',
cache: false,
};

const result = compressTargetForDisplay('build', config);

expect(result).toBe("build: nx:run-commands - 'echo test' | cache: false");
});

it('should truncate long dependency lists', () => {
const config = {
executor: '@nx/gradle:gradle',
dependsOn: [
'dep1',
'dep2',
'dep3',
'dep4',
'dep5',
'dep6',
'dep7',
'dep8',
'dep9',
'dep10',
'dep11',
],
cache: true,
};

const result = compressTargetForDisplay('build', config);

expect(result).toBe(
'build: @nx/gradle:gradle | depends: [dep1, dep2, dep3, +8 more]',
);
});

it('should not truncate short dependency lists', () => {
const config = {
executor: '@nx/gradle:gradle',
dependsOn: ['dep1', 'dep2', 'dep3'],
cache: true,
};

const result = compressTargetForDisplay('build', config);

expect(result).toBe(
'build: @nx/gradle:gradle | depends: [dep1, dep2, dep3]',
);
});

it('should show atomized targets with abbreviated names', () => {
const config = {
executor: 'nx:noop',
dependsOn: ['test-ci--Test1', 'test-ci--Test2', 'test-ci--Test3'],
cache: true,
};
const atomizedTargets = [
'test-ci--Test1',
'test-ci--Test2',
'test-ci--Test3',
];

const result = compressTargetForDisplay('test-ci', config, atomizedTargets);

expect(result).toBe(
'test-ci: nx:noop | depends: [3 atomized targets] | atomized: [Test1, Test2, Test3]',
);
});

it('should truncate long atomized target lists', () => {
const config = {
executor: 'nx:noop',
cache: true,
};
const atomizedTargets = [
'test-ci--Test1',
'test-ci--Test2',
'test-ci--Test3',
'test-ci--Test4',
'test-ci--Test5',
'test-ci--Test6',
];

const result = compressTargetForDisplay('test-ci', config, atomizedTargets);

expect(result).toBe(
'test-ci: nx:noop | atomized: [Test1, Test2, Test3, +3 more]',
);
});

it('should handle target without executor', () => {
const config = {
cache: true,
};

const result = compressTargetForDisplay('build', config);

expect(result).toBe('build: no executor');
});

it('should handle nx:run-commands with multiple commands', () => {
const config = {
executor: 'nx:run-commands',
options: {
commands: ['echo test1', 'echo test2', 'echo test3'],
},
cache: true,
};

const result = compressTargetForDisplay('build', config);

expect(result).toBe('build: nx:run-commands - 3 commands');
});

it('should handle nx:run-script executor', () => {
const config = {
executor: 'nx:run-script',
metadata: {
runCommand: 'npm run test',
},
cache: true,
};

const result = compressTargetForDisplay('test', config);

expect(result).toBe("test: nx:run-script - 'npm run test'");
});
});
Loading
Loading