CasperJS click not working properly with multiple submit buttons - casperjs

I have a form with 3 save buttons with ids 'save', 'save_new' & 'save_copy'. My server code performs different actions after saving depending on the presence of one of these fields in the http request block. When I use the browser and click on save for example the save parameter appears in the request object. When I use CasperJS click the save parameter is not present in the request block, so my code just performs the default action which is not the correct result.
casper.test.begin('Routine sample test', function suite (test) {
casper.start();
casper.setHttpAuth('<login>', '<pw>');
casper.thenOpen('http://localhost/<sitename>/sample/routine/edit/0', function eval() {
test.assertSelectorHasText("h1", "Routine Sample" );
this.fill('form#routine_form', {
<fill parameters>
}, false);
this.click("#save_new");
});
casper.then(function() {
this.echo(this.getCurrentUrl());
test.assertSelectorHasText("h1", "Routine Sample" );
var sample_id = this.fetchText('[name="sample_id"]');
test.assertEval( function(sample_id) { return sample_id > 0 }, "Sample created" );
});
casper.run(function() {test.done();});
});
The final test fails because the server has not returned the page I was expecting.

Related

Laravel 7: how to redirect to success page with Paypal after transaction?

I'm trying some new things in Laravel, how can I redirect the user to a new view ''success page'' after the transaction, instead of having the standard alert of the script?
paypal.Buttons({
createOrder: function(data, actions) {
// This function sets up the details of the transaction, including the amount and line item details.
return actions.order.create({
purchase_units: [{
amount: {
value: '0.10' // <---- totale
}
}]
});
},
onApprove: function(data, actions) {
// This function captures the funds from the transaction.
return actions.order.capture().then(function(details) {
// This function shows a transaction success message to your buyer.
alert('Transaction completed by ' + details.payer.name.given_name);
});
}
}).render('#paypal-button-container');
//This function displays Smart Payment Buttons on your web page.
</script> ```
In that particular callback function you can use actions.redirect()
The current PayPal demo now has a sample with that commented as an option, vs. a no-redirect option of showing a message within the <div> also: https://developer.paypal.com/demo/checkout/#/pattern/client
The general JS answer is to set window.location.href to the new destination

Exit Event / Welcome Event Not Firing

We're trying to get some events/messages to post when a user exits a chatbot window (or the site) (or a welcome message), but so far the events are not firing.
I can see within Inspector tools:
Screen Shot 2020-02-18 at 3 15 39 PM
Various activities/conversations are created, the chatbot works, but no welcome/exit events are triggered.
The code we're using is nearly if not identical to documentation code here: https://github.com/microsoft/BotFramework-WebChat/blob/master/docs/WELCOME_MESSAGE.md
and here: How to handle user leaving conversation
I have a function that fires when the window is closed, as follows:
const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => async action => {
return next( action );});
window.addEventListener( 'sendEventActivity', ( { data } ) => {
store.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'user_event',
value: {
name: 'end_conversation',
value: 'user ended conversation'
},
text: 'The user has left the conversation.'
}
})
});
function exitEvent(){
const eventSendActivity = new Event( 'sendEventActivity' );
eventSendActivity.data = 'User left conversation';
window.dispatchEvent( eventSendActivity );
console.log('Exit Event Submitted (hopefully)');
}
exitEvent();
I have tried other variations, defining the store earlier, above render chat, after render chat, sending welcome messages from various locations and at various times but can't seem to get it to send.
We are using https://cdn.botframework.com/botframework-webchat/latest/webchat.js
Any idea what the issue might be? Not sure where we are going wrong or why it's not firing - copying in theory known to be working code straight into our code doesn't seem to do the trick.
Thanks in advance and please let me know if I have failed to include any necessary details- new to chatbot and do not post much on github. Many thanks,
EDIT:
I was able to marry the aforementioned code and code from here: https://github.com/microsoft/BotFramework-WebChat/issues/2120#issuecomment-516056614 in order to achieve what I wanted. I'll post below in case it helps anyone else...
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join'
}
});
}
return next(action);
});
window.addEventListener( 'sendEventActivity', ( { data } ) => {
store.dispatch( {
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/exit'
}
} );
} );
document.getElementById("action_menu_btn").addEventListener( 'click', function() {
const eventSendActivity = new Event( 'sendEventActivity' );
eventSendActivity.data = 'User left conversation';
window.dispatchEvent( eventSendActivity );
console.log('End Converstaion Event Fired');
});
Cheers!
I failed to mention this in the other post (I'll update it), but the reason the code works is because of the window.onbeforeunload() function. Without it, the window closes before any code can finish executing. The result being no event is created, is caught by a listener, nor is sent via the Web Chat store to the bot.
Here, using the above, refreshing the page produces the "User left conversation" activity.
Also, something to note, any function you create and pass thru like you have with exitEvent() is going to run as soon as the page loads. Take the following code which gets the user's location via the browser (placed just before the closing </script> tag). As you can see, it's loading even before Web Chat. If you are wanting a function to run according to some activity passed from the bot, then utilize either the store's actions (i.e. DIRECT_LINE/INCOMING_ACTIVITY, or some other) or via the available middleware.
let geoLoc = async () => {
await navigator.geolocation.getCurrentPosition(position => {
console.log('Latitude: ', position.coords.latitude);
console.log('Longitude: ', position.coords.longitude);
});
}
geoLoc();
Regarding a welcome message, you have two options. Either send as an activity from your bot (reference this sample) or initiate an event on your page after some initial activity is received (reference this sample).
Lastly, I would recommend getting the code working as-is before tinkering with it. This usually trips me up, so thought I'd pass it along.
Hope of help!

Django render template on AJAX success

I am trying to make a web application based on Django that takes user input and performs Heavy background task that completes in almost five to ten minutes. When the background task is completed, few parameters are supplied to the template to render. Everything works fine and the page loads after that.
But when I am trying to use AJAX for this as it does'nt seems good that the page is loading for so long due to background heavy processing, I am not able to figure out how to reload the page (Though I am able to show an alert on completion but instead of this I want to re-render the page)
Here is my views.py code:
def index(request):
#All Background process code goes here
return render(request, 'form.html', {'scanResults' : scanResults, 'context_list' : context_list, 'scanSummary' : scanSummary})
Here is my AJAX call
<script type="text/javascript">
$(document).on('submit','#scanForm', function(e){
e.preventDefault();
$.ajax({
type: 'POST',
url: '/scanner/',
data: {
email: $('#email').val(),
context: $('#context').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success:function(response){
alert('Scan Completed');
location.reload();
}
});
});
I am not able to figure out, what should I write in success function to reload the page that index function has returned to template.
My main motive is to show a progress bar that tells the progress of process in background (I have'nt implemented the code yet )and once the process is completed , refresh the page with response.
Thank You
If you want to check the progress of a process you may need a polling mechanism
as a solution.
This requires you to have a Model that has a state to determine if your scan
is still in progress or has succeeded.
Since you will reload the page to display the results, you should have
a logic in your index view to return a different template or context
for when a user has yet to start scanning and when the scanning is successful.
from django.http import JsonResponse
def index(request):
if status == 'success':
# `status` may come from a Model which has a state .
# If `status` is 'success' this means that your scanning has
# finished so you can have a different page or update context_list
# based on success data.
# Display input form
form = scannerForm()
return render(request, 'form.html', {
'form': form,
'context_list' : context_list,
'scanSummary' : scanSummary
})
You need a view to continuously check the scan status and returns a JSON response.
def scanner(request):
#All Background process code goes here
form = scannerForm(request.POST)
status = form.perform_task()
# During the task, your Model state should also be
# updated and return the status whether it is success, pending or failed etc..
return JsonResponse({
'status': status,
})
Run the ajax poll to check the scanner view.
<script type="text/javascript">
$(document).on('submit','#scanForm', function(e){
e.preventDefault();
checkScanStatus();
});
function checkScanStatus () {
$.ajax({
type: 'POST',
url: '/scanner/',
data: {
email: $('#email').val(),
context: $('#context').val(),
csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
},
success: handleCheckScanStatus,
error: handleScanError
});
}
function handleCheckScanStatus (result) {
if (result.status == 'success') {
// Reload the page and display the condition you set for 'success' state
// on the `index` view.
location.reload();
} else {
// Show progress bar indicating that the process running in the background
const interval = 5000; // Five seconds
window.setTimeout(checkScanStatus, interval);
}
}
function handleScanError (response) {
console.error(response)
}
</script>
I would suggest to look into django celery for async tasks and django-fsm for transitioning model states.
If you just want a simple loader and do not need the check the specific status of your background task, you can use jQuery AJAX's beforeSend method to display a progress bar until the AJAX request finishes.

session.setAttribute only updates after page reload

I have an ajax request which invokes GetTierNamesServlet:
$('#application').change(function() {
$.ajax({
url : 'GetTierNamesServlet',
data : {
name : $('#application').find(":selected").text()
},
type : 'get',
cache : false,
success : function(data) {
},
error : function() {
alert('error');
}
}).done(function() {
var test = '<c:out value="${tiers}" />';
alert(test)
})
});
GetTierNamesServlet saves 'tiers' to a session attribute as follows and forwards back to the same page (index.html).
HttpSession session = request.getSession(false);
session.setAttribute("tiers", tiers);
getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
When alert(test) is called, it alerts the selected tiers from the previous time the ajax request was processed.
The session attribute 'tiers' always seems to "lag" one refresh behind.
What am I doing incorrectly here? I would expect that by placing the alert within the .done portion of the ajax request it would wait the asynchronous call to return before doing something.
This fragment of JavaScript:
var test = '<c:out value="${tiers}" />';
is rendered with the value of ${tiers} before your servlet is called. If you inspect the HTML on the page you will likely find something like:
...
}).done(function() {
var test = 'null'; // or some other "old" value
alert(test)
})
the JSP content is translated to HTML and sent to the browser (page 1)
some event on page 1 causes the JavaScript to be executed
the AJAX call results in the page being rendered again and returned to the browser (page 2)
the JavaScript in page 1 finishes executing via the .done(...) function.
You AJAX call is returning a page when it should probably return a JSON fragment containing your tiers content which will then be consumed by the .done function.

Extjs 4 (with a code for 3.4 below) downloading a file returned from a post request

I have seen questions slightly related to this, but none that answer my problem. I have set up an Ext.Ajax.request as follows:
var paramsStringVar = 'param1=1&param2=two&param3=something&param4=etc';
Ext.Ajax.request({
url: '/cgi-bin/url.pl',
method:'POST',
params:paramsStringVar,
timeout:120000,
success: function(response, opts){
var objhtml = response.responseText; //content returned from server side
console.log(objhtml);
}
});
This request retrieves the appropriate content from the backend. One parameter is outputType, which can take values {html, excel, csv}. When returning html to display I am able to handle and display it correctly. Now on to the problem...
When I set the outputType parameter to csv or excel, I get back the appropriate content as csv or tsv(excel) as requested. BUT, I don't want the content, I want a prompt to download the file(csv or excel). How can I have the browser auto prompt the user to download the file instead of just retrieving the text content within extjs?
Version 4.07 so I can't use any 4.1 only features
There seems to be no bulletproof solution but there are several approaches I would try:
1) Use an iframe instead of real XHR to POST data to the server, e.g. <form action="/something" target="myiframe"> where myiframe is the name of your hidden iframe. That way your form would use the iframe (not your main window) to submit data to the configured URL. Your server should set response header as application/octet-stream (or some ither MIME type for binary data) so the browser triggers download. Otherwise (if html returned in your case) you can just retrieve iframe's body innerHTML and display it to the user in UI. While using an iframe (or a new window) instead of XHR doesn't sound like the best idea, this solution seems to be the most reliable so far (and with best browser support).
Here is a slightly modified example from Ext.form.Basic docs page:
Ext.create('Ext.form.Panel', {
title: 'Basic Form',
renderTo: Ext.getBody(),
width: 350,
// Any configuration items here will be automatically passed along to
// the Ext.form.Basic instance when it gets created.
// *THIS* makes the form use a standard submit mechanism, not XHR
/**/standardSubmit: true,
// URL to submit to
url: 'save-form.php',
items: [{
fieldLabel: 'Field',
xtype: 'textfield',
name: 'theField'
}],
buttons: [{
text: 'Submit',
handler: function() {
// The getForm() method returns the Ext.form.Basic instance:
var form = this.up('form').getForm();
if (form.isValid()) {
// Submit the Ajax request and handle the response
form.submit({
success: function(form, action) {
Ext.Msg.alert('Success', action.result.msg);
},
failure: function(form, action) {
Ext.Msg.alert('Failed', action.result.msg);
},
// You can put the name of your iframe here instead of _blank
// this parameter makes its way to Ext.form.Basic.doAction()
// and further leads to creation of StandardSubmit action instance
/**/ target: '_blank'
});
}
}
}]
});
There are two key parameters here (lines marked with /**/):
standardSubmit: true config that you pass to your form will make it do a standard submit instead of XHR.
Passing a target parameter to the form's submit action. This feature is not documented but you can see it being used in Ext.form.action.Submit source code (all options that you pass to Ext.form.Basic.submit() method end up as parameters of Ext.form.action.* instance.
In the example code I put target: '_blank' to demonstrate that it works right away (will create a new browser window). You can replace it with the name of your iframe later but I suggest that you first test how your form submits data to a regular new window and then develop logic that creates and processes an iframe. You will have to process the result inside iframe yourself, thought. It's not that difficult, see Ext.data.Connection.upload() implementation as an example of iframe processing.
ExtJS actually already uses the iframe technique for file uploads. See Ext.data.Connection and Ext.form.field.Field.isFileUpload() for an idea of how it can work.
2) Suggested here: Using HTML5/Javascript to generate and save a file.
If you don't want to go the iframe way, you can try generate data URI from response data and navigate to that URI triggering download:
content = "Hello world!";
uriContent = "data:application/octet-stream," + encodeURIComponent(content);
window.location.href = uriContent;
Again, mimetype is essential here. This worked for me, you should note, however, that browsers impose a size limit to data URIs (256Kb is a safe bet).
3) Another answer in the mentioned thread links to FileSaver.js library the implements the (abandoned?) w3 spec. Usage and demo here. It uses [BlobBuilder] to generate a blob of binary data that is further used to initialize downloads using one of several methods. While this solution seems to work, it uses deprecated APIs and may not be future-proof.
Below is my solution. This is how I have it currently working. The response generates a download/open prompt, based on a response type of text/csv. Note that no iFrame or reference to an iframe are needed. I spent a lot of time hung up on the need for an iFrame, which actually broke my solution. An iFrame is not needed to generate a download prompt. What is needed is a request(submittal) similar to this one, along with a backend generating the appropriate csv with text/csv response header.
var hiddenForm = Ext.create('Ext.form.Panel', {
title:'hiddenForm',
standardSubmit: true,
url: /cgi-bin/url.pl
timeout: 120000,
height:0,
width: 0,
hidden:true,
items:[
{xtype:'hiddenField', name:'field1', value:'field1Value'},
// additional fields
]
})
hiddenForm.getForm().submit()
The standardSubmit line is vital
You don't need to create a form panel and make it hidden in your extjs file. We can add a html form and on click of button in extjs file we can submit the form using the url. This will work both in IE as well as chrome browsers. Below is my code i tried and its working fine,
<form action="<%=fullURL%>/DownloadServlet.do" method="get" id="downloadForm" name="downloadForm" target="_self">
</form>
click:
{
fn: function()
{
document.getElementById('downloadForm').submit();
}
}
To get it working on ExtJS 3.4:
var hiddenForm = new Ext.FormPanel({
id:'hiddenForm',
region: 'south',
method: 'POST',
url: "/cgi/test.wsgi",
height: 0,
standardSubmit: true,
hidden:true,
items:[
{xtype:'hidden', name:'p', value:p},
{xtype:'hidden', name:'g', value:g},
// ...
],
});
linkThis = new Ext.Button({
text: 'Download this CSV',
handler: function() {
hiddenForm.getForm().submit();
},
maxHeight: 30,
});
Remember that in order to make it working, you should put the hiddenForm in any container (i.e. in the same Ext.Window of the button), for example:
risultatiWindow = new Ext.Window({
title: 'CSV Export',
height: 400,
width: 500,
....
items: [...., hiddenForm]
});

Resources