2016-07-21 81 views
0

我有以下代碼片段。打破循環/承諾,並從功能返回

this.clickButtonText = function (buttonText, attempts, defer) { 
    var me = this; 
    if (attempts == null) { 
     attempts = 3; 
    } 
    if (defer == null) { 
     defer = protractor.promise.defer(); 
    } 

    browser.driver.findElements(by.tagName('button')).then(function (buttons) { 
     buttons.forEach(function (button) { 
      button.getText().then(
       function (text) { 
        console.log('button_loop:' + text); 
        if (text == buttonText) { 
         defer.fulfill(button.click()); 
         console.log('RESOLVED!'); 
         return defer.promise; 
        } 
       }, 
       function (err) { 
        console.log("ERROR::" + err); 
        if (attempts > 0) { 
         return me.clickButtonText(buttonText, attempts - 1, defer); 
        } else { 
         throw err; 
        } 
       } 
      ); 
     }); 
    }); 

    return defer.promise; 
}; 

不時我的代碼達到「錯誤:: StaleElementReferenceError:陳舊的元素參考:元素沒有連接到頁面文件」線,所以我需要再次嘗試並調用我的函數「的嘗試 - 1「參數。這是預期的行爲。 但是一旦到達「已解決!」線它不斷迭代,所以我看到水木清華這樣的:

button_loop:wrong_label_1 
button_loop:CORRECT_LABEL 
RESOLVED! 
button_loop:wrong_label_2 
button_loop:wrong_label_3 
button_loop:wrong_label_4 

的問題是:如何打破循環/承諾後的console.log從函數返回;(「解決了!」)一行?

+0

您是否嘗試過使用'.done'回調? –

+0

不,但似乎檢查我的共享延遲是否解決了我的作品。將等待更優雅的答案,如果不會提供我自己 –

回答

0

出於好奇,你有什麼要完成?對我來說,似乎你想單擊一個基於它的文本的按鈕,這樣你就可以遍歷頁面上的所有按鈕,這些按鈕被一個嘗試編號所限制,直到找到與文本匹配的內容爲止。

它也像你使用的是無角的頁面,如果你用你的規範文件browser.ignoreSynchronization = true;conf.js文件onPrepare塊,所以你仍然可以利用量角器API,它有兩個元素會更容易上量角器輕鬆實現這一點的定位器。

this.clickButtonText = function(buttonText) { 
    return element.all(by.cssContainingText('button',buttonText)).get(0).click(); 
}; 

OR

this.clickButtonText = function(buttonText) { 
    return element.all(by.buttonText(buttonText)).get(0).click(); 
}; 

如果有另一個原因通過按鍵想環路我可以寫一個使用bluebird遍歷元素的更復雜的解釋。這是解決承諾的非常有用的庫。

0

通過創建額外的延遲對象,可以讓自己變得更加困難。如果點擊失敗,您可以使用承諾自行重試該操作。

var clickOrRetry = function(element, attempts) { 
    attempts = attempts === undefined ? 3 : attempts; 
    return element.click().then(function() {}, function(err) { 
     if (attempts > 0) { 
      return clickOrRetry(element, attempts - 1); 
     } else { 
      throw new Error('I failed to click it -- ' + err); 
     } 
    }); 
}; 

return browser.driver.findElements(by.tagName('button')).then(function(buttons) { 
    return buttons.forEach(function(button) { 
     return clickOrRetry(button); 
    }); 
}); 
0

一個辦法是建立(在每一個「嘗試」)的繼續失敗,但跳到成功結束一個承諾鏈。這樣的鏈將是通用形式的...

return initialPromise.catch(...).catch(...).catch(...)...; 

...和簡單編程方式使用JavaScript數組方法.reduce()構造。

在實踐中,該代碼將被製成大體積:

  • 需要調用異步button.getText()然後匹配的文本執行相關聯的測試,
  • 需要協調3次嘗試,

但仍不太笨拙。

據我所知,你想是這樣的:

this.clickButtonText = function (buttonText, attempts) { 
    var me = this; 
    if(attempts === undefined) { 
     attempts = 3; 
    } 
    return browser.driver.findElements(by.tagName('button')).then(function(buttons) { 
     return buttons.reduce(function(promise, button) { 
      return promise.catch(function(error) { 
       return button.getText().then(function(text) { 
        if(text === buttonText) { 
         return button.click(); // if/when this happens, the rest of the catch chain (including its terminal catch) will be bypassed, and whatever is returned by `button.click()` will be delivered. 
        } else { 
         throw error; //rethrow the "no match" error 
        } 
       }); 
      }); 
     }, Promise.reject(new Error('no match'))).catch(function(err) { 
      if (attempts > 0) { 
       return me.clickButtonText(buttonText, attempts - 1); // retry 
      } else { 
       throw err; //rethrow whatever error brought you to this catch; probably a "no match" but potentially an error thrown by `button.getText()`. 
      } 
     }); 
    }); 
}; 

注:

  • 通過這種方法,就沒有必要在延期對象傳遞。事實上,無論採取什麼方法,無論如何這都是不好的做法。延期很少有必要,甚至很少需要傳遞。
  • 我搬了終端catch(... retry ...)塊成爲最後一個漁獲物,通過減少建造漁獲物之後。這比button.getText().then(onSucccess, onError)結構更有意義,它會在第一次失敗時重試,以匹配buttonText;這對我來說似乎是錯誤的。
  • 您甚至可以將終端接收器進一步向下移動,使得browser.driver.findElements()引發的錯誤將被捕獲(重試),儘管這可能是矯枉過正。如果browser.driver.findElements()一次失敗,則可能會再次失敗。
  • 「重試」策略可以通過3x串聯由.reduce()過程構建的捕獲鏈來實現。但是你會看到更大的內存峯值。
  • 爲了清楚起見,我省略了各種console.log(),但它們應該很容易重新使用。