denis
denis

Reputation: 63

Puppeteer: how to listen for on innerHTML change

I have a chat app with status represented by this line:

<span id='status'>Offline</span> 

and I want Puppeteer to log every time the text within this span changes.

Say, in the beginning the status was "Offline", then it was changed to "Online", and then after some time to "Away" and so on. I want Puppeteer to capture those moments and the status (Offline>Online>Away)

What I managed to do is the following:

const page = await browser.newPage();
await page.goto('https://chat.com');
const statusHandle = await page.$('span#status');
let statusText = await page.evaluate(() => document.querySelector('#status').innerText);
let iniVal = {statusHandle,statusText };

at this point I have the statusHandle and the initial status.

Now, my understanding (as per 1 and 2) is that I need to combine the two in

await page.waitForFunction(
  (iniVal) => iniVal.statusHandle.innerHTML !== iniVal.statusText, 
  { timeout: 0 }, 
  iniVal
) 

and place it in a loop. That's the point, where I'm struggling.

First it gives a type error "TypeError: Converting circular structure to JSON", which is due to the passed key value pairs not being primitives, but even when I oversimplify and just do (as per 1):

await page.waitForFunction(
  'document.querySelector("span#status").inner‌​Text === "Online"'
)

it yields nothing.

To sum up: I am looking to

  1. Make Puppeteer evaluate the change in document.querySelector('#status').innerText !== statusText

  2. Return the new status value

  3. Have the process run in a loop

Upvotes: 4

Views: 5274

Answers (2)

niutech
niutech

Reputation: 29942

Rather than polling with recursion and setTimeout, better use MutationObserver like in this answer.

Upvotes: 0

laggingreflex
laggingreflex

Reputation: 34667

I'd just set a recursive function with a callback:

async function monitor (selector, callback, prevValue) {
  const newVal = await page.$(selector);
  if (newVal !== prevValue) {
    callback(newVal);
  }
  /* add some delay */
  await new Promise(_ => setTimeout(_, 1000))
  /* call recursively */
  monitor (selector, callback, newVal);
}
monitor('span#status', status => {
  // Fires whenever `status` changes
})

Upvotes: 4

Related Questions