C#でSeleniumプロジェクトを開始しました。ページの読み込みが完了するのを待ってから、次のアクションに進みます。
私のコードは次のようになります。
loginPage.GoToLoginPage();
loginPage.LoginAs(TestCase.Username, TestCase.Password);
loginPage.SelectRole(TestCase.Orgunit);
loginPage.AcceptRole();
loginPage.SelectRole(TestCase.Orgunit)内:
RoleHierachyLabel = CommonsBasePage.Driver.FindElement(By.XPath("//span[contains(text(), " + role + ")]"));
RoleHierachyLabel.Click();
RoleLoginButton.Click();
要素RoleHierachyLabelを検索します。私はいくつかのタイムアウトを許可して、要素のプロパティのページの読み込みまたは検索を待つために複数の方法を使用しようとしています:
1. _browserInstance.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));
2. public static bool WaitUntilElementIsPresent(RemoteWebDriver driver, By by, int timeout = 5)
{
for (var i = 0; i < timeout; i++)
{
if (driver.ElementExists(by)) return true;
}
return false;
}
この障害にどのように取り組みますか?
私は代替案を探していましたが、次のバージョンに落ち着きました。すべては、定義されたタイムアウトで明示的な待機を使用し、最初のケースでは要素のプロパティに基づいており、2番目のケースでは要素の陳腐化に基づいています。
最初の選択は、タイムアウトに達するまで要素のプロパティをチェックします。ページで利用できることを確認する次のプロパティに到達しました。
存在-ページのDOMに要素が存在することを確認するための期待。これは、必ずしも要素が表示されることを意味しません。
//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Enabled)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementExists(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementExists(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
Visibility-ページのDOMに要素が存在し、表示されていることを確認するための期待。可視性とは、要素が表示されるだけでなく、高さと幅が0より大きいことも意味します。
//this will not wait for page to load
Assert.True(Driver.FindElement(By elementLocator).Displayed)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementVisible(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementIsVisible(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found.");
throw;
}
}
Clickable-要素をチェックするための期待値が表示され、クリックできるようになっています。
//this will not wait for page to load
//both properties need to be true in order for element to be clickable
Assert.True(Driver.FindElement(By elementLocator).Enabled)
Assert.True(Driver.FindElement(By elementLocator).Displayed)
//this will search for the element until a timeout is reached
public static IWebElement WaitUntilElementClickable(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
return wait.Until(ExpectedConditions.ElementToBeClickable(elementLocator));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
2番目の選択肢は、トリガーオブジェクト(メニュー項目など)がクリックされた後にDOMに添付されなくなった場合に適用されます。これは通常、要素に対するクリックアクションが別のページへのリダイレクトをトリガーする場合です。この場合、check StalenessOf(element)が便利です。ここで、elementは、新しいページへのリダイレクトをトリガーするためにクリックされたアイテムです。
public static void ClickAndWaitForPageToLoad(By elementLocator, int timeout = 10)
{
try
{
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeout));
var element = Driver.FindElement(elementLocator);
element.Click();
wait.Until(ExpectedConditions.StalenessOf(element));
}
catch (NoSuchElementException)
{
Console.WriteLine("Element with locator: '" + elementLocator + "' was not found in current context page.");
throw;
}
}
driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5);
また、 この回答 を参照してください
このタイプの問題に対処するためにこれを行いました。タイマーとループの組み合わせで、特定のミリ秒後にタイムアウトするまで特定の要素を探します。
private IWebElement FindElementById(string id, int timeout = 1000)
{
IWebElement element = null;
var s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
{
try
{
element = _driver.FindElementById(id);
break;
}
catch (NoSuchElementException)
{
}
}
s.Stop();
return element;
}
また、要素が有効になったものも作成しました
private IWebElement ElementEnabled(IWebElement element, int timeout = 1000)
{
var s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromMilliseconds(timeout))
{
if (element.Enabled)
{
return element;
}
}
s.Stop();
return null;
}
一般に、Selenium 2.0では、Webドライバーは、ページが読み込まれたと判断した場合にのみ、呼び出し元のコードに制御を返します。見つからない場合は、
waitforelemement
を呼び出すことができます。これは、findelement
が見つかるか、タイムアウトになるまで循環します(タイムアウトを設定できます)。
通常、これには明示的な待機を使用し、要素が表示されるまで待機してから、次のアクションに進みます。これは次のようになります。
WebDriverWait waitForElement = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
waitForElement.Until(ExpectedConditions.ElementIsVisible(By.Id("yourIDHere")));
ここでの明示的な待機の詳細: 明示的な待機Selenium C# およびここで WebDriverの明示的な待機
そのシンプルさから、このソリューションが気に入っています。また、過剰な待機を回避し、待機の上限となる可能性のあるものから推測作業を取り除くという利点もあります。
public bool WaitToLoad(By by)
{
int i = 0;
while (i < 600)
{
i++;
Thread.Sleep(100); // sleep 100 ms
try
{
driver.FindElement(by);
break;
}
catch { }
}
if (i == 600) return false; // page load failed in 1 min
else return true;
}
ページの読み込み遅延を監視する必要がある場合は、「タイマー」も含めるように変更できます。
public int WaitToLoad(By by)
{
int i = 0;
while (i < 600)
{
i++;
Thread.Sleep(100); // sleep 100 ms
try
{
driver.FindElement(by);
break;
}
catch { }
}
return i; // page load latency in 1/10 secs
}