I'm trying to write some ruby to perform the following:
I'm testing a web page which has a form, a search button, and a search results underneath.
When I enter an invoice number into the form e.g. 123456 and I click the "Search" button, if the Invoice has been successfully saved , then it will show up under the "Search Results" section, and if not, then it will say "No results found". Sometimes it takes a few seconds for the database to finish processing an invoice so I would like to make a loop that keeps pressing the search button every few seconds until the invoice is found, and once the condition is met, then do something else.
You can set up a while loop that breaks once a WebElement meeting certain criteria has been located.
# Keep track of whether or not invoice has been found
found = false
# First, attempt to locate the desired invoice
begin
# click the search button
driver.find_element(:name, "search_button").click
# check if invoice exists, set found to true if it does
expect(driver.find_element(some_locator_here).displayed?).to eql true
found = true
rescue Selenium::WebDriver::Error::NoSuchElementError
# catch NoSuchElementError if invoice does not exist, leave found as false
puts("Element not found")
# if invoice is not found, continue trying to find it in a loop
while found == false do
begin
# click the search button
driver.find_element(:name, "search_button").click
# attempt to locate the invoice
expect(driver.find_element(some_locator_here).displayed?).to eql true
found = true
rescue Selenium::WebDriver::Error::NoSuchElementError
puts("Element not found")
This will click the search button and attempt to locate the desired invoice in a loop, then catch the NoSuchElementError if the desired invoice does not exist. You will need to replace some_locator_here with something like :name, "invoice_name" so that you can locate your invoice and determine whether or not it has been found. Hope this helps a bit.
Related
I am trying to implement a FormAction here, and I’ve overridden validate method.
Here is the code for the same:
def validate(self, dispatcher, tracker, domain):
logger.info("Validate of single entity called")
document_number = tracker.get_slot("document_number")
# Run regex on latest_message
extracted = re.findall(regexp, tracker.latest_message['text'])
document_array = []
for e in extracted:
document_array.append(e[0])
# generate set for needed things and
document_set = set(document_array)
document_array = list(document_set)
logger.info(document_set)
if len(document_set) > 0:
if document_number and len(document_number):
document_array = list(set(document_array + document_number))
return [SlotSet("document_number", document_array)]
else:
if document_number and len(document_number):
document_array = list(set(document_array + document_number))
return [SlotSet("document_number", document_array)]
else:
# Here it doesn't have previously set slot
# So Raise an error
raise ActionExecutionRejection(self.name(),
"Please provide document number")
So, ideally as per the docs, when ActionExecutionRejection occurs, it should utter a template with name utter_ask_{slotname} but it doesn’t trigger that action.
Here is my domain.yml templates
templates:
utter_greet:
- text: "Hi, hope you are having a good day! How can I help?"
utter_ask_document_number:
- text: "Please provide document number"
utter_help:
- text: "To find the document, please say the ID of a single document or multiple documents"
utter_goodbye:
- text: "Talk to you later!"
utter_thanks:
- text: "My pleasure."
The ActionExecutionRejection doesn't by default utter a template with the name utter_ask_{slotname}, but rather leaves the form logic to allow other policies (e.g. FallbackPolicy) to take action. The utter_ask_{slotname} is the default for the happy path in which it's trying to get a required slot for the first time. This default implementation of the action rejection is there in order to handle certain unhappy paths such as if a user decides they want to exit the flow by denying, or take a detour by chatting, etc.
If you want to implement the template to re-ask for the required slot using the utterance, you could replace the ActionExecutionRejection with dispatcher.utter_template(<desired template name>, tracker). However, this will leave you with no way to exit the form action without validation -- I don't know what your intents are, but perhaps you want to also incorporate some logic based on the intent (i.e. if it's something like "deny", let the ActionExecutionRejection happen so it can exit, it it's an "enter data" type of intent make sure it asks again).
I need to write a method which will get text with the help of index number from popup and then i need to compare with the expected text
i.e i need to verify expected plan name is displayed at the bottom of the popup box
Setting the correct id for the query (which you can get by doing on calabash console the command query("*", :id)) on code below should do the trick. If you can't use id try to get another component property (like Android component by using query("*") ) and set the query inside theget_text calls.
def get_text(query)
query(plan_query, :text).first
end
def text_equals(text, expected_text)
unless text == expected_text
fail "#{text} not equal to #{expected_text}"
end
end
def verify_plan(index, expected_text)
plan_text = get_text("* id:'PLAN_TEXTS_ID' index:#{index}") # Can change 'id:...'' by Android class if plan does not have id
expected_text = get_text("* id:'BOTTOM_PLAN_ID'") # Same as above
text_equals(plan_text, expected_text)
end
What I need- some kind of way to grab the number entered into the form in order to check it against previous records PRIOR to updating, so that if a validation error occurs, the user can be prompted to confirm before the form is submitted. Params would work, but are only returned after the form is posted- so no help. Is there an ajax call that I can pass into a ruby variable? Or perhaps some kind of ruby code that will read the input in the text box without submitting or linking?
What I'm doing- I'm trying to set up a 'manual validation' because I don't want the validation to 'prevent' from saving. Instead, it should be more like a confirmation.
If you care for context, Here's the run-down- I have a client that pays monthly deposits. We confirm these deposits over the phone through a third party. Naturally, in order to get the most accurate data as possible, we have to account for human error and other factors. A deposit this month should never be less than a deposit last month- but deposits can be "moved" from one account to another, which would make it seem like it was less. I have a form that new data is input on, and I want it to check against previous records to see if the deposit is more or less than reported previously. If less, it should ask for confirmation- an "are you sure?" kind of thing.
The code is old & outdated, should be changed from the ground up, but would take months when I have days to do this. I'm just looking for a patch.
What I have so far- note that cur_deposit is this months and rec_deposit is last months.
<%
arr1 = []
arr2 = []
is_less = false
r = #recent_inquiries.last
r.inquiry_deposits.order(:id).each do |t|
arr1 << t.cur_deposit.to_f
arr1 << t.rec_deposit.to_f
end
#inquiry.inquiry_deposits.order(:id).each do |td|
#============THIS is the part that needs help
arr2 << params["cur_deposit_text_box"]
arr2 << params["rec_deposit_text_box"]
end
i = 0
while i < (arr1.size - 1)
comp_arr1 = []
comp_arr2 = []
comp_arr1 << arr1[i]
comp_arr1 << arr1[i + 1]
comp_arr2 << arr2[i]
comp_arr2 << arr2[i + 1]
if Inquiry.compare_deposits(comp_arr1, comp_arr2) != nil then is_less = true end
i = i + 2
end
if is_less
strConf = "A deposit from last month is greater than the same deposit this month, which should not happen. Are you sure?"
end
%>
<%= submit_tag "Save Inquiry", :onclick=>"$('#submit_form').val('Save Inquiry summary');", :class => 'tgButton3', :id => 'save_inquiry_button_bottom', :confirm => strConf %>
When I get this code working, I will stash all the functioning code into a model- I just have it in the view for testing. It is safe to assume that all the 'custom methods' this script calls to are functioning. If you need code from them, I'll happily share it.
Rails version 3.0.20
Can you use jQuery on your website? (if not it is doable in plain javascript)
$('#id-of-your-field').change(function(e){
//do here your client side logic if any needed
var yourfirstvalue = $(e.target).val();
//now take the value and send it to server (your ruby stuff)
$.ajax({
url: yourURL + "/" + yourfirstvalue,
success: function(data){
//this data can be sent as JSON in structure which suits the best to you
//so you can use it to populate your second dropdown
var values = JSON.parse(data);
//use your values
}
});
});
Google "combo box example" it might help you.
In order to close this question out, and in case anybody else is wondering, I will answer my own question. This is what I've found out.
Because of the nature of the relationship between client & server, there is really no way to get the value of the text input, store it in a ruby variable, and check it against another ruby variable. Ruby script only runs once and then is rendered, so while ajax may be able to continually run in the background and gather inputs, etc, the integration with ruby falls short when talking client-side only interaction. (Correct me if I'm wrong- after all, I posted the question to get everybody's input!)
The fix: I created a switch using hidden tags. When the form loads, the hidden tag is blank. After submitting the form, the update action checks the params of the newly entered data against the numbers from last month. If the conditions check out, it saves. If not, it re-loads the page with a message. If the message is confirmed, an ajax command changes the hidden tag to "true" which bypasses the comparison once it hits the update action again. Otherwise, the data is not saved. Problem solved!
I'm making this a community wiki answer in case anybody would like to add their two cents.
Background: This is using page-object, and Rspec. The page, objects are setup correctly. Basically what is happening is its skipping the while statement and going directly to checking of the variable label exists on the page.
What it SHOULD do is check if the label variable is on the page and if not then wait 20 seconds and refresh the page then check again for up to 30 times and if it fails on the 30th time then it should fail all together. If it finds it then it should check again and pass it.
def check_label(label, current_page)
labels_filter_element.click
check_label_sla(label, current_page)
current_page.text.should include label
end
def check_label_sla(label, current_page)
t = 30
i = 0
while i < t
if current_page.text.should include label
return
else
sleep(20)
current_page.refresh
i += 1
end
end
end
I think what is happening is if current_page.text.should include label is always returning TRUE, but I'm not sure. If more info is needed please let me know.
I am making the following assumptions:
The behaviour you are seeing is that the page is first loaded, the labels_filter_element is clicked, the label is not on the page and the test fails immediately without refreshing the page.
label is a string
Given these assumptions, the problem is with the if-statement:
if current_page.text.should include label
When the if statement is executed, it will assert that the page includes the label:
If the page has the label, the code in the if will be executed (ie it will immediately return and the assertion in check_label will pass).
In the case that the page does not have the label, the assertion will throw an exception causing the test to fail immediately (ie the else code will not get executed). So the test is failing inside the check_label_sla method, not at the end of the check_label method (which makes it seem like the while loop is not working).
You want the if statement to check that the text is included, without making an assertion. Therefore you want:
if current_page.text.include? label
So your check_label_sla method would become:
def check_label_sla(label, current_page)
t = 30
i = 0
while i < t
if current_page.text.include? label
return
else
sleep(20)
current_page.refresh
i += 1
end
end
end
Or you could reduce it to:
def check_label_sla(label, current_page)
30.times do
return if current_page.text.include? label
sleep(20)
current_page.refresh
end
end
I have this Xpath query inside a loop,
//div[#class='listing_content'][#{i}]/div/div/h3/a/text()
I want to process each node individually
The problem it gives the correct nodes, but all of them at once at once.
Also when i > 1, it returns nothing at all?
for i in (1...30)
name = page.xpath("//div[#class='listing_content'][#{i}]/div/div/h3/a/text()")
puts "this is name"
puts name
#Get Business phone
phone = page.xpath("//div[#class='listing_content'][#{i}]//span[#class='business-phone phone']/text()")
puts "this is phone"
puts phone
#Get Business website(if any)
puts "this is website"
website = page.xpath("//div[#class='listing_content'][#{i}]//li[#class='website-feature']//#href")
puts website
end
Also when i > 1, it returns nothing at all?
This is the second most FAQ in XPath:
Use:
(//div[#class='listing_content'])[#{i}]/div/div/h3/a/text()
The cause of the observed behavior is that in XPath the [] has higher precedence (priority) than the // pseudo-operator.
So, in your original expression you specify that every div[#class='listing_content'] element that is the i-th child of its parent should be selected.
However, in the XML document you are working with, every div[#class='listing_content'] happens to be the first (and only) child of its parent -- therefore if i > 1 then nothing is selected.
As in any other language, in order to override the default priority, we must use brackets.