【问题标题】:Selenium (Node.js) screenshots are too slowSelenium (Node.js) 截图太慢了
【发布时间】:2018-03-08 22:14:27
【问题描述】:

我正在使用 Selenium + Mocha(在 Node.js 中)在网站上进行一些 UI 测试。每次测试后,我都想截取屏幕截图,以便查看/分享可见的结果。

但是,在进行基本 UI 更改(即插入文本并点击提交)之后,会触发一个 AJAX 调用 + JavaScript 动画,我想成为我的屏幕截图的一部分。

我得到的屏幕截图似乎是在下一步开始之后拍摄的。 (所以,第一次测试运行>触发截图>第二次测试开始>截图被实际捕获)

我已经尝试过 .sleep() 和超时 - 但是我的使用可能是错误的。

function takeScreenshot(name='out'){
      driver.takeScreenshot().then(function(data){
        var base64Data = data.replace(/^data:image\/png;base64,/,"")
        fs.writeFile(`screenshots/${name}.png`, base64Data, 'base64', function(err) {
          if(err) console.log(err);
        });
      });
}

describe('UI Tests', async function() {

  before(async function() {
    driver = await new Builder().forBrowser('chrome').build();
    await driver.get('http://localhost:8000').then( async function(){ await getAssets(); });
    /* search | submit | reset are declared in getAssets() */
  });

  after(async function() {
    driver.quit();
  });

  afterEach(async function(){
    step++;
    driver.sleep(3000).then(
      takeScreenshot(step) 
    );
  });

  describe('User Types/Modifies Input and Submits Query', async function() {

    it('type in search + click submit', async function(){
        search.sendKeys("Puppies and Kittens");
        submit.click();
    });

    it('click the X icon to clear search', async function(){
        reset.click();
    });

  });

});

在上面的 sn-p 中,第一个测试 ('type in search + click submit') 的屏幕截图将显示输入字段已从第二个测试中清除。

【问题讨论】:

    标签: javascript node.js selenium mocha.js screenshot


    【解决方案1】:

    发送到 selenium 的命令是异步的,这意味着函数将安排工作在未来的某个时间运行,但立即返回以便代码继续运行。

    在 selenium-webdrivers 的情况下,这些函数返回一个“承诺”,它将在未来的某个时候解决。 Mocha 可以使用 promise 来等待结果。

    承诺和摩卡

    Mocha 使用测试的返回值来确定它是否应该等待一个承诺解决。您可以使用await.then 控制承诺流程。

    如果正在使用Promise A+ 代码,那么您将始终在测试中使用return someFormOfPromise

    it(waits, function(){
      return Promise.resolve(true)
        .then(res => expect(res).to.be.true)
    })
    

    如果正在使用async,则保证会返回一个承诺,但您必须await 任何异步操作,否则测试将继续进行

    it(waits, async function(){
      let res = await Promise.resolve(true)
      expect(res).to.be.true
    })
    

    回调类似,但它们使用done 函数来指示测试继续进行。

    it(waits, function(done){
      someTrueCallback((err, res) => {
        if (err) return done(err)
        expect(res).to.be.true
        done()
      }) 
    })
    

    在发布的代码中有很多混合的Promise A+async,甚至还有一个回调。选择一种方式并尽可能坚持下去,我将使用async/await

    Promise 回调

    任何异步回调都可以转换成promise,所以从fs.writeFile回调函数开始,把它变成promise:

    function writeFile(path, data, format){
      return new Promise((resolve, reject)=>{
        fs.writeFile(path, data, format, function(err){
          if (err) return reject(err)
          resolve(true)
        })
      })
    }
    

    幸运的是,这是非常标准的,Node.js 在util.promisify 中有一个帮助器,所以帮助器可以变成:

    const writeFile = util.promisify(fs.writeFile)
    
    function async takeScreenshot(name='out'){
        let data = await driver.takeScreenshot()
        var base64Data = data.replace(/^data:image\/png;base64,/,"")
        return await writeFile(`screenshots/${name}.png`, base64Data, 'base64')
    }
    

    测试

    await 可用时,无需使用.then

    每当调用返回承诺的函数时,如果您想使用解析后的值,您可能需要awaitlet res = await...

    describe('UI Tests', function() {
    
      before(async function() {
        driver = await new Builder().forBrowser('chrome').build();
        await driver.get('http://localhost:8000')
        await getAssets()
        /* search | submit | reset are declared in getAssets() */
      });
    
      after(async function() {
        await driver.quit();
      });
    
      afterEach(async function(){
        step++;
        await takeScreenshot(step) 
      });
    
      describe('User Types/Modifies Input and Submits Query', function() {
    
        it('type in search + click submit', async function(){
            await search.sendKeys("Puppies and Kittens");
            await submit.click();
        });
    
        it('click the X icon to clear search', async function(){
            await reset.click();
        });
    
      });
    
    });
    

    作为旁注,这些测试实际上并没有检查任何内容。通常会使用像chai 这样的断言库来确保事情是你expect 的方式。

    【讨论】:

    • 感谢您精彩的文章和解释 :) 我(显然)对测试有点偏执;所以我不确定分解测试的粒度有多细——为简洁起见,我没有包括每个测试,但我确实有一些实际检查预期值的地方。无论如何,我现在也在研究 chai。再次感谢您。
    • 不用担心。一旦 async/promise 的东西点击了所有节点就变得容易多了!
    猜你喜欢
    • 1970-01-01
    • 2013-03-10
    • 2014-06-07
    • 2016-05-31
    • 2011-07-07
    • 2015-08-23
    • 2012-07-05
    • 2016-01-08
    • 2014-03-12
    相关资源
    最近更新 更多