61

I'm trying to test amending text in an editable input which contains the title of the current record - and I want to able to test editing such text, replacing it with something else.

I know I can use await page.type('#inputID', 'blah'); to insert "blah" into the textbox (which in my case, having existing text, only appends "blah"), however, I cannot find any page methods1 that allow deleting or replacing existing text.

Grant Miller
  • 27,532
  • 16
  • 147
  • 165
Javier Arias
  • 2,329
  • 3
  • 15
  • 26
  • Possible duplicate of [How to clear an item value in puppeteer](https://stackoverflow.com/questions/46907941/how-to-clear-an-item-value-in-puppeteer) – Felix K. May 08 '19 at 17:18

9 Answers9

123

You can use page.evaluate to manipulate DOM as you see fit:

await page.evaluate( () => document.getElementById("inputID").value = "")

However sometimes just manipulating a given field might not be enough (a target page could be an SPA with event listeners), so emulating real keypresses is preferable. The examples below are from the informative issue in puppeteer's Github concerning this task.

Here we press Backspace as many times as there are characters in that field:

const inputValue = await page.$eval('#inputID', el => el.value);
// focus on the input field
await page.click('#inputID');
for (let i = 0; i < inputValue.length; i++) {
  await page.keyboard.press('Backspace');
}

Another interesting solution is to click the target field 3 times so that the browser would select all the text in it and then you could just type what you want:

const input = await page.$('#inputID');
await input.click({ clickCount: 3 })
await input.type("Blah");
Vaviloff
  • 16,282
  • 6
  • 48
  • 56
  • 28
    **await input.click({ clickCount: 3 })** , that is interesting! Just like we use browser! – tuxuday Oct 04 '18 at 07:27
  • 10
    Be aware that the triple click solution this will not work with textareas containing multiple lines, as that will only highlight one. – cburgmer Nov 09 '18 at 13:32
  • @vsync 2 clicks select just one word and 3 clicks select all the text in an input, which is what the question is about :) – Vaviloff Jul 11 '19 at 01:59
  • 2
    The Backspace idea is nice, but now (Puppeteer 2) it must be ```await page.keyboard.press('Backspace');``` instead of ```await page.press('Backspace');``` – Michael Apr 23 '20 at 09:56
  • the * page.keyboard.press('Backspace')* is the only method that works for me (using react), maybe because it is more "Blackbox" / reliable than just changing the value, meaning, some updates won't happen if you just change the value of an element. – Coding Edgar Jun 03 '20 at 19:02
  • 4
    `await input.click({ clickCount: 4 })` for multiline select – Sailesh Kotha Jul 05 '20 at 23:21
  • 1
    this example with `keyboard.press('Backspace')` should call out that you may need to run `await page.click('#inputID')` first so input is focused, otherwise your backspace might not do anything – nf071590 Sep 19 '22 at 16:31
33

You can use the page.keyboard methods to change input values, or you can use page.evaluate().

Replace All Text:

// Using page.keyboard:

await page.focus('#example');
await page.keyboard.down('Control');
await page.keyboard.press('A');
await page.keyboard.up('Control');
await page.keyboard.press('Backspace');
await page.keyboard.type('foo');

// Using page.evaluate:

await page.evaluate(() => {
  const example = document.getElementById('example');
  example.value = 'foo';
});

Append Text:

// Using page.keyboard:

await page.focus('#example');
await page.keyboard.press('End');
await page.keyboard.type(' bar qux');

// Using page.evaluate:

await page.evaluate(() => {
  const example = document.getElementById('example');
  example.value += ' bar qux';
});

Backspace Last Character:

// Using page.keyboard:

await page.focus('#example');
await page.keyboard.press('End');
await page.keyboard.press('Backspace');

// Using page.evaluate:

await page.evaluate(() => {
  const example = document.getElementById('example');
  example.value = example.value.slice(0, -1);
});

Delete First Character:

// Using page.keyboard:

await page.focus('#example');
await page.keyboard.press('Home');
await page.keyboard.press('Delete');

// Using page.evaluate:

await page.evaluate(() => {
  const example = document.getElementById('example');
  example.value = example.value.slice(1);
});
Grant Miller
  • 27,532
  • 16
  • 147
  • 165
  • The Mac equivalent for the Windows Control + A is Command + A. – mckenna Jul 16 '19 at 18:32
  • 2
    For cross-platform keyboard solutions, you could instead use `page.keyboard.down('Shift')`, `page.keyboard.press('End')`, followed by `page.keyboard.press('Backspace')` – Developer Dave Aug 26 '20 at 23:49
  • Replace all text doesn't work with Mac because ctrl + A keystroke in Mac would not select the entire text but instead place the cursor at the start of the field – neonidian Mar 04 '21 at 17:32
15

If you are not interested in simulating any key events, you could also use puppeteer's page.$eval method as a concise means to remove the textarea's value...

await page.$eval('#inputID', el => el.value = '');
await page.type('#inputID', 'blah');

...or even completely replace the value in one step, without simulating the subsequent typing:

await page.$eval('#inputID', el => el.value = 'blah');
Felix K.
  • 14,171
  • 9
  • 58
  • 72
5

This works perfect for "clear only" method:

const input = await page.$('#inputID');
await input.click({ clickCount: 3 })
await page.keyboard.press('Backspace')
Gleb Dolzikov
  • 776
  • 8
  • 13
2

above answers has an ESLint issues. the following solution passing ESLint varification:

await page.evaluate(
  (selector) => { (document.querySelector(selector).value = ''); },
  inputBoxSelector,
);
2

Use the Keyboard API which simulates keystrokes:

await page.focus(css);            // CSS selector of the input element
await page.keyboard.down('Shift'); 
await page.keyboard.press('Home');
await page.keyboard.up('Shift');  // Release the pressed 'Shift' key
await page.keyboard.press('Backspace');

This keystroke is cross-platform as opposed to using ctrl + A(does not work in Mac to select all characters in a input field)

neonidian
  • 1,221
  • 13
  • 20
1

The most clean way for me is:

  • Setup
const clearInput = async (page, { selector }) => {
  const input = await page.$(selector)
  await input.click({ clickCount: 3 })
  await page.keyboard.press('Backspace')
}
  • Usage
const page = await context.newPage()

await clearInput(page, { selector: 'input[name="session[username_or_email]"]' })
await clearInput(page, { selector: 'input[name="session[password]"]' })
Victor
  • 1,904
  • 18
  • 18
0

Well, the reason you want to delete existing text generally may be want to replace it.

You can use page.evalute

let title = getTitle()
let selector = getSelector()

await page.evaluate(
  ({selector, title}) => {
    let el = document.querySelector(selector)
    if ('value' in el) el.value = title
    else el.innerText = title
  },
  {selector, title}
)
levy9527
  • 39
  • 3
-3

someField.type("");

Pass the empty string before typing your content.

This worked for me.

Vendetta
  • 2,078
  • 3
  • 13
  • 31