0

Here is the input element I would like to type into:

<input name="name" ng-model-options="{ debounce: 300 }" ng-model="contestantState.form.name" ng-pattern=".*" placeholder="Alice Smith" required="" style="width: 246px" type="text" class="ng-empty ng-invalid ng-invalid-required ng-valid-pattern ng-dirty ng-valid-parse ng-touched">

One of my tries:

 await page.type('input[name="name"]',"my name");

No matter what way I try to type into this field, nothing happens: it stays blank because it is not identifiable by its name or classes.

What do I do to have Puppeteer enter a Name into that field?

The website I'm trying to do this on is: https://gleam.io/hxVaH/win-a-krooked-big-eyes-too-skateboard?gsr=hxVaH-4hKgdgSzfh (The Full Name and email field).

ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • Welcome to SO! Are you clicking on "Refer Friends For Extra Entries" first? If so, please show your code that gets you up to the point where you're ready to type as a [mcve]. Thanks. You can use headful mode to debug your script if you aren't already. – ggorlen Jul 02 '21 at 17:53

3 Answers3

1

Existing answers have been useful, but this should do the full submission and give you the share URL.

Since this AngularJS app doesn't seem to use ids and classes much, using text contents seems like a reasonable choice for hitting a couple of the buttons.

I had to use .evaluate(el => el.click()) instead of .click() to click one of the buttons successfully as described here.

const puppeteer = require("puppeteer");

const clickXPath = async (page, xp) => {
  await page.waitForXPath(xp);
  const [el] = await page.$x(xp);
  await el.evaluate(el => el.click());
};

const randomEmail = () => 
  Array(10).fill().map(() => 
    String.fromCharCode(~~(Math.random() * 26 + 97))
  ).join("") + 
  `${(Math.random() + "").replace(/\./, "")}@gmail.com`
;

let browser;
(async () => {
  const url = "https://gleam.io/hxVaH/win-a-krooked-big-eyes-too-skateboard";
  browser = await puppeteer.launch({headless: false});
  const [page] = await browser.pages();
  await page.goto(url, {waitUntil: "networkidle0"});
  await clickXPath(page, `//span[contains(text(), "Refer Friends")]`);
  const nameSel = '[class="entry-method  expanded"] input[name="name"]';
  const emailSel = '[class="entry-method  expanded"] input[name="email"]';
  await page.waitForSelector(nameSel);
  await page.type(nameSel, "my name33");
  await page.type(emailSel, randomEmail());

  const hasText = () => page.evaluate(() => 
    !!document.querySelector(".share-link__link")?.innerText.trim()
  );

  for (let tries = 1000; !(await hasText()) && tries--;) {
    await clickXPath(page, `//span[contains(text(), "Save")]`);
    await page.waitForTimeout(100);
  }

  const shareCode = await page.$eval(".share-link__link", el => el.innerText);
  console.log(shareCode); // => https://wn.nr/w9Wz5p
})()
  .catch(err => console.error(err))
  .finally(async () => await browser.close())
;
ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • 1
    wow! thank you so much for taking time and actually coding this out! I'm sure I can learn tons from this perfect code! (it runs so smooth, mine was SO slow even till where it worked) WORKS JUST LIKE I WANT IT TO! THANKS GGORLEN! thank you very much i really appreciate you helping me with this one! – whoknowswho Jul 03 '21 at 16:11
0

There is more than one matching element using your locator. Try this:

await page.type('[class="entry-method  expanded"] input[name="name"]',"my name");
ggorlen
  • 44,755
  • 7
  • 76
  • 106
Tanuj Vishnoi
  • 309
  • 2
  • 8
  • 1
    thank you for trying to help! Sadly this does not work: (node:6184) UnhandledPromiseRejectionWarning: Error: No node found for selector: [class="entry-method expanded"] input[name="name"] IS there a way i can use this element and type into it: $('input[name="name"]').toArray()[2] Because there are 4 inputs with the name "name" and i want to use the third one. Thanks again! – whoknowswho Jul 02 '21 at 17:49
0

You need to toggle the input first to make it available in the DOM (until that this element is only an Angular Template inside a <script> tag). And as Tanuj wrote: you should go with a selector which have only one instance. E.g.:

await page.click('#em5682795 > a'); // "Refer friends for extra entries"
await page.type('[class="entry-method  expanded"] input[name="name"]',"my name");
theDavidBarton
  • 7,643
  • 4
  • 24
  • 51