[microsoft/playwright][问题] 点击“表单按钮取消”后,对话框不出现(仅适用于模式-调试)

2024-06-25 930 views
6

测试只能在调试模式下进行,但不能进入,为什么?

单击表单按钮取消后,应该会出现一个警报(您确实要丢弃结果吗?)。测试尝试等待警报但它仅在调试模式下有效。在其他模式下,整个表单都会关闭而不显示警报。为什么?

const {test, expect} = require('@playwright/test');
const myProject = 'demo-project-nuremberg';

test('click form-button-cancel does not show alert ', async ({page}) => {
  //login:
  await page.goto('https://dmitrygozman.fieldcode.com');
  await page.locator('[id="username"]').fill('dgozman.demo@gmail.com');
  await page.locator('[id="password"]').fill('Dgozman123');
  await page.locator('[id="fc-login-button"]').click();

  //open sidebar:
  await page.locator('svg[data-icon="angle-double-right"] >> nth=0').waitFor();
  await page.locator('svg[data-icon="angle-double-right"] >> nth=0').click();

  //click button-create-ticket:
  await page.locator('[id="sidebarMenu"] >> [title="Create ticket"]').waitFor();
  await page.locator('[id="sidebarMenu"] >> [title="Create ticket"]').click();

  //chose project to open form:
  const selector_myproject = '[data-ui-test="ticketCreationProject"] >> text='+myProject+'';
  await page.locator(selector_myproject).waitFor({state:"visible"});
  //await page.locator(selector_myproject).click({delay:1000, force:true});
  await page.locator(selector_myproject).click({delay:1000});

  //check form is open:
  await page.locator('text=Create ticket for project').waitFor({state:"visible"});
  await expect(page.locator('text=Create ticket for project')).toBeVisible;

  //click form-button-cancel:
  /*
  Here is the problem , it works in mode-debug but not --headed ,etc. Why?
  after click ->  await page.locator(buttonCancel).click({delay:500});
  the whole form disappears, without showing the alert-discard-results
  */
  const buttonCancel = 'button:has-text("Cancel")';
  await page.locator(buttonCancel).waitFor({state:"visible"});
  await page.locator(buttonCancel).focus();
  await page.locator(buttonCancel).hover({force:true});
  await page.locator(buttonCancel).click({delay:500});  // What am I doing wrong in this click????

  //ERROR HERE! playwright can't find the dialog locator 
  await page.locator('text=Do you really want to discard the results?').waitFor();
  await page.locator('button:has-text("Yes")').waitFor();
  await page.locator('button:has-text("Yes")').click({delay:500});

  //check form is closed:
  const selector = 'text=Create ticket for project';
  await page.locator(selector).waitFor({state:"detached"});
  await expect(page.locator(selector)).toHaveCount(0);

});

回答

9

请查看这些文档链接:

https://playwright.dev/docs/api/class-dialog

如果警报类型为alert,则需要执行以下操作(从上面的链接):

page.on('dialog', async dialog => {
    console.log(dialog.message());
    await dialog.dismiss(); // you can change the action you need, like `.accept({ promptText: "Yes" }) or `.dismiss()` for cancel actions
  });
0

@ltsuda 谢谢你的信息。但我有几个问题:

  • 为什么在调试模式下工作。行为与标题不同?
  • 我测试了所有代码(没有定位器),它们运行正常,打开对话框等。怎么会这样?嗯,除非 UI 因新的 React 特性而发生任何变化)
0

任何时候。

让我们等待 Playwright 团队的某个人来回答您的问题,因为我只使用该框架进行学习,从未使用过警报 API。

3

@ltsuda 所说的对话框是指 HTML 对话框,而不是普通的警报/确认对话框。


@AngelLopezBellmont 我能够重现它,但尚无法从中获得最小的可重现性。

2

我已经从 v1.17 升级到 v 21.1,我遇到了同样的问题。单击 HTML 按钮后,弹出对话框没有出现。我尝试过较低版本,直到 v1.20。它一直运行到 V1.20。在 V1.21 和 V1.22 上也遇到了这个问题 图像

0

@NagaAppariGlobal 你的问题不同。请提交其他问题,谢谢。

2

@AngelLopezBellmont 对我来说,这更像是应用程序内部的竞争条件。因为如果你在await page.waitForTimeout(500);前面放一个const buttonCancel = 'button:has-text("Cancel")';,它对我来说就起作用了。

7

@mxschmitt 太棒了,你明白了 :)。有了你的新线路,我也一样。现在我们不需要延迟点击或聚焦等,只需简单的点击就可以了(坏消息是 page.waitForTimeout 完全不被鼓励)

....
  //click form-button-cancel:
  /*
  Here is the problem , it works in mode-debug but not --headed ,etc. Why?
  after click ->  await page.locator(buttonCancel).click({delay:500});
  the whole form disappears, without showing the alert-discard-results
  */
  await page.waitForTimeout(500);                 //insert by mxschmitt
  const buttonCancel = 'button:has-text("Cancel")';
  await page.locator(buttonCancel).waitFor({state:"visible"});
  //await page.locator(buttonCancel).focus();
  //await page.locator(buttonCancel).hover({force:true});
  //await page.locator(buttonCancel).click({delay:500}); 
  await page.locator(buttonCancel).click(); 

另一方面, 完全不鼓励使用 await page.waitForTimeout

types.d.ts:

  /**
   * Waits for the given `timeout` in milliseconds.
   *
   * Note that `page.waitForTimeout()` should only be used for debugging. Tests using the timer in production are going to be
   * flaky. Use signals such as network events, selectors becoming visible and others instead.
   *
   * ```js
   * // wait for 1 second
   * await page.waitForTimeout(1000);
   * ```
   *
   * Shortcut for main frame's
   * [frame.waitForTimeout(timeout)](https://playwright.dev/docs/api/class-frame#frame-wait-for-timeout).
   * @param timeout A timeout to wait for
   */
  waitForTimeout(timeout: number): Promise<void>;

在我的代码的其他部分,使用 await this.page.locator(myselector).waitFor({state:"visible"}); 就足够了,但不知何故在这种情况下不起作用。好吧,我想我会破例并仅为此对话框问题添加 page.waitForTimeout(500)。

所以现在,我不知道是否应该关闭该问题并在 Bug 中再次打开它

7

@dgozman 对此有什么想法吗?

6

当然,这是不鼓励的,但(我们猜测)该应用程序的行为很不雅,Playwright 也无法修复它。

如果您能够为我们提供一个较小的再现版本,也许仅以单个 HTML 站点/演示此问题的组件的形式,这将对我们有很大帮助,让我们能够确定 Playwright 是否真的可以修复此问题。

3

@mxschmitt 嗨,抱歉,我没有完全理解你的问题。你指的是有问题的对话框的 html 吗?在上面的例子中,我创建了一个完整的租户来展示问题https://dmitrygozman.fieldcode.com在调试模式下运行上面的小测试,你可以访问整个 html(但也许我没有理解你的问题 :( )

但是好的,我可以在这里粘贴出现问题的 html 对话框 https://user-images.githubusercontent.com/12471931/169382229-87fac31c-71d6-4048-905d-00d7e101b4f0.png

button which trigger the dialog:
<button class="MuiButtonBase-root MuiButton-root MuiButton-text jss147 jss1309 jss1012 jss151 jss1312 jss155 MuiButton-textSecondary MuiButton-textSizeLarge MuiButton-sizeLarge" tabindex="0" type="button">
  <span class="MuiButton-label">Cancel</span>
</button>

problematic dialog:
<div class="MuiDialog-container MuiDialog-scrollPaper" role="none presentation" tabindex="-1" style="opacity: 1; transition: opacity 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;">
  <div class="MuiPaper-root MuiDialog-paper jss1324 jss1318 jss1322 MuiDialog-paperScrollPaper MuiDialog-paperWidthSm MuiPaper-elevation24 MuiPaper-rounded" role="dialog">
    <div class="jss1326">
      <div class="jss1329 jss1316"><span class="jss1336">Discard results</span></div>
      <div class="jss1332 jss1317"></div>
    </div>
    <div class="MuiDialogContent-root jss1330 jss1337">
      <div class="jss1320">Do you really want to discard the results?</div>
    </div>
    <div class="MuiDialogActions-root jss1334 jss1319 MuiDialogActions-spacing">
      <button
          class="MuiButtonBase-root MuiButton-root jss1335 MuiButton-text jss147 jss1338 jss149 jss1339 MuiButton-textPrimary"
          tabindex="0" type="button"><span class="MuiButton-label">Yes</span></button>
      <button class="MuiButtonBase-root MuiButton-root jss1335 MuiButton-text jss147 jss1345 jss151 jss1348 MuiButton-textSecondary" tabindex="0" type="button"><span class="MuiButton-label">No</span></button>
    </div>
  </div>
</div>

2022_05_19_21_01_03_DevTools_dmitrygozman 字段代码 com_

图像

如果我需要粘贴任何其他信息等,请告诉我。问候

9

@AngelLopezBellmont 问题在于,playwright 在按钮变为可操作状态时立即点击按钮,这在大多数情况下已经足够了,但在您的示例中,按钮尚未立即准备好处理点击(可能尚未添加点击侦听器/尚未正确设置),因此您需要等待特定于您的应用程序的条件来了解按钮何时变为可操作状态(waitForFunction之类的东西可能会派上用场)。话虽如此,这确实是应用程序中的一个错误,因为人类有时也可以点击按钮而没有任何效果,最好的方法是修复行为,以便按钮不会显示或至少在准备好处理点击之前被禁用。

由于剧作家方面没有通用的解决方案,因此关闭该问题。

7

@yury-s 是的,你说得对。我发现了问题。我在按下点击按钮之前检查了表单的加载情况,但我的检查并非 100% 正确 :(。我太专注于按钮取消,以至于没有意识到这一点 :(。我检查了标题和按钮,它们是自动加载的,但里面需要几毫秒的时间。
当然,正如你所说,Yury,playwright 在应用程序处理它之前就点击了按钮取消(因为表单尚未加载)所以一切都可以解决,只需在表单内的任何元素上添加一个简单的 waitFor。

  //check form is open:
  await page.locator('text=Create ticket for project').waitFor({state:"visible"});
  await expect(page.locator('text=Create ticket for project')).toBeVisible;
  await page.locator('text=Last name*').waitFor({state:"visible"});     //with this new line everything works

现在一切正常,无需等待 page.waitForTimeout(500) 等

再次感谢大家的帮助,特别是@yury-s @mxschmitt 的帮助