2017-04-26 50 views
0

我們的CircleCI測試使用硒,通過selenium-webdriver通過PhantomJS運行UI測試。測試中我們遊民ENV工作100%的時間在本地,但未能約1開出3次對CircleCI與像ECONNREFUSED錯誤:CircleCI上的間歇硒ECONNREFUSED錯誤

Error: ECONNREFUSED connect ECONNREFUSED 10.0.4.1:59525 
     at ClientRequest.<anonymous> (node_modules/selenium-webdriver/http/index.js:238:15) 
     at Socket.socketErrorListener (_http_client.js:310:9) 
     at emitErrorNT (net.js:1278:8) 
     at _combinedTickCallback (internal/process/next_tick.js:74:11) 
     at process._tickCallback (internal/process/next_tick.js:98:9) 
    From: Task: WebDriver.navigate().to(http://127.0.0.1:8080/src/public/login.php?t=ur&ign=1&ut=ad) 
     at thenableWebDriverProxy.schedule (node_modules/selenium-webdriver/lib/webdriver.js:816:17) 
     at Navigation.to (node_modules/selenium-webdriver/lib/webdriver.js:1140:25) 
     at thenableWebDriverProxy.get (node_modules/selenium-webdriver/lib/webdriver.js:997:28) 
     at User.logIn (testJs/ui/utils/user.js:9:16) 
     at Host.logInAsHost (testJs/ui/utils/host.js:13:14) 
     at Preferences.disableRevenueGeneration (testJs/ui/utils/preferences.js:57:14) 
     at Context.<anonymous> (testJs/ui/tests/preferences.js:13:22) 

這些錯誤發生在整個測試中隨機時間,他們沒有被由我們測試中的任何特定地點觸發。據我所知,這個問題發生在selenium/selenium-webdriver端,因爲web服務器保持運行並且不會產生任何錯誤。

我已經嘗試了所有的以下,其中沒有一個已經工作:

  1. 升級到最新的硒的webdriver(3.4.0)
  2. 升級到較新版本的的NodeJS(6.9 0.2)
  3. 使用不同的Web服務器
  4. 升級到使用最新版本PhantomJS(1.9.7-15)
  5. 的嘗試export DBUS_SESSION_BUS_ADDRESShttps://github.com/SeleniumHQ/docker-selenium/issues/87
  6. 在node_modules/selenium-webdriver/http/index.js中,我修改了代碼以重試ECONNREFUSED錯誤,方法是重新使用ECONNRESET中已有的重試,即if (e.code === 'ECONNRESET') {變爲if (e.code === 'ECONNRESET' || e.code === 'ECONNREFUSED') {。這不起作用,因爲那時selenium-webdriver只是無限期地重試,並且從中我意識到問題似乎是一旦遇到ECONNREFUSED錯誤,硒/硒驅動程序是不可恢復的。

有沒有人找到解決方案?

回答

0

警告:這僅僅是一個破解,絕不是一個合適的解決方案,但它是唯一一個在CircleCI上可靠地爲我們工作的人。希望別人能找到更好的解決方案。

我們的測試框架,摩卡,似乎有一個專門爲硒開發的重試機制(去圖):http://mochajs.org/#retry-tests。第一個問題是afterbefore中的代碼未被重試。因此,您需要將代碼移至beforeEachafterEach。第二個問題是,您需要在beforeEachafterEach中使用一些特殊邏輯來處理驅動程序錯誤。

因此,爲了利用這種機制,我們不得不重構我們的測試,使每個測試有一個beforeEach,設置了一個新的webdriver的實例,然後一個afterEach是退出該驅動程序實例。這樣,一個崩潰的驅動程序實例不會停止所有後續測試。我們開發了一個輔助函數,我們在所有describe塊的開頭調用,以便我們不必爲測試添加太多的代碼。

然後,我們將this.retries(10)添加到我們最頂端的describe區塊。

這裏是輔助類:

var webdriver = require('selenium-webdriver'); 

// We default to using phantomjs, but in the future, when we run tests in other browsers, e.g. via 
// SauceLabs, we'll want to change the browser. 
var customPhantom = webdriver.Capabilities.phantomjs(); 
customPhantom.set('ssl-protocol', 'any'); 

// For convenience in tests 
global.By = webdriver.By; 
global.until = webdriver.until; 

var SeleniumStabilizer = function() {}; 

SeleniumStabilizer.prototype.MAX_RETRIES = 10; 

SeleniumStabilizer.prototype.createDriver = function() { 
    global.driver = new webdriver.Builder() 
     // .forBrowser('phantomjs') 
     .withCapabilities(customPhantom) 
     .build(); 

    // Resolves when driver is ready 
    return global.driver; 
}; 

SeleniumStabilizer.prototype.init = function (opts) { 

    var self = this, 
     n = 0; 

    var beforeEachWithRetries = function() { 
     // Create a fresh selenium driver for the next test 
     return self.createDriver().then(function() { 
      if (opts.onBeforeEach) { 
       // Execute the test-specific defined onBeforeEach 
       return opts.onBeforeEach(); 
      } 
     }).catch(function (err) { 
      // ECONNREFUSED error and we should retry? 
      if (err.message.indexOf('ECONNREFUSED') !== -1 && n++ < self.MAX_RETRIES) { 
       return beforeEachWithRetries(); 
      } else { 
       throw err;    
      } 
     }); 
    }; 

    opts.beforeEach(function() { 
     n = 0; 
     return beforeEachWithRetries(); 
    }); 

    var afterEachWithRetries = function() { 
     return Promise.resolve().then(function() { 
      if (opts.onAfterEach) { 
       // Execute the test-specific defined onAfterEach 
       return opts.onAfterEach(); 
      } 
     }).then(function() { 
      // Quit the selenium driver before starting the next test 
      return driver.quit(); 
     }).catch(function (err) { 
      // ECONNREFUSED error and we should retry? 
      if (err.message.indexOf('ECONNREFUSED') !== -1 && n++ < self.MAX_RETRIES) { 
       // Create a new driver 
       return self.createDriver().then(function() { 
        return afterEachWithRetries(); 
       }); 
      } else { 
       throw err;    
      } 
     }); 
    }; 

    opts.afterEach(function() { 
     n = 0; 
     return afterEachWithRetries(); 
    }); 
}; 

然後,你的測試看起來像:

var seleniumStabilizer = new SeleniumStabilizer(); 

describe('my tests', function() { 

    this.retries(seleniumStabilizer.MAX_RETRIES); 

    describe('search engines', function() { 

    seleniumStabilizer.init({ 
     beforeEach: beforeEach, 
     afterEach: afterEach, 
     onBeforeEach: function() { 
     // e.g. return doPromiseAfterDriverSetUp(); 
     }, 
     onAfterEach: function() { 
     // e.g. return doPromiseBeforeDriverQuits(); 
     } 
    }); 

    it('should get google', function() { 
     return driver.get('https://www.google.com'); 
    }); 

    it('should get amazon', function() { 
     return driver.get('https://www.amazon.com'); 
    }); 

    }); 

});