我可以忽略“离开站点”吗?使用 Puppeteer 浏览无头时的对话框?

dyo*_*ung 5 javascript dialog google-chrome node.js puppeteer

我正在使用 Puppeteer 在网站上测试一些表单。当我运行测试时,我注意到尝试在页面之间导航时执行会卡住。我自己手动进行了一次试运行,并意识到该页面正在发出一个对话框,因为某些表单输入已更改而未提交表单。

这条消息说:

Leave site?
Changes you made may not be saved.
Run Code Online (Sandbox Code Playgroud)

有一些明显的解决方法,例如我可以确保每次导航到下一页之前都提交表单。但是,理想情况下,我希望能够完全忽略此对话框,因为我只是在运行测试,并且我不在乎更改是否会被保存。

有没有办法禁用这些消息?如果没有,有没有办法检查是否有一个对话框打开然后将其关闭?

小智 6

尝试通过 puppeteer 设置 window.onbeforeunload = null

await page.evaluate(() => {
  window.onbeforeunload = null;
});
Run Code Online (Sandbox Code Playgroud)


ggo*_*len 3

为了详细说明现有的答案beforeunload您尝试处理的事件会导致出现对话框提示。该对话框的处理方式与prompts 和alerts 相同,带有page.on("dialog", dialog => ...)

dialog可以检查传递给处理程序的对象的类型,"beforeunload" 然后您可以根据您想要的行为调用dismiss()或。停留在当前页面,中止导航操作,同时同意离开网站。accept()dismiss()accept()

您可能的解决方案是同意离开该网站accept()

const puppeteer = require("puppeteer");

let browser;
(async () => {
  const html = `
    <h1>a page that prompts before unload</h1>
    <script>
    window.addEventListener("beforeunload", function (e) {
      e.preventDefault();
      (e || window.event).returnValue = "";
      return "";
    });
    </script>
  `;
  browser = await puppeteer.launch({headless: false});
  const [page] = await browser.pages();

  const acceptBeforeUnload = dialog => 
    dialog.type() === "beforeunload" && dialog.accept()
  ;
  page.on("dialog", acceptBeforeUnload); 

  await page.setContent(html);

  await page.goto("https://www.example.com");
  console.log(page.url()); // => => https://www.example.com
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close())
;
Run Code Online (Sandbox Code Playgroud)

window.beforeunload = null请注意,使用现有答案的简单设置回调的方法evaluate不适用于此页面。您可以通过删除page.on并添加evaluate上面的调用来测试这一点page.goto

然而,对于更复杂的行为,例如动态启用和禁用卸载,该evaluate方法似乎有助于避免中止抛出以及删除解雇处理程序,如本示例所示:

const puppeteer = require("puppeteer");

let browser;
(async () => {
  const html = `
    <h1>a page that prompts before unload</h1>
    <script>
    window.addEventListener("beforeunload", function (e) {
      e.preventDefault();
      (e || window.event).returnValue = "";
      return "";
    });
    </script>
  `;
  browser = await puppeteer.launch({headless: false});
  const [page] = await browser.pages();

  const dismissBeforeUnload = dialog => 
    dialog.type() === "beforeunload" && dialog.dismiss()
  ;
  page.on("dialog", dismissBeforeUnload); 

  await page.setContent(html);

  // throws Error: net::ERR_ABORTED at https://www.example.com
  await page.goto("https://www.example.com").catch(() => {});
  console.log(page.url()); // => about:blank

  // add to avoid Error: net::ERR_ABORTED when adding a new handler
  await page.evaluate(() => {
    window.onbeforeunload = null;
  });
  page.off("dialog", dismissBeforeUnload); 
  
  // next unload, we'll accept the dialog
  page.on("dialog", dialog => 
    dialog.type() === "beforeunload" && dialog.accept()
  );
  
  // this navigation will succeed
  await page.goto("https://www.example.com");
  console.log(page.url()); // => https://www.example.com
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close())
;
Run Code Online (Sandbox Code Playgroud)