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

如何为Puppeteer编写自定义命令?原Nightwatch.js用户咨询

How to Create Custom "Commands" in Puppeteer (Like Nightwatch.js)

Great question! Coming from Nightwatch.js where custom commands let you wrap repetitive workflows into clean, reusable calls like browser.myCustomCommand(), it makes total sense to want the same convenience with Puppeteer. The good news is you absolutely can do this—here are two straightforward approaches:

1. Extend Puppeteer's Page Prototype

This is the closest analog to Nightwatch's custom commands, since it adds your method directly to every Page instance, letting you call page.commonAction() just like native methods.

const puppeteer = require('puppeteer');

// Add your custom method to the Page prototype
puppeteer.Page.prototype.commonAction = async function() {
  // Replace with your actual workflow
  await this.click('#primary-button');
  await this.waitForSelector('.success-message');
  const messageText = await this.$eval('.success-message', el => el.textContent);
  console.log(`Action completed: ${messageText}`);
};

// Use the custom method in your script
(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://your-app.com');

  // Call your custom command just like any native Page method
  await page.commonAction();

  await browser.close();
})();

Note: Be careful with method names—avoid using names that might conflict with future Puppeteer updates (check the official Page docs for existing methods first).

2. Create a Wrapper Class (Cleaner for Large Projects)

If you prefer not to modify the global Page prototype (a common best practice to avoid conflicts), wrap the Puppeteer Page instance in your own class with custom methods. This keeps your code modular and isolated.

const puppeteer = require('puppeteer');

class CustomPage {
  constructor(page) {
    // Wrap the native Page instance
    this.page = page;
    // Optionally bind native methods to keep your API consistent
    this.goto = page.goto.bind(page);
    this.waitForSelector = page.waitForSelector.bind(page);
  }

  // Your custom "command"
  async commonAction() {
    await this.page.click('#primary-button');
    await this.page.waitForSelector('.success-message');
    return this.page.$eval('.success-message', el => el.textContent);
  }

  // Another example: a reusable form-filling method
  async fillLoginForm(username, password) {
    await this.page.type('#username', username);
    await this.page.type('#password', password);
    await this.page.click('#login-submit');
    await this.page.waitForNavigation();
  }
}

// Usage
(async () => {
  const browser = await puppeteer.launch();
  const rawPage = await browser.newPage();
  const page = new CustomPage(rawPage);

  await page.goto('https://your-app.com/login');
  await page.fillLoginForm('test-user', 'secure-password');
  const successMsg = await page.commonAction();

  console.log(successMsg);
  await browser.close();
})();

Key Difference from evaluate()

You mentioned looking into evaluate()—that runs code inside the browser's JavaScript context, while these custom methods run in your Node.js context, controlling the browser through Puppeteer's API. This is exactly like how Nightwatch commands work: you're orchestrating browser actions from your test script, not injecting code into the page itself.

Both approaches let you wrap repetitive tasks into reusable, readable calls—pick the one that fits your project's structure best!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:34:44