Option selection in WebDriver - webdriver

I'm using WebDriver and selenium-firefox-driver version 2.3.1. Now when option.setSelected(); deprecated, one must do option.click(); directly or more exactly :
if (value.equals(option.getAttribute("value"))) {
if(!option.isSelected()) {
option.click();
break;
}
}
The problem is, that I get this exception without reason.
Element is not currently visible and so may not be interacted with
<select id="deadLineDay" name="deadLineDay">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
Also, it is definitely not a timing issue... Any idea what the hell is that ? The exception is thrown only sometimes, but as I say, not a timing issue, I'm debugging that
This is the code :
public FillOutForm(WebDriver driver, UploadDocumentPage parent) {
this.driver = driver;
this.parent = parent;
PageFactory.initElements(new AjaxElementLocatorFactory(driver, 3), this);
}
#FindBy(how = How.NAME, using = day)
private WebElement deadLineDay;
#CacheLookup
#FindBy(how = How.NAME, using = hour)
private WebElement deadLineHour;
#CacheLookup
#FindBy(how = How.NAME, using = minute)
private WebElement deadLineMinute;
#CacheLookup
#FindBy(how = How.NAME, using = AmPm)
private WebElement deadLineAmPm;
#CacheLookup
#FindBy(how = How.ID, using = desc)
private WebElement description;
#CacheLookup
#FindBy(how = How.ID, using = comm)
private WebElement comment;
public boolean validationPasses(Map<String, String> map) {
try {
for (String key : map.keySet()) {
WebElement we = (WebElement) this.getClass().getDeclaredField(key).get(this);
setSelectedField(we, map.get(key));
}
} catch (Exception e) {
throw new Error(e.getMessage());
}
valid = elementExists(driver, By.className(validatorError));
return valid;
}
public void setSelectedField(WebElement element, String value) {
List<WebElement> options = element.findElements(By.tagName("option"));
for (WebElement option : options) {
if (value.equals(option.getAttribute("value"))) {
if(!option.isSelected()) {
option.click();
break;
}
}
}
}

I had this problem too. Try wrapping the WebElement with a Select object:
import org.openqa.selenium.support.ui.Select;
...
public void setSelectedField(WebElement element, String value) {
Select dropdown = new Select(element);
dropdown.selectByVisibleText(value);
}

Man it might seem hard to believe, but a month ago I often got out of space on disk and suddenly all tests were failing like this. It obviously doesn't have a reason to fail as far as I can see from the code you pasted...
Also I see you're using AjaxElementLocatorFactory. Switch to DefaultElementLocatorFactory, it might go away.

Related

Validating forms only on submit with Blazor

I've recently started using Blazor. Is there a way to trigger form model validation only on submit, instead of live on each change?
Just for clarification, let's say I have something like this:
<EditForm Model="this" OnValidSubmit="SubmitForm">
<DataAnnotationsValidator />
<ValidationSummary />
<Label For="Name">Name</Label>
<InputText id="Name" name="Name" class="form-control" #bind-Value="Name"/>
<button type="submit">Save</button>
</EditForm>
#code {
[StringLength(10, ErrorMessage="Name too long")]
public string Name { get; set; }
private async Task SubmitForm()
{
// ...
// send a POST request
}
}
By default, it seems like the validity of the field and the error messages displayed in the ValidationSummary get re-evaluated on every change of the text input (e.g. as soon as I delete the 11th character from the input, the "too long" message disappears).
I would prefer if the displayed messages would remain frozen until the Submit button is clicked.
I suppose it would be possible to implement it by removing the ValidationSummary component and implementing a custom solution (e.g. displaying a List of error messages that's refreshed only on submit), but I was wondering if there is some idiomatic solution that I'm not aware of.
When validation occurs is controlled by the Validator you're using.
There are two events that you can receive from EditContext:
OnValidationRequested is invoked either when EditContext.Validate is called or as part of the form submission process.
OnFieldChanged is invoked every time a field value is changed.
A validator uses these events to trigger it's validation process, and outputs the results to the EditContext's ValidationMessageStore.
DataAnnotationsValidator wires up for both events and triggers validation whenever either is invoked.
There are other validators out there, and writing your own is not too difficult. Other than those from the usual control suppliers, there's Blazored, or mine. Mine is documented here - https://shauncurtis.github.io/articles/Blazor-Form-Validation.html. it has a DoValidationOnFieldChange setting!
#enet's answer sparked an alternative answer. Build your own DataAnnotationsValidator.
Here's the EditContext Extensions code. It's a modified version of the original MS Code with some extra control arguments.
using Microsoft.AspNetCore.Components.Forms;
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
namespace StackOverflowAnswers;
public static class EditContextCustomValidationExtensions
{
public static IDisposable EnableCustomValidation(this EditContext editContext, bool doFieldValidation, bool clearMessageStore)
=> new DataAnnotationsEventSubscriptions(editContext, doFieldValidation, clearMessageStore);
private static event Action? OnClearCache;
private static void ClearCache(Type[]? _)
=> OnClearCache?.Invoke();
private sealed class DataAnnotationsEventSubscriptions : IDisposable
{
private static readonly ConcurrentDictionary<(Type ModelType, string FieldName), PropertyInfo?> _propertyInfoCache = new();
private readonly EditContext _editContext;
private readonly ValidationMessageStore _messages;
private bool _doFieldValidation;
private bool _clearMessageStore;
public DataAnnotationsEventSubscriptions(EditContext editContext, bool doFieldValidation, bool clearMessageStore)
{
_doFieldValidation = doFieldValidation;
_clearMessageStore = clearMessageStore;
_editContext = editContext ?? throw new ArgumentNullException(nameof(editContext));
_messages = new ValidationMessageStore(_editContext);
if (doFieldValidation)
_editContext.OnFieldChanged += OnFieldChanged;
_editContext.OnValidationRequested += OnValidationRequested;
if (MetadataUpdater.IsSupported)
{
OnClearCache += ClearCache;
}
}
private void OnFieldChanged(object? sender, FieldChangedEventArgs eventArgs)
{
var fieldIdentifier = eventArgs.FieldIdentifier;
if (TryGetValidatableProperty(fieldIdentifier, out var propertyInfo))
{
var propertyValue = propertyInfo.GetValue(fieldIdentifier.Model);
var validationContext = new ValidationContext(fieldIdentifier.Model)
{
MemberName = propertyInfo.Name
};
var results = new List<ValidationResult>();
Validator.TryValidateProperty(propertyValue, validationContext, results);
_messages.Clear(fieldIdentifier);
foreach (var result in CollectionsMarshal.AsSpan(results))
{
_messages.Add(fieldIdentifier, result.ErrorMessage!);
}
// We have to notify even if there were no messages before and are still no messages now,
// because the "state" that changed might be the completion of some async validation task
_editContext.NotifyValidationStateChanged();
}
}
private void OnValidationRequested(object? sender, ValidationRequestedEventArgs e)
{
var validationContext = new ValidationContext(_editContext.Model);
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(_editContext.Model, validationContext, validationResults, true);
// Transfer results to the ValidationMessageStore
_messages.Clear();
foreach (var validationResult in validationResults)
{
if (validationResult == null)
{
continue;
}
var hasMemberNames = false;
foreach (var memberName in validationResult.MemberNames)
{
hasMemberNames = true;
_messages.Add(_editContext.Field(memberName), validationResult.ErrorMessage!);
}
if (!hasMemberNames)
{
_messages.Add(new FieldIdentifier(_editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage!);
}
}
_editContext.NotifyValidationStateChanged();
}
public void Dispose()
{
if (_clearMessageStore)
_messages.Clear();
if (_doFieldValidation)
_editContext.OnFieldChanged -= OnFieldChanged;
_editContext.OnValidationRequested -= OnValidationRequested;
_editContext.NotifyValidationStateChanged();
if (MetadataUpdater.IsSupported)
{
OnClearCache -= ClearCache;
}
}
private static bool TryGetValidatableProperty(in FieldIdentifier fieldIdentifier, [NotNullWhen(true)] out PropertyInfo? propertyInfo)
{
var cacheKey = (ModelType: fieldIdentifier.Model.GetType(), fieldIdentifier.FieldName);
if (!_propertyInfoCache.TryGetValue(cacheKey, out propertyInfo))
{
// DataAnnotations only validates public properties, so that's all we'll look for
// If we can't find it, cache 'null' so we don't have to try again next time
propertyInfo = cacheKey.ModelType.GetProperty(cacheKey.FieldName);
// No need to lock, because it doesn't matter if we write the same value twice
_propertyInfoCache[cacheKey] = propertyInfo;
}
return propertyInfo != null;
}
internal void ClearCache()
=> _propertyInfoCache.Clear();
}
}
And the CustomValidation component:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
namespace StackOverflowAnswers;
public class CustomValidation : ComponentBase, IDisposable
{
private IDisposable? _subscriptions;
private EditContext? _originalEditContext;
[CascadingParameter] EditContext? CurrentEditContext { get; set; }
[Parameter] public bool DoEditValidation { get; set; } = false;
/// <inheritdoc />
protected override void OnInitialized()
{
if (CurrentEditContext == null)
{
throw new InvalidOperationException($"{nameof(DataAnnotationsValidator)} requires a cascading " +
$"parameter of type {nameof(EditContext)}. For example, you can use {nameof(DataAnnotationsValidator)} " +
$"inside an EditForm.");
}
_subscriptions = CurrentEditContext.EnableCustomValidation(DoEditValidation, true);
_originalEditContext = CurrentEditContext;
}
/// <inheritdoc />
protected override void OnParametersSet()
{
if (CurrentEditContext != _originalEditContext)
{
// While we could support this, there's no known use case presently. Since InputBase doesn't support it,
// it's more understandable to have the same restriction.
throw new InvalidOperationException($"{GetType()} does not support changing the " +
$"{nameof(EditContext)} dynamically.");
}
}
/// <inheritdoc/>
protected virtual void Dispose(bool disposing)
{
}
void IDisposable.Dispose()
{
_subscriptions?.Dispose();
_subscriptions = null;
Dispose(disposing: true);
}
}
You can use it like this:
<EditForm EditContext=this.editContext OnValidSubmit=OnValidSubmit>
<CustomValidation DoEditValidation=false/>
#*<DataAnnotationsValidator/>*#
<div class="row">
<div class="col-2">
Date:
</div>
<div class="col-10">
<InputDate #bind-Value=this.Record.Date></InputDate>
</div>
</div>
.......

How do you hand over files to the user?

in a #WASM / #UNO-platform project, how do you hand over files to the user?
In my case I’m generation locally a PDF and had to download it or display it in the browser.
Any clue?
Regards,
Michael
There's no API to do that directly, yet. But you can create a data: url on an anchor (a) HTML element.
For this you'll need to create some JavaScript. Here's how you can do it:
IMPORTANT: following code will only work with very recent version of Uno.UI. Version starting with v3.0.0-dev.949+
Create a ContentControl for the <a> tag
[HtmlElement("a")]
public partial class WasmDownload : ContentControl
{
public static readonly DependencyProperty MimeTypeProperty = DependencyProperty.Register(
"MimeType", typeof(string), typeof(WasmDownload), new PropertyMetadata("application/octet-stream", OnChanged));
public string MimeType
{
get => (string) GetValue(MimeTypeProperty);
set => SetValue(MimeTypeProperty, value);
}
public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register(
"FileName", typeof(string), typeof(WasmDownload), new PropertyMetadata("filename.bin", OnChanged));
public string FileName
{
get => (string) GetValue(FileNameProperty);
set => SetValue(FileNameProperty, value);
}
private Memory<byte> _content;
public void SetContent(Memory<byte> content)
{
_content = content;
Update();
}
private static void OnChanged(DependencyObject dependencyobject, DependencyPropertyChangedEventArgs args)
{
if (dependencyobject is WasmDownload wd)
{
wd.Update();
}
}
private void Update()
{
if (_content.Length == 0)
{
this.ClearHtmlAttribute("href");
}
else
{
var base64 = Convert.ToBase64String(_content.ToArray());
var dataUrl = $"data:{MimeType};base64,{base64}";
this.SetHtmlAttribute("href", dataUrl);
this.SetHtmlAttribute("download", FileName);
}
}
}
Use it in Your XAML Page
<myControls:WasmDownload FileName="test.txt" x:Name="download">
Click here to download
</myControls:WasmDownload>
Note you can put anything in the content of your control, as any other XAML ContentControl.
Set the File Content in Code Behind
Loaded += (sender, e) =>
{
download.MimeType = "text/plain";
var bytes = Encoding.UTF8.GetBytes("this is the content");
download.SetContent(bytes);
};
Result
Direct support by Uno
There is a PR #3380 to add this feature to Uno natively for all platforms. You can also wait for it instead of doing custom way.
The PR for FileSavePicker has been merged and the feature is now available in package Uno.UI since version 3.0.0-dev.1353.

populate JcomboBox from MSAccess Database in java

I'm new in using JComboBox, I wanted to populate JComboBox from my MSAccess Database. I have the following codes:
public check_Writer() //Constructor
{
gui();
fillCombo();
}
public void gui()
{
JFrame mainFrame = new JFrame("Frame");
mainFrame.setSize(500,500);
mainFrame.setVisible(true);
JPanel mainPanel = new JPanel();
mainPanel.setBackground(color.BLUE);
mainFrame.add(mainPanel);
JComboBox listofSuppliersCombo = new JComboBox()
mainPanel.add(listofSuppliersCombo);
}
public void fillCombo()
{
String dataSourceName = "CheckWriterDB";
String db = "jdbc:odbc:" + dataSourceName;
try
{
Class.forName(sun.jdbc.odbc.JdbcOdbcDriver);
Connection conn = DriverManager.getConnection(db, "", "");
Statement st1 = conn.createStatement();
st1.execute("select Suppliers from SuppliersTable");
ResultSet rs1 = st1.getResultSet();
if (rs1!null)
{
while(rs1.next())
{
System.out.println(rs1.getString(1));
}
}
}
catch(Exception e)
{
JOptionPane.showMessageDialog(null, e)
}
}
}
I edited my codes sir, my code works just fine i can print my data in the console, but i can't populate my JComboBox, I tried this code, listOfSuppliersCombo.addItem(rs1.getString(1)); but error message(java.lang.NullPointerException). Is there something wrong with the way created my combo box above, thank you very much sir.
You have defined listofSuppliersCombo locally in gui function, in order to reference any object, in two different mehods, you need to declare it in upper scope.
Your code will work if you try like below:
JComboBox listofSuppliersCombo;
public void gui()
{
//Your Code
listofSuppliersCombo=new JComboBox();
//Your Code
}
public void fillCombo()
{
//Your Code
listofSuppliersCombo.addItem("Your Item");
//Your Code
}

How to implement Generics in business object class definition with DAL to create a proper user control dropdown

I am woefully new to generics, being tied to the support of a corporate intranet web application whose upgrade process is bound to red tape and slowwwly-changing standards. Consequently, today (thankfully!) I finally find myself scrambling during our upgrade to .Net 3.5 and transitioning all the code I can to a properly tiered model.
I have been reading all morning about generics trying to digest how to transition dropdown user controls into a proper business object that gets its data from a class in the data access layer.
There is a perfectly succinct question here that details exactly what I am interested in exploring: Set selected index in a Dropdownlist in usercontrol.
What I would love to see, however, is what Travel_CarSizes.GetCarSizes() actually looks like inside and how the class Travel_CarSizes is defined. (I am having a hard time with <T> and knowing where it should occur.)
For my own specific circumstance at the moment I need a dropdown user control to contain location directionals (N, S, W, C/O, NW, SE, etc) that are stored in a SQL table in the DB and whose selected index needs to be able to be set by whichever page it happens to be in, when form data exists.
I have begun to implement the model in the example from the link above but right now without using Generics because I can't figure it out:
The dropdown user control:
public partial class DropDownStreetPrefix : System.Web.UI.UserControl
{
public string StreetPrefixValue
{
get { return ddlStreetPrefix.SelectedValue.ToString(); }
set
{
Bind();
ddlStreetPrefix.SelectedIndex = ddlStreetPrefix.Items.IndexOf(ddlStreetPrefix.Items.FindByValue(value));
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Bind();
}
}
private void Bind()
{
if (ddlStreetPrefix.Items.Count == 0)
{
SqlDataReader rdr = StreetDirectionals.GetDirectionals();
ddlStreetPrefix.DataSource = rdr;
ddlStreetPrefix.DataBind();
ddlStreetPrefix.DataValueField = "StreetSuffixPrefixAbbr";
ddlStreetPrefix.DataTextField = "StreetSuffixPrefixAbbr";
ListItem li = new ListItem("", "");
ddlStreetPrefix.Items.Insert(0, li);
ddlStreetPrefix.SelectedIndex = 0;
}
}
}
The StreetDirectionals class:
public class StreetDirectionals
{
private StreetDirectionals () { }
public static SqlDataReader GetDirectionals ()
{
string sqlText = "SELECT StreetSuffixPrefixAbbr FROM common..tblStreetSuffixPrefix " +
"ORDER BY StreetSuffixPrefixAbbr";
SqlDataReader rdr = SqlClient.ExecuteFetchReturnDataReader( theConnectionString, CommandType.Text, sqlText);
return rdr;
}
}
I will separate out the database interaction inside the StreetDirectionals class as soon as I can figure out how to change its code if I were to transform the Bind() method from my dropdown user control into this:
private void Bind()
{
if (!IsPostBack)
{
**List<StreetDirectionals> sd = StreetDirectionals.GetDirectionals();**
ddlStreetPrefix.DataSource = sd;
ddlStreetPrefix.DataTextField = "StreetSuffixPrefixAbbr";
ddlStreetPrefix.DataValueField = "StreetSuffixPrefixAbbr";
ddlStreetPrefix.DataBind();
}
}
Any assistance would be sooo much appreciated!
public class StreetDirectional
{
public string StreetSuffixPrefixAbbr { get; set; }
public static IEnumerable<StreetDirectional> GetDirectionals ()
{
string sqlText = "SELECT StreetSuffixPrefixAbbr FROM common..tblStreetSuffixPrefix "
+ "ORDER BY StreetSuffixPrefixAbbr";
SqlDataReader rdr = SqlClient.ExecuteFetchReturnDataReader( theConnectionString, CommandType.Text, sqlText);
var list = new List<StreetDirectional>();
while (rdr.Read())
{
var item = new StreetDirectional() { StreetSuffixPrefixAbbr = (string)rdr["StreetSuffixPrefixAbbr"] };
list.Add(item);
}
return list;
}
}
then you can do this
ddlStreetPrefix.DataSource = StreetDirectional.GetDirectionals();

Selenium2 wait for specific element on a page

I am using Selenium2(2.0-b3) web driver
I want to wait for a element to be present on the page. I can write like below and it works fine.
But I do not want to put these blocks for every page.
// Wait for search to complete
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver webDriver) {
System.out.println("Searching ...");
return webDriver.findElement(By.id("resultStats")) != null;
}
});
I want to convert it into a function where I can pass elementid and the function waits for a specified time and returns me true of false based on element is found or not.
public static boolean waitForElementPresent(WebDriver driver, String elementId, int noOfSecToWait){
}
I am reading that wait does not return till page is loaded etc, but I want to write the above method so that i can click on link to a page and call waitForElementPresent method to wait for element in next page before I do anything with the page.
Can you please help me write the method, I am getting into issue because I do not know how to restructure the above method to be able to pass parameters.
Thanks
Mike
This is how I do that in C# (checks every 250 milliseconds for the element to appear):
private bool WaitForElementPresent(By by, int waitInSeconds)
{
var wait = waitInSeconds * 1000;
var y = (wait/250);
var sw = new Stopwatch();
sw.Start();
for (var x = 0; x < y; x++)
{
if (sw.ElapsedMilliseconds > wait)
return false;
var elements = driver.FindElements(by);
if (elements != null && elements.count > 0)
return true;
Thread.Sleep(250);
}
return false;
}
Call the function like this:
bool found = WaitForElementPresent(By.Id("resultStats"), 5); //Waits 5 seconds
Does this help?
You can do like this, new a class and add below method:
public WebElement wait4IdPresent(WebDriver driver,final String elementId, int timeOutInSeconds){
WebElement we=null;
try{
WebDriverWait wdw=new WebDriverWait(driver, timeOutInSeconds);
if((we=wdw.until(new ExpectedCondition<WebElement>(){
/* (non-Javadoc)
* #see com.google.common.base.Function#apply(java.lang.Object)
*/
#Override
public WebElement apply(WebDriver d) {
// TODO Auto-generated method stub
return d.findElement(By.id(elementId));
}
}))!=null){
//Do something;
}
}catch(Exception e){
//Do something;
}
return we;
}
Do not try to implement interface ExpectedCondition<>, that's a bad idea. I got some problems before. :)
from here:
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
#Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});

Resources