Chrome-remote-interface: Wait for reflow or render to finish after applying style

Created on 16 Aug 2017  路  7Comments  路  Source: cyrus-and/chrome-remote-interface

How should I wait for the re-render to occur after I apply a style to a div? Is there any event for this?

Or else I am getting an error of Error: Could not compute box model. when calling DOM.getBoxModel() right after applying a style.

const CDP = require('chrome-remote-interface');
const chromeLauncher = require('chrome-launcher');

chromeLauncher.launch({
  port: 9222,
  chromeFlags: [
    '--disable-gpu',
    '--headless',
  ],
}).then(async (chrome) => {
  const client = await CDP({ port: chrome.port });
  client.on('error', (err) => {
    console.error(err);
  });

  const { Page, DOM, CSS } = client;

  await Page.enable();
  await Page.navigate({
    url: 'http://github.com',
  });
  await Page.loadEventFired();

  await DOM.enable();
  await CSS.enable();

  const { root: { nodeId: docNodeId } } = await DOM.getDocument();
  const { nodeId: formId } = await DOM.querySelector({
    nodeId: docNodeId,
    selector: 'form[action="/join"]',
  });

  await CSS.setEffectivePropertyValueForNode({
    nodeId: formId,
    propertyName: 'display',
    value: 'none',
  });

  await CSS.setEffectivePropertyValueForNode({
    nodeId: formId,
    propertyName: 'display',
    value: 'block',
  });

  // Here the above code applies the style
  // but doesn't wait for the render to finish.

  await DOM.getBoxModel({ nodeId: formId });

  // So after this line it is throwing an error saying
  // Could not compute box model

  client.close();
  chrome.kill();
}).catch((err) => {
  console.error(err);
});

| Component | Version
|-|-
| Operating system | OSX 10.12.6
| Node.js | v8.2.1
| Chrome Canary | v62.0.3187.0
| chrome-remote-interface | v0.24.3

Is Chrome running in a container? NO

protocol question

Most helpful comment

I'd wait for two sequential requestAnimationFrame()s to fire. then you can be sure these changes have applied.

All 7 comments

I'd wait for two sequential requestAnimationFrame()s to fire. then you can be sure these changes have applied.

Okay, so I wrote a function like this.

async function waitForNextAnimationFrame(count = 1) {
  const { Runtime } = client;

  for (let i = 0; i < count; i++) {
    await Runtime.evaluate({
      expression: 'new Promise((resolve) => window.requestAnimationFrame(resolve));',
      awaitPromise: true,
    });
  }
}

And used it like this.

await CSS.setEffectivePropertyValueForNode({
    nodeId: formId,
    propertyName: 'display',
    value: 'block',
});

await waitForNextAnimationFrame(2);

await DOM.getBoxModel({ nodeId: formId });

Is this the right approach of doing this?

@Jimut it's IMO the right approach; with this change the Could not compute box model. error doesn't seem to happen.

Yet, if I run the snippet continuously DOM.querySelector seldom returns a 0 nodeId, not sure why.

Yet, if I run the snippet continuously DOM.querySelector seldom returns a 0 nodeId, not sure why.

Well, lol, I apparently triggered the abuse mechanism of GitHub... ignore this.

Is this the right approach of doing this?

It's not a huge deal IMO but i would just hardcode the 2 nested raf inside a single runtime.evaluate...

roughly like

  await Runtime.evaluate({
    expression: `new Promise((resolve) => 
                  window.requestAnimationFrame(_ => 
                  window.requestAnimationFrame(resolve)));`,
    awaitPromise: true
  });

Thank you a lot @paulirish @cyrus-and.

@Jimut you're welcome, please close this if you've found an acceptable solution.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

westy92 picture westy92  路  3Comments

elsigh picture elsigh  路  3Comments

renschler picture renschler  路  5Comments

DavidXanatos picture DavidXanatos  路  3Comments

hbakhtiyor picture hbakhtiyor  路  7Comments