microsoft / playwright

Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API.
https://playwright.dev
Apache License 2.0
67.2k stars 3.7k forks source link

[Bug]: Filling a textarea element with lots of text lines is surprisingly slow #33761

Open tomppa65 opened 1 day ago

tomppa65 commented 1 day ago

Version

1.48.0

Steps to reproduce

  1. Copy this gist to you python IDE: https://gist.github.com/tomppa65/4ddea187309e41401869e0f1e3ffb35b
  2. Run it.
  3. Go grab a cup of your favorite beverage
  4. In about five minutes you will have the results the python script prints out.

Expected behavior

I would expect all three browsers to act like firefox does. It can fill a textarea with 4000 lines of text in under a second.

Actual behavior

Webkit takes some seconds at 2000 lines of text being filled to a textarea, 7 seconds at 3000 and over 12 at 4000 lines. Chromium takes the biscuit, though: 5 seconds at 1000, 22 seconds at 2000 lines, 48 seconds at 3000 lines and about 85 seconds at 4000 lines.

Additional context

This is not a serious bug, just something I stumbled upon when writing automated test cases. Found a workaround too, I implemented a javascript function to just set the value attribute of a textarea element, then press tab on it so events fire.

The times seem to vary a bit. There have been times when four minutes were not enough for chromium to get the job done. This may not even be Playwright problem but perhaps you can forward it, if that turns out to be true?

Environment

- Operating System: [Windows 11 Pro, 23H2]
- CPU: [Intel Core i7 10875H CPU @ 2.30 GHz]
- Browser: [All]
- Python Version: [3.12]
- Other info:
mxschmitt commented 15 hours ago

Repro script for Node.js:

// @ts-check
const { chromium, firefox, webkit, expect } = require('@playwright/test');

const T_O = 300000; // Five minutes

async function textareaFillSeparatedBy(page, sep) {
  for (let i = 1000; i <= 4000; i += 1000) {
    const joinedString = Array(i).fill('some text').join(sep);
    const start = Date.now();

    await page.getByLabel('Message:', { timeout: T_O }).fill(joinedString);

    const end = Date.now();
    const combinator = sep === ' ' ? 'blanks' : 'newlines';
    const delta = ((end - start) / 1000).toFixed(3);

    console.log(`Entering ${i} text separated by ${combinator} took ${delta} seconds`);
    await page.locator('textarea#message-text').fill('');
  }
}

(async () => {
  for (const browserConfig of [firefox, webkit, chromium]) {
    const browser = await browserConfig.launch({ headless: false });
    console.log('\nBrowser is:', browserConfig.name());

    const page = await browser.newPage();
    await page.goto('https://demoblaze.com/index.html');

    // Expect a title
    await expect(page).toHaveTitle('STORE');

    await page.getByRole('link', { name: 'Contact' }).click();

    await textareaFillSeparatedBy(page, ' ');
    await textareaFillSeparatedBy(page, '\n');

    await browser.close();
  }
})().catch(err => {
  console.error('Error occurred:', err);
  process.exit(1);
});