@@ -53,6 +53,14 @@ const listProjectsOutputSchema = {
5353 'The prefix to use for component selectors.' +
5454 ` For example, a prefix of 'app' would result in selectors like '<app-my-component>'.` ,
5555 ) ,
56+ unitTestFramework : z
57+ . enum ( [ 'jasmine' , 'jest' , 'vitest' , 'unknown' ] )
58+ . optional ( )
59+ . describe (
60+ 'The unit test framework used by the project, such as Jasmine, Jest, or Vitest. ' +
61+ 'This field is critical for generating correct and idiomatic unit tests. ' +
62+ 'When writing or modifying tests, you MUST use the APIs corresponding to this framework.' ,
63+ ) ,
5664 } ) ,
5765 ) ,
5866 } ) ,
@@ -84,21 +92,25 @@ export const LIST_PROJECTS_TOOL = declareTool({
8492 title : 'List Angular Projects' ,
8593 description : `
8694<Purpose>
87- Provides a comprehensive overview of all Angular workspaces and projects within a monorepo .
95+ Provides a comprehensive overview of all Angular workspaces and projects within the repository .
8896It is essential to use this tool as a first step before performing any project-specific actions to understand the available projects,
8997their types, and their locations.
9098</Purpose>
9199<Use Cases>
92100* Finding the correct project name to use in other commands (e.g., \`ng generate component my-comp --project=my-app\`).
93101* Identifying the \`root\` and \`sourceRoot\` of a project to read, analyze, or modify its files.
94- * Determining if a project is an \`application\` or a \`library\` .
102+ * Determining a project's unit test framework (\`unitTestFramework\`) before writing or modifying tests .
95103* Getting the \`selectorPrefix\` for a project before generating a new component to ensure it follows conventions.
96104* Identifying the major version of the Angular framework for each workspace, which is crucial for monorepos.
97105* Determining a project's primary function by inspecting its builder (e.g., '@angular-devkit/build-angular:browser' for an application).
98106</Use Cases>
99107<Operational Notes>
100108* **Working Directory:** Shell commands for a project (like \`ng generate\`) **MUST**
101109 be executed from the parent directory of the \`path\` field for the relevant workspace.
110+ * **Unit Testing:** The \`unitTestFramework\` field tells you which testing API to use (e.g., Jasmine, Jest).
111+ If the value is 'unknown', you **MUST** inspect the project's configuration files
112+ (e.g., \`karma.conf.js\`, \`jest.config.js\`, or the 'test' target in \`angular.json\`) to determine the
113+ framework before generating tests.
102114* **Disambiguation:** A monorepo may contain multiple workspaces (e.g., for different applications or even in output directories).
103115 Use the \`path\` of each workspace to understand its context and choose the correct project.
104116</Operational Notes>` ,
@@ -230,9 +242,55 @@ async function findAngularCoreVersion(
230242 return undefined ;
231243}
232244
233- // Types for the structured output of the helper function .
245+ // Helper types inferred from the Zod schema for structured data processing .
234246type WorkspaceData = z . infer < typeof listProjectsOutputSchema . workspaces > [ number ] ;
235247type ParsingError = z . infer < typeof listProjectsOutputSchema . parsingErrors > [ number ] ;
248+ type VersioningError = z . infer < typeof listProjectsOutputSchema . versioningErrors > [ number ] ;
249+
250+ /**
251+ * Determines the unit test framework for a project based on its 'test' target configuration.
252+ * It handles both the modern `@angular/build:unit-test` builder with its `runner` option
253+ * and older builders where the framework is inferred from the builder name.
254+ * @param testTarget The 'test' target definition from the workspace configuration.
255+ * @returns The name of the unit test framework ('jasmine', 'jest', 'vitest'), 'unknown' if
256+ * the framework can't be determined from a known builder, or `undefined` if there is no test target.
257+ */
258+ function getUnitTestFramework (
259+ testTarget : import ( '@angular-devkit/core' ) . workspaces . TargetDefinition | undefined ,
260+ ) : 'jasmine' | 'jest' | 'vitest' | 'unknown' | undefined {
261+ if ( ! testTarget ) {
262+ return undefined ;
263+ }
264+
265+ // For the new unit-test builder, the runner option directly informs the framework.
266+ if ( testTarget . builder === '@angular/build:unit-test' ) {
267+ const runner = testTarget . options ?. [ 'runner' ] as 'karma' | 'vitest' | undefined ;
268+ if ( runner === 'karma' ) {
269+ return 'jasmine' ; // Karma is a runner, but the framework is Jasmine.
270+ } else {
271+ return runner ; // For 'vitest', the runner and framework are the same.
272+ }
273+ }
274+
275+ // Fallback for older builders where the framework is inferred from the builder name.
276+ if ( testTarget . builder ) {
277+ const testBuilder = testTarget . builder ;
278+ if (
279+ testBuilder . includes ( 'karma' ) ||
280+ testBuilder === '@angular-devkit/build-angular:web-test-runner'
281+ ) {
282+ return 'jasmine' ;
283+ } else if ( testBuilder . includes ( 'jest' ) ) {
284+ return 'jest' ;
285+ } else if ( testBuilder . includes ( 'vitest' ) ) {
286+ return 'vitest' ;
287+ } else {
288+ return 'unknown' ;
289+ }
290+ }
291+
292+ return undefined ;
293+ }
236294
237295/**
238296 * Loads, parses, and transforms a single angular.json file into the tool's output format.
@@ -255,13 +313,16 @@ async function loadAndParseWorkspace(
255313 const ws = await AngularWorkspace . load ( configFile ) ;
256314 const projects = [ ] ;
257315 for ( const [ name , project ] of ws . projects . entries ( ) ) {
316+ const unitTestFramework = getUnitTestFramework ( project . targets . get ( 'test' ) ) ;
317+
258318 projects . push ( {
259319 name,
260320 type : project . extensions [ 'projectType' ] as 'application' | 'library' | undefined ,
261321 builder : project . targets . get ( 'build' ) ?. builder ,
262322 root : project . root ,
263323 sourceRoot : project . sourceRoot ?? path . posix . join ( project . root , 'src' ) ,
264324 selectorPrefix : project . extensions [ 'prefix' ] as string ,
325+ unitTestFramework,
265326 } ) ;
266327 }
267328
@@ -278,9 +339,6 @@ async function loadAndParseWorkspace(
278339 }
279340}
280341
281- // Types for the structured output of the helper function.
282- type VersioningError = z . infer < typeof listProjectsOutputSchema . versioningErrors > [ number ] ;
283-
284342/**
285343 * Processes a single `angular.json` file to extract workspace and framework version information.
286344 * @param configFile The path to the `angular.json` file.
0 commit comments