I have been searching for a solution for this, but to no avail. I have a button I'm clicking, that is sometimes taking a long while to return data, and the driver is timing out and just killing the app I guess.
I am trying to use the WebDriverWait class to accomplish this, but the Click() method is not available in the way I'm using it.
WebDriverWait wait = new WebDriverWait(browser, new TimeSpan(0, 5, 0));
bool clicked = wait.Until<bool>((elem) =>
{
elem.Click(); //Doesn't Work
return true;
});
The ImplicitlyWait() method is only for waiting for elements to load, but this times out on Click(), so it can't even look for an element.
The SetScriptTimeout() method just works with executing javascript, which I'm not doing.
Does anyone know of a way to do this?
try this :
WebDriverWait wait = new WebDriverWait(driver , 1000) ;
wait.until(ExcepctedConditions.elementToBeClickable(ById("element"));
Element can be ID of any element present on the next page you are redirected to .
Once Page loads fully then it will start executing your code .
Instead of Click you could try to use SendKeys. Unlike Click, SendKeys does not wait for the page to finish loading before resuming code execution. So you can do something like this:
WebDriverWait wait = new WebDriverWait(browser, new TimeSpan(0, 5, 0));
elem.SendKeys(Keys.Enter);
wait.Until<bool>((_driver) =>
{
//Check here if results have loaded yet
return true;
});
As a side note, I'm pretty sure Until takes in a IWebBrowser as an input, not an element, which is why you can't click on elem.
In addition to prestomanifesto's solution I can offer a less than ideal solution to that I implemented to solve this issue. It turns out it is throwing an exception - No Response etc... - so I just surrounded it in a try catch then waited for the popup to close, which seems to work fine.
You can substitute whatever you want in your loop, just make sure to put a counter in so it won't loop forever.
try
{
element.Click();
}
catch
{
cnt++;
do
{
//wait for whatever
cnt++;
Thread.Sleep(1000);
// Wait for 30 seconds for popup to close
} while (!string.IsNullOrEmpty(browser.CurrentWindowHandle) && cnt < 30);
}
I use this script :
private static void waitUntilScriptFoundAndExecute(String script) {
int tries = 0;
boolean found = false;
do {
tries++;
try {
driver.executeScript(script);
found = true;
} catch (NoSuchElementException nse) {
System.out.println("Wait for script NSE (" + tries + ")");
} catch (WebDriverException wde) {
System.out.println("Wait for script WDE (" + tries + ")");
} catch (Exception e) {
System.out.println("Wait for script E (" + tries + ")");
}
// Waiting
if (!found) {
System.out.println("Wait for script Not found (" + tries + ")");
waiting(SCRIPT_WAITING_INTERVAL);
}
} while (!found && tries < MAX_SCRIPT_WAIT_TRIES);
if (!found) {
System.out.println("Script aborted: " + script);
}
}
RepeatUntil Extension Method using LINQ Lambda expressions
Copy this code to your project:
public static class SeleniumExtensionMethods
{
public static IWebElement RepeatUntil<T>(this T obj,
Func<T, IEnumerable<IWebElement>> func,
Func<IWebElement, bool> compare,
int MaxRetry = 20)
{
//call function to get elements
var eles = func(obj);
IWebElement element = null;
while (element == null && MaxRetry > 0)
{
MaxRetry-=1;
//call the iterator
element = IterateCollection(compare, eles);
if (element == null)
{
Thread.Sleep(500);
//get new collection of elements
eles = func(obj);
}
};
return element;
}
private static IWebElement IterateCollection(
Func<IWebElement, bool> compare,
IEnumerable<IWebElement> eles){
IWebElement element = null;
eles.ToList().ForEach(
ele =>
{
//call the comparator
var found = compare(ele);
if (found) element = ele;
});
return element;
}
}
Call it using this syntax:
// You can change PageObjectType to IWebDriver or IWebElement so that
// cb is of any type.
var element = cb.RepeatUntil<MyPageObjectType>(
//This is the first function to provide the elements
p => p.FindElements(By.ClassName("TreeNode")),
//This is the comparator
ele => ele.Text == nodeText && ele.Location.Y>YLocation);
Note: In the example above we are passing in a PageObjectType but you could change this to be of type IWebDriver or event IWebElement. All the type parameter does it allow you to use this as an extension method for the type you specify.
Note the flexibility of the extension method in that the caller can determine the collection as well as the comparator.
don't use thread sleep
public class(IWebDriver driver)
{
this.driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMinutes(1);
wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver,TimeSpan.FromMinutes(1));
}
public void class1()
{
wait.Until(ExpectedConditions.ElementToBeClickable(elem)).Click();
}
Related
Given I need wait for one textbox appears, do something, and later I will need wait another Textbox.
I want to know if this code is correct:
var waitForTextBox = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
waitForTextBox.Until(ExpectedConditions.ElementIsVisible(By.Id("txtFirstName"))).SendKeys("John");
waitForTextBox.Until(ExpectedConditions.ElementIsVisible(By.Id("txtLastName"))).SendKeys("Skeet");
or if instead of reusing waitForTextBox, I will need do like this:
var waitForFirstName = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
waitForFirstName.Until(ExpectedConditions.ElementIsVisible(By.Id("txtFirstName"))).SendKeys("John");
var waitForLastName = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
waitForLastName.Until(ExpectedConditions.ElementIsVisible(By.Id("txtLastName"))).SendKeys("Skeet");
Reusing the WebDriverWait objects for multiple "waits" is best. The only time you need a different WebDriverWait object is if you need two different timeout periods. Otherwise the only state that a WebDriverWait keeps is the driver and how long it waits.
Ok, I found the source code for the WebDriverWait and Until method, and I find there is no problem reusing this object:
public virtual TResult Until<TResult>(Func<T, TResult> condition, CancellationToken token)
{
if (condition == null)
{
throw new ArgumentNullException("condition", "condition cannot be null");
}
var resultType = typeof(TResult);
if ((resultType.IsValueType && resultType != typeof(bool)) || !typeof(object).IsAssignableFrom(resultType))
{
throw new ArgumentException("Can only wait on an object or boolean response, tried to use type: " + resultType.ToString(), "condition");
}
Exception lastException = null;
var endTime = this.clock.LaterBy(this.timeout);
while (true)
{
token.ThrowIfCancellationRequested();
try
{
var result = condition(this.input);
if (resultType == typeof(bool))
{
var boolResult = result as bool?;
if (boolResult.HasValue && boolResult.Value)
{
return result;
}
}
else
{
if (result != null)
{
return result;
}
}
}
catch (Exception ex)
{
if (!this.IsIgnoredException(ex))
{
throw;
}
lastException = ex;
}
// Check the timeout after evaluating the function to ensure conditions
// with a zero timeout can succeed.
if (!this.clock.IsNowBefore(endTime))
{
string timeoutMessage = string.Format(CultureInfo.InvariantCulture, "Timed out after {0} seconds", this.timeout.TotalSeconds);
if (!string.IsNullOrEmpty(this.message))
{
timeoutMessage += ": " + this.message;
}
this.ThrowTimeoutException(timeoutMessage, lastException);
}
Thread.Sleep(this.sleepInterval);
}
}
I will mark the previous answer as correct, just putting here for a more detailed and added authoritative source also.
The program for ordering statements on the registry, I can not go to their pop-up window, selenium does not see that any new is being created.
Is it possible to do it through Xpath without using the transition to the Popup window, a browser function, or in another way in Selenium (Chrome)?
New window detection function:
public static string ClickAndSwitchWindow(IWebElement elementToBeClicked,
IWebDriver driver, int timer = 2000)
{
System.Collections.Generic.List<string> previousHandles = new
System.Collections.Generic.List<string>();
System.Collections.Generic.List<string> currentHandles = new
System.Collections.Generic.List<string>();
previousHandles.AddRange(driver.WindowHandles);
elementToBeClicked.Click();
Thread.Sleep(timer);
for (int i = 0; i < 20; i++)
{
currentHandles.Clear();
currentHandles.AddRange(driver.WindowHandles);
foreach (string s in previousHandles)
{
currentHandles.RemoveAll(p => p == s);
}
if (currentHandles.Count == 1)
{
driver.SwitchTo().Window(currentHandles[0]);
Thread.Sleep(100);
return currentHandles[0];
}
else
{
Thread.Sleep(500);
}
}
return null;
}
The piece of code itself:
//After this click of this element, a window opens:
//"Send request"
IWebElement PopWindowsstart = ww.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/div[1]/div[6]/div[4]/div/div/section/div[2]/div[2]/div/div/div[2]/div/div[2]/div/div/div/div[1]/div/div/div/div[1]/div/div/div/div[4]/div/div/div/div[1]/div/div/div/div[1]/div/div/span/span")));
//Search for a new window
string newWin = ClickAndSwitchWindow(PopWindowsstart, Browser, 2500);
PopupWindowFinder finder = new PopupWindowFinder(Browser);
//Switch to a new window
Browser.SwitchTo().Window(newWin);
//Statement Number:
IWebElement NumExctract = ww.Until(ExpectedConditions.ElementIsVisible(By.XPath("div[class='v-label v-label-tipFont tipFont v-label-undef-w'] b")));
//Read check
MessageBox.Show(NumExctract.Text);
//"Continue work"
ww.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/div[7]/div/div/div/div[3]/div/div/div/div[1]/div/div/div/div[2]/div/div/div/div[1]/div/div/div/div[1]/div/div/span/span"))).Click();
//"Change"
ww.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/div[1]/div[6]/div[4]/div/div/section/div[2]/div[2]/div/div/div[2]/div/div[2]/div/div/div/div[1]/div/div/div/div[2]/div/div/div/div[1]/div/div/div/div[2]/div/div/span/span"))).Click();
Thread.Sleep(300000);
Type window:
Let's make this a bit easier.
If you need to switch to a popup, try the below.
public static string SwitchToPopup()
{
var mainHandle = Driver.CurrentWindowHandle;
var handles = Driver.WindowHandles;
foreach (var handle in handles)
{
if (mainHandle == handle)
{
continue;
}
Driver.SwitchTo().Window(handle);
break;
}
var result = Url;
return result;
}
When you need to switch back, use:
public static void GoToMainHandle()
{
var handles = Driver.WindowHandles;
foreach (var handle in handles)
{
Driver.SwitchTo().Window(handle);
break;
}
}
That being said, your xpath is not something that should ever be used. Please look at https://www.w3schools.com/xml/xpath_intro.asp and rewrite it. When you use chrome to give you your xpath like:
ww.Until(ExpectedConditions.ElementIsVisible(By.XPath("/html/body/div[1]/div[6]/div[4]/div/div/section/div[2]/div[2]/div/div/div[2]/div/div[2]/div/div/div/div[1]/div/div/div/div[2]/div/div/div/div[1]/div/div/div/div[2]/div/div/span/span"))).Click();
If your dev adds a div in here somewhere, all of your tests will now fail. If your devs are not providing unique identifiers, work with them to resolve that. You should have id's, class names etc.
Try:
public static void PopUp()
{
_webDriver.SwitchTo().Alert().Accept();
}
So I am trying to build a program to control a machine. Communications with said machine is via a serial port for which I have written a driver. Continuous polling to the machine is necessary for status feedback etc. In my program I have a dedicated ExecutionEngine() class to handle serial send and receive. I also need to have two separate control sequences running, which I have put into methods RunSequenceA() and RunSequenceB() respectively. During normal operation, all three methods need to run until both control sequences finish, at which point the StopSequence() method is called. My issue is that sometimes, for whatever reason, the StopSequence() method is never called, leaving my ExecutionEngine() method in an infinite loop!
Code for ExecutionEngine():
private static void ExecutionEngine()
{
// Clear both lists in case they have old data
_commandList.Clear();
_pollingList.Clear();
// Poll while user has not yet clicked "STOP"
while (!_cTokenSource.Token.IsCancellationRequested)
{
// If there are commands to be sent, send them first
if (_commandList.Count > 0)
{
Command[] tempCommandArray;
lock (_commandList)
tempCommandArray = _commandList.ToArray();
foreach (var c in tempCommandArray)
{
if (_cTokenSource.Token.IsCancellationRequested)
break;
var response = SerialDriver.ComCycle(c.CommandBytes, _serialPort);
var success = CheckErrorReturn(response, false);
if (success)
{
AddPolling(c);
RemoveCommand(c);
}
}
}
// Do polling operation on applicable controllers
if (_pollingList.Count > 0)
{
Command[] tempPollingArray;
lock (_pollingList)
tempPollingArray = _pollingList.ToArray();
foreach (var c in tempPollingArray)
{
if (_cTokenSource.Token.IsCancellationRequested)
break;
var response = SerialDriver.ComCycle(c.PollBytes, _serialPort);
var success = ProcessPollReturn(response);
if (success)
{
c.FlagDone();
RemovePolling(c);
}
}
}
if (_commandList.Count + _pollingList.Count == 0)
{
// Will get stuck here if neither list gets new items added
Console.WriteLine("Bad place");
Thread.Sleep(500);
}
}
// Cancellation has been requested
lock (_commandList)
_commandList.Clear();
lock (_pollingList)
_pollingList.Clear();
ResetTriggers();
var endCommand = new Command("GL_SYSCMD", 0);
SerialDriver.ComCycle(endCommand.CommandBytes, _serialPort);
_serialPort.Close();
_vm.SequenceRunning = false;
return;
}
Code for running sequences:
private static async Task RunSequencesAsync()
{
var taskArray = new Task[2];
var a = new Action(RunSequenceA);
var b = new Action(RunSequenceB);
taskArray[0] = Task.Run(a);
taskArray[1] = Task.Run(b);
await Task.WhenAll(taskArray).ConfigureAwait(continueOnCapturedContext: false);
// Sometimes this never fires, WHY?
UpdateStatus("All done!");
StopSequence();
}
// Run A sequence
internal static void RunSequenceA()
{
if (_sequenceA1 != null && _sequenceA1.Count > 0)
{
foreach (var s in _sequenceA1)
{
if (_cTokenSource.Token.IsCancellationRequested)
return;
s.Execute();
if (s.Reference != null && TriggerStepCompleted != null)
TriggerStepCompleted(s, EventArgs.Empty);
}
// This part always fires
Console.WriteLine("Sequence A finished");
return;
}
else
return;
}
And finally, the methods to start and stop everything:
private static async Task StartSequenceAsync()
{
_serialPort.PortName = _vm.SelectedComPort;
_serialPort.Open();
_serialPort.DiscardInBuffer();
_serialPort.DiscardOutBuffer();
// Start
_cTokenSource = new CancellationTokenSource();
_vm.SequenceRunning = true;
var taskArray = new Task[2];
taskArray[0] = Task.Run(() => ExecutionEngine());
Thread.Sleep(50);
taskArray[1] = Task.Run(() => RunSequencesAsync());
await Task.WhenAll(taskArray).ConfigureAwait(continueOnCapturedContext: false);
}
private static void StopSequence()
{
_cTokenSource.Cancel();
}
To reiterate, the problem doesn't happen every time. In fact, most times the program runs fine. It seems that problems only arise if I manually call the StopSequence() method half way through execution. Then it's 50/50 as to whether the problem shows up. I'm pretty sure my issue is threading related, but not sure exactly what is going wrong. Any help pointing me in the right direction will be greatly appreciated!
I have written an app that goes through our own properties and scraps the data. To make sure I don't run through the same URLs, I am using a MySQL database to store the URL, flag it once its processed. All this was being done in a single thread and it's fine if I had only few thousand entries. But I have few hundred thousand entries that I need to parse so I need to make changes in the code (I am newbie in multithreading in general). I found an example and was trying to copy the style but doesn't seem to work. Anyone know what the issue is with the following code?
EDIT: Sorry didn't mean to make people guess the issue but was stupid of me to include the exception. Here is the exception
"System.InValidCastException: 'Specified cast is not valid.'"
When I start the process it collects the URLs from the database and then never hits DoWork method
//This will get the entries from the database
List<Mappings> items = bot.GetUrlsToProcess(100);
if (items != null)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
Worker.Done = new Worker.DoneDelegate(WorkerDone);
foreach (var item in items)
{
urls.Add(item.Url);
WaitingTasks.Enqueue(new Task(id => new Worker().DoWork((int)id, item.Url, token), item.Url, token));
}
LaunchTasks();
}
static async void LaunchTasks()
{
// keep checking until we're done
while ((WaitingTasks.Count > 0) || (RunningTasks.Count > 0))
{
// launch tasks when there's room
while ((WaitingTasks.Count > 0) && (RunningTasks.Count < MaxRunningTasks))
{
Task task = WaitingTasks.Dequeue();
lock (RunningTasks) RunningTasks.Add((int)task.AsyncState, task);
task.Start();
}
UpdateConsole();
await Task.Delay(300); // wait before checking again
}
UpdateConsole(); // all done
}
static void UpdateConsole()
{
Console.Write(string.Format("\rwaiting: {0,3:##0} running: {1,3:##0} ", WaitingTasks.Count, RunningTasks.Count));
}
static void WorkerDone(int id)
{
lock (RunningTasks) RunningTasks.Remove(id);
}
public class Worker
{
public delegate void DoneDelegate(int taskId);
public static DoneDelegate Done { private get; set; }
public async void DoWork(object id, string url, CancellationToken token)
{
if (token.IsCancellationRequested) return;
Content obj;
try
{
int tries = 0;
bool IsUrlProcessed = true;
DateTime dtStart = DateTime.Now;
string articleDate = string.Empty;
try
{
ScrapeWeb bot = new ScrapeWeb();
SearchApi searchApi = new SearchApi();
SearchHits searchHits = searchApi.Url(url, 5, 0);
if (searchHits.Hits.Count() == 0)
{
obj = await bot.ReturnArticleObject(url);
if (obj.Code != HttpStatusCode.OK)
{
Console.WriteLine(string.Format("\r Status is {0}", obj.Code));
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.HttpCode = obj.Code;
}
else
{
string title = obj.Title;
string content = obj.Contents;
string description = obj.Description;
Articles article = new Articles();
article.Site = url.GetSite();
article.Content = content;
article.Title = title;
article.Url = url.ToLower();
article.Description = description;
string strThumbNail = HtmlHelper.GetImageUrl(url, obj.RawResponse);
article.Author = HtmlHelper.GetAuthor(url, obj.RawResponse);
if (!string.IsNullOrEmpty(strThumbNail))
{
//This condition needs to be added to remove ?n=<number> from EP thumbnails
if (strThumbNail.Contains("?"))
{
article.ImageUrl = strThumbNail.Substring(0, strThumbNail.IndexOf("?")).Replace("http:", "https:");
}
else
article.ImageUrl = strThumbNail.Replace("http:", "https:");
}
else
{
article.ImageUrl = string.IsNullOrEmpty(strThumbNail) ? article.Url.GetDefaultImageUrls() : strThumbNail.Replace("http:", "https:");
}
articleDate = HtmlHelper.GetPublishDate(url, obj.RawResponse);
if (string.IsNullOrEmpty(articleDate))
article.Pubdate = DateTime.Now;
else
article.Pubdate = DateTime.Parse(articleDate);
var client = new Index(searchApi);
var result = client.Upsert(article);
itemfound.HttpCode = obj.Code;
if (result)
{
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate);
UpdateItem(itemfound);
}
else
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
UpdateItem(itemfound, tries, IsUrlProcessed);
}
}
}
else
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = true;
itemfound.HttpCode = HttpStatusCode.OK;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
}
}
catch (Exception e)
{
tries = itemfound.UrlMaxTries + 1;
IsUrlProcessed = false;
itemfound.DateCreated = DateTime.Parse(articleDate);
itemfound.DateModified = DateTime.Parse(articleDate) == null ? DateTime.Now : DateTime.Parse(articleDate);
}
finally
{
DateTime dtEnd = DateTime.Now;
Console.WriteLine(string.Format("\r Total time taken to process items is {0}", (dtEnd - dtStart).TotalSeconds));
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Done((int)id);
}
}
All this code is based from Best multi-thread approach for multiple web requests this link. Can someone tell me how to get this approach running?
I think the problem is in the way you're creating your tasks:
new Task(id => new Worker().DoWork((int)id, item.Url, token), item.Url, token)
This Task constructor overload expected Action<object> delegate. That means id will be typed as object and you need to cast it back to something useful first.
Parameters
action
Type: System.Action<Object>
The delegate that represents the code to execute in the task.
state
Type: System.Object
An object representing data to be used by the action.
cancellationToken
Type: System.Threading.CancellationToken
-The CancellationToken that that the new task will observe.
You decided to cast it to int by calling (int)id, but you're passing item.Url as the object itself. I can't tell you 100% what the type of Url is but I don't expect Url-named property to be of type int.
Based on what #MarcinJuraszek said I just went back to my code and added an int as I couldn't find another way to resolve it. Here is the change I made
int i=0
foreach (var item in items)
{
urls.Add(item.Url);
WaitingTasks.Enqueue(new Task(id => new Worker().DoWork((string)id, item.Url, token), item.Url, token));
i++;
}
I have a list of records with for example status, department, amount, title and some buttons.
If I wanted to assert for example the title I used the following code:
private IWebElement GetTitleElement(int actionRowNumber)
{
var xpath = $"//tr[#id = 'ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__{actionRowNumber}']/td[9]";
return BrowserFactory.Driver.FindElement(By.XPath(xpath));
}
I am doing the same for type, status, department
And then I used a try catch method to go through each record untill I found the desired record in the system:
public void CheckActionxxx(ActionTypes type, Enum.Departments departments, Enum.ActionStatus actionstatus, string title)
{
Wait();
var actiontype = type;
try
{
for (var i = 0; i <= 4; i++)
{
if (GetTitleElement(i).Text == title && GetActionTypeElement(i).Text == actiontype.ToString())
{
Assert.AreEqual(type.ToString(), GetActionTypeElement(i).Text);
Assert.AreEqual(actionstatus.ToString(), GetActionStatusElement(i).Text);
Assert.AreEqual(departments == Enum.Departments.None ? " " : departments.ToString(),
GetActionDepartmentElement(i).Text);
return;
}
}
throw new NoSuchElementException();
}
catch (NoSuchElementException)
{
throw new NoSuchElementException($"Not found with'{title}'");
}
}
Because the id’s only had a difference in numbers (e.g. 0,1,2) I was able to use integer
Department:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__0"]/td[5]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__1"]/td[5]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__2"]/td[5]
Status:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__0"]/td[2]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__1"]/td[2]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__2"]/td[2]
Title:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__0"]/td[9]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__1"]/td[9]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00__2"]/td[9]
Now I want to use a try catch that finds a button based on the same way of working but the id of this button is as follow:
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl04_ButtonClose"]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl06_ButtonClose"]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl08_ButtonClose"]
//[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl10_ButtonClose"]
//*[#id="ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl12_ButtonClose"]
As you can see it starts at ctl04 and continues in steps of two.
I cannot figure out how to design my private webelement. I tried:
private IWebElement GetActionCloseButtonElement(int actionRowNumber)
{
var xpath = $"//tr[#id = 'ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_{actionRowNumber}_ButtonClose']";
return BrowserFactory.Driver.FindElement(By.XPath(xpath));
}
But that doesnt work.
Something like this should work.
actionRowNumber should be 04, 06, 08, 10, 12 as from the xpath.
private IWebElement GetActionCloseButtonElement(int actionRowNumber)
{
return BrowserFactory.Driver.FindElement(By.Xpath("//tr[#id = 'ctl00_ctl00_CPH_CPH_ActionsOverviewControl1_RadGridActions_ctl00_ctl"+ actionRowNumber +"_ButtonClose']"));
}