# @cucumber/playwright 中文文档

规范地址：https://npmcn.com/package/%40cucumber/playwright/

版本：3\.1\.0
npm 元数据更新时间：2025-09-17T21:16:46.129Z
中文译文更新时间：2026-11-11T04:37:19.452Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cucumber/playwright
原文对照：https://npmcn.com/package/%40cucumber/playwright/?lang=original
项目主页：https://github.com/cucumber/playwright.js#readme
源码仓库：https://github.com/cucumber/playwright.js

弃用说明：Use @cucumber/screenplay instead

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：55.4 kB，42 个文件
- 模块格式：CommonJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- peer 依赖：@cucumber/cucumber ^7\.0\.0
- 首次发布：2021-07-07T10:54:58.211Z
- 最新版本发布：2021-07-07T11:03:21.667Z
- 近 30 天下载量：4132（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：2（近 12 个月 0 个）

## 中文简介

用 Cucumber.js 写更好的情景

## 安装

```sh
npm install @cucumber/playwright
```

也可以使用：`pnpm add @cucumber/playwright`、`yarn add @cucumber/playwright`、`bun add @cucumber/playwright`

## README

# @cucumber/ playwright (中文(简体) )

[![CI](https://github.com/cucumber/playwright.js/actions/workflows/ci.yml/badge.svg)](https://github.com/cucumber/playwright.js/actions/workflows/ci.yml)

Cucumber Playwright 是一个小型的图书馆, 用于 [黄瓜.js](https://github.com/cucumber/cucumber-js/) 能够更好 验收测试(Gherkin 情景):

-   QQ 运行的全装验收测试 **毫秒**
-   \* 鼓励比较容易单独测试的松绑系统组件
-   QQ 以多种方式集合系统组件, 这样您就可以优化 **速度** 或者说 **测试覆盖率**
-   可读的情景描述 **什麽** 代替 **怎么样**
-   • 可维护的自动化代码

见 [贷方](https://npmcn.com/package/%40cucumber/playwright/#readme-credits) 章节,介绍启发此库的先前工作的细节.

当您使用 Cucumber Playwright 时,您的步骤定义通常是单行道:

```typescript
When('{actor} logs in successfully', async function (actor: Actor) {
  await actor.attemptsTo(logIn(`${actor.name}@test.com`, 'valid-password'))
})
```

您可以提供几种执行方式: `logIn` - 一个与用户界面交互,但 _(单位:千美元)_ 一个 与 API 层交互 _内侧_ 通过直接函数调用或HTTP请求的用户界面.

这迫使您在“ 填充字段” 和“ 点击按钮” 等情景中避免使用UI 语言, 因为它不能使 觉得应该这样 `logIn` 不使用UI的执行。 同样,它迫使你避免使用HTTP 语言如"执行HTTP POST /login",因为这样做在其中没有意义 `logIn` 执行 使用UI.

这些限制鼓励您写作 _可读_ 描述 _用户可以做什么_ 狂风比 _您的系统是如何执行的_.你的场景变成活的文件 所有人都能理解 团队.

## 大会

有了Cucumber Playwright,你就可以演化出一个接受测试套件,用多种配置来运行,或者 _集会_编辑 [组装图](https://github.com/subsecondtdd/assembly-diagrams#readme) 下级 说明如何:

-   ![#FFB000](https://via.placeholder.com/15/FFB000/000000?text=+) 测试组件
-   ![#DC267F](https://via.placeholder.com/15/DC267F/000000?text=+) 基础设施构成部分
-   ![#648FFF](https://via.placeholder.com/15/648FFF/000000?text=+) 生产部件

| DOM - HTTP - 域名 | DOM 域 | HTTP 域 | 域名 |
| --- | --- | --- | --- |
| ![DOM-HTTP-Domain](https://npmcn.com/package/%40cucumber/playwright/images/dom-http-domain.svg) | ![DOM-Domain](https://npmcn.com/package/%40cucumber/playwright/images/dom-domain.svg) | ![HTTP-Domain](https://npmcn.com/package/%40cucumber/playwright/images/http-domain.svg) | ![Domain](https://npmcn.com/package/%40cucumber/playwright/images/domain.svg) |

## 安装

首先,将库添加到您的项目中:

```
npm install @cucumber/playwright --save-dev
```

## 使用量

这个向导会带你们走过去 `@cucumber/playwright` 。 步骤。 详情请参见: 转到 `features` 目录(也是本库的验收测试).

### 演员

核心概念 `@cucumber/playwright` 这是 `Actor`。一个演员对象代表用户与 系统.

为了从您步骤定义中访问演员对象, 您首先需要定义 `{actor}` [参数类型](https://cucumber.io/docs/cucumber/cucumber-expressions/#parameter-types)。 。 。 .

创建名为的文件 `features/support/World.ts` (如果你还没有获得)并添加以下代码:

```typescript
import { defineParameterType, setWorldConstructor } from '@cucumber/cucumber'
import { ActorWorld, ActorParameterType } from '@cucumber/playwright'

// Define an {actor} parameter type that creates Actor objects
defineParameterType(ActorParameterType)

// Define your own World class that extends from ActorWorld
export default class World extends ActorWorld {
}
setWorldConstructor(World)
```

您的步法定义将会通过 `Actor` 对象用于 `{actor}` 参数,例如:

```gherkin
When Martha logs in
```

```typescript
When('{actor} logs in', async function (actor: Actor) {
  // The logIn() function is an Interaction
  await actor.attemptsTo(logIn(`${actor.name}@test.com`, 'valid-password'))
})
```

继续阅读以学习如何定义 _互动_。 。 。 .

### 与系统的互动

现在你的步法定义可以通过 `Actor` 对象,我们需要定义 `Interaction`s,演员可以使用 改为 _交互_ 与系统.

交互是返回另一个函数的函数 `Actor` 参数.

添加以下内容到 `features/support/interactions/logIn.ts`数字 :

```typescript
type LogIn = (email: string, password: string) => Interaction<Promise<string>>

export const logIn: LogIn = (email, password) => {
  return async (actor: Actor) => {
    // Just a dummy implementation for now - we'll come back and flesh this out later
    return '42'
  }
}
```

在步骤定义中,我们现在可以导入此交互:

```typescript
import { logIn } from '../support/interactions/logIn'

When('{actor} logs in', async function (actor: Actor) {
  const userId = await actor.attemptsTo(logIn(`${actor.name}@test.com`, 'valid-password'))
})
```

#### 互动和问题

何况 `Actor#attemptsTo` 还有一个 `Actor#ask` 方法。 它的签名完全一样 行为作为 `Actor#attemptsTo`。它经常使您的代码更容易读取 `Actor#attemptsTo` 在你身边 `When` 步骤定义 _修改_ 系统状态,以及 `Actor#ask` 内 `Then` 步骤定义 那个 _查询_ 系统状态.

例如:

```typescript
export type InboxMessages = () => Interaction<readonly string[]>

export const inboxMessages: InboxMessages = (userId) => {
  return (actor: Actor) => {
    return ['hello', 'world'] 
  }
}
```

在步骤定义中:

```typescript
import { inboxMessages } from '../support/interactions/inboxMessages'

Then('{actor} should have received the following messages:', function (actor: Actor, expectedMessages: DataTable) {
  const receivedMessages = actor.ask(inboxMessages())
  assert.deepStrictEqual(receivedMessages, expectedMessages.rows.map(row => row[0]))
})
```

### 使用不同的互动执行

往往可以采取多种方式实施同样的互动。 这允许你 通过快速反馈逐步建立新的功能.

例如,您可能正在研究允许用户登录的新要求。 你可以开始 在您执行 HTTP 层或周围的 UI 之前, 仅构建服务器侧域逻辑 快速反馈随着你的进展.

稍后,你可以再次运行相同的情景, 但这次交换您的交互 执行 使 HTTP 请求或与 DOM 交互 - 不更改任何代码.

如果你看着 [包含在此重播中的高喊示例](https://npmcn.com/package/%40cucumber/playwright/features)你会看到,我们组织 我们在两个目录中的相互作用:

```
features
├── hear_shout.feature
└── support
    └── interactions
        ├── dom
        │   ├── inboxMessages.ts
        │   ├── moveTo.ts
        │   └── shout.ts
        └── session
            ├── inboxMessages.ts
            ├── moveTo.ts
            └── shout.ts
```

为了在运行时决定使用何种交互执行,您可以使用 _交互加载器_ 提供 内 `@cucumber/playwright`数字 :

```typescript
import { setWorldConstructor } from '@cucumber/cucumber'
import { ActorWorld, defineActorParameterType, Interaction } from '@cucumber/playwright'
import { InboxMessages, Shout, StartSession } from './interactions/types'

export default class World extends ActorWorld {
  public startSession: StartSession
  public shout: Shout
  public inboxMessages: InboxMessages
}
setWorldConstructor(World)

Before(async function (this: World) {
  // Loads this.startSession, this.shout and this.inboxMessages
  await this.loadInteractions()
})
```

这个 `await this.interaction(...)` 调用将从基于 数值 `interactions` [世界参数](https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/world.md#world-parameters), (中文(简体) ), 定义 `./cucumber.js` 配置文件 .

如果你使用这种技术,你还需要调整你的步骤定义,以参考来自 _世界_ (单位:千美元)`this`:

```typescript
When('{actor} shouts {string}', async function (this: World, actor: Actor, message: string) {
  await actor.attemptsTo(this.shout(message))
})
```

### 步骤之间共享数据

你的演员们有权力 `remember` 财务报告和审定财务报表 `recall` 数据在步间。 例如:

```typescript
When('{actor} logs in', async function (actor: Actor<World>) {
  const userId = await actor.attemptsTo(logIn(`${actor.name}@test.com`, 'valid-password'))
  actor.remember('userId', userId)
})

Then('{actor} should be logged in', function (actor: Actor) {
  assert.ok(actor.recall('userId'))
})
```

您也可以将函数传递给 `remember` 以纪念一个值 :

```typescript
function getSomething(actor: Actor) {
  actor.recall('something', () => ({ foo: 'bar' }))
}

// The same object is returned every time
assert.strictEqual(getSomething(actor), getSomething(actor))
```

**说明:** 记录的数据范围为: `Actor`,所以你不能访问一个演员从另一个演员中记住的数据 一个 你可以让多个演员用同一个密钥存储不同的数据. 每个 `Actor` 在结尾处丢弃 每一个情景,所以你将无法 `recall` 任何来自之前的情景.

### 从行为者处接触世界

如果您的交互需要访问数据 `world`他们可以通过 `Actor#world` 属性。 狦琌 为此,您还应声明互动执行中角色的通用类型:

```typescript
export const moveTo: MoveTo = (coordinate) => {
  // We're declaring the World type of the actor so that we can access its members
  return async (actor: Actor<World>) => {
    actor.world.shouty.moveTo(actor.name, coordinate)
  }
}
```

### 同步行为和最终的一致性

在分布式系统中,行动结果在整个系统中传播可能需要一段时间.

例如,在聊天应用程序中,当一个用户发送消息时,可能要花上几毫秒的时间才能到达 其他用户收到消息,因为它通过网络行走,即使它都在你的机器上.

在这样的情况下,你可以使用 `eventually` 函数以定期检查特定条件:

```typescript
Then('{actor} hears {actor}’s message', async function (this: World, listener: Actor<World>, shouter: Actor) {
  const shouterLastMessage = shouter.recall('lastMessage')

  await eventually(() => {
    const listenerMessages = listener.ask(this.inboxMessages())
    assert.deepStrictEqual(listenerMessages, [shouterLastMessage])
  })
})
```

这个 `eventually` 函数接受单个参数 - 零参数 `condition` 函数。 如果 `condition` 函数 丢出一个错误, 它会在常规中再次被调用 `interval` 直到它没有例外. 如果它不通过或完成在一个 `timeout` 时,会显示超时出错.

默认 `interval` 实值 `50ms` 默认 `timeout` 实值 `1000ms`。这可以用一秒钟取代 `{ interval: number, timeout: number }` 参数 `condition`。 。 。 .

## 高级配置

以下是一些更高级配置的准则.

### 使用承诺

默认类型 `Interaction` 实值 `void`。如果您的系统是同步的 (即用途) `async` 函数返回 a `Promise`),可以使用 `PromiseInteraction` 类型代替 `Interaction`。 。 。 .

### 使用明确的演员查询

如果无法延长 `ActorWorld`,您可以添加一个 `ActorLookup` 字段到您这样的现有世界类:

```typescript
import { ActorLookup } from '@cucumber/playwright'

class World {
  private readonly actorLookUp = new ActorLookup()

  public findOrCreateActor(actorName: string): Actor<World> {
    return this.actorLookUp.findOrCreateActor(this, actorName)
  }
}
```

### 覆盖演员 Paremeter 类型选项

这个 `defineParameterType(ActorParameterType)` 函数调用定义命名的参数类型 `{actor}` 默认, 它使用 RegExp `/[A-Z][a-z]+/` (一作入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入入.

如果您想要使用不同的名称或正则表达式, 您可以覆盖这些默认 :

```typescript
defineParameterType({ ...ActorParameterType, name: 'acteur' })
defineParameterType({ ...ActorParameterType, regexp: /Marcel|Bernadette|Hubert/ })
defineParameterType({ ...ActorParameterType, name: 'acteur', regexp: /Marcel|Bernadette|Hubert/ })
```

## 设计建议

当你合作的时候 `@cucumber/playwright` 我们建议你们只用两层 互动执行:

-   `dom` 用于使用 DOM 的相互作用
-   `session` 用于使用 `Session`

A 类 `Session` 代表一个与您的系统有互动会话的用户(参与者). A 类 `Session` 将通常使用 在代码的两个位置:

-   从你的 `session` 互动
-   从您的 UI 代码( React/Vue 组件等)

`Session` 是一个针对您执行的界面,您应当执行您自己。 您的用户界面代码 将使用它与服务器交互。 这种对关切的区分使网络实施细节无法用于 血液进入UI代码.

你通常有两次执行 `Session` 接口 - `HttpSession` 财务报告和审定财务报表 `ShoutySession`。 。 。 .

这个 `HttpSession` 也就是你将所有 `fetch`, (中文(简体) ), `WebSocket` 财务报告和审定财务报表 `EventSource` 逻辑 这是班级 你的UI会用于生产。 你也会在测试中使用它.

这个 `ShoutySession` 是直接与服务器侧域层交谈并直接调用函数的操作 (不设任何网络). 这一实施将仅用于测试.

通过这种方式组织你的代码,你有四种方式 你可以运行你的"木瓜假想".

-   `session` 使用 `ShoutySession` (快速测试,域层覆盖)
-   `session` 使用逗号 `HttpSession` (较慢的测试,http+域层覆盖)
-   `dom` 使用 `ShoutySession` (较慢的测试,UI+域层覆盖)
-   `dom` 使用 `HttpSession` (最慢测试,UI+http+域层覆盖)

我们用的例子 [世界参数](https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/world.md#world-parameters) 控制如何与系统互动以及系统如何组装.

## 贷项

这个图书馆的灵感来自 _剧作家_ 模式.

-   [Beyond Page Objects: 下一代测试 带有宁静和 Playwright 模式的自动化](https://www.infoq.com/articles/Beyond-Page-Objects-Test-Automation-Serenity-Playwright/) 由安迪·帕尔默,安东尼·马尔卡诺,约翰·弗格森·斯马特和扬·莫拉克出演
-   [静态/静态](https://serenity-js.org/) - JavaScript/TypeScript首次由Jan Molak执行 Playwright 模式
-   [剧作家模式](https://serenity-js.org/handbook/thinking-in-serenity-js/Playwright-pattern.html) 如扬·莫拉克所描述的
-   [理解剧作家](https://cucumber.io/blog/bdd/understanding-Playwright-\(part-1\)/) - Matt Wynne的博客系列

这个库旨在提供一个比原Playwright模式更温和的学习曲线,因此有些概念如: _能力_ 财务报告和审定财务报表 _任务_ 被排除在外.

## 常见问题

### @cucumber/playwright 是什么？

用 Cucumber\.js 写更好的情景注意：该包已被作者标记为弃用——Use @cucumber/screenplay instead

### 如何安装 @cucumber/playwright？

在项目目录运行 npm install @cucumber/playwright，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@cucumber/cucumber（^7\.0\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @cucumber/playwright 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @cucumber/playwright 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @cucumber/playwright 可以商用吗？

@cucumber/playwright 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @cucumber/playwright 的下载量有多少？

根据 npm 官方下载统计，@cucumber/playwright 在 2026/10/11 – 2026/11/09 这 30 天内被下载 4,132 次，日均约 138 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @cucumber/playwright 还在维护吗？

最新版本 3\.1\.0 发布于 2021/07/07（5 年前）；至今共发布 2 个版本，其中过去 12 个月发布了 0 个；首次发布于 2021/07/07。作者已将其标记为弃用，新项目建议寻找替代方案。

