---
url: 'https://dxpr.com/zh-hans/hc/documentation/learn-dxpr-builder/development/testing'
title: '测试 | DXPR'
author:
  name: Jurriaan
  url: 'https://dxpr.com/users/jurriaan'
date: '2026-10-24T00:45:50+00:00'
updated: '2026-10-24T09:09:48+00:00'
copyright: 'Copyright DXPR. All rights reserved.'
type: article
summary: 'DXPR Builder 有四种自动化检查：编辑器的 Puppeteer 测试、Drush 命令的 Bash 端到端测试、独立 dxpr_maven 仓库中的 Selenium 视觉回归套件，以及代码检查。本页列出每种、本地运行方法和 CI 运行方法。'
tags:
  - Tooling
image: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
published: true
og:
  site_name: DXPR
  updated_time: '2026-10-24T09:09:48+0000'
  'image:alt': 'DXPR, powered by Drupal: AI-powered Drupal for marketers.'
schema:
  '@context': 'https://schema.org'
  '@graph':
    -
      mainEntity: {  }
    -
      '@type': TechArticle
      headline: 测试
      description: 'DXPR Builder 有四种自动化检查：编辑器的 Puppeteer 测试、Drush 命令的 Bash 端到端测试、独立 dxpr_maven 仓库中的 Selenium 视觉回归套件，以及代码检查。本页列出每种、本地运行方法和 CI 运行方法。'
      image:
        '@type': ImageObject
        url: 'https://dxpr.com/themes/custom/dxpr_com/images/dxpr-share-card.jpg'
        width: '1200'
        height: '630'
      datePublished: '2026-10-24T00:45:50+0000'
      dateModified: '2026-10-24T09:09:48+0000'
      author:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
        url: 'https://dxpr.com/'
        logo:
          '@type': ImageObject
          url: 'https://dxpr.com/themes/custom/dxpr_com/dxpr-logo-dark.svg'
          width: '1348'
          height: '501'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
        url: 'https://dxpr.com/'
        logo:
          '@type': ImageObject
          url: 'https://dxpr.com/themes/custom/dxpr_com/dxpr-logo-dark.svg'
          width: '1348'
          height: '501'
      mainEntityOfPage: 'https://dxpr.com/zh-hans/hc/documentation/learn-dxpr-builder/development/testing'
      articleSection: Tooling
    -
      '@type': WebPage
      '@id': 'https://dxpr.com/zh-hans/hc/documentation/learn-dxpr-builder/development/testing'
      description: 'DXPR Builder 有四种自动化检查：编辑器的 Puppeteer 测试、Drush 命令的 Bash 端到端测试、独立 dxpr_maven 仓库中的 Selenium 视觉回归套件，以及代码检查。本页列出每种、本地运行方法和 CI 运行方法。'
      breadcrumb:
        '@type': BreadcrumbList
        itemListElement:
          -
            '@type': ListItem
            position: 1
            name: 首页
            item: 'https://dxpr.com/zh-hans'
      publisher:
        '@type': Organization
        '@id': 'https://dxpr.com/#organization'
        name: DXPR
      inLanguage: zh-hans
---
[Help Center](/zh-hans/node/75)/[Documentation](/zh-hans/hc/documentation) /[Learn DXPR Builder](/hc/documentation/learn-dxpr-builder) /[Extend](/hc/documentation/learn-dxpr-builder/extend) /[Tooling](/hc/documentation/learn-dxpr-builder/extend/tooling) # 测试.

 Learn DXPR BuilderExtendTooling

   ## In this guide

 Related guides

- [参与贡献](/zh-hans/hc/documentation/learn-dxpr-builder/development/contributing)
- [Drush 命令](/zh-hans/hc/documentation/learn-dxpr-builder/development/drush-commands)

DXPR Builder 有四种自动化检查：编辑器的 Puppeteer 测试、Drush 命令的 Bash 端到端测试、独立 `dxpr_maven` 仓库中的 Selenium 视觉回归套件，以及代码检查。本页列出每种、本地运行方法和 CI 运行方法。

## 有哪些检查

| 检查 | 位置 | 运行于 |
|---|---|---|
| 编辑器控制台和布局测试 | `test/test-editor.js` | 改动 JavaScript、HTML 或 `test/` 的拉取请求（`.github/workflows/fe-test.yaml`） |
| Drush 端到端测试 | `scripts/drush-e2e/` | 改动 PHP、YAML 或 Markdown 的拉取请求（`.github/workflows/review.yaml`） |
| Selenium 视觉回归套件 | `dxpr_maven` 仓库 | PR 评论命令（`.github/workflows/e2e-command.yaml`、`e2e-bs3-command.yml`、`e2eV2-command.yaml`） |
| PHP 编码规范（phpcs） | `scripts/linters/run-drupal-lint.sh`、`phpcs.xml.dist` | 改动 PHP、YAML 或 Markdown 的拉取请求；每次推送到 `3.x` |
| PHPStan | `scripts/linters/run-drupal-check.sh` | 改动 PHP、YAML 或 Markdown 的拉取请求；每次推送到 `3.x` |
| ESLint、Stylelint、Rust Clippy | `scripts/linters/` | 拉取请求，按改动路径筛选 |
| 弃用检测器 | `.github/workflows/deprecations.yml` | 拉取请求改动了 `js/` 或 `dxpr_builder/build/` |
| 文档检查（markdownlint、`check_docs.py`、Vale） | `.markdownlint-cli2.yaml`、`docs/lint/`、`.vale.ini` | 改动 `docs/` 的拉取请求（`review.yaml`） |

仓库中唯一的 PHPUnit 测试是旧媒体子模块的 `modules/dxpr_builder_media/tests/src/FunctionalJavascript/MediaEntityBrowserTest.php`。没有 GitHub 工作流运行它；drupal.org GitLab 流水线（`.gitlab-ci.yml`）使用标准 DrupalCI 模板，那里的 PHPUnit 任务没有关闭。

## 编辑器控制台测试

`test/test-editor.js` 在 3000 端口启动静态服务器（`test/start-standalone-server.js`），在无头 Chrome 中打开 `test/standalone-editor/` 的四个独立页面：`test-bs5-anon.html`、`test-bs5-cms-block.html`、`test-bs5-editor.html` 和 `test-bs5-clean-html.html`。以下情况失败：

- 页面抛出 JavaScript 错误；
- 完整编辑器 2000 毫秒内未就绪，或加载后仍有屏幕外控件延迟（性能门）；
- 强力用户模式下元素控件重叠（基线为零对重叠）；
- 完整编辑器页面的已保存 HTML 大于 32094 个字符的基准；
- 页面专属检查失败，例如干净 Bootstrap HTML 的解析、面包屑、Panel 类型、本地视频 **Muted** 设置或 CMS 区块预览。

页面加载 `dxpr_builder/` 中的构建文件，因此先构建。

1. 安装依赖：

    ```bash
    npm install

    ```
2. 构建编辑器包。CI 脚本按此顺序运行这些任务（`test/scripts/run-fe-tests.sh`）：

    ```bash
    npx grunt concat
    npx grunt exec:gen
    npx grunt babel
    npx grunt terser
    npx grunt sass
    npx grunt postcss

    ```
3. 运行测试：

    ```bash
    npm run fe-test

    ```

    用 `npm run fe-test:headed` 观看浏览器，用 `npm run fe-test:dev` 只提供独立页面不运行断言。

CI 中 `.github/workflows/fe-test.yaml` 通过 Docker 运行同样的测试：

```bash
docker compose --profile fe-test run --rm fe-test

```

## Drush 端到端测试

`scripts/drush-e2e/run-e2e-tests.sh` 在 Composer 容器中用 SQLite 安装全新的 Drupal 11 网站，将模块符号链接进去，启用它，用 `dxpr_builder_text` 格式化器创建 Basic page 内容类型、页面模板和用户模板，再运行每个 `scripts/drush-e2e/test-*.sh` 文件：

| 文件 | 测试的命令 |
|---|---|
| `test-cleartext-key-update.sh` | 更新 9026 清除 Key 模块存储下遗留的明文产品密钥，所选 Key 不存在时保留（`cleartext-key-update.php`） |
| `test-cms-cache-tags.sh` | 区块和视图列表的缓存失效（`cms-cache-tags.php`） |
| `test-elements.sh` | `drush dxb:element:list` |
| `test-migration-summary.sh` | 迁移列摘要的单复数措辞（`migration-summary.php`） |
| `test-migrations.sh` | `drush dxb:migrate` 和内容迁移回归（`migration-regressions.php`） |
| `test-page-controller.sh` | 页面控制器为其路由的构建（`page-controller.php`） |
| `test-page-create.sh` | `drush dxb:page:create` |
| `test-page-get-update.sh` | `drush dxb:page:get`、`drush dxb:page:update` |
| `test-page-module.sh` | Drag and Drop Page 模块装齐它列出的所有配置（`page-module.php`） |
| `test-profile-buttons.sh` | 构建器档案的文本编辑器按钮（`profile-buttons.php`） |
| `test-profile-order.sh` | 哪个档案按权重适用，以及档案列表的顺序（`profile-order.php`） |
| `test-settings-form.sh` | 在 **General Settings** 上保存和验证产品密钥，及其触发的许可证同步（`settings-form.php`） |
| `test-setup-ai.sh` | `drush dxb:setup-ai` |
| `test-templates.sh` | `drush dxb:template:list` |
| `test-user-licenses-page.sh` | 许可证卡片在 **User Licenses** 上显示一次，在 **People** 上仍显示（`user-licenses-page.php`） |
| `test-user-settings.sh` | 每位编辑人员自己的编辑器设置（`user-settings.php`） |
| `test-user-templates.sh` | `drush dxb:user-template:list`、`drush dxb:user-template:create` |

运行全部：

```bash
docker compose --profile drush-e2e run --rm e2e-test

```

传入部分文件名运行单个文件；脚本匹配 `scripts/drush-e2e/test-*<filter>*.sh`：

```bash
docker compose --profile drush-e2e run --rm e2e-test page-create

```

添加测试时，创建 `scripts/drush-e2e/test-<name>.sh`，调用 `section "<Title>"`，并使用 `scripts/drush-e2e/_helpers.sh` 的辅助函数：`assert_success`、`assert_fail`、`assert_eq`、`assert_has`、`assert_not_empty`、`assert_runs` 和 `assert_dry_run`。每个辅助函数接受描述和命令字符串。

CI 中该套件是 `.github/workflows/review.yaml` 的“Run Drush E2E tests”任务。拉取请求更改 `.php`、`.module`、`.inc`、`.install`、`.yml`、`.md`、`composer.json` 或 `composer.lock` 文件时运行。

## Selenium 视觉回归套件

浏览器测试是 `dxpr_maven` 仓库中的 Java TestNG 套件。它们针对 `docker-compose.test.yml` 定义的 Docker 栈（Selenium 中心、Chrome 节点和 Maven 容器），在从本仓库安装的网站上运行。您不从本地检出运行它们；从拉取请求评论触发。`.github/workflows/command-dispatcher.yml` 将评论转为工作流运行。

| 命令 | 套件 | 工作流 |
|---|---|---|
| `/e2e` | `chrome.editor.bs5.parallel.xml` 加匿名 BS5 套件 | `e2e-command.yaml` |
| `/e2e-bs3` | `chrome.editor.bs3.parallel.xml` | `e2e-bs3-command.yml` |
| `/e2eV2` | DXPR CMS 栈上的 BS5 编辑器和匿名套件 | `e2eV2-command.yaml` |
| `/qa-demo-2x-dxpr_theme6x-tests` | 带 DXPR Theme 6.x 的 QA 演示 | `qa-demo-2x-dxpr_theme6x-tests-command.yaml` |

选项见 `CONTRIBUTING.md`：

- `groups=row-element-test,icon-element-test` 运行套件 XML 中命名的 `<test name="...">` 分组。
- `tests=RowColumnLayoutVisualTest` 运行命名的测试类。
- `maven_ref=branch-name` 使用 `dxpr_maven` 分支，构建器改动与其测试更新一起检查的方式。

工作流上传 `target/reports/**` 和截图作为构建产物，并将结果作为评论发到拉取请求，列出失败或只在重试中通过的测试。每个套件任务 90 分钟超时。

## 代码检查与静态分析

每个检查是 Docker Compose 服务，因此除 Docker 外无需本地工具链。

| 服务 | 命令 | 检查内容 |
|---|---|---|
| `drupal-lint` | `docker compose run --rm drupal-lint` | phpcs，PHPCompatibility（PHP 8.3 及以上）、`Drupal` 和 `DrupalPractice` 规范 |
| `drupal-check-D11` | `docker compose run --rm drupal-check-D11` | PHPStan 5 级，带 `mglaman/phpstan-drupal`，全新 `drupal/recommended-project` |
| `eslint` | `docker compose run --rm eslint` | ESLint 覆盖 `js/` 和 `dxpr_builder/build/`，拼写检查覆盖 `dxpr_builder/extracted_t_functions.js` |
| `stylelint` | `docker compose run --rm stylelint` | Stylelint 检查 `dxpr_builder/sass/` 和 `sass/` |
| `rust-lint` | `docker compose run --rm rust-lint` | Clippy 检查 Rust 源码 `rust/` |
| `no-jquery`、`no-underscore`、`html-in-js` | `docker compose run --rm <service>` | 弃用检测器来自 `.github/workflows/deprecations.yml` |

phpcs、ESLint 和 Stylelint 有自动修复变体（`drupal-lint-auto-fix`、`eslint-auto-fix`、`stylelint-auto-fix`）。同样的检查不用 Docker 也可用：`npm run lint:scss`、`npm run lint:no-jquery`、`npm run lint:no-underscore` 和 `npm run lint:html-in-js`。

`npm install` 还安装 Husky pre-commit 钩子（`.husky/pre-commit`）。它对暂存的 JavaScript、PHP 和 SCSS 文件及 Rust 源码运行匹配的自动修复和检查服务，还运行 `docs/video-tools/bin/lint-videos.mjs`（暂存 `docs/` 下的文件时）。

`.github/workflows/review.yaml` 在每个拉取请求上运行匹配改动路径的检查。`.github/workflows/main.yaml` 在每次推送时运行 `drupal-lint`、`eslint`、`drupal-check-D11` 和 `rust-lint`（推送到 `3.x` 时）。两者在检查失败时让构建失败，并写带问题文件的摘要。

## 接下来做什么？

- [参与贡献](/zh-hans/hc/documentation/learn-dxpr-builder/development/contributing)：拉取请求流程和测试更新的 `maven_ref` 工作流。
- [Drush 命令](/zh-hans/hc/documentation/learn-dxpr-builder/development/drush-commands)：Bash 套件练习的命令。