You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在VS Code中用Playwright+Cucumber+TypeScript结合POM搭建自动化项目

Playwright + Cucumber + POM + TypeScript 完整实现方案

一、标准项目文件夹结构

playwright-cucumber-pom-ts/
├── features/                # Cucumber Feature文件(按业务模块划分)
│   ├── auth/
│   │   └── login.feature
│   └── dashboard/
│       └── dashboard_navigation.feature
├── src/
│   ├── pages/               # POM页面类(封装页面元素与操作)
│   │   ├── basePage.ts      # 基础页面类,封装通用操作
│   │   ├── loginPage.ts
│   │   └── dashboardPage.ts
│   ├── step-definitions/    # 步骤定义文件(与Feature一一对应)
│   │   ├── authSteps.ts
│   │   └── dashboardSteps.ts
│   ├── test-data/           # 测试数据文件(按模块分类存储)
│   │   ├── authData.json
│   │   └── dashboardData.json
│   ├── utils/               # 工具类(数据读取、通用方法)
│   │   └── testDataUtils.ts
│   └── cucumber.conf.ts     # Cucumber核心配置
├── playwright.config.ts     # Playwright配置
├── package.json
└── tsconfig.json

二、端到端实现流程

1. 初始化项目与安装依赖

npm init -y
# 安装Playwright核心依赖
npm install @playwright/test playwright
# 安装Cucumber与TypeScript相关依赖
npm install @cucumber/cucumber typescript ts-node @types/node @types/cucumber --save-dev

2. 配置TypeScript与Cucumber

tsconfig.json(TypeScript编译配置):

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*", "features/**/*"]
}

cucumber.conf.ts(Cucumber执行配置):

import { defineConfig } from '@cucumber/cucumber';

export default defineConfig({
  requireModule: ['ts-node/register'],
  require: ['src/step-definitions/**/*.ts'],
  paths: ['features/**/*.feature'],
  format: ['progress-bar', 'html:cucumber-report.html'], // 生成测试报告
});

3. 编写POM页面类

先封装BasePage(通用操作复用):

import { Page, Locator } from '@playwright/test';

export class BasePage {
  protected page: Page;

  constructor(page: Page) {
    this.page = page;
  }

  async waitForElement(locator: Locator): Promise<void> {
    await locator.waitFor({ state: 'visible' });
  }

  async clickElement(locator: Locator): Promise<void> {
    await this.waitForElement(locator);
    await locator.click();
  }

  async fillElement(locator: Locator, text: string): Promise<void> {
    await this.waitForElement(locator);
    await locator.fill(text);
  }

  async navigateTo(url: string): Promise<void> {
    await this.page.goto(url);
  }
}

再编写业务页面类,比如LoginPage(继承BasePage):

import { Page } from '@playwright/test';
import { BasePage } from './basePage';

export class LoginPage extends BasePage {
  // 页面元素定位
  private readonly usernameInput = this.page.locator('#username');
  private readonly passwordInput = this.page.locator('#password');
  private readonly loginButton = this.page.locator('button[type="submit"]');

  constructor(page: Page) {
    super(page);
  }

  // 封装页面操作
  async login(username: string, password: string): Promise<void> {
    await this.fillElement(this.usernameInput, username);
    await this.fillElement(this.passwordInput, password);
    await this.clickElement(this.loginButton);
  }

  async navigateToLoginPage(): Promise<void> {
    await this.navigateTo('/login');
  }
}

4. 编写Feature文件

用Gherkin语法描述测试场景(features/auth/login.feature):

Feature: User Login Functionality
  As a user
  I want to log into the application
  So that I can access the dashboard

  Scenario: Successful login with valid credentials
    Given I am on the login page
    When I enter valid username and password
    And I click the login button
    Then I should be redirected to the dashboard

  Scenario Outline: Failed login with invalid credentials
    Given I am on the login page
    When I enter username "<username>" and password "<password>"
    And I click the login button
    Then I should see error message "<errorMsg>"

    Examples:
      | username   | password    | errorMsg                      |
      | wrong_user | wrong_pass  | Invalid username or password |
      | test_user  | wrong_pass  | Invalid username or password |

5. 编写步骤定义

对应Feature中的Gherkin语句,串联POM操作(src/step-definitions/authSteps.ts):

import { Given, When, Then } from '@cucumber/cucumber';
import { LoginPage } from '../pages/loginPage';
import { DashboardPage } from '../pages/dashboardPage';
import { getAuthData } from '../utils/testDataUtils';

let loginPage: LoginPage;
let dashboardPage: DashboardPage;

Given('I am on the login page', async function () {
  loginPage = new LoginPage(this.page); // 通过this获取Playwright Page实例
  await loginPage.navigateToLoginPage();
});

When('I enter valid username and password', async function () {
  const validUser = getAuthData('validUser');
  await loginPage.login(validUser.username, validUser.password);
});

When('I enter username {string} and password {string}', async function (username, password) {
  await loginPage.login(username, password);
});

When('I click the login button', async function () {
  await loginPage.clickElement(loginPage['loginButton']);
});

Then('I should be redirected to the dashboard', async function () {
  dashboardPage = new DashboardPage(this.page);
  await dashboardPage.waitForElement(dashboardPage['dashboardHeader']);
});

Then('I should see error message {string}', async function (errorMsg) {
  await this.page.locator(`text=${errorMsg}`).waitFor();
});

6. 配置测试运行命令

在package.json中添加脚本:

"scripts": {
  "test": "cucumber-js --config src/cucumber.conf.ts",
  "test:headed": "cucumber-js --config src/cucumber.conf.ts --headed", // 可视化运行
  "test:report": "cucumber-js --config src/cucumber.conf.ts --format html:cucumber-report.html"
}

三、Feature与步骤定义的集成规则

  • 步骤定义通过Given/When/Then装饰器匹配Feature中的Gherkin语句,支持精确字符串匹配或正则匹配
  • Cucumber会自动扫描cucumber.conf.ts中require字段指定目录下的步骤定义文件,自动关联Feature中的步骤
  • 步骤定义中的this.page是Playwright与Cucumber集成后注入的全局Page实例,无需手动创建

四、步骤定义中运用POM实现复用与维护

  • 所有页面元素定位和操作都封装在POM页面类中,步骤定义只做流程串联,不写具体DOM操作
  • 当页面元素或交互逻辑变更时,仅需修改对应的POM页面类,无需改动步骤定义和Feature文件
  • 通用操作(如等待元素、点击、输入)统一封装在BasePage中,所有业务页面类继承BasePage实现复用

五、测试数据的使用与维护

1. 测试数据存储

按业务模块分类存储在JSON文件中(src/test-data/authData.json):

{
  "validUser": {
    "username": "test_user",
    "password": "test_pass123"
  },
  "lockedUser": {
    "username": "locked_user",
    "password": "locked_pass"
  }
}

2. 测试数据读取

编写工具类统一读取数据(src/utils/testDataUtils.ts):

import * as fs from 'fs';
import * as path from 'path';

export function getAuthData(userType: string): any {
  const filePath = path.join(__dirname, '../test-data/authData.json');
  const rawData = fs.readFileSync(filePath, 'utf-8');
  return JSON.parse(rawData)[userType];
}

3. 维护规则

  • 测试数据与代码分离,新增/修改数据无需改动业务代码
  • 敏感数据可通过环境变量注入,避免硬编码在JSON文件中
  • 复杂场景可结合Feature的Scenario Outline+Examples表格管理多组测试数据

内容的提问来源于stack exchange,提问作者Jagruti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 10:35:37