用于输入的 Puppeteer 方法永远不会完成输入传递给它们的完整字符串

Els*_*rit 5 javascript jestjs puppeteer jest-puppeteer

问题

问题摘要:我正在编写几个测试套件(使用 Jest 和 Puppeteer)来自动化我的 AngularJS 应用程序主页的测试。我想自动化的许多测试涉及用<textareas>'s填写表单,其中需要输入字符串(不同长度)。但问题是每个 Puppeteer 可用于打字的方法都极其不一致,因为并非所有传递给这些方法的字符串中的字符都最终被打字,有时这些方法甚至会破坏后续方法做不相关的事情。

测试环境概览

  • 傀儡师版本:1.19.0
  • 玩笑版本:24.8.0

我努力做到的

研究:我在 Puppteeer 的 Github 问题页面上广泛搜索了解决方案,因为这个问题似乎非常普遍。到目前为止,我已经尝试了#1648#2784#1958#1223 中提供的解决方案。以下是我尝试过的代码片段,摘自这些不同的答案。到目前为止,他们都没有工作。

<!-- index.html -->
<html>
  <body ng-app="myApp" ng-controller="myCtrl">
    <div>
      <md-content>
        <form test-id="myForm">
          <md-input-container>
            <div>
              <textarea ng-model="myCtrl.user.name" test-id="userName"></textarea>
            </div>
          </md-input-container>
          <md-input-container>
            <input type="file" ng-model="myCtrl.user.photo" test-id="uploadPhoto">
          </md-input-container>
          <md-dialog-actions>
            <button type="submit" test-id="submitForm">Submit</button>
          </md-dialog-actions>
        </form>
      </md-content>
    </div>
    <!-- These divs appear after the form has been submitted -->
    <div>
      <p><!-- username goes here --></p>
    </div>
    <div>
      <img><!--  photo goes here --></img>
    </div>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)
// index.spec.js
describe('fill out and submit form', () => {

  test('page has loaded', async() => {

    // note: I've tried both these methods for waiting for all the DOM
    // content to load before starting to fill out the form,
    // and neither make much of a difference in the typing behavior,
    // so I usually go with waiting for all network connections
    // to finish
    await page.goto('https://my-website.com', {waitUntil: 'networkidle0'});
    // await page.goto('https://my-website.com', {waitUntil: 'networkidle2'});

  });

  test('fill out form', async() => {

    let formSelector = 'form[test-id="myForm"]';
    // waits for form to appear
    await page.waitForSelector(formSelector, {visible: true, timeout: 3000});

    let longNameInputSelector = 'textarea[test-id="userName"]';

    // attempt 1: focus then page.keyboard.type
    // behavior: rarely finishes typing
    await page.focus(longNameInputSelector);
    await page.keyboard.type('Casey');

    // attempt 2: page.type
    // behavior: sometimes finishes typing
    await page.type(longNameInputSelector, 'Casey');

    // attempt 3: page.type then press 'Enter' 
    // behavior: this method tends to fix the typing but
    // breaks the photo uploading code below
    await page.type(longNameInputSelector, 'Casey');
    await page.keyboard.press('Enter');

    // attempt 4: page.type then press 'Tab'
    // behavior: sometimes finishes typing
    await page.type(longNameInputSelector, 'Casey');
    await page.keyboard.press('Tab');

    // attempt 5: wait for input selector to be visible and then type
    // behavior: rarely finishes typing
    await page.waitForSelector(longNameInputSelector, {visible: true, timeouts: 3000});
    await page.focus(longNameInputSelector);
    await page.keyboard.type('Casey');

    // attempt 6: convert input to Element Handle and then click
    // behavior: more reliable but fails occasionally
    let inputHandle = await page.$(longNameInputSelector);
    await inputHandle.click();
    await page.keyboard.type('Casey');

    // upload photo
    let inputPhotoSelector = 'input[type="file" test-id="uploadPhoto"]';
    const inputPhotoHandle = await page.$(inputPhotoSelector);
    const filePath = path.relative(process.cwd(), __dirname + '/me.png');
    await inputPhotoHandle.uploadFile(filePath);
  });

  test('submit form', async() => {

    // note: I've played a little with the way I'm submitting the form
    // to see if that could make any difference. So far it hasn't.
    // Here is what I've tried:

    // attempt 1: wait for the submit button to no longer be
    // disabled (i.e. wait for entire form to be filled out)
    // behavior: doesn't fix the problem. typing behavior still inconsistent
    let submitBtnSelector = 'button[test-id="submitForm"]:not([disabled])';
    await page.click(submitBtnSelector);

    // attempt 2: issue a fake click over the submit button to 
    // prevent autocomplete
    // behavior: doesn't fix the problem. typing still erratic
    await page.evaluate((sel) => {
      document.querySelector(sel).click();
    }, submitBtnSelector);

  });

});
Run Code Online (Sandbox Code Playgroud)

最后的想法/问题:

有谁知道在 Puppeteer 中自动打字的可靠方法,这样我的测试就不会偶尔失败?

Md.*_*her 1

我试图测试 Angular 应用程序,但与单击和类型相关的操作不起作用。最后用MouseEventKeyboardEvent API解决了。

它适用于 MouseEvent 和 KeyboardEvent。这是 MouseEvent 的示例。

function simulateEvent(eventx, elem) {
    const event = new MouseEvent(eventx, {
        view: window,
        bubbles: true,
        cancelable: true,
    });
    return elem.dispatchEvent(event);
};

function simulateType(selector, value) {
    const elem = document.querySelector(selector);
    elem.value = value;
    const events = ['click', 'focus', 'keydown', 'keypress', 'mousedown', 'compositionend', 'compositionstart', 'blur']
    for (let fakeEvent of events) {
        simulateEvent(fakeEvent, elem);
    }
};
Run Code Online (Sandbox Code Playgroud)

它将值设置为输入字段,并发送大量事件,如您所见。

为什么?有些网站会监视 keydown、keypress 等。但是,我见过很多网站如果我不单击输入字段,甚至不允许我提交表单。