5

问题

问题摘要:我正在编写几个测试套件(使用 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>
// 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);

  });

});

最后的想法/问题:

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

4

1 回答 1

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);
    }
};

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

为什么?一些网站会监视 keydown、keypress 等。但是,我看到很多网站如果我没有点击输入字段,甚至不让我提交表单。

于 2019-08-27T02:17:07.843 回答