Cucumber, selenium, ruby: best practices to check 301 redirect - ruby

I need to check 301 redirect.
So I have old URLs that should redirect to new ones.
What are the best practices to verify it?
Now I'm thinking about simple way: navigate to an old URL and check that the new URL is correct and corresponding page displays. Can I check that it was 301 redirect?
I found the following article: http://www.natontesting.com/2010/09/06/announcing-responsalizr-test-http-response-codes-in-ruby/
but after redirection I see the current status code =200
any suggestion how can I catch 301 status code?
Thank you in advance

Don't do it in a feature spec. In a feature spec (cucumber), you test the site how the user sees it, and the user doesn't care what the status code was. If you really care about the response, do it in a controller or better request spec. With rspec, it could look like this:
describe 'redirects' do
context 'on GET /old_users' do
before do
get '/old_users'
end
it 'redirects /old_users to /users' do
expect(response).to redirect_to('/users')
end
it 'responds with a 301 - Permanently moved' do
expect(response.status).to eq(301)
end
end
end
https://www.relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec

Related

Difference between Laravel testing method assertRedirect($uri) and assertLocation($uri)?

I was reading Laravel document HTTP tests and a question occurred.
I can't tell the difference between assertLocation($uri) and assertRedirect($uri), since both are for redirecting to specific uri.
Anyone could help would be so much appreciated.
If we look functionality of both
assertLocation($uri) would assert that the current location header matches the given URI.
But assertRedirect($uri) would assert whether the response is redirecting to a given URI.
I agree with example given by #apokryfos,
only 3xx responses are considered to be redirect responses while a 201 is not a redirect so assertLocation will pass if the response is 201 with a specified location while assertRedirect will not pass for 201 responses.
If we look code wise,
The assertRedirect() function also calls assertLocation() internally but it also checks using PHPUnit::assertTrue() that the response is redirected, if not then it will send a message
'Response status code [201] is not a redirect status code.', where 201 specifies the status code of response.
Checkout the assertRedirect() from github repo of framework

Ruby: Net::HTTP and redirects

I'm working through tutorials at http://ruby.bastardsbook.com/chapters/web-crawling/ and would like a little clarification on the Handling Redirects one, because the DOD website that the author uses as an example has been remade since the time of writing and I have run into some unexpected results while adjusting his code to work with the current version. (Please note that I don't need help rewriting the code, I'm just wondering why the stuff that happens here happens)
Specifically, I get code 301 no matter whether the page I'm trying to get with Net::HTTP.get_response exists or not. For example:
require 'net/http'
VALID = 'https://www.defense.gov/News/Contracts/Contract-View/Article/14038760'
INVALID = 'https://www.defense.gov/News/Contracts/Contract-View/Article/14038759'
resp = Net::HTTP.get_response(URI.parse(VALID))
puts resp.code # 301
resp = Net::HTTP.get_response(URI.parse(INVALID))
puts resp.code # 301
So, why does a valid address return a 301 Moved Permanently? And not only that, but actually trying to follow that redirect (useless in the scope of that tutorial, since the whole point was to skip anything that isn't a 2xx) as suggested here Ruby Net::HTTP - following 301 redirects gives me a 404, presumably because the redirect link has a trailing slash.
if resp.code == '301'
resp = Net::HTTP.get_response(URI.parse(resp.header['location']))
end
puts resp.code # 404
Even more puzzling to me is that when I looked at resp.body I found that despite that 404 error, I had, in fact, successfully downloaded the page's contents.
I would be very grateful if somebody walked me through whatever exactly is going on here. Thank you for your help and for taking your time in advance.
It doesn't seem like Ruby issue but just www.defense.gov manner. https://www.defense.gov/News/Contracts/Contract-View/Article/14038760 gives redirect (301) and then 404 despite the way to get it.
https://www.defense.gov/News/Contracts/Contract-View/Article/14038760 seems like a url to some missing data but https://www.defense.gov/News/Contracts/Contract-View/Article/1403876/ works fine (actual for 26.17.2017 03:24 +7). Why do you think the url with id 14038760 is valid?
I've found out that https://www.defense.gov/News/Contracts/Contract-View/Article/1403876 redirects to https://www.defense.gov/News/Contracts/Contract-View/Article/1403876/ (the same url but with trailing slash) while the url with trailing slash gives 200 response immediately.
What you can do? Try to get here https://www.defense.gov/News/Contracts/source/nav/ a list of actual contracts first and then request each of them with separated requests.

Is there a Lemoon route for /{slug}

I'm looking for an existing route (in Mindroute.Lemoon.Helpers.RouteHelper) that will already handle a path like http://www.mylemoonsite.com/blogpost3. It doesn't appear by requesting that URL that such a route is active, but it looks like some of the routes in RouteHelper.cs are attempting to cover that case. I can request http://www.mylemoonsite.com/blog/blogpost3, but I'm looking specifically for the former. Thanks.
Lemoon adds the catch-all route {slug*} to the end of the route-table, effectively catching everything that is not handled by other route handlers such as custom Controllers etc.
In order for Lemoon to respond to the request http://www.mylemoonsite.com/blogpost3 you need to have a page in your site with the permalink blogpost3. Since you get a response when requesting http://www.mylemoonsite.com/blog/blogpost3 I am guessing the permalink for your page is blog/blogpost3.
There are 2 things you can do to get a response from the path http://www.mylemoonsite.com/blogpost3.
Edit the permalink of the page
Add an alias to the page
If you add the alias blogpost3 the page will respond to both http://www.mylemoonsite.com/blogpost3 and http://www.mylemoonsite.com/blog/blogpost3. When adding the alias you can also specify the HTTP response code for the alias (200 OK, 301 Moved or 302 Found).

Return error to ajax on action decision

I have a controller action which looks like so -
def upvote
#post = Post.find(params[:id])
if user_has_rated_post?
# I want to interrupt AJAX here
redirect_to[:forum, #post.question], :notice => "You already voted for this post"
else
#post.upvote
add_rating_to_post(1, #post)
#post.save
redirect_to[:forum, #post.question], :notice => "Post Up Voted"
end
end
and I have an AJAX call to up vote a post, which works perfectly fine except I need it to stop the AJAX call if the first condition, user_has_rated_post? is met.
So the question is how can I interrupt or force an error to return to AJAX, or should I be trying to go about this another way?
Yes you have to return something that jQuery(or your AJAX solution) interprets as an error. Then you will have to handle this error in javascript code(or just do nothing if that fits). I think anything above 400 is by convention considered an error. See the list of HTTP status codes and pick the one that suits you most http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. Here I would bet on 403 - The server understood the request, but is refusing to fulfill it. You can always just render 500, but I think it's better to be specific.

Grab Facebook signed_request with Sinatra

I'm trying to figure out whether or not a user likes our brand page. Based off of that, we want to show either a like button or some 'thank you' text.
I'm working with a sinatra application hosted on heroku.
I tried the code from this thread: Decoding Facebook's signed request in Ruby/Sinatra
However, it doesn't seem to grab the signed_request and I can't figure out why.
I have the following methods:
get "/tab" do
#encoded_request = params[:signed_request]
#json_request = decode_data(#encoded_request)
#signed_request = Crack::JSON.parse(#json_request)
erb :index
end
# used by Canvas apps - redirect the POST to be a regular GET
post "/tab" do
#encoded_request = params[:signed_request]
#json_request = decode_data(#encoded_request)
#signed_request = Crack::JSON.parse(#json_request)
redirect '/tab'
end
I also have the helper messages from that thread, as they seem to make sense to me:
helpers do
def base64_url_decode(payload)
encoded_str = payload.gsub('-','+').gsub('_','/')
encoded_str += '=' while !(encoded_str.size % 4).zero?
Base64.decode64(encoded_str)
end
def decode_data(signed_request)
payload = signed_request.split('.')
data = base64_url_decode(payload)
end
end
However, when I just do
#encoded_request = params[:signed_request]
and read that out in my view with:
<%= #encoded_request %>
I get nothing at all.
Shouldn't this return at least something? My app seems to be crashing because well, there's nothing to be decoded.
I can't seem to find a lot of information about this around the internet so I'd be glad if someone could help me out.
Are there better ways to know whether or not a user likes our page? Or, is this the way to go and am I just overlooking something obvious?
Thanks!
The hint should be in your app crashing because there's nothing to decode.
I suspect the parameters get lost when redirecting. Think about it at the HTTP level:
The client posts to /tab with the signed_request in the params.
The app parses the signed_request and stores the result in instance variables.
The app redirects to /tab, i.e. sends a response with code 302 (or similar) and a Location header pointing to /tab. This completes the request/response cycle and the instance variables get discarded.
The client makes a new request: a GET to /tab. Because of the way redirects work, this will no longer have the params that were sent with the original POST.
The app tries to parse the signed_request param but crashes because no such param was sent.
The simplest solution would be to just render the template in response to the POST instead of redirecting.
If you really need to redirect, you need to carefully pass along the signed_request as query parameters in the redirect path. At least that's a solution I've used in the past. There may be simpler ways to solve this, or libraries that handle some of this for you.

Resources