2016-07-21 3 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; 
}; 

「:古い要素参照:ERROR :: StaleElementReferenceErrorを要素は、ページの文書に添付されていない」達するラインので、私はもう一度試してみて「の試みと私の関数を起動する必要があります - 1 "パラメータ。それは期待される行動です。 しかし、一度それがに達したら "解決済み!" (「!RESOLVED」):質問がある

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

forEach()ループを停止または中断する方法はありませんが、例外をスローする以外にはありません。このような振る舞いが必要な場合は、forEach()メソッドが間違ったツールであり、代わりにプレーンループを使用します。

SOURCE:あなたが達成しようとしているか好奇心のうちhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

+0

これは_forEach_ではなく_button.getText()_が実行を継続する。だから私は分裂器の流れを破る必要がある –

0

?私には、そのテキストに基づいてボタンをクリックしたいので、テキストの一致が見つかるまで、試行番号で制限されたページのすべてのボタンを反復しているようです。あなたはまだ2つの要素を持っている分度器のAPIを活用することができるように、あなたのスペックファイル内browser.ignoreSynchronization = true;またはconf.jsファイル内onPrepareブロックを使用した場合、それは容易になるだろう非角度ページに分度器を使っているようですが、また見え

これを簡単に達成するロケータ。

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()`. 
          } 
         }); 
        }); 
    }; 
    

    注:

    は、私の知る限り、あなたはこのような何かをしたいです。実際、どのようなアプローチを採用しても、とにかくそれは悪い習慣です。遅延はめったに必要ではなく、まれに回る必要はほとんどありません。

  • reduceによって構築されたキャッチ・チェーンの後に、端末catch(... retry ...)ブロックを最終的なキャッチに移動しました。これはbutton.getText().then(onSucccess, onError)構造体よりも理にかなっているため、最初の失敗時に再試行してbuttonTextと一致させることができます。それは私にとって間違っているようです。
  • browser.driver.findElements()によってスローされたエラーが(再試行のために)キャッチされるように、ターミナルキャッチをさらに下に移動することはできますが、それはおそらく過剰です。 browser.driver.findElements()が一度失敗すると、おそらく再び失敗します。
  • 「再試行」戦略は、.reduce()プロセスによって構築されたキャッチチェーンの3倍の連結によって代替的に達成できます。しかし、あなたはより大きなメモリスパイクを見るでしょう。
  • わかりやすくするために、さまざまなconsole.log()を省略しましたが、再投入するのは非常に簡単です。
関連する問題