How does CasperJs bind variables? - variables

I have the following code which does not post data as expected
var casper = require('casper').create();
var myData;
var utils = require('utils');
casper.start();
casper.then(function () {
myData = {"source":"casperjs"};
utils.dump(myData);
});
casper.thenOpen('http://my-api/api/upload/', {
method: "post",
data: JSON.stringify(myData),
headers: {
"Content-Type":"application/json"
}
}, function () {
utils.dump(myData);
});
casper.run();
The message was sent to my server but without valid data. However, if I move the thenOpen(...) into the then(...) like this
casper.then(function () {
myData = {"source":"casperjs"};
utils.dump(myData);
this.thenOpen('http://my-api/api/upload/', {
method: "post",
data: JSON.stringify(myData),
headers: {
"Content-Type":"application/json"
}
}, function () {
utils.dump(myData);
});
});
Then the post would succeed. Or If i change the thenOpen part in the original code (i.e., without moving it in to the casper.then(...) part, like this
casper.thenOpen('http://my-api/api/upload/', {
method: "post",
data: JSON.stringify({"source":"casperjs"}),
headers: {
"Content-Type":"application/json"
}
}, function () {
utils.dump(myData);
});
Then the post would also be successful. So it looks like myData has to be initialized when the thenOpen(...) is seen. So is this expected or I have done something wrong? I could not find reference about this behavior. Thanks!

This is expected behavior as casperjs schedules the steps before running them. This means for your first listing that JSON.stringify(undefinded) will be sent to the server. The reason is that your first casper.then block was not yet executed when the object is evaluated for your casper.thenOpen block. Therefore your data was not yet assigned properly to myData, which happens inside the step.
The evaluation of the POST data on the other hand is done for the thenOpen call and not inside, so it is executed synchronously.
You already provided some good alternatives.

Related

Update data without refresh the page with Vue and axios

I have a page with 2 tabs (Questions and Data) made on Vue and Axios.
In first Tab, I fill the form and submit it - Save button v-on:click="save".
save: function() {
axios({
method: 'patch',
url: url,
data: this.data
})
.then(function (response) {
this.data = response.data;
}
In the second Tab(Data) I have the list of saved data:
mounted() {
axios
.get('/api/recommended-products/?patient_uuid=' + '{{patient.uuid}}')
.then(response => (this.data= response.data.results))
}
Now when I change answers in Questions Tab my list in Data Tab should change automatically. It changes if I refresh the page - mounted() works.
I tried to create updateList() function:
updateList: function() {
axios
.get('/api/recommended-products/?patient_uuid=' + '{{patient.uuid}}')
.then(response => (this.data= response.data.results))
}
and added it to save() function like:
save: function() {
axios({
method: 'patch',
url: url,
data: this.data
})
.then(function (response) {
this.data = response.data;
this.updateList();
}
The problem is that this way works other second time (sometime works sometimes not). So I just added location.reload(); to save() but I don't like this approach. Is it possible to update Data list without refreshing the page? What am I doing wrong with updateList() function?
In my opinion here you should use vuex and its getters.
You would then have only one request in all the application and the data would be automatically refreshed once updated in the state.
You can then access the data using a computed property which will be automatically re-rendered when the state is updated.
Here is an example using multiple tabs : https://codesandbox.io/s/vuex-axios-demo-forked-m0cqe4?file=/src/App.vue
In this example, i'm loading posts information through the JsonPlaceHolder API.
Every time the form is re send (using a function). The action of the store is called, then the state is updated which trigger the getter to re-render the data.
Note: i'm loading the first post into the mounted with a default value of 1 here.
save: function() {
axios({
method: 'patch',
url: url,
data: this.data
})
.then(function (response) {
this.data = […this.data, …response.data]
}
You have re rendered issue I think can can you try above solution
I think this might be helpful. Try to implement something like following.
async function() {
try{
await axios.post() // or any request
//action if success
//another action if success
...
} catch(error) {
//do something with error.
console.log(error)
}

Net Core and JQuery autocomplete

Im having some real problems getting JQuery autocomplete to work in Net Core.
here is my client side script :
<script>
$(document).ready(function () {
$('#txtSystemUserDisplayName').autocomplete({
change: function (event, ui) {
if (!ui.item) {
$('#txtSystemUserDisplayName').val("");
}
},
source: function (request, response) {
$.ajax({
url: "#(Url.Action("SearchEmployeesAJAX", "Home" ))",
// data: "{ 'term': '" + request.term.replace(/'/gi, "\\'") + "'}",
data: { term: 'fumanchu' },
dataType: "json", type: "POST",
contentType: "application/json; charset=utf-8",
success: function (data) {
var x = Array.prototype.slice.call(data);
response($.map(x, function (item) {
return {
label: item.employeeDisplayName,
}
}))
}, error: function (response) { alert(response.responseText); }, failure: function (response) { alert(response.responseText); }
});
},
select: function (e, i) {
$("#hfSystemUserDisplayName").val(i.item.label);
},
minLength: 1
});
});
Now when i start typing , the autocomplete fires but the param in the controller method is NULL , no matter what i do. it doesnt matter what i call the 'term' in the data object of the request. And yes i am making sure that the controller method parameter is named the same . eg
public JsonResult SearchEmployeesAJAX(String term) {
as you can see ive even commented it out and hardcoded a string in there, still null.
it DOES work if I set the string as part of the URL eg:
url: "#(Url.Action("SearchEmployeesAJAX", "Home", new {#term="blahblahblah" }
This is how I have always done autocompletes in the past on .Net Framework, and never had an issue. Is there something different about Net Core that im not aware of, maybe something different about how requests are formed?
Any help would be appreciated.
Ok so if anyone else is also having this problem, it appears that you cant use the Url.Action helper anymore and still have the parameter not be null.
You will need to use a raw string as the url instead, which seemed to solve this.

Cypress access alias with this.* doesn't works

I'm having a little problem understanding Cypress documentation. In the alias section they've added a use case of accessing alias with fixtures using the this.* reference:
beforeEach(() => {
// alias the users fixtures
cy.fixture("users.json").as("users");
});
it("utilize users in some way", function () {
// access the users property
const user = this.users[0];
// make sure the header contains the first
// user's name
cy.get("header").should("contain", user.name);
});
But when I try to reproduce it, I keep getting the error: Cannot read property 'SOAP_body' of undefined.
I don't understand where is my error. Here is my spec:
/// <reference types="cypress"/>
describe("SOAP API Test", () => {
beforeEach(() => {
cy.fixture("SOAP_body.xml").as("SOAP_body");
});
it("Test with task", function () {
const body = this.SOAP_body;
cy.request({
method: "POST",
headers: {
"content-type": "text/xml; charset=utf-8",
Authorization: "Token myVerySecretToken",
SOAPAction: "http://tempuri.org/TrackingFull",
},
url: `https://path.of/the/application.asmx`,
body: body,
failOnStatusCode: false,
}).then((result) => {
expect(result.status).to.equal(200);
cy.task("XMLtoJSON", result.body).then((response) => {
expect(
response.elements[0].elements[1].elements[0].elements[0]
.elements[1].elements[0].elements[0].elements[0]
.elements[0].elements[0].text
).to.equal("something");
});
});
});
});
and my task
/**
* #type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
on("task", {
XMLtoJSON(XML_body) {
var convert = require("xml-js");
let result = convert.xml2js(XML_body, {
compact: false,
spaces: 2,
});
return result;
},
});
};
Using debugger just before the const definition I can see that the variables are undefined
I do know about cy.get(), but I just wanted to learn how to use the this.* pattern.
After fiddling with the code I've realized that I was using an arrow function in the step definition:
it("Test with task", () => { ... }
I've done it simply because I use a lot of code snippets in VSC, and never paid attention to the syntax is used.
So, after seeing it, I've remembered that it would never work, as the MDN documentation says:
An arrow function expression is a compact alternative to a traditional
function expression, but is limited and can't be used in all
situations.
Differences & Limitations:
Does not have its own bindings to this or super, and should not be used as methods.
Does not have arguments, or new.target keywords.
Not suitable for call, apply and bind methods, which generally rely on establishing a scope.
Can not be used as constructors.
Can not use yield, within its body.
The solution was simple as replacing it with a function definition:
it("Test with task", function () { ... }
and the this context was as expected
Moral of the history, don't trust blindly in your code editor (even if its VSC)

Blueimp fileupload() callbacks not called

I am using Blueimp fileupload() to post image files to a django-tastypie API.
The code below works correctly as far as the file is being uploaded:
$("#image").fileupload({
dataType: 'json',
start: function() {
console.log("start fileupload");
},
progress: function(e, data) {
console.log(data.loaded + " " + data.total);
},
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
},
done: function(e, data) {
console.log("done uploading file.");
}
});
$("#image").bind('fileuploadfinished', function (e, data) {
console.log("fileuploadfinished");
});
However, the done callback is never called. I tried binding the fileuploadfinished and that is also never called.
start and progress are both called as expected.
beforeSend is undocumented, but is needed by django-tastypie for SessionAuthentication - removing it doesn't change that done and fileuploadfinished is never called.
As it turns out, django-tastypie correctly returns a 201 status code. However, this status code is not considered a success by fileupload.
This code handles the status code manually:
$("#image").fileupload({
dataType: 'json',
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
},
complete: function(xhr) {
if (xhr.readyState == 4) {
if (xhr.status == 201) {
console.log("Created");
}
} else {
console.log("NoGood");
}
},
});
That means, the complete callback is called whether success or failure, and checking the readyState and status together can tell whether it succeeded.
There are some other ways to get this to work, however I think this is the best. More details here:
Data inserted successful but jquery still returning error
I was having the same problem. it is because you set your datatype 'json'.
Just leave this out or put it to plain and it will work.
Your server , or uploadhandler isn't return a json answer.

Accessing ioArgs from callback functions

I'm upgrading a bunch of old dojo to 1.8. For our ajax request handling we've got a decorator (well, function wrapper) that will perform redirects in certain cases based on the response content, for example:
// Decorator func:
var redirectDecorator = function(func) {
var f = function(data, ioArgs) {
if(data.redirect) {
// A manual location redirect:
window.location.href = data.redirect;
if(data.redirect_xhr) {
// clone ioArgs, spawn new request to follow redirect etc
// <snip>
} else {
func(response);
}
}
return f;
}
// Used like so:
dojo.xhrPost({
url: url
handleAs: "json",
form: form,
load: redirectDecorator(function(data, ioArgs) {
// do stuff
})
});
Now, in dojo 1.8 (the dojo/request/xhr module) xhr() returns a Deferred for chaining and the callbacks are only supplied the data argument (no ioArgs - apparently these are attached to the promise - see http://bugs.dojotoolkit.org/ticket/12126).
In other words, the above ajax call becomes:
xhr.post(url, {
handleAs: "json",
form: form
}).then(function(data) {
// do stuff
});
Problem is, I can no longer wrap the anonymous function because ioArgs are not supplied. Inspecting the deferred (by breaking the chaining) doesn't appear to work either and would require more re-engineering than I'd like.
Any ideas?
Thanks Ken (for your help at #dojo too). To elaborate, the solution is to use dojo/request and use the .response deferred promise instead, which provides the necessary info:
// Decorator func:
var redirectDecorator = function(func) {
var f = function(response) {
var data = response.data;
if(data.redirect) {
// A manual location redirect:
window.location.href = data.redirect;
if(data.redirect_xhr) {
request(data.redirect_xhr, response.options).then(func);
} // more conditions follow.
}
return f;
}
request.post(url, {
handleAs: "json",
form: form
}).response.then(redirectDecorator(function(response) { // <-- note .response.then(
// do stuff where data is response.data
}));
Promises returned from dojo/request are actually objects with an additional response promise that provides more information. See the following places for information:
http://www.sitepen.com/blog/2012/08/21/introducing-dojorequest/
http://dojotoolkit.org/reference-guide/1.8/dojo/request.html
http://dojotoolkit.org/documentation/tutorials/1.8/ajax/