Use SmartMenu with Selenium WebDriver - c#

I have a SmartMenu in a web app which I need to test with Selenium. I can find the root menu items by partial link text but none of the sub menu items can be found.
Has anyone found a way to do this?
Here is my code:
var menu = IEBrowser.DriverInstance.FindElement(By.Id("main-menu"));
var navigate = menu.FindElement(By.PartialLinkText("Navigate"));
navigate.Click();
var offsite = navigate.FindElement(By.PartialLinkText("off-site"));
offsite.Click();
I get a "NoSuchElementException" on line 5.
I also tried:
var menu = IEBrowser.DriverInstance.FindElement(By.Id("main-menu"));
var navigate = menu.FindElement(By.PartialLinkText("Navigate"));
Actions a = new Actions(IEBrowser.DriverInstance);
a.MoveToElement(navigate).Build().Perform();
a.Click();
var offsite = navigate.FindElement(By.PartialLinkText("off-site"));
a.MoveToElement(offsite).Build().Perform();
a.Click();
This also fails on the "offsite" var.

I managed to locate the elements using
var offsite = menu.FindElements(By.TagName("a"))[2];
I don't know why that worked and By.PartialLinkText didn't.

Related

Element not interactable with C# app that uses Chrome WebDriver

PREFACE: After a lengthy Stack Overflow search I found two suggested solutions to solve the "element not interactable" problem I am having when I try to interact with the target node element. Neither of them worked, as described below.
I have a C# app that uses the OpenQA.Selenium package to remote control a YouTube web page. I am trying to click on a button on the page that opens a dialog box, but when I do I get the notorious "element not interactable" message. I found the following two suggestions on Stack Overflow:
Actions actions = new Actions(chromeDriver);
actions.MoveToElement(webElem);
actions.Perform();
And this suggestion that one commenter said is ill-advised because it can click on elements that are not visible or are below modal objects:
IJavaScriptExecutor executor = (IJavaScriptExecutor)chromeDriver;
executor.ExecuteScript("arguments[0].click();", webElem);
I tried the second one anyways to see if it worked. Unfortunately, with the first suggestion that uses the Actions interface, I still got "element not interactable" message but this time on the Perform() statement. The third attempt did not get the error message but it failed to click the button. I know this because clicking the button opens a dialog window when it works, and no dialog window appeared when I tried the third solution.
Below is the code I am using to try and click on the element. The collection it iterates are the elements I select via an XPath statement that finds the button I am want to click. It tries every button that matches the XPath statement and skips those that fail to work. Unfortunately, none of the 3 buttons found by the XPath statement work.
What is strange is that if I take the exact same XPath statement I am using in my C# app and plug it into the Chrome DevTools debugger, referencing the first element in the array of found elements, it works:
$x(strXPath)[0].click()
But so far nothing I have tried from C# app works. Does anyone have an idea on why I am having this problem?
public IWebElement ClickFirstInteractable(ChromeDriver chromeDriver)
{
string errPrefix = "(ClickFirstInteractable) ";
if (this.DOM_WebElemensFound == null || this.DOM_WebElemensFound.Count() < 1)
throw new NullReferenceException(errPrefix + "The DOM_WebElementsFound collection is empty.");
IWebElement webElemClicked = null;
foreach (IWebElement webElem in this.DOM_WebElemensFound)
{
// Try and "click" it.
try
{
// First make sure the element is visible, or we will get
// the "element not interactable" error.
/* FIRST ATTEMPT, didn't work.
*
webElem.scrollIntoView(true);
webElem.Click(); // <<<<<----- Error occurs here
*/
/* SECOND ATTEMPT using Actions, didn't work
* and I go the error message when the Perform() statement executes.
Actions actions = new Actions(chromeDriver);
actions.MoveToElement(webElem);
actions.Perform(); // <<<<<----- Error occurs here
*/
/* THIRD ATTEMPT using script execution, didn't work.
* I did not get the error message, but the button did not get clicked.
*/
IJavaScriptExecutor executor = (IJavaScriptExecutor)chromeDriver;
executor.ExecuteScript("arguments[0].scrollIntoView();", webElem);
executor.ExecuteScript("arguments[0].click();", webElem);
// Click operation accepted. Stop iteration.
webElemClicked = webElem;
break;
}
catch (ElementNotInteractableException exc)
{
// Swallow this exception and go on to the next element found by the XPath expression.
System.Console.WriteLine(exc.Message);
}
}
return webElemClicked;
}
I tried to reproduce your scenario by clicking on a "hidden" button, waiting for the modal to appear, then acting on that modal, etc.
I hope it helps you!
const string Target = #"https://www.youtube.com/";
using var driver = new ChromeDriver();
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20))
{
PollingInterval = TimeSpan.FromMilliseconds(250),
};
driver.Navigate().GoToUrl(Target);
// i don't consent cookies to
// save time, so just do it
// here manually and then press enter to console
Console.ReadLine();
var menuLocator = By.XPath("//a[#id = 'video-title-link'][1]" +
"/ancestor::div[#id = 'meta']" +
"/following-sibling::div[#id = 'menu']" +
"//button[#class = 'style-scope yt-icon-button']");
var menu = wait.Until(d => d.FindElement(menuLocator));
var actions = new Actions(driver);
actions.MoveToElement(menu).Click().Perform();
var shareLocator = By.XPath("//div[#id = 'contentWrapper']//*[normalize-space(text()) = 'Share']");
var share = wait.Until(d => d.FindElement(shareLocator));
actions.MoveToElement(share).Click().Perform();
var copyLinkLocator = By.XPath("//button[#aria-label = 'Copy']");
var copyLink = wait.Until(d => d.FindElement(copyLinkLocator));
actions.MoveToElement(copyLink).Click().Perform();

How can i access the console logs on chrome and assert if a line exists?

Quite new to selenium, have been looking to find an answer to this question, but so far, all the times I have tried I was not able to get my desired result.
I followed other answers to access the chrome console logs but i get an exception:
ChromeOptions options = new ChromeOptions();
options.SetLoggingPreference(LogType.Browser, LogLevel.All);
var driver = new ChromeDriver(options);
driver.Manage().Window.Maximize();
driver.Url = "https://test.test";
var homePage = new HomePage(driver); //POM
homePage.SignIn().Click();
homePage.Email("email");
homePage.Password("pw");
homePage.LogIn();
var logs = driver.Manage().Logs.GetLog(LogType.Browser);
foreach (var log in logs)
{
Console.WriteLine(log.ToString());
}
the exception is thrown on : var logs = driver.Manage().Logs.GetLog(LogType.Browser);
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I haven't been able to understand why it is thrown.
After that, i would like to assert the console logs to see if a specific entry is present. Is it possible?
So, this is a dirty workaround. If you get any good answer, please don't use mine.
Modify the default console.log method to store data in a newly introduced global variable:
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
//Multiline string used for readability. Write it in single line
js.ExecuteScript("
window.oldConsoleLog = window.console.log;
window.logCalls = [];
window.console.log = function(){
oldConsoleLog.apply(window.console, arguments);
window.logCalls.push(arguments);
}
");
Now you'll be able to get all calls using the next code:
var calls = js.ExecuteScript("return window.logCalls");
If you need a cleanup:
js.ExecuteScript("delete window.logCalls;window.console.log = window.oldConsoleLog;")

Use White UI and FlaUI together

Can I use WhiteUI and FlaUI together in a project?
public TestStack.White.Application app = null;
public TestStack.White.UIItems.WindowItems.Window=null;
var processStartInfo = new ProcessStartInfo(#"winword.exe");
var application = Application.Launch(processStartInfo);
app=Application.Attach("winword");
FlaUI.Core.Application fpp = (FlaUI.Core.Application)app;
TestStack.White.UIItems.WindowItems.Window window = app.GetWindow("Microsoft Word");
FlaUI.Core.AutomationElements.Window fwin = (FlaUI.Core.AutomationElements.Window) Window;
Unable to cast window and application of Test Stack to FlaUI.
You would need to get the underlying AutomationElement from the White control and then create the FlaUI control using that AutomationElement. This means you will be limited to using UIAv2 only since White does not have a UIAv3 implementation.
Every UIItem in White exposed a AutomationElement property where you can get the underlying UIAv2 wrapper. Then you should be able to construct the FlaUI UIA2FrameworkAutomationElement using the AutomationElement from White as the second parameter. Then you will pass the UIA2FrameworkAutomationElementfrom FlaUI into the ComboBox from FlaUI. So it will look something like the following.
var processStartInfo = new ProcessStartInfo(#"winword.exe");
var application = Application.Launch(processStartInfo);
TestStack.White.Application app = Application.Attach("winword");
TestStack.White.UIItems.WindowItems.Window window = app.GetWindow("Microsoft Word");
TestStack.White.UIItems.ListBoxItems.ComboBox whiteCombox = window.Get<ComboBox>(SearchCriteria.ByAutomationId("MyComboBox"));
var flaUiAutomationElment = new FlaUI.UIA2.UIA2FrameworkAutomationElement(new UIA2Automation(), whiteCombox.AutomationElement);
var flaUiComboBox = new FlaUI.Core.AutomationElements.ComboBox(flaUiAutomationElment);
I would suggest just doing everything in FlaUI if at all possible.
The answer is simple: Yes, because both solutins work on the same page, and that's Automation UI.
But you gonna need to inform to FLAUI what process ID you are dealing with, like below:
var automation = new UIA3Automation(); //start new instance of FALUI
var app = FlaUI.Core.Application.Attach(application.Process.Id); //.Id its a property of you var application
var window = app.GetMainWindow(automation); //With that, FlaUI gets hold of the window
After you deal with the FLAUI, you can attach the same ID on the White and vice-versa. It's pretty straight foward.

Access the Source Control Explorer in TFS from C#.net code

Here is the code which I have written to access the Projects and the team, but it shows some error. I want to access the project and then the Source Code present in the Source Control Explorer in the Project/Team.
Uri _serverUri = new Uri("MyURI");
string _teamProjectName = "MyProject";
TfsTeamProjectCollection collection =
TfsTeamProjectCollectionFactory.GetTeamProjectCollection(_serverUri);
// Retrieve the project URI. Needed to enumerate teams.
var css4 = collection.GetService<ICommonStructureService>();
ProjectInfo projectInfo = css4.GetProjectFromName(_teamProjectName);
// Retrieve a list of all teams on the project.
TfsTeamService teamService = collection.GetService<TfsTeamService>();
var allTeams = teamService.QueryTeams(projectInfo.Uri);
allTeams.ToList().ForEach
(
allteams => { Console.WriteLine(allteams); });
The error which it shows is "The type or namespace 'Core' does not exist in the namespace Microsoft.TeamFoundation.Server
I also want to access the source control, so if anyone can help me with both of my issues.

Is it possible to let webinator use the instance of selenium that was already created? C#

I was wondering if it was possible to let Webinator use the browser window that i have already opened using selenium. Because now I need to create a new instance(config) and this just opens another browser window.
I think my code will do more explaining.
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(d => { return d.FindElement(By.Id("mainContentPlaceholder_Wizard1_ButtonCSV")).Displayed; });
driver.FindElement(By.Id("mainContentPlaceholder_Wizard1_ButtonCSV")).Click();
var config = new Config
{
LogScreenshots = true,
LogLevel = Config.AvailableLogLevels.Verbose,
BaseUrl = driver.Url,
Browser = Config.AvailableBrowsers.FirefoxPlugins,
Framework = Config.AvailableFrameworks.WebDriver,
};
// new instance so new browser window opens
var web = WebManagerFactory.CreateInstance(config);
var fileUpload = LocateBy.Attributes(ByAttribute.Name("ctl00$mainContentPlaceholder$Wizard1$AsyncFileUploadCsv$ctl02"));
web.Click(fileUpload, WaitUntil.DialogAppears("File Upload"));
web.Dialog.SelectFiles(Comparison.Contains, "File Upload", #"C:\Users\bram\Desktop", "test2.csv");
No.
It is one of the oldest and most-asked for issues raised against Selenium project:
https://code.google.com/p/selenium/issues/detail?id=18

Categories

Resources