Using .net 6, bUnit 1.13.5 Mudblazor 6.0.17
I am trying to write unit tests for a razor component that is in a dialog box and bUnit is unable to find any of the components or class/ids in it. I am getting the following error...
Message:
Bunit.ElementNotFoundException : No elements were found that matches the selector '#CancelButton'
in the ColumnTrackerEditDialog.razor there is the following line
<MudButton id="CancelButton" OnClick="#Cancel">Cancel</MudButton>
This should always be rendered and it not under any conditional statements. The unit test for this is as follows (so far)
[Test]
public async Task ColumnTrackerEditDialogUITest_CancelButton()
{
var item = GetColumnTrackerPeco();
PopulateData(item);
var page = TestContext!.RenderComponent<ColumnTrackerEditDialog>(parameters =>
parameters.Add(p => p.Item, item));
Assert.IsNotNull(page);
var cancelButton = page.Find("#CancelButton");
Assert.IsNotNull(cancelButton);
cancelButton.Click();
}
The test set up is fine as the page is not null and on non dialog pages I can find elements by ids, classes or components.
Is this an issue because it's a dialog or am I missing something else?
I have tried to find "button", ".mud-button" and other classes, as well as .FindComponent and other tags within the component and it's not finding anything.
Is the component being added asynchronously? If that's the case, try using cut.WaitForElement("#CancelButton") instead.
Another approach is to stub out the MudBlazor component, so it's not directly influences your test, and instead find the stub and assert you passed the expected parameters to it. Learn more here: https://bunit.dev/docs/providing-input/substituting-components
Related
I am trying to determine which instance of my multi-instance UWP application should be activated based on the argument passed to it:
var instances = AppInstance.GetInstances();
if (instances.Count() != 0)
{
instances[0].RedirectActivationTo();
}
I have tried placing the code in app.xaml.cs (OnActivated) and main.xaml.cs (OnNavigatedTo) and they both throw the "The group or resource is not in the correct state to perform the requested operation." error for which there appears to be no documentation.
How can I redirect the activation to a current instance?
The AppInstance class should be used in a main method. This is mentioned in the document: The AppInstance class is intended to be used in the Main method of the app. If this class is used later, the property values may be null, and the methods may fail.
To create a main method of UWP app, you will need to disable the defaulted main method which is generated automatically first. Please right click on your project and choose properties, in the Build tab, add DISABLE_XAML_GENERATED_MAIN to the Conditional Compilation Symbols.
Then you could add a new static class to your project and add a new static main mehtod in the class.
I found a blog which have detailed steps about how to use AppInstance.RedirectActivationTo method, you could take a look at: Multiple instances support for UWP apps (Part 2): Redirection
Besides if you want to redirect to an existing instance, it will be better to register the instance first.
I'm making a plugin based C# application in Unity 5.6, where some plugins might sometimes be installed, sometimes not.
In my plugin Plugin1, I have a component Plugin1.Component1. In that same project, I implement a custom editor for it, called Plugin1.Component1Editor, that is a [CustomEditor(typeof(Plugin1.Component1))]. When Plugin1 is installed, the Component1 is available, and rendered with the custom editor.
My plugin Plugin2 depends on Plugin1. Depending on settings in its component Plugin2.Component2, it would like to alter the custom editor for Plugin1.Component1.
I have implemented a new custom editor in Plugin2, called Plugin2.Component1Editor, that is also a [CustomEditor(typeof(Plugin1.Component1))]. It inherits from UnityEditor.Editor, not from Plugin1.Component1Editor, as the latter caused problems with serialized properties not being found in Plugin1.Component1Editor.
Plugin2.Component1Editor won't collide with Plugin1.Component1Editor at compile time, as it has its own namespace. But what actually happens in the Unity inspector?
The behaviour when I test it is the desired behaviour: The Plugin2.Component1Editor renders the inspector, unless Plugin2 not installed. But why?
I don't want to trust that it will keep doing so unless I know why.
Thank you!
EDIT: I was wrong, it wasn't rendering the Plugin2.Component1Editor, it was the default Unity editor running. Neither of my custom editors are used. How can I specify which one I want to use?
It seems that the solution was indeed inheritance.
I made the serialized properties handled by Plugin1.Component1Editor and their retrieval protected instead of private, and then Plugin2.Component1Editor inherits from Plugin1.Component1Editor instead of UnityEditor.Editor. Then the Plugin2.Component1Editor became the rendering one, calling the Plugin1.Component1Editor as needed.
The main part of the solution was that I made the OnEnable call in Plugin1.Component1Editor, which retrieves the serialized properties, protected, so that I could call it from Plugin2.Component1Editor via base.OnEnable().
For anyone stumbling on this question, the OP's solution only works (for me at least) if you have Plugin1 and Plugin2, where as if you have Plugin3 the last plugin will not be loaded as a custom editor. So i came up with another solution to this.
I've decided to use an "Editor Hub", a custom editor for Component1, that looks for ICustomEditor interface implementations using System.Reflection, also Unity has a nice class like TypeCache which can get you loaded classes
public interface ICustomEditor
{
EditorType Type { get; }
void OnEnable(SerializedObject target);
void OnInspectorGUI(SerializedObject target);
}
I've decided to go for EditorType.Before or EditorType.After to render custom features before or after the main editor.
protected virtual void OnEnable()
{
CollectEditors();
OnEnableEditors();
}
public override void OnInspectorGUI()
{
OnInspectorGUIBefore();
base.OnInspectorGUI();
OnInspectorGUIAfter();
}
private void CollectEditors()
{
var types = TypeCache.GetTypesDerivedFrom(typeof(ICustomEditor));
var list = new List<ICustomEditor>();
foreach (var e in types)
{
var editor = (ICustomEditor)Activator.CreateInstance(e);
list.Add(editor);
}
m_beforeEditors = list
.Where(t => t.Type == EditorType.Before)
.ToArray();
m_afterEditors = list
.Where(t => t.Type == EditorType.After)
.ToArray();
}
So I'm working with the Telerik reports, creating a server / client proof of concept project and I'm using ASP.NET WebAPI 2.0 with the HTML5 Report Viewer. I've got it to work when I have the .trdx files inside the server, and if I only ever wanted to use the standalone report generator, and then add the files into the project folder this would be fine.
However I'd prefer to be able to use the integrated visual studio report generator to make my reports. The output of the integrated generator is of course cs files, but I am not sure how I would call them on the client such that the HTML5 viewer there would resolve them properly. The controller on the server is as follows.
public class ReportsController : ReportsControllerBase
{
protected override IReportResolver CreateReportResolver()
{
var appPath = HttpContext.Current.Server.MapPath("~/");
return new ReportFileResolver(appPath);
}
protected override ICache CreateCache()
{
return Telerik.Reporting.Services.Engine.CacheFactory.CreateFileCache();
}
}
The code that is requesting the data on the client is as follows.
$(document).ready(function () {
$("#reportViewer1")
.telerik_ReportViewer({
serviceUrl: "http://localhost:XXXXX/api/reports/",
templateUrl: 'ReportViewer/templates/telerikReportViewerTemplate.html',
reportSource: { report: "Reports/Accounting/InvoiceSubGroup/Invoice.trdx" },
viewMode: telerikReportViewer.ViewModes.INTERACTIVE,
scaleMode: telerikReportViewer.ScaleModes.SPECIFIC,
scale: 1.0,
ready: function () {
},
});
});
Any information that would make it more clear to me how to change this, I'd appreciate it.
So I'm not entirely sure if it's possible to do this using the FileReportResolver as I was using previously, however I've more or less figured out how to do this in general and it doesn't break the case where I'm using trdx files elsewhere.
Changes to the html page are as follows:
Old, this is still going to be how to call a report that will be a trdx type. -
reportSource: { report: "Reports/Warehouse/Facts/Invoice.trdx" },
New, this is how you're going to reference a report made through the integrated report viewer -
reportSource: { report: "TelerikRESTHost.Reports.Warehouse.Facts.People, TelerikRESTHost" },
The first parameter is the namespace inside of the [report name].Designer.cs file (at the top) and the specific one you're looking for. In my case the report was People.cs and the namespace was as you can see above. The difference between the two is what type of file they are, old was a .trdx file and the new is a .cs file. The second parameter is the Assembly name of the project the file lives in.
The important things here are that the report source second parameter HAS to be the assembly name of the project, that was what was really messing with me for quite awhile since I renamed it through the solution explorer, but that doesn't change the assembly name.
As far as the controller goes, I had to modify it as follows
return new ReportFileResolver(appPath)
.AddFallbackResolver(new ReportTypeResolver());
This will obviously try to resolve it based on the file name first (The old method) and if it can't do that then it will try to resolve it as a type (the new method).
I hope this helps someone else avoid the time I spent trying to figure this out. If anyone can figure out an easy way to combine these approaches so that the client doesn't have to know what type of file format is on the server, I will mark your answer as the solution (assuming it works) since that was what I was looking for in the first place. This is at least an acceptable work around for now though.
I am trying to use CssSelector to locate an element on my webpage. I am using Firefox driver.
Here is how I am using the locator (I checked that Selenium IDE is able to locate my element with this
[FindsBy(How = How.CssSelector, Using = "label:contains('Version: 2.0.')")]
public IWebElement labelVersion;
But when use this in the C# code and initialize it with
PageFactory.InitElements in my constructor.
I hit this error... (the error itself is pretty clear but I don't know how to fix it)
Appreciate any inputs.
OPC.Tests.SmokeTest (TestFixtureSetUp): SetUp :
OpenQA.Selenium.InvalidSelectorException : The given selector
css=label:contains('Version: 2.0.') is either invalid or does not
result in a WebElement. The following error occurred: [Exception...
"An invalid or illegal string was specified" code: "12" nsresult:
"0x8053000c (NS_ERROR_DOM_SYNTAX_ERR)" location:
"file:///........../anonymous439571104.webdriver-profile/extensions/fxdriver#googlecode.com/components/driver_component.js
Line: 5811"]
Selenium delegates CSS queries down to the browser. This means that CSS queries need to follow CSS standard.
Unfortunately :contains was removed from the standard a while back. I recommend that you redo your selector with whats available from the spec or use XPATH.
:contains works in Selenium RC because RC uses Sizzle, the selector search library in jQuery if you are wondering why it works in RC and not WebDriver
I'm using Selenium's IWebDriver to write Unit Tests in C#.
Such is an example:
IWebDriver defaultDriver = new InternetExplorerDriver();
var ddl = driver.FindElements(By.TagName("select"));
The last line retrieves the select HTML element wrapped in a IWebElement.
I need a way to simulate selection to a specific option in that select list but I can't figure out how to do it.
Upon some research, I found examples where people are using the ISelenium DefaultSelenium class to accomplish the following, but I am not making use of this class because I'm doing everything with IWebDriver and INavigation (from defaultDriver.Navigate()).
I also noticed that ISelenium DefaultSelenium contains a ton of other methods that aren't available in the concrete implementations of IWebDriver.
So is there any way I can use IWebDriver and INavigation in conjunction with ISelenium DefaultSelenium ?
As ZloiAdun mentions, there is a lovely new Select class in the OpenQA.Selenium.Support.UI namespace. That's one of the best ways to access a selection element and it's options because it's api is so easy. Let's say you've got a web page that looks something like this
<!DOCTYPE html>
<head>
<title>Disposable Page</title>
</head>
<body >
<select id="select">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
</body>
</html>
You're code to access the select would look like this. Note how I create the Select object by passing a normal IWebElement to it's constructor. You have plenty of methods on the Select object. Take a look at the source for more information, until it gets properly documented.
using OpenQA.Selenium.Support.UI;
using OpenQA.Selenium;
using System.Collections.Generic;
using OpenQA.Selenium.IE;
namespace Selenium2
{
class SelectExample
{
public static void Main(string[] args)
{
IWebDriver driver = new InternetExplorerDriver();
driver.Navigate().GoToUrl("www.example.com");
//note how here's i'm passing in a normal IWebElement to the Select
// constructor
Select select = new Select(driver.FindElement(By.Id("select")));
IList<IWebElement> options = select.GetOptions();
foreach (IWebElement option in options)
{
System.Console.WriteLine(option.Text);
}
select.SelectByValue("audi");
//This is only here so you have time to read the output and
System.Console.ReadLine();
driver.Quit();
}
}
}
A couple things to note about the Support class however. Even if you downloaded the latest beta, the support DLL won't be there. The Support package has a relatively long history in the Java libraries (that's where PageObject lives) but it's still pretty fresh in the .Net driver. Fortunately, it's really easy to build from source. I pulled from SVN then referenced the WebDriver.Common.dll from the beta download and built in C# Express 2008. This class hasn't been as well tested as some of the other classes, but my example worked in Internet Explorer and Firefox.
There's a few other things that I should point out based on your code above. Firstly the line you were using to find the select element
driver.FindElements(By.TagName("select"));
is going to find all select elements. you should probably use driver.FindElement, without the 's'.
Also, very rarely would you use INavigation directly. You'll do most of your navigation like driver.Navigate().GoToUrl("http://example.com");
Lastly, DefaultSelenium is the way to access the older Selenium 1.x apis. Selenium 2 is a pretty significant departure from Selenium 1, so unless you're trying to migrate old tests to the new Selenium 2 api (often referred to as the WebDriver api) you won't use DefaultSelenium.
You should get all option elements from your select using ddl.FindElements(By.TagName("option"));. Then you can iterate through the returned collection and select required item(s) by using SetSelected method of the IWebElement
Update: It seems that there's now a C# implementation of the Select in WebDriver - previously it was in Java only. Please take a look at its code and it is easier to use this class