Uploading a file in Cypress when no input type="file" - file-upload

I need to upload a file, but the thing is that the button doesn't have the tag input and attr type="file". How do I solve this?
The DOM:
I tried:
cy.contains('div#dropdown-grouped', "Bon d'intervention").siblings('div.d-none').find('input[type="file"]')
.selectFile('cypress/fixtures/bon.pdf', {force: true})
But this returns a statusCode 422
Also tried:
const filePath = 'My reportis.jpg'
cy.contains('#dropdown-group-1', "Bon d'intervention").attachFile(filepath)
But this obviously does nothing.
What if I would change the tag of the button from button to input, and add an attr type="file", would that work? If yes, how do you I change the tag with cypress?
Thank you very much!
Solution:
cy.contains('#dropdown-group-1', "Bon d'intervention").click()
cy.get('input[type="file"]').selectFile('cypress/fixtures/bon.pdf', {force: true})

Your first code is correct,
cy.contains('div#dropdown-grouped', "Bon d'intervention")
.siblings('div.d-none')
.find('input[type="file"]')
.selectFile('cypress/fixtures/Call order.pdf', {force: true})
Status code 422 is a response from the server, so selectFile() worked and the app fired a POST, but the server did not like what it was given.
422 Unprocessable Entity
The HyperText Transfer Protocol (HTTP) 422 Unprocessable Entity response status code indicates that the server understands the content type of the request entity, and the syntax of the request entity is correct, but it was unable to process the contained instructions.
From further discussion, it looks like following the steps a user takes gives a working test, which means adding a button click() before the selectFile().
This is the final working test:
cy.contains('#dropdown-group-1', "Bon d'intervention").click()
cy.get('input[type="file"]')
.selectFile('cypress/fixtures/bon.pdf', {force: true})

Related

Is there a way to prevent form state being reset after server 400 error on an Edit form in react-admin?

I have an Edit component that contains a TabbedForm that has been set to pessimistic mode. I am also using a custom data provider based on react-admin's simple rest provider.
<Edit
title="Edit entity"
mutationMode="pessimistic"
{...props}
>
<TabbedForm>
<FormTab label="Details">
<TextInput source="name" />
</FormTab>
</TabbedForm>
</Edit>
There is a validation rule in the API that ensures that another entity with the same name does not exist.
When this validation fails, the server returns a 400 error with a message. I've set this up to display this error in a toast and this is working fine.
The problem I am having is that the entire form state gets reset when there is a 400 error response, so all progress that the user has made on the form has been lost. For example, if the original value of the name field was "Entity A", and I change this to "Entity B" and submit the form, the API discovers that there is already an entity with that name, returns back the error and then resets the name field back to "Entity A". If there were other fields on this form, they are all reset back to the original state as well.
It appears that there is another HTTP request that is sent to the API to get the entity by ID again after the 400 response comes back (i.e. the getOne method on the data provider is being called again).
Is there a way to prevent the form state being reset after a 400 response from the server?
I'm thinking an alternative solution is to prevent 400 errors coming back at all by using client-side validation - perhaps by adding a custom validator that performs an API request to check if there's an entity with that name.
I figured out a way to prevent the form being refreshed after a failure on submit by overriding the onFailure behaviour.
const onFailure = (error: any) => {
notify(
typeof error === "string"
? error
: error.message || "ra.notification.http_error",
{ type: "warning" }
);
};
I have only emitted the logic to refresh() the page as described in the react-admin documentation.
Reference: https://marmelab.com/react-admin/CreateEdit.html#onfailure

How to obtain response to be used on hooks

I am trying to make a simplified version of test report where I am generating a single HTML file report containing only assertion and error response message when there is any (attempting to not publish all the logs and steps).
I understand that we have hooks in karate. However I have looked for karate objects in the github but unable to found any objects where I can extract the response from (to be passed to the js function called on hook)
What I am doing right now is this:
Config:
//karate-config.js
karate.configure('afterScenario', karate.call('classpath:hooks.js'));
Hook:
//hooks.js
//Looking on how to extract the response and log it here
function(){
var info = karate.tags;
karate.log('Tags', info);
}
Am I missing anything on the karate objects? Or this should be achieved in another way?
Thanks a lot!
Try this:
var response = karate.get('response');
EDIT better example:
Background:
* configure afterScenario = function(){ karate.log('***', karate.get("response.headers['X-Karate']")) }
Scenario:
Given url 'http://httpbin.org'
And path 'headers'
And header X-Karate = 'test'
When method get
# this will fail
Then status 400
I have tried with both karate.get('response') and response directly, and both work. If you use karate.call() pass the response as a parameter.

Force reload cached image with same url after dynamic DOM change

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.

Second request is not working in dojo.io.iframe.send in dojo 1.7

I am uploading a file using dojo.io.iframe.send ajax call using below code.
Am using dojo 1.7 and WebSphere Portal Server 8.0
dojo.io.iframe.send({
form: "workReqIDFormWBS",
handleAs: "text/html",
url:"<portlet:actionURL/>",
load: function(response, ioArgs) {
console.log(response, ioArgs);
return response;
},error: function(response, ioArgs) {
console.log(response, ioArgs);
return response;
}
});
When am uploding the file for the first time it's working fine,where as from second time onwards nothing is happening. Any solution for this issue.
Action URLs are only valid to be invoked once by default. Portal protects against form submission replay incidents by internally assigning an ID within the action URL produced.
You should also be seeing some logging on those subsequent action url requests: http://www-01.ibm.com/support/docview.wss?uid=swg21613334
I suggest either using resource URL and serveResource() in your portlet or ensuring that your response from the render phase following the action URL processing regenerate the Action URL value and update a variable your posted javascript reads and uses in subsequent send() calls.

What's the easiest way to display content depending on the URL parameter value in DocPad

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%>