Problem
Summary of problem: I'm writing several test suites (using Jest and Puppeteer) to automate tests of my AngularJS app's home page. Many of the tests I'd like to automate involve filling out forms with <textareas>
's wherein strings (of varying length) need to be typed. But the problem is that every Puppeteer method available for typing is extremely inconsistent, in that not all characters in the strings passed to these methods are ultimately typed, and sometimes these methods even break subsequent methods doing unrelated things.
Overview of testing environment
- Puppeteer version: 1.19.0
- Jest version: 24.8.0
What I've tried to far
Research: I've searched extensively for a solution on the Puppteeer's Github Issues page, as it seems like this problem is pretty widespread. So far I've tried the solutions provided in #1648, #2784, #1958 and #1223. Below are the code snippets I've tried, taken from those various answers. None of them have worked so far.
<!-- 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);
});
});
Final thoughts/question:
Does anyone know of a reliable way of automating typing in Puppeteer so that my tests won't fail sporadically?