So I have this test page: https://demo.seleniumeasy.com/basic-select-dropdown-demo.html
On the bottom there is a listbox, from which I should select some States and verify the selection with buttons below.
I tried doing this:
string expectedResult = "First selected option is : Florida";
List<string> selectedStates = new List<string> { "Florida", "New York", "Texas" };
foreach (string state in selectedStates)
{
BasicSelectDropdownDemo.SelectMultiElements(state);
}
BasicSelectDropdownDemo.ClickFirstSelectedButton();
string actualResult = BasicSelectDropdownDemo.GetMultipleSelectedMessage();
Assert.AreEqual(expectedResult, actualResult);
But I get the result: "First selected option is : Texas"
Visually it seems that the selection is ok, all three States from the List are selected, but practically it seems that only the last selection stays.
My "ClickFirstSelectedButton" methods looks like this:
public static void SelectMultiElements(string selectedState)
{
Common.MultiSelectByValue(selectStatesMultiSelectLocator, selectedState);
}
Futher, my "MultiSelectByValue" looks like this:
SelectElement selectElement = GetSelectElement(locator);
Actions actions = new Actions(Driver.GetDriver());
actions.KeyDown(Keys.Control);
selectElement.SelectByValue(value);
actions.Perform();
Maybe it is something wrong with my Actions code?
It may be a little confusing, as I have all my methods separated in other classes, but as I mentioned - visually it looks like I'm getting there, I'm getting the selection, but somehow only the last one stays in the end. I'm I missing something to "save" the previous selections? I guess that after actions.Perform(); the Driver "forgets" the selection and starts with each variable from scratch. But then again - on the screen I see the grey-out selections.
Related
I'm currently creating automatic tests for an application form which I'm using selenium in combination with Specflow.
In my Specflow scenario I have an scenario outline with a few examples that I wish to use. I have no problem populating simple text fields with values from the example in the scenario outline but I can't seem to get selenium to select the same item from the drop down list as I have in my specflow scenario outline.
Specflow scenario outline step
Specflow scenario outline example data
Sending the data from the example
Cathing and populating the text field
How would I duplicate this but instead of populating a text field I want to select an item in a drop down list that is the same as the value in the specflow scenario outline?
Currently I have the step and the example created but I don't know how to correctly send the data and catch and click on the correct item in the dropdown list
Specflow scenario outline step for dropdown
Specflow scenario outline example data for drop down items
EDIT 1:
Current code I have tried for the layer and steps page
Successfully clicks the dropdown but does not choose the same value as in the feature outline
public string MaritalStatus
{
set
{
_driver.FindElement(By.Id("mainApplicant.maritalStatus")).Click();
_driver.FindElement(By.XPath("//ul[#class='dropdown-menu show']//li[#role='presentation']//a[#class='dropdown-item']")).SendKeys(value);
}
}
[Then(#"I choose value (.*) in dropdown MainApplicantMaritalStatus and Check Value")]
public void ThenIChooseValueInDropdownMainApplicantMaritalStatusAndCheckValue(string value)
{
_cashLoanPage.MaritalStatus = value;
}
Successfully clicks the dropdown but only selects the first item in the dropdownlist
public void MaritalStatus1()
{
_driver.FindElement(By.Id("mainApplicant.maritalStatus")).Click();
_driver.FindElement(By.XPath("//ul[#class='dropdown-menu show']//li[#role='presentation']//a[#class='dropdown-item']")).Click();
}
[Then(#"I choose value (.*) in dropdown MainApplicantMaritalStatus and Check Value")]
public void ThenIChooseValueInDropdownMainApplicantMaritalStatusAndCheckValue1(string x)
{
_cashLoanPage.MaritalStatus1();
}
EDIT 2:
With the help from Dazed this code works as intended incase anyone ever stumbles on a similar problem
public void MaritalStatus(string value)
{
_driver.FindElement(By.Id("mainApplicant.maritalStatus")).Click();
_driver.FindElement(By.XPath(string.Format("//ul[#class='dropdown-menu show']//li[#role='presentation']//a[text()='{0}']", value))).Click();
}
I typically use string format for this. I am not sure what your html markup looks like but this will take the "value" you pass in from the scenario outline and replace it in your locator type, xpath in this instance.
[Then(#"I choose (.*) in dropdown MainApplicantMaritalStatus and Check value")]
public void IChooseInDropdownMainApplicantMaritalStatusAndCheckValue(string value)
{
driver.FindElement(By.XPath(string.Format("//select[#id='status']/option[text()='{0}']",
value))).Click();
}
****Update***
go here https://www.w3schools.com/html/tryit.asp?filename=tryhtml_elem_select if you look at an xpath of
//select[#name='cars']/option ---- you get 4 results
If I add this
//select[#name='cars']/option[contains(text(), 'Saab')] -- you get one result
If I change the path in my code to this, I can pass in the value I want to select.
string value = "Saab";
driver.FindElement(By.XPath(string.Format("//select[#name='cars']/option[contains(text(), '{0}')]", value))).Click();
so using your code, it looks like you are using POM? You could add this to the page as a method, and call it from the step. Since we can't see your full html though, I can give you the exact xpath for the drop down value.
from steps:
string myValue = "Married"
Pages.MyPage.SetMaritalStatus(string myValue);
from Pages:
public void SetMaritalStatus(string value)
{
_driver.FindElement(By.Id("mainApplicant.maritalStatus")).Click();
_driver.FindElement(By.XPath(string.Format("//ul[#class='dropdown-menu show']//li[#role='presentation']//a[#class='dropdown-item']/option[text()='{0}']", value))).Click();
}
Here is the approach that should work.
[Then(#"I choose (.*) in dropdown MainApplicantMaritalStatus and Check value")]
public void IChooseInDropdownMainApplicantMaritalStatusAndCheckValue(string status)
{
// lets say you have select element
WebElement maritalStatus = driver.findElement();
WebElement option = maritalStatus.findElement(By.xpath("./option[normalize-space(.)='" + status + "']"));
// click on option
option.click();
}
I'm working on a small program as part of my A Level Computing course that is designed to track orders. It is written in C# using the Windows Forms.
I am having an issue where I enter all the information for a new order and then press OK and it should update the ListView with the information. I have my ListView in Detail view with 4 columns but nothing ever gets added to the ListView. The section of code that should add the items to the ListView is being executed and is not throwing any errors or causing the program to crash but nothing is being added. Its weird because I am using the exact same method that I used in my little prototype mock up but for some reason now it is not working.
All the things I've found on here or on the internet seem to suggest its an issue with the View mode of the ListView and I've tried modifying this property to no avail.
Any ideas why this section of code is refusing to add anything to the ListView?
//Create an array to store the data to be added to the listbox
string[] orderDetails = { Convert.ToString(id + 1), rNameBox.Text, dateBox.Value.ToString(), orderBox.Text };
//DEBUGGING
Console.WriteLine(orderDetails[0]);
Console.WriteLine(orderDetails[1]);
Console.WriteLine(orderDetails[2]);
Console.WriteLine(orderDetails[3]);
//END DEBUGGING
//Add the order info to the ListView item on the main form
var listViewItem = new ListViewItem(orderDetails);
ths.listView1.Items.Add(listViewItem);
If you need any more information just say. Apologies if this is in the wrong format or something this is my first time here.
Your problem is that your ListViewItem contains a string array and it has no useful way of displaying it.
What you should be doing (there are a number of ways of doing this, but here's one) is creating a class, OrderDetail, with an Id, a Name, a Date, and so on. Give it a ToString() method (public override string ToString()) which returns what you want to display, e.g.:
public override string ToString()
{
return this.Name;
}
Create an instance of OrderDetail and set its properties. Create ListViewItem giving it the OrderDetail instance and add to the ListView. Repeat for as many OrderDetail instances you want.
Cheers -
Added: code which works:
int id = 12;
string rNameBoxText = "rName";
DateTime dateBoxValue = DateTime.Now;
string orderBoxText = "order";
string[] orderDetails = { Convert.ToString(id + 1), rNameBoxText, dateBoxValue.ToString(), orderBoxText };
//DEBUGGING
Console.WriteLine(orderDetails[0]);
Console.WriteLine(orderDetails[1]);
Console.WriteLine(orderDetails[2]);
Console.WriteLine(orderDetails[3]);
//END DEBUGGING
this.listView1.Columns.Clear();
this.listView1.Columns.Add("Id");
this.listView1.Columns.Add("rName");
this.listView1.Columns.Add("Date");
this.listView1.Columns.Add("Order");
this.listView1.View = View.Details;
//Add the order info to the ListView item on the main form
var listViewItem = new ListViewItem(orderDetails);
this.listView1.Items.Add(listViewItem);
I currently have a ListBox (called wafersListBox) bounded to an ArrayList of a certain object type (called wafers). When I want to add to the ListBox dynamically, I use the following code:
wafersListBox.DataSource = null;
wafersListBox.DataSource = wafers;
wafersListBox.Refresh();
This successfully changes the items in the ListBox, but all of the items disappear (they're still there and can be selected, but the user just can't see them).
Any ideas on how to fix this?
UPDATE:
This is my Wafer class:
public class Wafer
{
public string maID;
public string MID
{
get
{
return maID;
}
set
{
maID = value;
}
}
public Wafer(string m)
{
maID = m;
}
}
This is the code that I call, it adds a copy of the currently selected item to the listbox:
Wafer w = wafersListBox.SelectedItem as Wafer;
wafers.Add(w);
wafersListBox.DataSource = null;
wafersListBox.DisplayMember = "MID";
wafersListBox.DataSource = wafers;
wafersListBox.Refresh();
You should probably tell the wafersListBox what property to use as it's caption.
Do it like this;
wafersListBox.DisplayMember = "PropertyNameThatYouWantToShow";
Sorry - I'm not able to add an additional comment, which would have been preferable over writing a new "answer" but do you see any difference if you switch the position of the lines as below?
Wafer w = wafersListBox.SelectedItem as Wafer;
wafers.Add(w);
wafersListBox.DataSource = null;
wafersListBox.DataSource = wafers;
wafersListBox.DisplayMember = "MID";
wafersListBox.Refresh();
One other thing I just came across on a different SO posting (ListBox doesn't show changes to DataSource):
"There is also a bug in the list box which can cause this problem. If you set the SelectionMode to None this problem appears.
As a work around I set the selection mode to One and then back to None when updating the datasource."
In the code behind of my Silverlight application, I have the need to re-populate the TreeView and then make a specific TreeViewItem selected.
The code itself is pretty simple, here it is (i'll trim and pseudo-code-ify it to make it as short as possible)
private void Button_Click()
{
Guid idToSelect = TellMeWhatToSelect();
List<myObject> myDataList = myObjectRepository.RetrieveData().ToList();
myTreeView.Items.Clear();
foreach(myObject o in myDataList)
{
myTreeView.Items.Add(new TreeViewItem() { Content = o.DataField, Tag = o.Id });
}
myTreeView.Items.First(o => ((Guid)(o as TreeViewItem).Tag).Equals(idToSelect)).IsSelected = true;
}
That's basically it: i'm reading some data into myDataList, then i cycle through it and create as many TreeViewItems as needed in order to display the data.
Problem is, myTreeView.SelectedItem is null at the end of this, and SelectionChanged event isn't triggered. I would think that, since Items collection has been cleared and re-filled, switching IsSelected on one of the items would act like clicking, but it seems it doesn't).
Oddly enough (for me at least), issuing myTreeView.Items.First().IsSelected = true; by itself (that is, calling a method with that single line of code inside) works as expected: SelectedItem is there and all events are fired appropriateyl.
What's wrong with my code and/or what am I missing ? Looks like cleaning items up kind of breaks something.
I'm fairly sure others have had similar issues, but a bunch of searches I tried didn't help (most of the info & questions I came up with are WPF-related).
Thanks for your time, I'll provide more info if needed. Also, sorry for the wall of text.
UPDATE
Modifying code like this, now the method works as expected.
private void Button_Click()
{
Guid idToSelect = TellMeWhatToSelect();
List<myObject> myDataList = myObjectRepository.RetrieveData().ToList();
myTreeView.Items.Clear();
foreach(myObject o in myDataList)
{
myTreeView.Items.Add(new TreeViewItem() { Content = o.DataField, Tag = o.Id });
}
Dispatcher.BeginInvoke(()=>
{
myTreeView.Items.First(o => ((Guid)(o as TreeViewItem).Tag).Equals(idToSelect)).IsSelected = true;
});
}
Set property IsSelected inside of Dispatcher.BeginInvoke.
I had the same problem a while ago, I've solved by calling the UpdateLayout method from the treeview before setting the TreeViewItem as selected.Like this:
myTreeView.UpdateLayout();
myTreeView.Items.First(o => ((Guid)(o as TreeViewItem).Tag).Equals(idToSelect)).IsSelected = true;
I've created a control derived from ComboBox, and wish to unit test its behaviour.
However, it appears to be behaving differently in my unit test to how it behaves in the real application.
In the real application, the Combobox.DataSource property and the .Items sync up - in other words when I change the Combobox.DataSource the .Items list immediately and automatically updates to show an item for each element of the DataSource.
In my test, I construct a ComboBox, assign a datasource to it, but the .Items list doesn't get updated at all, remaining at 0 items. Thus, when I try to update the .SelectedIndex to 0 in the test to select the first item, I recieve an ArgumentOutOfRangeException.
Is this because I don't have an Application.Run in my unit test starting an event loop, or is this a bit of a red herring?
EDIT: More detail on the first test:
[SetUp]
public void SetUp()
{
mECB = new EnhancedComboBox();
mECB.FormattingEnabled = true;
mECB.Location = new System.Drawing.Point( 45, 4 );
mECB.Name = "cboFind";
mECB.Size = new System.Drawing.Size( 121, 21 );
mECB.TabIndex = 3;
mECB.AddObserver( this );
mTestItems = new List<TestItem>();
mTestItems.Add( new TestItem() { Value = "Billy" } );
mTestItems.Add( new TestItem() { Value = "Bob" } );
mTestItems.Add( new TestItem() { Value = "Blues" } );
mECB.DataSource = mTestItems;
mECB.Reset();
mObservedValue = null;
}
[Test]
public void Test01_UpdateObserver()
{
mECB.SelectedIndex = 0;
Assert.AreEqual( "Billy", mObservedValue.Value );
}
The test fails on the first line, when trying to set the SelectedIndex to 0. On debugging, this appears to be because when the .DataSource is changed, the .Items collection is not updated to reflect this. However, on debugging the real application, the .Items collection is always updated when the .DataSource changes.
Surely I don't have to actually render the ComboBox in the test, I don't even have any drawing surfaces set up to render on to! Maybe the only answer I need is "How do I make the ComboBox update in the same way as when it is drawn, in a unit test scenario where I don't actually need to draw the box?"
Since you're simply calling the constructor, a lot of functionality of the combobox will not work. For example, the items will be filled when the ComboBox is drawn on screen, on a form. This does not happen when constructing it in a unit test.
Why do you want to write a unit test on that combobox?
Can't you seperate the logic which now is in the custom control? For example put this in a controller, and test that?
Why don't you test on the DataSource property instead of the Items collection?
I'm sure that Application.Run absence cannot affects any control's behavior
I'm having the same problem with a combo box where the items are data bound. My current solution is to create a Form in the test, add the combo box to the Controls collection, and then show the form in my test. Kind of ugly. All my combo box really does is list a bunch of TimeSpan objects, sorted, and with custom formatting of the TimeSpan values. It also has special behavior on keypress events. I tried extracting all the data and logic to a separate class but couldn't figure it out. There probably is a better solution but what I'm doing seems satisfactory.
To make testing easier, I created these classes in my test code:
class TestCombo : DurationComboBox {
public void SimulateKeyUp(Keys keys) { base.OnKeyUp(new KeyEventArgs(keys)); }
public DataView DataView { get { return DataSource as DataView; } }
public IEnumerable<DataRowView> Rows() { return (DataView as IEnumerable).Cast<DataRowView>(); }
public IEnumerable<int> Minutes() { return Rows().Select(row => (int)row["Minutes"]); }
}
class Target {
public TestCombo Combo { get; private set; }
public Form Form { get; private set; }
public Target() {
Combo = new TestCombo();
Form = new Form();
Form.Controls.Add(Combo);
Form.Show();
}
}
Here is a sample test:
[TestMethod()]
public void ConstructorCreatesEmptyList() {
Target t = new Target();
Assert.AreEqual<int>(0, t.Combo.DataView.Count);
Assert.AreEqual<int>(-1, t.Combo.SelectedMinutes);
Assert.IsNull(t.Combo.SelectedItem);
}
This solve some problems if target is ComboBox or any other control:
target.CreateControl();
but I was unable to set SelectedValue it has null value, my test working with two data sources for combo box, one as data source and second is binded to selevted value. With other controls everithing working fine. In the begining I was also creating form in tests, but there is problem when form on created on our build server while tests are executed.
I did a little hack to allow this in my custom derived combobox:
public class EnhancedComboBox : ComboBox
{
[... the implementation]
public void DoRefreshItems()
{
SetItemsCore(DataSource as IList);
}
}
The SetItemsCore function instructs the base combobox to load internal items with the provided list, it's what uses internally after the datasource changes.
This function never gets called when the control is not on a form, because there are lots of checks for CurrencyManagers and BindingContexts that are failing because this components, I believe, are provided by the parent form somehow.
Anyway, in the test, you have to call mECB.DoRefreshItems() just after the mECB.DataSource = mTestItems and everything should be fine if you only depend on the SelectedIndex and the Items property. Any other behavior like databinding is probably still not functional.