rspec: How to expect that page has the desired html - ruby

I have below html which I took from the launched page source.
<dt title="No. days">No. days:</dt>
<dd>7</dd>
In my test I have to expect the same html, I tried below
expect(page.html).to include("<dt title=\"No. days\">No. days:</dt><dd>7</dd>")
But got the error.
What format exactly I need to write in the include to expect the same html
Thank you in advance

String is not safe HTML.
expect(page).to have_selector('dt[title="No. days"]', text: "No. days:")
expect(page).to have_selector('dd', text: "7")

Related

Unable to click download button with web scraper

for whatever reason mechanize is unable to click this export button to automate downloading a public government csv file, i'm trying to automate downloading a fishing report, does anyone have any ideas on how to get it to work?
agent = Mechanize.new
url = 'https://nrm.dfg.ca.gov/FishPlants/'
log :debug, "reading HTML from #{url}"
page = agent.get(url)
log :debug, 'loaded page'
form = page.search('#aspnetForm').first
button = page.search('.application_button').first
log :debug, 'clicking Export button'
response = agent.submit(form, button)
i get a stack trace with the following error
...
form.add_button_to_query(button) if button
^^^^^^^^^^^^^^^^^^^^
/Users/aronlilland/.rvm/gems/ruby-3.1.2/gems/mechanize-2.8.5/lib/mechanize.rb:581:in `submit'
/Users/aronlilland/Documents/dev/fishing-report/tasks/download/fishing_report.rake:27:in `block (2 levels) in <top (required)>'
Tasks: TOP => download:fishing_report
(See full trace by running task with --trace)
the form is confirmed returns successfully, but the button is an input field
the page seems relatively straight forward, so dont know why i'm unable to scrape it - and its also public data
<form method="post" action="./" id="aspnetForm">
<!-- .... -->
<input
type="submit"
name="ctl00$cphContentMiddle$btnExport"
value="Export"
id="ctl00_cphContentMiddle_btnExport"
class="application_button"
>
<!-- .... -->
</form>
agent.submit got the wrong type for form
The issue here could be seen if you had included the beginning of the stack trace:
.../ruby/gems/3.1.0/gems/mechanize-2.8.5/lib/mechanize.rb:581:in `submit': undefined method `add_button_to_query' for #<Nokogiri::XML::Element:0x1ea14 name="form" attributes=
[#<Nokogiri::XML::Attr:0xbd38 name="method" value="post">, ...
Mechanize expects the submit to act on a Mechanize::Form instance, but instead got an instance of Nokogiri::XML::Element, as you can see by adding this to your code:
form.class # => Nokogiri::XML::Element
If you check the docs for the Mechanize::Form class, you can see the example they give to get you the form object is this:
form = page.forms.first # => Mechanize::Form
as opposed to what you used:
form = page.search('#aspnetForm').first
The call to search here is delegated to Nokogiri, and therefore doesn't return the object type you need, but rather a Nokogiri element.
button also has the wrong type
By the way the same applies to this line:
button = page.search('.application_button').first
If you fix the type of form, you'll get into a similar issue with button not being the expected type. Again, there's an example in the docs showing how a button is found:
agent.submit(page.forms.first, page.forms.first.buttons.first)
You'll need to figure out how to find the specific button you need though, I haven't worked with Mechanize before, so I can't offer a suggestion here. Presumably there's a way to convert the button you find through search to a Mechanize::Form::Button instance.

How to test if an alert message is showing what I wanted it to show using Cypress?

I have password reset page I'd like to perform some tests on. If my current password won't match with my typed current password area it shows a "Password don't match" alert. Here is my alert:
<p-message *ngIf="error" severity="error" id="alert-danger" class="alert alert-danger" text="{{'password.messages.error' | translate}}" >
<ng-template pTemplate>
<div jhiTranslate="password.messages.error" ></div>
</ng-template>
</p-message>
What I've tried so far:
cy.get('[severity="error"] > .p-inline-message > .p-inline-message-text')
.should("have.text","password.messages.error")
But I get an error in cypress saying "expected password.messages.error but the text was Passwords don't match!. Which is understandable it takes directly whatever text was inside my element. Then I've tried:
cy.get('[severity="error"] > .p-inline-message > .p-inline-message-text')
.invoke('attr','jhiTranslate')
.should('eq','password.messages.error')
this gives me "expected undefined to equal password.messages.error"
What I'm doing wrong and what else should I try here?
Just change the text Cypress is checking,
cy.get('[severity="error"] > .p-inline-message > .p-inline-message-text')
.should("have.text", "Passwords don't match!")
The HTML you show above is the source code, but AngularJS has looked up the variable password.messages.error and output the string contained in that variable.
It then removes jhiTranslate from the element, so you cannot test it at runtime (in the browser).
You can see what the runtime HTML is by right-clicking on an element and inspecting it in the dev-tools.
You can do something like:
cy.get('p-message#alert-danger').within(() => {
cy.get('div').should('have.attr', 'jhiTranslate', 'password.messages.error')
})

Ruby Hash and Tumblr API

controller page, Json output from api
I'm trying to display posts from the users tumblr account on my view page using ruby. I have never done anything with api's before. I'm trying to use Hash tables. my controller code is as such:
#Posts = client.posts"zombieprocess1.tumblr.com"
on my view page using html I have
<%=Posts%>
the response is such
{"blog"=>{"title"=>"Untitled", "name"=>"zombieprocess1", "total_posts"=>1, "posts"=>1, "url"=>"URL", "updated"=>1478191052, "description"=>"", "is_nsfw"=>false, "ask"=>false, "ask_page_title"=>"Ask me anything", "ask_anon"=>false, "followed"=>false, "can_send_fan_mail"=>true, "is_blocked_from_primary"=>false, "share_likes"=>true, "likes"=>1, "twitter_enabled"=>false, "twitter_send"=>false, "facebook_opengraph_enabled"=>"N", "tweet"=>"N", "facebook"=>"N", "followers"=>0, "primary"=>true, "admin"=>true, "messages"=>0, "queue"=>0, "drafts"=>0, "type"=>"public", "reply_conditions"=>3, "subscribed"=>false, "can_subscribe"=>false}, "posts"=>[{"blog_name"=>"zombieprocess1", "id"=>152689921093, "post_url"=>"URL", "slug"=>"", "type"=>"photo", "date"=>"2016-11-03 16:37:32 GMT", "timestamp"=>1478191052, "state"=>"published", "format"=>"html", "reblog_key"=>"NCDqGTzW", "tags"=>[], "short_url"=>"URL", "summary"=>"", "recommended_source"=>nil, "recommended_color"=>nil, "followed"=>false, "liked"=>true, "note_count"=>1, "caption"=>"", "reblog"=>{"tree_html"=>"", "comment"=>""}, "trail"=>[], "image_permalink"=>"url", "photos"=>[{"caption"=>"", "alt_sizes"=>[{"url"=>"URL", "width"=>400, "height"=>544}, {"url"=>"URL", "width"=>250, "height"=>340}, {"url"=>"URL", "width"=>100, "height"=>136}, {"url"=>"URL", "width"=>75, "height"=>75}], "original_size"=>{"url"=>"URL", "width"=>400, "height"=>544}}], "can_like"=>false, "can_reblog"=>true, "can_send_in_message"=>true, "can_reply"=>true, "display_avatar"=>true}], "total_posts"=>1}
I have tried many different formats and can't seem to just get the post url. My thought is to get the post_url and embed each of them so it shows as it would in tumblr on my webpage. Can anyone help me?
Try this:
#posts['posts'].first['post_url']
Or if your response contains more than one post you can return them all like this:
(0...#posts['total_posts']).map { |i| #posts['posts'][i]['post_url'] }
EDIT: Fixed capitalization in second line of code. I assume you are using lowercase variable as per Ruby convention, '#posts'. If not, you should change to a lowercase variable as this may be confusing something.

Select2 feature test with Capybara

I'm trying to write a rspec feature test with capybara but,
I have some trouble with a test on a select2 element.
see my test code.
Using feature test with capybara
feature "Backend Landing Pages" do
let!(:landing_page) { create(:landing_page, country: country) }
let!(:country) { create(:country, id: 2) }
let!(:restaurant) { create(:restaurant_with_locale) }
let!(:landing_page_restaurant) { create(:landing_page_restaurant,landing_page: landing_page, restaurant: restaurant) }
before(:each) do
login
click_on("Website")
click_on("Landing Pages")
end
scenario "user creates a landingpage", js: true do
first(:link,"netherlands").click
fill_in "landing_page_domain", with: landing_page.domain
fill_in "landing_page_slug_nl", with: landing_page.slug_nl
fill_in "landing_page_slug_en", with: landing_page.slug_en
fill_in "landing_page_header_title", with: landing_page.header_title
fill_in "landing_page_title", with: landing_page.title
attach_file "landing_page_header_image",( Rails.root + 'app/assets/images/site_builder/image3.jpg')
page.find('#landing_page_restaurant_select').set('Le Garage - Amsterdam')
page.save_screenshot ("test.png")
click_on("Save")
expect(page).to have_content("successfully created")
expect(LandingPage.count).to eq 2
expect(LandingPage.last.landing_page_restaurants.count).to eq 1
end
scenario "user edits a LandingPage", js: true do
click_on("Edit")
expect(page).to have_content 'Edit landing Page '
page.save_screenshot ("edit.png")
end
end
I'm getting the next error.
Failures:
1) Backend Landing Pages user creates a landingpage
Failure/Error: expect(LandingPage.last.landing_page_restaurants.count).to eq 1
expected: 1
got: 0
(compared using ==)
# ./spec/features/backend/landing_pages_spec.rb:33:in `block (2 levels) in <top (required)>'
Who can see what im doing wrong here
cant figure out why the restaurant is not connected to the landingPages
thanks in advance
In the question you mention you are using a select2, but then you are calling set on what I assume is a regular select element. When you are using JS widgets they will often overwrite the values of the hidden elements they build off on a submit event of the form they're in. Because of this it is probable the value you're setting is getting overridden. Rather than set the values of hidden elements (which most capybara drivers don't allow for this specific reason - not sure which driver you're using) you need to replicate the users behaviors. From the select2 examples page it appears the select2 widget is built from a span element and a ul list with the options in it. Therefore something along the lines of
find('span.select2').click # the selector may need to be more specific to locate the exact span, without your html I don't know what that selector would be
find('li', text: 'Le Garage - Amsterdam').click
This would click on the select2 element opening the dropdown, and then click on the li element with the correct text - thereby selecting it.

text_field.set not working in test script but works fine in irb

I'm trying to rename a folder from:
<li class="selected rename" id="labelset-624" folderid="624" foldertype="labelset" permissionlevel="2" labelsetid="624">
<div class="folder-insert-drop ui-droppable"></div>
<div class="clear"></div>
<div class="folder-item droppable hoverable empty ui-droppable">
<div id="mlink-labelset-624" class="folder-menu-link" data-hasfullperm="true" data-subfoldertype="undefined"></div>
<div class="expander"></div>
<div class="folder-name labelset label-set">New Label Set</div>
<div class="target-bar"></div>
<div class="folder-rename">
<input value="New Label Set" id="folder-rename-624" maxlength="100" type="text">
</div>
with watir-webdriver using the following commands:
#b.li(:class, "selected rename").div(:class, "folder-rename").text_field.wait_until_present
#b.li(:class, "selected rename").div(:class, "folder-rename").text_field.set labelsetName
#b.li(:class, "selected rename").div(:class, "folder-rename").text_field.send_keys :return
And it gives me the following error:
Watir::Exception::UnknownObjectException: unable to locate element, using {:class=>"selected rename", :tag_name=>"li"}
When I run my test script (test-unit), I can see the value for labelsetName entered into the text field, but it quickly disappears and reverts to the default value. This causes the send_keys statement to err.
When I enter the same commands into irb, it works perfectly. I tried adding sleeps of up to 15 seconds between steps to no avail. Is there any reason the two would work differently? Any suggestions for fixing this going forward?
Unless you have a compelling reason otherwise, try accessing the <input> tag directly using the id attribute:
b.text_field(:id => "folder-rename-624").set "foo"
b.text_field(:id => "folder-rename-624").send_keys :return
And--if there's an associated submit button--try using that instead of send_keys :return.
EDIT: Unfortunately, I can't reproduce the disappearing text issue. But I'm adding this snippet, which should handle the incrementing id attribute:
tfs = b.text_fields
b.text_field(:id => "#{tfs.last.id}").set "foo"
b.text_field(:id => "#{tfs.last.id}").send_keys :return
Turns out that because I had run the test a number of times, each time creating a new folder, that the folder I was trying to rename got pushed off screen. This is what caused the error.

Resources