☰
AdminJS 的 Cypress 测试辅助模块(adminjs/cy)使用指南:为 Node.js 管理后台编写端到端测试
2026/9/25 17:19:36 网站建设 项目流程
  • 后端
  • 低代码

【免费下载链接】adminjs

AdminJS is an admin panel for apps written in node.js

项目地址:https://gitcode.com/gh_mirrors/ad/adminjs
点击查看免费下载

导读

AdminJS(node.js 应用的管理后台框架)在 cy/cypress.doc.md 中提供了一套专供 Cypress 端到端(E2E)测试使用的辅助模块adminjs/cy。本文以该文档为主体,结合仓库中四个内置命令的实现源码与类型声明,完整讲解如何把该模块引入你的 Cypress 项目、如何用abLogin/abLoginAPI/abKeepLoggedIn/abGetProperty快速完成登录、会话保持与表单字段定位,从而为 AdminJS 管理后台编写稳定、可复用的 E2E 测试用例。

一、adminjs/cy是什么:模块定位与当前状态

根据 cy/cypress.doc.md 的说明,cy是一个收集 Cypress 辅助工具(helpers)的模块,用途是"当你(像 AdminJS 官方一样)用 Cypress 对自己的 AdminJS 管理面板做 E2E 测试时"可以直接复用这些现成的命令。它本身不依赖具体的数据库适配器或业务代码,只关注管理后台的通用交互模式:登录、会话 Cookie 维持、表单属性定位。

需要特别说明的是,文档明确标注了该模块的成熟度:

Cypress helpers project is currently in the WIP/POC phase, that is why there are not much helpers here. But you can expect that gradually we will add more.

即该项目当前仍处于WIP(进行中)/ POC(概念验证)阶段,目前内置命令数量不多,但会逐步扩充。因此在实际项目中使用时,建议把它当作"可扩展的测试基座"而非完备的测试框架——你仍然需要根据自己的资源模型编写大量业务断言。

从仓库目录结构看,模块的入口在 cy/index.js,它通过四行 import 一次性注册了全部四个命令:

import './commands/ab-login.js' import './commands/ab-login-api.js' import './commands/ab-keep-logged-in.js' import './commands/ab-get-property.js'

而 cy/index.d.ts 则提供了对应的 TypeScript 类型声明,供 Cypress 项目获得完整的智能提示。

二、引入模块:在 Cypress 的 support 文件中注册命令

Cypress 的自定义命令必须在测试运行前完成注册,官方推荐的挂载点是cypress/support目录下的入口文件。文档给出的引入方式如下,你可以在以下任意一个文件中写入:

  • /support/index.js
  • /support/commands.js
require('adminjs/cy')

引入之后,四个辅助命令(abLogin、abLoginAPI、abKeepLoggedIn、abGetProperty)就会注册为 Cypress 链式命令,可以在describe / context / it中直接以cy.abLogin(...)的形式调用。

对于 TypeScript 项目,为了让编辑器与 Cypress 的类型检查识别这些命令,还需要在测试文件顶部添加类型引用:

/// <reference types="cypress" /> /// <reference types="adminjs/cy" />

其中adminjs/cy的类型声明来自 cy/index.d.ts,它通过declare namespace Cypress扩展了Chainable接口,使cy.abLogin等调用具备参数类型校验。仓库中该文件的完整声明如下:

declare namespace Cypress { type AbLoginParams = { email?: string; password?: string; loginPath?: string; } type AbKeepLoggedInParams = { cookie?: string; } interface Chainable<Subject> { abLogin(params?: AbLoginParams): Chainable<any>; abLoginAPI(params?: AbLoginParams): Chainable<any>; abGetProperty(propertyPath: string, selector?: string): Chainable<any>; abKeepLoggedIn(params?: AbKeepLoggedInParams): Chainable<any>; } }

可以看到四个命令的签名:前两个接收AbLoginParams(可选 email / password / loginPath),abGetProperty接收属性路径与可选的内层选择器,abKeepLoggedIn接收会话 Cookie 名称。

三、标准测试骨架:登录 + 会话保持 + 页面访问

文档给出了一个完整的测试用例骨架,覆盖"登录 API + 会话保持 + 访问目标页面"的典型流程,原样继承如下:

/// <reference types="cypress" /> /// <reference types="adminjs/cy" /> context('resources/Company/actions/new', () => { before(() => { cy.abLoginAPI({ password: Cypress.env('ADMIN_PASSWORD'), email: Cypress.env('ADMIN_EMAIL') }) }) beforeEach(() => { cy.abKeepLoggedIn({ cookie: Cypress.env('COOKIE_NAME') }) cy.visit('resources/Company/actions/new') }) //... })

这个骨架体现了 AdminJS E2E 测试的两个关键约定:

  1. 登录只需一次(before阶段):通过abLoginAPI直接发 HTTP 请求完成认证,避免每个用例都走一次页面渲染;
  2. 会话在用例间保持(beforeEach阶段):通过abKeepLoggedIn保留会话 Cookie,然后才访问目标路由,如resources/Company/actions/new(对应 AdminJS 的资源新增页)。

把环境变量(如ADMIN_PASSWORD、ADMIN_EMAIL、COOKIE_NAME)从代码中抽离、放进Cypress.env(),是为了避免在测试源码里硬编码凭据,这也是官方示例的推荐做法。

四、内置命令详解

4.1cy.abLogin(options):页面表单登录

实现位于 cy/commands/ab-login.js。它的行为是:访问登录页 → 依次填充[name=email]与[name=password]两个输入框 → 点击按钮提交。

Cypress.Commands.add('abLogin', ({ email, password, loginPath } = {}) => { cy.visit(loginPath || '/login') cy.get('[name=email]').type(email || Cypress.env('AB_EMAIL')) cy.get('[name=password]').type(password || Cypress.env('AB_PASSWORD')) cy.get('button').click() })

参数及默认值如下:

参数说明默认值
email登录邮箱Cypress.env('AB_EMAIL')
password登录密码Cypress.env('AB_PASSWORD')
loginPath登录页路由'/login'

注意两个细节:默认登录路径是/login(AdminJS 默认的登录路由);选择器直接采用 AdminJS 登录表单中固定的name=email/name=password属性。该方法会真实渲染登录页面,属于"UI 驱动"的登录方式,适合需要验证登录页本身的用例(例如对登录表单做回归测试)。

4.2cy.abLoginAPI(options):API 直连登录(推荐)

实现位于 cy/commands/ab-login-api.js。文档明确对比了两者的差异:与abLogin不同,abLoginAPI不会渲染页面,而是直接通过cy.request向登录接口发 POST 请求,以设置会话 Cookie 的方式完成登录。

Cypress.Commands.add('abLoginAPI', ({ email, password, loginPath } = {}) => ( cy.request('POST', loginPath || '/login', { email: email || Cypress.env('AB_EMAIL'), password: password || Cypress.env('AB_PASSWORD'), }) ))

参数与abLogin完全一致(默认AB_EMAIL/AB_PASSWORD/'/login'),但请求体以 JSON 形式携带email与password。由于跳过了页面渲染,它明显更快,适合绝大多数"先登录、再测业务页面"的场景——文档给出的测试骨架正是用它配合abKeepLoggedIn使用。

使用提示:调用后需要在后续用例中配合cy.abKeepLoggedIn保留会话 Cookie,否则每个it()之间的 Cookie 会被 Cypress 默认清空,导致未登录。

4.3cy.abKeepLoggedIn(options):跨用例保持会话

实现位于 cy/commands/ab-keep-logged-in.js,其核心只有一行:

Cypress.Commands.add('abKeepLoggedIn', ({ cookie }) => { Cypress.Cookies.preserveOnce(cookie || Cypress.env('AB_COOKIE_NAME')) })

它调用 Cypress 内置的Cypress.Cookies.preserveOnce,把指定名称的会话 Cookie 在多个测试用例之间保留。参数cookie用于指定会话 Cookie 名,默认取Cypress.env('AB_COOKIE_NAME')。文档在注释中还给出了它在beforeAll场景下的用法示例:

before(() => { cy.abLogin() }) beforeAll(() => { cy.abKeepLoggedIn({ cookie: 'my-session-cookie' }) cy.visit('your/path') })

这也解释了为什么 AdminJS 官方示例要同时使用abLoginAPI+abKeepLoggedIn:前者负责建立会话,后者负责维持会话,二者缺一不可。

4.4cy.abGetProperty(propertyPath, selector?):按属性定位表单字段

实现位于 cy/commands/ab-get-property.js,用于定位 AdminJS 表单中某个属性对应的 DOM 节点:

Cypress.Commands.add('abGetProperty', (path, selector = null) => { let propertySelector = `[data-testid$="-${path}"]` if (selector) { propertySelector = [propertySelector, selector].join(' ') } return cy.get(propertySelector) })

它的核心机制是利用AdminJS 渲染表单时生成的data-testid属性做属性级定位:

  • 基础选择器为[data-testid$="-${path}"],其中$=表示"以……结尾"的属性匹配,path即属性路径(支持点分路径,如嵌套属性);
  • 第二个可选参数selector用于在该属性的包裹容器内继续选择具体元素,例如input[type="checkbox"]、label、option等,最终组合成类似[data-testid$="-isAdmin"] input[type="checkbox"]的选择器。

文档给出的典型用法——针对一个名为isAdmin的属性(在资源配置中形如properties: { isAdmin: {...} })断言其禁用与勾选状态:

cy.abGetProperty('isAdmin', 'input[type="checkbox"]') .should('be.disabled') .should('not.be.checked') cy.abGetProperty('isAdmin', 'label') .click() .should('not.be.checked')

值得说明的是,data-testid的生成逻辑在前端组件中确有对应实现。例如 base-property-component.tsx 中通过data-testid={testId}输出属性级测试标记;array/edit.tsx 中数组属性还额外输出了data-testid={property.path}、data-testid="delete-item"与data-testid={${property.path}-add}等细粒度标记。因此abGetProperty不仅能定位普通属性,也能配合数组、嵌套等复杂属性的编辑控件使用——这也与 cy/readme.md 中针对"Complicated"复杂资源表单的手工测试用例(MRF-1)所覆盖的场景相互印证。

五、把环境变量集中到 Cypress 配置

四个命令默认值均从Cypress.env()读取,因此推荐在 Cypress 配置(cypress.json/cypress.config.ts或系统环境变量)中统一提供:

环境变量用途
AB_EMAIL默认登录邮箱(abLogin/abLoginAPI)
AB_PASSWORD默认登录密码(abLogin/abLoginAPI)
AB_COOKIE_NAME默认会话 Cookie 名(abKeepLoggedIn)

例如在cypress.config.ts的env字段中声明:

export default defineConfig({ e2e: { env: { AB_EMAIL: 'admin@example.com', AB_PASSWORD: 'change-me', AB_COOKIE_NAME: 'adminjs', }, }, })

当然,你完全可以在调用处显式传参覆盖默认值,就像文档示例中那样使用Cypress.env('ADMIN_PASSWORD')、Cypress.env('ADMIN_EMAIL')、Cypress.env('COOKIE_NAME')——这些自定义变量名并不绑定模块内部逻辑,只是把凭据收拢到测试配置的一种方式。

六、扩展方向:把手工用例逐步自动化

与 cy/cypress.doc.md 同目录的 cy/readme.md 记录了三套与 AdminJS 功能强相关的手工测试用例文档:

  • LPF-1 登录页表单:验证有效凭据登录成功并跳转到/admin页面——可直接用abLogin自动化;
  • MRF-1 Mongoose 复杂资源新增:覆盖"String Array / Authors / Parents / Item"等数组与嵌套属性的增删改(涉及Add New Item按钮与 bin 图标交互)——正是abGetProperty+ 数组属性data-testid的用武之地;
  • SRF-1 Sequelize 资源过滤:覆盖Name、Id、User Id下拉、Published At日期范围、Description关键字等过滤交互,以及Apply changes/Reset按钮行为——可围绕 filter.ts 对应的过滤参数体系设计断言。

这些用例虽未标注 Cypress 自动化实现,但可以看作"待自动化"的测试资产清单;结合本文介绍的四个命令,你已经具备把它们落地为 Cypress 用例所需的基础设施。

七、总结

adminjs/cy用四个命令覆盖了 AdminJS 管理后台 E2E 测试最常用的三条路径:UI 登录(abLogin)、API 登录(abLoginAPI)、会话保持(abKeepLoggedIn)与属性定位(abGetProperty)。文档给出的引入方式(在 support 文件中require('adminjs/cy'))与"登录一次、会话贯穿"的骨架可以直接套用;而abGetProperty与前端data-testid体系(参见 base-property-component.tsx、array/edit.tsx)的结合,让表单断言可以精确到单个属性甚至其内部控件。

需要再次强调:该模块仍处于 WIP/POC 阶段,内置命令有限,官方承诺会逐步补充。在正式项目里,建议以这四个命令为起点建立自己的测试辅助层,并留意该模块的后续版本更新。

  • 后端
  • 低代码

【免费下载链接】adminjs

AdminJS is an admin panel for apps written in node.js

项目地址:https://gitcode.com/gh_mirrors/ad/adminjs
点击查看免费下载

相关推荐

上一篇:用 Falco 规则检测容器逃逸:Anthropic-Cybersecurity-Skills 实战工作流指南
下一篇:抢票总手慢?这套大麦自动抢票工具帮你盯开售、挑价位、自动下单

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询