It is possible to attach files by clicking on capybara - webdriver

I'm using capybara, cucumber and webDriver to perform file tests
I am doing a study and need to attach a file, however the file input does not exist in the dom, and it is only created when the button is clicked, currently my code is like this:
HTML
<a id="input-id" href="#" onClick="callInput">Attach</a>
Script
function callInput(){
const input = document.createElement("input");
input.style.display = "none";
input.type = "file";
input.click();
}

If it's possible the only way would be using the attach_file block mode
attach_file('/file/to/be/attached') do
click_link('Attach')
end
Since you're setting display to 'none' rather than hiding via setting it offscreen or other methods it's possible the make_visible option could make it work if the above doesn't
attach_file('/file/to/be/attached', make_visible: true) do
click_link('Attach')
end
If neither of those work then it's not possible for Capybara to work with the way you've implemented file upload on your page.
Note: odds of either working is pretty low because you're never actually attaching the input to the page so events won't get routed anywhere Capybara can detect.

Related

attach file in invisible elements with Capybara

I'm starting with capybara, cucumber and webdriver, and I was given the task of testing the upload of an image field.
So I simulated a shipping environment in which I could learn, it worked correctly, however, I need to leave the element "hidden", and I don't know if there is any method for capybara to select it.
So my code went in this direction:
HTML
<input type="file" name="attach-file" style="display: none;">
Capybara/Cucumber
addMedicine_page.attach_file('attach-file', 'assets/asset.jpg')
However it results in an Unable to find visible file field "attach-file" message that is not disabled (Capybara :: ElementNotFound)
If you're going to make the file input element non-visible you have to have some visible element available for the user to interact with which will in turn trigger the file inputs file selection. The best solution in that case is to use the block accepting from of attach_file
page.attach_file('assets/asset.jpg') do
# perform whatever action the user would to trigger the file selection
click_button 'Upload file'
end
if you can't that to work for you, you really should be able to and it most closely replicates a users behavior therefore making the test most valid, then you can use the make_visible option
page.attach_file('attach-file', 'assets/asset.jpg', make_visible: true)
which will temporarily make the file input visible, attach a file to it, and then re-hide it. If the standard CSS applied by make_visible by your page doesn't work to make the input visible you can set hash of CSS values to use rather than true
See https://www.rubydoc.info/github/jnicklas/capybara/Capybara/Node/Actions#attach_file-instance_method

Print Friendly Page

So I would like to be able to have a print button for entries in our database so users can print an entry via a print friendly "form".
My thought was to create a separate page, add labels and have those labels pull the relevant information.
I know I can add the open widget information via this code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.TestPrint);
But I'm running into a few problems:
I can't get the page to open in a new window. Is this possible?
window.open(app.pages.TestPrint);
Just gives me a blank page. Does the browser lose the widget source once the new window opens?
I can't get the print option (either onClick or onDataLoad) to print JUST the image (or widget). I run
window.print();
And it includes headers + scroll bars. Do I need to be running a client side script instead?
Any help would be appreciated. Thank you!
To get exactly what you'd want you'd have to do a lot of work.
Here is my suggested, simpler answer:
Don't open up a new tab. If you use showPage like you mention, and provide a "back" button on the page to go back to where you were, you'll get pretty much everything you need. If you don't want the back to show up when you print, then you can setVisibility(false) on the button before you print, then print, then setVisibility(true).
I'll give a quick summary of how you could do this with a new tab, but it's pretty involved so I can't go into details without trying it myself. The basic idea, is you want to open the page with a full URL, just like a user was navigating to it.
You can use #TestPrint to indicate which page you want to load. You also need the URL of your application, which as far as I can remember is only available in a server-side script using the Apps Script method: ScriptApp.getService().getUrl(). On top of this, you'll probably need to pass in the key so that your page knows what data to load.
So given this, you need to assemble a url by calling a server script, then appending the key property to it. In the end you want a url something like:
https://www.script.google.com/yourappaddress#TestPage?key=keyOfYourModel.
Then on TestPage you need to read the key, and load data for that key. (You can read the key using google.script.url).
Alternatively, I think there are some tricks you can play by opening a blank window and then writing directly to its DOM, but I've never tried that, and since Apps Script runs inside an iframe I'm not sure if it's possible. If I get a chance I'll play with it and update this answer, but for your own reference you could look here: create html page and print to new tab in javascript
I'm imagining something like that, except that your page an write it's html content. Something like:
var winPrint = window.open('', '_blank', 'left=0,top=0,width=800,height=600,toolbar=0,scrollbars=0,status=0');
winPrint.document.write(app.pages.TestPage.getElement().innerHTML);
winPrint.document.close();
winPrint.focus();
winPrint.print();
winPrint.close();
Hope one of those three options helps :)
So here is what I ended up doing. It isn't elegant, but it works.
I added a Print Button to a Page Fragment that pops up when a user edits a database entry.
Database Edit Button code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showDialog(app.pageFragments.FragmentName);
That Print Button goes to a different (full) Page and closes the Fragment.
Print Button Code:
app.datasources.ModelName.selectKey(widget.datasource.item._key);
app.showPage(app.pages.ModelName_Print);
app.closeDialog();
I made sure to make the new Print Page was small enough so that Chrome fits it properly into a 8.5 x 11" page (728x975).
I then created a Panel that fills the page and populated the page with Labels
#datasource.item.FieldName
I then put the following into the onDataLoad for the Panel
window.print();
So now when the user presses the Print Button in the Fragment they are taken to this new page and after the data loads they automatically get a print dialog.
The only downside is that after printing the user has to use a back button I added to return to the database page.
1.
As far as I know, you cannot combine window.open with app.pages.*, because
window.open would require url parameter at least, while app.pages.* is essentially an internal routing mechanism provided by App Maker, and it returns page object back, suitable for for switching between pages, or opening dialogs.
2.
You would probably need to style your page first, so like it includes things you would like to have printed out. To do so please use #media print
ex: We have a button on the page and would like to hide it from print page
#media print {
.app-NewPage-Button1 {
display : none;
}
}
Hope it helps.
1. Here is how it is done, in a pop up window, without messing up the current page (client script):
function print(widget, title){
var content=widget.getElement().innerHTML;
var win = window.open('', 'printWindow', 'height=600,width=800');
win.document.write('<head><title>'+title+'/title></head>');
win.document.write('<body>'+content+'</body>');
win.document.close();
win.focus();
win.print();
win.close();
}
and the onclick handler for the button is:
print(widget.root.descendants.PageFragment1, 'test');
In this example, PageFragment1 is a page fragment on the current page, hidden by adding a style with namehidden with definition .hidden{display:none;} (this is different than visible which in App Maker seems to remove the item from the DOM). Works perfectly...
2. You cannot open pages from the app in another tab. In principle something like this would do it:
var w=window.parent.parent;
w.open(w.location.protocol+'//'+w.location.host+w.location.pathname+'#PrintPage', '_blank');
But since the app is running in frame nested two deep from the launching page, and with a different origin, you will not be able to access the url that you need (the above code results in a cross origin frame access error). So you would have to hard code the URL, which changes at deployment, so it gets ugly very fast. Not that you want to anyway, the load time of an app should discourage you from wanting to do that anyway.

How to change css style locally and save this changes

i have an webapp and i need to onclick change css style, but i need to save this change in the webapp instaled into the phone of my user, and only in his phone. The javascript for onclick change css style it's working but i don't have no idea to how to save this css changes.
Can somebody help me with this?
Since now thanks
In general CSS styles can't be directly saved on an HTML client.
What you can do is make an Ajax call back to your server and save the information there. The next time the user asks for the page send HTML with the appropriate style class already on the element you wish to style based on the saved information.
There are several hackish client side possibilities involving JavaScript & cookies or local storage but I would avoid that sort of solution if at all possible since it's very likely to lead to an annoying flicker as the page loads and renders styled one way and then the JavaScript finally runs and corrects the style.
To elaborate on my comment:
el1.addEventListener('click', function() {
el2.style.color = 'red';
localStorage['color'] = el2.style.color;
})
And then on startup:
window.addEventListener('load', function() {
if (localStorage['color']) {
el2.style.color = localStorage['color'];
}
}
Of course, you may want to add error checking and fallbacks as appropriate.

Jquery Select Box not working on dynamically generated elements

I am with a problem. I am using jQuery.SelectBox for the select box and dropdowns.
It is working fine when the elements are loaded with the page load. But its not working when they are loaded by the ajax i.e on dynamicaly generated elements it is not working.
You can check the file here :- http://rvtechnologies.info/brad/jquery.selectBox.js
This line:
jQuery('<link rel="stylesheet" href="<?php echo DIVATEMPLATEPATH . "/css/jquery.selectBox.css"; ?>">').appendTo("head");
Is completely invalid. You cannot combine PHP and Javascript! PHP is executed on the server, not in the browser. Please learn about the fundamentals of web development. PHP gets run on the server, it generates code that gets sent to the client, which then in turn runs the code locally on the computer (HTML and JavaScript).
CSS codes are style declaration and stylesheets, once the element gets added to the DOM they will be loaded or applied.
Check the name of id, classes and attributes of the generated elements using tools like firebug and see the generated markup.
I have sorted it out.
I need to call the selecbox again on Ajax success.
I have done like this :-
success: function(html) {
jQuery('#loader').empty();
jQuery("#right_search").append(html);
jQuery("SELECT").selectBox(); //Just Added this
initdatepicker();
stat = 0;
}

UpdatePanel - Any ideas on how to avoid a flicker in UI? - ASP.NET/Jquery

I have rather a complex UI. However, for the purpose of this question, let's say that there is a HTML table that renders UILayout1 by default (say default mode). There is a button that a user can use to toggle between the default mode and a preview mode (UILayout2)
When in preview mode, there are some columns in the table that are invisible and there are reordering of rows. I am using JS (jquery) on load to check the mode and change it accordingly.
The table and the toggle button are in UpdatePanels.
Functionally, everything works as expected. However, when a user toggles between default and preview mode or vice versa, there is this short time interval in which the the table renders in default and then JS runs to make changes.
This results in degraded UI experience. Are there any creative ways to avoid this "flicker"?
you can use DIVs or don't use update panel in your UI generation use any concept else
The problem is likely to be that your code is running on load. I'm assuming that you're doing this using the standard jQuery method of running code on load, and not using the window's onload event. In any case, even using jQuerys $(document).ready(...) will be too slow if you have a lot of other javascript files to load, as the .ready event isn't fired on the document until all javascript includes have loaded.
You should be able to work around the issue by including your code that modifies the table just after the html for the table in your page and not running it on load i.e. make sure you don't wrap it in $(document).ready(...);
For this approach to work, you will need to have all javascript required by the code which is modifying the table included earlier in the page.
If you have other non-essential javascript files included, you should try to include them later in the page.
I'm not 100% sure how being inside an update panel will affect it - you will need to make sure that your code is being re-triggered when the updatepanel updates, but I believe this should all happen automatically.
Presumably your UI is controlled by CSS? You might be able to get rid of the flickering by adding something like this at the start of your JavaScript or in the <head> of your HTML:
if (previewMode) {
document.documentElement.className = 'preview';
}
Then if you modify your CSS rules that apply to your preview mode to reflect the HTML element having the class="preview" to something like:
.preview table .defaultMode {
display:none;
}
hopefully your table should render correctly first time and will not need to be re-drawn.

Resources