如何等待按钮被启用并点击木偶操作?

How to wait for a button to be enabled and click with puppeteer?

我有一个包含用户名和密码两个字段的表单。输入用户名后,将启用下一步按钮,一旦我单击它,它就会显示一个密码字段,一旦输入,它就会再次启用下一步按钮。如何在表单更新之间等待按钮启用?

我尝试了以下方法,一个有评论,另一个没有。两者都不适合我。


(async () => {
    const browser = await puppeteer.launch({headless: false});
const page = await browser.newPage();
await page.goto('http://localhost:9000/start#!');

await page.type('#login-form-un-field', 'xxxx')
// await page.waitForTarget('#default-next-btn:not([disabled])')
await page.$eval('#default-next-btn:not([disabled])', elem => elem.click());
// const btnNext = await page.$('#default-next-btn');
// btnNext.click();
await page.type('login-form-passcode', '1234');
await page.click('#default-next-btn');
await browser.close();
})();```

Thanks for the help in advance.

Edit: the button is always present on the page. It is just disabled while form entries are being validated.

正确的方法是使用await page.waitFor(selector)。有关详细信息,请查看文档 here

// First you wait for button to appear on screen
await page.waitFor('#default-next-btn');

// Then you click it
await page.click('#default-next-btn');

你可以使用 await page.waitForSelector(selector) => docs

您的代码变为:

(async () => {

    const browser = await puppeteer.launch({headless: false});
    const page = await browser.newPage();
    await page.goto('http://localhost:9000/start#!');

    await page.type('#login-form-un-field', 'xxxx')

    await page.waitForSelector('YOUR_SELECTOR_1')
    await page.click('YOUR_SELECTOR_1')

    await page.type('login-form-passcode', '1234');

    await page.waitForSelector('YOUR_SELECTOR_2')
    await page.click('YOUR_SELECTOR_2')

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

等待按钮(或输入)不再被禁用,即 <button id="id" disabled> 在传递给 waitForSelector.

的选择器字符串中使用 :not([disabled])

示例:

page.waitForSelector('button#id:not([disabled])');

我遇到了这个问题,但找不到任何解决方案。所以我正在检查要重复启用的按钮

// Using Typescript but you can remove the Types to make it JS :)

function runRepeatedly(callback: () => Promise<boolean>, options?: TOptions) {
  return new Promise((resolve, reject) => {
    let totalTime = 0;
    const interval = options?.interval || 2000;
    const maxLimit = options?.maxLimit || 50000;
    const id = setInterval(async () => {
      const isDisabled = await callback();
      totalTime += interval;
      if (!isDisabled) {
        clearInterval(id);
        resolve();
      }
      if (totalTime === maxLimit) {
        clearInterval(id);
        reject("Max time reached");
      }
    }, interval);
  });
}

下面是你如何使用它

try {
    await runRepeatedly(async function () {
      const response = (await page.evaluate(
        `document.querySelector("button").hasAttribute("disabled")`,
      )) as boolean;
      return response;
    });
} catch (err) {
  // Handle the error here 
  console.error("Error", err);
}

希望对你有帮助

我通过查询 class 列表对象完成了它,其中 returns 所有 classes 包括 'disabled'

await page.waitForSelector('#buttonId') 
const isDiabled = await page.evaluate(() =>
      document
        .querySelector('#buttonId')
        .classList.contains('disabled')
    )

将 isDisabled 值设置为 false 后,您可以继续执行后续步骤。当测试人员只想创建一个测试来检查屏幕上显示的对象是否被禁用时,此解决方案很有用。