首页
/ Angular 仓库 AI Agent 开发规范:pnpm + Bazel 环境、Zoneless 测试范式与贡献工作流

Angular 仓库 AI Agent 开发规范:pnpm + Bazel 环境、Zoneless 测试范式与贡献工作流

2026-09-06 15:08:46作者:段琳惟

Angular 官方仓库内置了一份专门面向 AI Agent 的开发规范(AGENTS.md / .agent/rules/agents.md),它浓缩了在此仓库中工作所需的三类关键能力:用 pnpm 与 Bazel 搭建构建测试环境、遵循 Zoneless(无 Zone.js)环境下的“Act, Wait, Assert”异步测试范式,以及通过 gh CLI 和规范化的 commit 消息提交 Pull Request。读完本文,你将能准确复现仓库中的测试运行方式,理解框架自身测试为何不再依赖 detectChanges(),并能按仓库标准完成一次合格的代码提交。

规范文件的定位:AI Agent 的“always_on”工作手册

仓库根目录下的 AGENTS.md.agent/rules/agents.md 内容一致,文件以如下 frontmatter 开头:

---
trigger: always_on
---

这表示该规范对任何进入本仓库工作的 AI Agent 始终生效,而非按需触发。全文仅 35 行,但覆盖四个维度:环境(Environment)、关键文档索引(Key Documentation)、测试约定(Testing)与 Pull Request 流程。它的核心断言是:

This is the source code for the Angular framework. This guide outlines standard practices for AI agents working in this repository.

换言之,该文件不是通用贡献指南,而是把 Angular 框架源码仓库中“与框架自身开发强绑定的约定”提炼为 Agent 可直接执行的规则。

环境与构建命令:pnpm 管理依赖,Bazel 驱动测试

规范文件 Environment 一节给出两条硬性约定:

  1. 使用 pnpm 进行包管理(版本由根目录 package.jsonengines 字段指定);
  2. 使用 pnpm bazel test //target 运行测试,其中 //target 是 Bazel 目标路径。

这两条约定与 构建与测试指南 完全一致,该指南是仓库中运行 Bazel 目标的“权威手册”。结合指南内容,完整的工作流命令如下:

# 1. 安装依赖(对应 package.json 中的依赖声明)
pnpm install

# 2. 构建 Angular 框架,产物输出到 dist/packages-dist
pnpm build

# 3. 运行指定 Bazel 目标的测试
pnpm bazel test //target

# 4. 提交 PR 前建议跑完整测试套件
pnpm test //packages/...

# 5. 代码格式检查 / 校验(prettier 格式由 CI 强制)
pnpm lint

# 6. 自动格式化
pnpm ng-dev format changed [shaOrRef]   # 只格式化相对某 ref 的变更文件,默认 main
pnpm ng-dev format all                  # 格式化全部源码

几个值得注意的前提与限制:

  • Bazel 是构建测试的第一工具,指南明确 “Bazel is used as the primary tool for building and testing Angular”,调试细节见 Bazel 构建指南 的 “Testing Angular” 章节;
  • 提交 PR 前应执行受影响的全部测试pnpm test //packages/...),CI 也会在提交后再次运行受影响测试,失败会在 GitHub 上以错误状态呈现;
  • 代码必须通过格式检查才能合并,仓库使用 prettier 自动格式化,CI 会强制校验。

关键文档索引:三份“必读”规范

规范文件 Key Documentation 一节列出了三份配套文档,均位于 contributing-docs/ 目录:

文档 作用
Building and Testing 运行各类目标(build/test/snapshot)的权威指南
Coding Standards TypeScript 及其他文件的代码风格规范
Commit Guidelines commit 消息与 PR 标题的格式规范

其中 编码规范 明确其适用范围“仅针对 Angular 框架本身的开发,而非用 Angular 构建的应用”,并以 Google JavaScript Style Guide 为基础、prettier 自动格式化由 CI 强制执行;它还包含若干具体的 API 设计要求(例如“避免用布尔参数表达‘做额外的事’,应拆分为不同函数”)。这些是 Agent 在修改框架源码时必须对照的风格基准。

测试约定(核心):Zoneless 与 Async-First

这是规范文件技术含量最高的部分,也是 Agent 在 Angular 仓库写测试时最容易出错的地方。

前提:假定运行在无 Zone 的环境中

规范第一条即声明:

Zoneless & Async-First: Assume a zoneless environment where state changes schedule updates asynchronously.

这意味着:框架自身测试默认运行在 zoneless(不依赖 Zone.js 的 NgZone/ProxyZone)模式下,状态变化会异步地调度变更检测与视图更新。直接推论是:

  • 禁止使用 fixture.detectChanges() 手动触发更新——它属于 Zone.js 时代的同步刷新手法,与异步调度模型相冲突;
  • 必须采用 “Act, Wait, Assert” 三步模式:
    1. Act(操作):更新状态或执行一个动作;
    2. Wait(等待)await fixture.whenStable(),让框架处理完已调度的更新;
    3. Assert(断言):验证输出。

这一模式在框架各包的测试中大量出现。例如 Router 包的 router_link_spec.ts 中每个用例都遵循“操作后 await fixture.whenStable() 再断言”的写法,导航集成测试 navigation.spec.ts 亦同。

用 useAutoTick() 通过“快进”假时钟减少等待

为了让测试保持快速,规范要求在可能的情况下最小化等待,推荐方式是引入 useAutoTick()(来自 packages/private/testing/src/utils.ts)通过 mock clock 快进时间。查看该文件源码可以看到其实现非常直白——它在 beforeEach 中安装 Jasmine 的 fake clock 并开启 autoTick,在 afterEach 中卸载:

// packages/private/testing/src/utils.ts (约 L204-L212)
export function useAutoTick() {
  beforeEach(() => {
    jasmine.clock().install();
    jasmine.clock().autoTick();
  });
  afterEach(() => {
    jasmine.clock().uninstall();
  });
}

由于定时器在假时钟下“即时推进”,依赖 setTimeout/setInterval 的异步逻辑无需真实等待。实际用例可见 form_builder_spec.ts:它在 describe 顶层调用 useAutoTick(),因此块内大量用例(包括涉及异步校验器的用例)都能以同步断言完成。

确需等待时:真实异步测试 + timeout() / whenStable()

规范同时给出“必须等待”场景的标准做法:使用真实异步测试(it('...', async () => { ... })),并搭配两个工具:

  • await timeout(ms):等待指定毫秒数;
  • await fixture.whenStable():等待框架进入稳定状态。

timeout 的实现位于同一文件(utils.ts 约 L183-L187),本质是一个基于 setTimeout 的 Promise 包装:

// packages/private/testing/src/utils.ts (约 L183-L187)
export async function timeout(ms?: number): Promise<void> {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

一个典型组合出现在 form_builder_spec.ts 中:

import {useAutoTick, timeout} from '@angular/private/testing';

describe('Form Builder', () => {
  useAutoTick(); // 顶层开启假时钟自动推进

  it('... 需要等待的用例 ...', async () => {
    // Act: 更新状态
    // Wait:
    await timeout();        // 让出宏任务(约 L250 处用法)
    await fixture.whenStable(); // 等待框架稳定(约 L279/L305 处用法)
    // Assert:
    expect(...).toEqual(...);
  });
});

从源码结构看,utils.ts 还配套了几个值得了解的测试辅助函数,Agent 在编写框架测试时同样可以复用:

  • waitFor(callback, options)(约 L264-L299):以真实时钟为基准的轮询等待器,默认超时 100ms、默认间隔 0,超时后抛出携带“尝试次数 + 最后一次错误 + 原始调用栈”的增强错误信息;
  • expectText(text, options)(约 L245-L258):基于 waitFor 断言容器(默认为最近 fixture 的 nativeElement)文本内容匹配字符串或正则;
  • withBody / withHead(约 L38-L75):为测试自动注入/清理 document.body / head 中的 HTML;
  • ensureDocument / cleanupDocument(约 L120-L166):在 Node 环境下用 domino 建立 document,并在 beforeEach/afterEach 中自动注册/还原。

Pull Request 与提交规范

规范文件 Pull Requests 一节要求:创建和管理 PR 使用 gh CLI(GitHub CLI)。与之配套的提交格式约束来自 Commit Message 规范,其核心结构为 header + body + footer 三段:

<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

Header 采用 <type>(<scope>): <short summary> 格式,其中 type 必须为 build / ci / docs / feat / fix / perf / refactor / test 之一,scope 为受影响的 npm 包名(如 animationscommoncompiler-clicoreformsrouter 等),summary 使用现在时、首字母小写、结尾无句号。Body 除 docs 类型外为必填,且至少 20 个字符;Footer 可选。该格式同时用于 PR 标题。

规范要点速查清单

场景 约定 依据
包管理 一律使用 pnpm AGENTS.md Environment 节
运行测试 pnpm bazel test //target AGENTS.md / 构建指南
触发更新 禁止 fixture.detectChanges(),改用 await fixture.whenStable() AGENTS.md Testing 节
减少等待 describe 顶层 useAutoTick() utils.ts
必须等待 真实 async 用例 + await timeout(ms) / await fixture.whenStable() utils.ts
代码格式 prettier,pnpm lint 校验,pnpm ng-dev format 修复 构建指南
PR / 提交 gh CLI + <type>(<scope>): <summary> 格式 AGENTS.md / 提交规范

需要强调的是,上述约定均以当前仓库实际内容为准:测试工具函数位于私有包 @angular/private/testing(源码路径 packages/private/testing/src/utils.ts),框架包内测试(如 packages/forms/test/packages/router/test/)即是这些约定的参考实现;Agent 在扩展测试时,优先对齐同包内既有用例的写法,比遵循任何外部惯例都更可靠。

登录后查看全文
热门项目推荐
相关项目推荐