Selenium + Node.js: is it possible to listen for reoccurring events?

时间秒杀一切 提交于 2021-01-29 04:49:11

问题


I am working on a site that is heavily powered by AJAX/REST API calls, which broadcast events on completion/failure.

What I am trying to accomplish is to listen for these document events and trigger a function in Selenium (Node.js) -- right now I'm settling for a console.log() -- and keep that listener running to report any new occurrences of the "customEvent"

My latest implementation looks like this:

driver = await new Builder().forBrowser('chrome').build();
await driver.get('http://www.google.com/');

...

driver.executeScript(`
  document.addEventListener("customEvent", (e) => {
    return e;
  })`).
then( (e) => { console.log( e ); } );

I've also tried executeAsyncScript()

The problems that I'm encountering:

  • This code just wants to run once (doesn't stay open)
  • It either doesn't catch the "customEvent" or it blocks the code from continuing, that would have triggered the event.

回答1:


Thanks to a co-worker, we have found a workaround solution:

  1. Use Selenium's .executeScript()
    • Create an HTML DIV (with a specific ID) in the loaded site,
    • Add the event listener to the document element created by Selenium's driver
    • Populate the created DIV with the data captured from the event
driver.executeScript(`
    var emptyDiv = document.createElement('div');
        emptyDiv.id = '${target}';
        emptyDiv.style.display = 'none';
    function _trackEvent(e){
        var target = document.getElementById('${target}');
        if( !target ){ document.body.appendChild( emptyDiv ); }
        target.innerHTML += JSON.stringify(e.detail);
    }
    document.addEventListener("${name}", _trackEvent);
`);
  1. Use driver.wait(until.elementLocated(By.id(''))) referencing the DIV id declared in step #1
    • This will make sure selenium pauses until something has been created at the browser's JS speed
trackEvent.start('customEvent', 'testTarget');
await driver.wait(until.elementLocated(By.id('testTarget')));
let testEvent = await trackEvent.stop('testTarget');
console.log( testEvent );
  1. Query the created element and return its data back to Selenium
return driver.executeScript(`
    return document.getElementById('${target}').innerHTML;
`).then(( data )=>{
    return data;
});
  1. Drop it all into the tests and try it out.
const trackEvent = {
    start  : ( name, target ) => {
        driver.executeScript(`
            var emptyDiv = document.createElement('div');
                emptyDiv.id = '${target}';
                emptyDiv.style.display = 'none';
            function _trackEvent(e){
                var target = document.getElementById('${target}');
                if( !target ){ document.body.appendChild( emptyDiv ); }
                target.innerHTML += JSON.stringify(e.detail);
            }
            document.addEventListener("${name}", _trackEvent);
        `);
    },
    stop  : ( target ) => {
        return driver.executeScript(`
            return document.getElementById('${target}').innerHTML;
        `).then(( data )=>{
            return data;
        });
    } 
};

With all of this, selenium is not trying to do two things at once. Selenium is running its tests and the website (that it spun up) is listening for the event(s) for us.

The only pause is when Selenium waits for the existence of the new DIV that is created by our executeScript JS.



来源:https://stackoverflow.com/questions/49265421/selenium-node-js-is-it-possible-to-listen-for-reoccurring-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!