I am trying to get URL which I am getting after redirection if do following:
cy.url().then(url => {
cy.log(url);
});
Then I get logged initial URL, but not the (new url), how do I get url in cypress after redirection?
redirection img (new url)
Solution:
To get the redirected URL just simply add cy.get and your element so it will wait until the redirect page loads. Here is the working solution for me:
cy.get('.crumb > p')
cy.url().then(url => {
cy.log(url);
});
Exactly as you wrote, you need to first wait for a element from the new URL to be visible, using a cy.get('any-element-from-the-new-url').
After that you can get the new URL just using cy.url(), in this case if you want to log this URL you can just use cy.log(cy.url()).
A more meaningful approach would be to add an assertion on the pathname to what you are expecting. The docs can shed some light on the cy.location(). You can use an include assertion on the pathname in the situation that you will not know all of the url string.
// visiting url - https://website.com/favorites
// redirects to - https://website.com/favorites/regional/local
cy.location('pathname') // yields "/favorites/regional/local"
.should('include', '/favorites/')
.then(cy.log)
If you do this, you don't have to do any previous step. Especially because the expectedUrl doesn't have to match the actual url which allow your test doesn't crash if that happens.
cy.url('match', 'expectedUrl').then(el=>{
cy.log(el)
})
Related
A client that follows redirects can be created as follows:
WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create().followRedirect(true)
))
After invoking a HEAD request on a URL, how can the final Location header be retrieved? In other words, how can we get the final URL redirected to?
It is true that HttpClient#followRedirect(true) enables the redirection.
However there is also HttpClient#followRedirect(BiPredicate<HttpClientRequest,HttpClientResponse>), here you can control more precisely when you want to redirect and in addition to this you have always access to the response and the Location header, so in any time you will know to which location there will be a redirection.
More info here and here
For example
WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create().followRedirect((req, res) -> {
System.out.println(res.responseHeaders().get("Location"));
return HttpResponseStatus.FOUND.equals(res.status());
})
))
I am trying to redirect the user that uses my website after he has logged into his account, he will be redirected to a dashboard.
The problem is that I can see a request for the /dashboard route in the Network tab of the browser Inspection Tools, but the page never loads.
This is my code so far.
router.post('/login', function(request, response){
// verify against database and send back response
var userData = {};
userData.email = request.body.email;
userData.password = request.body.password;
userData.rememberPassword = request.body.rememberPassword;
// check if in the database and re-route
var query = database.query('SELECT * FROM users WHERE email = ?', [userData.email], function(error, result){
if(error){
console.log('Error ', error);
}
if(result.length){
// check if the password is correct
if(userData.password === result[0].password){
// redirect to the dashboard
// TODO this piece of code does not redirect correctly
response.redirect('/dashboard'); // < HERE
console.log('Haha');
}
}
else{
// do something when there is are no results
// invalid email status code
response.statusCode = 405;
response.send('');
}
});
});
And this is the route towards the dashboard, and it is being rendered properly when accessed in the browser.
router.get('/dashboard', function(request, response){
response.render(path.resolve(__dirname, 'views', 'dashboard.pug'));
});
Why can't it redirect when the user completes the login process?
Thanks.
The issue can be in the frontend and not in the backend. If you are using AJAX to send the POST request, it is specifically designed to not change your url.
Use window.location.href after AJAX's request has completed to update the URL with the desired path.But the easiest way would be to create a form with action as /login and use the submission to trigger the url change.
To make sure that the problem does not lie with the backend,
Add a logging statement to router.get('/dashboard' to verify if
the control was passed.
Check that the HTTP status code of the /login route is 302 indicating a redirect and location header has the route /dashboard.
Content type of response /dashboard is text/html.If not please set it using res.setHeader("Content-Type", "text/html").
I'm developping an angular2 application (single page application). My page is never "reloaded", but it's content changes according to user interactions.
I'm having some cache problems especially with images.
Context :
My page contains an editable image list :
<ul>
<li><img src="myImageController/1">Edit</li>
<li><img src="myImageController/2">Edit</li>
<li><img src="myImageController/3">Edit</li>
</ul>
When i want to edit an image (Edit link), my dom content is completly changed to show another angular component with a fileupload component.
The myImageController returns the LastModified header, and cache-control : no-cache and must-revalidate.
After a refresh (hit F5), my page does a request to get all img src, which is correct : if image has been modified, it is downloaded, if not, i just get a 304 which is fine.
Note : my images are stored in database as blob fields.
Problem :
When my page content is dynamically reloaded with my single page app, containing img tags, the browser do not call a GET http request, but immediatly take image from cache. I assume this a browser optimization to avoid getting the same resource on the same page multiple times.
Wrong solutions :
The first solution is to add something like ?time=(new Date()).getTime() to generate unique urls and avoid browser cache. This won't send the If-Modified-Since header in the request, and i will download my image every time completly.
Do a "real" refresh : the first page load in angular apps is quite slow, and i don't to refresh all.
Tests
To simplify the problem, i trying to create a static html page containing 3 images with the exact same link to my controller : /myImageController/1. With the chrome developper tool, i can see that only one get request is called. If i manage to get mulitple server calls in this case, it would probably solve my problem.
Thank you for your help.
5th version of HTML specification describes this behavior. Browser may reuse images regardless of cache related HTTP headers. Check this answer for more information. You probably need to use XMLHttpRequest and blobs. In this case you also need to consider Same-origin policy.
You can use following function to make sure user agent performs every request:
var downloadImage = function ( imgNode, url ) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "blob";
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200 || xhr.status == 304) {
var blobUrl = URL.createObjectURL(xhr.response);
imgNode.src = blobUrl;
// You can also use imgNode.onload callback to release blob resources.
setTimeout(function () {
URL.revokeObjectURL(blobUrl);
}, 1000);
}
}
};
xhr.send();
};
For more information check New Tricks in XMLHttpRequest2 article by Eric Bidelman, Working with files in JavaScript, Part 4: Object URLs article by Nicholas C. Zakas and URL.createObjectURL() MDN page and Same-origin policy MDN page.
You can use the random ID trick. This changes the URL so that the browser reloads the image. Not that this can be done in the query parameters to force a full cache break or in the hash to allow the browser to re-validate the image from the cache (and avoid re-downloading it if unchanged).
function reloadWithCache(img: HTMLImageElement, url: string) {
img.src = url.replace(/#.*/, "") + "#" + Math.random();
}
function reloadBypassCache(img: HTMLImageElement, url: string) {
let sep = img.indexOf("?") == -1? "?" : "&";
img.src = url + sep + "nocache=" + Math.random()
}
Note that if you are using reloadBypassCache regularly you are better off fixing your cache headers. This function will always hit your origin server leading to higher running costs and making CDNs ineffective.
I'd like to check for an URL parameter and then display the confirmation message depending on it.
E.g. if I a GET request is made to /form?c=thankyou docpad shows the form with thank you message
I think there is two basic ways to do this.
look at the url on the server side (routing) and display differing content according to URL parameters
Look at the parameter on the client side using JavaScript and either inject or show a dom element (eg div) that acts as a message box.
To do this on the server side you would need to intercept incoming requests in the docpad.coffee file in the serverExtend event. Something like this:
events:
# Server Extend
# Used to add our own custom routes to the server before the docpad routes are added
serverExtend: (opts) ->
# Extract the server from the options
{server} = opts
docpad = #docpad
# As we are now running in an event,
# ensure we are using the latest copy of the docpad configuraiton
# and fetch our urls from it
latestConfig = docpad.getConfig()
oldUrls = latestConfig.templateData.site.oldUrls or []
newUrl = latestConfig.templateData.site.url
server.get "/form?c=thankyou", (req,res,next) ->
document = docpad.getCollection('documents').findOne({relativeOutPath: 'index.html'});
docpad.serveDocument({
document: document,
req: req,
res: res,
next: next,
statusCode: 200
});
Similar to an answer I gave at how to handle routes in Docpad
But I think what you are suggesting is more commonly done on the client side, so not really specific to Docpad (assumes jQuery).
if (location.search == "?c=thankyou") {
$('#message-sent').show();//show hidden div
setTimeout(function () {
$('#message-sent').fadeOut(1000);//fade it out after a period of time
}, 1000);
}
This is a similar answer I gave in the following Docpad : show error/success message on contact form
Edit
A third possibility I've just realised is setting the document to be dynamically generated on each request by setting the metadata property dynamic = true. This will also add the request object (req) to the template data passed to the page. See Docpad documentation on this http://docpad.org/docs/meta-data.
One gotcha that gets everyone with setting the page to dynamic is that you must have the docpad-plugin-cleanurls installed - or nothing will happen. Your metadata might look something like this:
---
layout: 'default'
title: 'My title'
dynamic: true
---
And perhaps on the page (html.eco):
<%if #req.url == '/?c=thankyou':%>
<h1>Got It!!!</h1>
<%end%>
I am creating an ajax request and building the url as follows:
function submitYear(year){
new Ajax.Request('update_make/'+year, { method: 'get'});
}
When I am at the new action for my car_infos controller, http://localhost:3000/car_infos/new this Ajax request works fine. I get a request that says:
Started GET "/car_infos/car_infos/update_make/2011"
The route matches up and all is well. However, if there is an error in the create the url becomes http://localhost:3000/car_infos and then when my ajax request triggers I get this with a routing error:
Started GET "/update_make/2002"
No route matches "/update_make/2002"
Here is what happens in my controller when create fails:
format.html { render :action => "new" }
I understand why I am getting the routing error, because I don't have a route set up as /update_make/. Here is my route.
match 'car_infos/update_make/:year', :controller => 'car_infos', :action => 'update_make'
So two questions.
Why does my get request change when the url changes from car_infos/new to car_infos
How do I resolve this so when I create the url in the javascript it works for both cases? I don't think putting a route for /update_make is the answer. If I redirect to /new then I lose the field values and the error message.
Thanks,
You're sending your ajax request to a relative path, so if your browser location path changes the request path changes too. The browser location path could be changing because of a redirect in Rails or in javascript.
Is this a typo (the 2x "/car_infos")?
Started GET "/car_infos/car_infos/update_make/2011
You could spell out the absolute url in your javascript:
function submitYear(year){
var absoluteUrl = 'http://' + window.location.host +
'/car_infos/update_make/' + year;
new Ajax.Request(absoluteUrl, { method: 'get'});
}