Evening! I'm trying to log in into a website with zombie.js, but I don't seem to be able to make it work.
Oh and the website is in Finnish, but it's not very hard to understand, two text fields and a button. First is for username, second for password and the button is the log in button.
At the moment my log in code is as follows:
var Browser = require("zombie");
browser = new Browser();
browser.visit("https://www.nordnet.fi/mux/login/startFI.html?cmpi=start-loggain",
function () {
// Here I check the title of the page I'm on.
console.log(browser.text("title"));
// Here I fill the needed information.
browser.document.getElementById("input1").value ="MYUSERNAME";
browser.document.getElementById("pContent").value ="MYPASSWORD";
// And here it fails. I try to submit the form in question.
browser.document.getElementById("loginForm").submit();
setTimeout(function () {
// This is here to check that we've submitted the info and have been
// redirected to a new website.
console.log(browser.text("title"));
}, 2000);
});
Now I know that I maybe should have used zombie's own "fill" method, but I tried that with no luck so I tried something new.
All I get from this is an error:
Y:\IMC\Development\Web\node_modules\zombie\lib\zombie\forms.js:72
return history._submit(_this.getAttribute("action"), _this.getAttribute(
^
TypeError: Cannot call method '_submit' of undefined
Now if I log that browser.document.getElementById("loginForm") it clearly does find the form, but alas, it doesn't like it for some reason.
I also tried the "conventional" method with zombie, which is using that log in button on the web page and pressing it. The problem is that it's not actually a button, just an image which has a link attached to it, and it's all inside <span>. And I have no idea how I can "click" that button.
It has no ID on it, so I can't use that, then I tried to use the text on it, but because it has umlauts on it I can't get it to work. Escaping the ä with /344 only gave an error:
throw new Error("No BUTTON '" + selector + "'");
^
Error: No BUTTON 'Kirjaudu sisään'
So yeah, that didn't work, though I have no idea why it doesn't recognize the escaped umlaut correctly.
This is my first question, the second one is a minor one, but I though why not ask it here too now that I've written this text.
If I get all this to work, can I somehow copy the cookie that this log in gives me, and use that in my YQL for screen scraping? Basically I'm trying to scrape stock market values, but without the log in the values are 15min deferred, which isn't too bad, but I'd like it to be live anyhow.
After couple of tests using zombie I came to the conclusion that it's still to early to use it for serious testing. Nevertheless, I came up with working example of form submit (using regular .submit() method).
var Browser = require("zombie");
var assert = require("assert");
browser = new Browser()
browser.visit("http://duckduckgo.com/", function () {
// fill search query field with value "zombie"
browser.fill('input[name=q]', 'mouse');
// **how** you find a form element is irrelevant - you can use id, selector, anything you want
// in this case it was easiest to just use built in forms collection - fire submit on element found
browser.document.forms[0].submit();
// wait for new page to be loaded then fire callback function
browser.wait().then(function() {
// just dump some debug data to see if we're on the right page
console.log(browser.dump());
})
});
As you can see, the clue is to use construct browser.wait().then(...) after submitting the form, otherwise browser object will still refer to the initial page (the one passed as an argument to visit method). Note: history object will contain address of page you submitted your form to even if you don't wait for the page to load - it confused me for a bit, as I was sure that I should already see the new page.
Edit:
For your site, the zombie seems to be working ok (I could submit the form and get "wrong login or password" alert). There are some JS errors but zombie isn't concerned with them (you should debug those however to see if the script are working ok for regular users). Anyhow, here's the script I used:
var Browser = require("zombie");
var assert = require("assert");
browser = new Browser()
browser.visit("https://www.nordnet.fi/mux/login/startFI.html?cmpi=start-loggain", function () {
// fill in login field
browser.fill('#input1', 'zombie');
// fill in password field
browser.fill('#pContent', 'commingyourway');
// submit the form
browser.document.forms[0].submit();
// wait for new page to be loaded then fire callback function
browser.wait().then(function() {
console.log('Form submitted ok!');
// the resulting page will be displayed in your default browser
browser.viewInBrowser();
})
});
As side note: while I was trying to come up with working example I've tried to user following pages (all have failed for different reasons):
google.com - even though I filled query box with a string and submitted the form I didn't get search results . Reason? Probably google took some measures to prevent automatic tools (such as zombie) to browse through search results.
bing.com - same as google - after submitting the form I didn't get search results. Reason? Probably same as for google.
paulirish.com - After filling in the search query box and submitting the form zombie encountered script errors that prevent it from completing the page (something about missing ActiveX from charts script).
perfectionkills.com - Surprisingly here I've encountered the same problems as with Paul Irish site - page with search results couldn't be loaded due to javascript errors.
Conclusion: It's not so easy to force zombie into doing your work after all... :)
Related
I want to create a static webpage which has a text field and a submit button, which after a user submits text it would automatically redirect from localhost/ to localhost/<test_person_submitted> .
Up to this point, this JavaScript is the only thing I was able to clobber together from all of the guides I found
function confirmInput() {
fname = document.forms[0].fname.value;
url = "http://localhost/"
command = (url + fname)
location.replace(command);
}
That does work, but no matter what I added as HTML to invoke the function it doesn't work properly.
Can someone please add a submit form that will properly execute this?
Right now I'm stumped and I just want to consider this small project "complete", rather to just leaving it without ever knowing how it could be resolved.
If you are wondering why I want to do this it's because I'm going to try to invoke some wild-card commands that will return JSON.
And this is just a fun project for me.
I am trying to create an automation script (action launch point, trigger by a button on UI) for Maximo using javascript to do some data validation then show popup if there is invalid data.
I try to call service.setWarning() but the script still process instead of showing a warning message, if I do some UI interaction later, that warning message randomly display later.
Then I try the service.error() which should show an error message similar to the exception message in Maximo, the script does stop running but there is no popup message.
If I check systemError.log, I can see both the warning and error message displayed in the log?
So what is causing this and how can I make it behave correctly?
EDIT1: here is the script, I already setup the message in database configuration (messagegroup RFQ, messagekey 2VENDORS):
load("nashorn:mozilla_compat.js");
importPackage(Packages.psdi.security);
importPackage(Packages.psdi.mbo);
importPackage(Packages.psdi.server);
var mxServer = MXServer.getMXServer();
var userInfo = mxServer.getSystemUserInfo();
var rfqLineSet = mbo.getMboSet("RFQLINE");
var totalCost = 0;
var current_datetime = new Date();
var today = current_datetime.toISOString();
for(var currMbo=rfqLineSet.moveFirst(); currMbo!=null; currMbo=rfqLineSet.moveNext()) {
totalCost = totalCost + currMbo.getDouble("LINECOST");
}
if (totalCost < 50000) {
var rfqVendorSet = mbo.getMboSet("RFQVENDOR");
if (rfqVendorSet.count() > 2) {
service.error("RFQ","2VENDORS",null);
}
}
Maximo version 7.6.1
EDIT2: I tried the service.yncerror("RFQ","2VENDORS",null); which should display a yes/no error popup message but same issue, it only appears in the systemError.log
EDIT3: I did some tests and found out that if I write the code in Jython then the popup works but not in Javascript. How can this be?
UPDATE: I moved all my scripts to use python instead of javascript, seems that Maximo works best with automation script written in python.
Thanks.
"Warnings" in Maximo are some bits of data that just ride along with the MBO set. As a warning, they aren't supposed to stop execution, just let you know of something important, but they won't even do that on their own. You need to do something at some point to fetch the warnings from the set and display them. If you don't, Maximo will on its own for certain actions (usually for those actions that would include a warning Maximo itself added), but that probably isn't when you actually want it to be displayed. I have seen many people mix this up and not understand what these warnings are or how they actually work.
"Errors" are meant to be logic stopping messages. Something went wrong and the user needs to know about it before more logic runs. This sounds more like your use case. Errors are still meant to be a message to the user though, so you have to supply a message for the error method. You can't just put any string you want as your message in there though (well, you shouldn't) as that doesn't allow Maximo to translate the message or fill in message variables. It also means you have to change code whenever you want to change the message, instead of simply changing a configuration live. Instead you need to go to Database Configuration and add a new message in there. When you do that, you will create a message group and message key value for your message. Now when you call the error method, you will pass in that error group and error key as parameters. Maximo will take that, look it up in the message table and then display the message associated with that group and key for your configured language. It can also replace some special message variables at this time too, but that's a lesson for another time.
For example, you might go to Database Configuration and open the dialog for the messages and add a message of "The value you entered in the 'count' field is not a number. Please enter a number before continuing." and give it a message group of "MyCustomGrp" and a key of "NotANumber". Then in your code when you want to stop the code and display that message, you would call service.error("MyCustomGrp", "NotANumber").
The other potential problem you could be having is that you do need to be running the code that throws the error in some way attached to the interactive user session. Generally, that's a given, but there are some things you could be doing that would cause your code to run separate from that interactive user session. If you are seeing your error message in the logs, then you have set that part up correctly and it likely means your code is not part of the interactive user session. This is where knowing the rest of your code is very important.
Given: Protractor Test with this html and js code. Was able to do browser.get and click on link to get to log on page successfully. The Log In form requires a userid and password which was entered correctly from the test, but I can't click the button.
<button type="submit" class="button positive">Log In</button>
element.all(by.buttonText('Log In')).then(function (item) {
item.forEach(function (final) {
final.submit();
final.click();
});
If I put a break point on the ForEach statement I see that 'item' is indeed an array with a length of 1. It I then break at 'final.submit();' I see this..
I even tried to submit the form instead of zeroing in on the button...
var af = element.all(by.name('loginForm'));
af.submit();
});
Results were the same...
The root cause of this problem was that the content of the form submission was wrong. This was only able to be seen by looking a network level response on the form submission, in essence, the click was working, it's just that the page did nothing. The developers of the login form didn't expose any login errors in the application.
So I looked into how to get the http response code using protractor and it's not supported because the Selenium team has decided it's not a part of the plan. Therefore, from a Protractor perspective, your only alternative is to put in the proper expect statement and fail the test if it doesn't 'get there'.
I also was able to determine that the screen shot above was the structure of the Seleneium WebElement class. Because Selenium is Asynchronous only, what is seen above is only the methods as it is the promise that returns the results of the properties and or the function calls.
I am very new to javascript and apex and am learning on the job so to speak.
Let me start of by describing what I want to achieve:
I'm trying to block the Function keys from running/executing the browser functions (F1 to bring up help, F3 for find, etc). I found the javascript code to block them, but do not know what to do after that.
Eg, when a user presses F1 it should not display help, but execute a process in apex.
Such a process could for example be to save all information on the apex page text fields to the database.
How can i do this?
See my example code: instead of the alert, how would I go about executing a process and how do I go about writing such a process?
<script language="javascript">
function my_onkeydown_handler() {
switch (event.keyCode) {
case 112: // 'F1'
document.onhelp = function() {
return (false);
}
window.onhelp = function() {
return (false);
}
alert("F1");
NewEntry();
break;
}
}
</script>
$(document).keydown(function(e){
if(e.which===112){
console.log('F1ed');
//NewEntry();
return false;
};
});
Safe to use jQuery, it comes with apex
Also see
Disable specific function key using jquery
Which can be translated to a dynamic action (you didn't specify an apex version. Dynamic actions were introduced with version 4.0). Why would you use them? They're very handy in that you can use them to easily leverage javascript without really knowing a lot about it, and they can be seen in the page structure. This way you don't need javascript cluttering about in several portions of your page. Even for more advanced javascript for which there are no pre-defined actions, you can still put your own code in by using 'Execute Javascript'. Again, accessibility and maintainability! Leverage it!
Create a new dynamic action.
Event: Key Down
Selection Type: DOM Object
DOM Object: document
Condition: None
As for the (true) action:
Action: Execute Javascript Code
Code:
var e = this.browserEvent;
switch (e.which) {
case 112: // 'F1'
alert("F1");
return false;
}
Much nicer and cleaner. And better you get comfortable with them now! Read up on them too.
On to the second part:
What i mean is that when eg F1 is pressed it must not display help
but execute a process in apex for example I would like to save all
information on the apex page text fields to the database. How would I
go about it. See my little code, instead of the alert, how would I go
about executing a process and how do I go about writing such a
process?
This makes me wonder (and frown, but just a little). How familiar are you with apex already? No offense, but this is rather basic functionality you're asking about.
Say you have a report and a form page, generated by the wizard. Say you have no weird things such as this javascript on it, but just barebones.
You go from the report to the form page. Values are fetched through a process and the page is rendered. Now you alter some values and submit the page. The submitted values are then processed in the page processing, and pass through the row processing process, which will insert/update/delete data.
If you are unfamiliar with that concept, i strongly recommend you to at least follow through the Oracle® Database 2 Day + Application Express Developer's Guide (Oracle Apex documentation). Many developers just jump in head-first without giving this guide a glance. Don't. This SHORT (and really, what are maybe a couple of hours) guide will teach you some of the very basics of apex!
Important things such as session state and submitting the page are crucial to understanding what it does.
Now, assuming we have a form page with this bit of javascript on it. Pressing F1 to update the values (read: press F1 to submit the page and invoke the row processing to process the submitted values), you can use the apex javascript api's: apex.submit('APPLY') (DOC).
This will submit the page with request APPLY. This value is important. Note that buttons will submit with their name set to request value aswell, and the row processing does different processing based on a list of valid request values.
var e = this.browserEvent;
switch (e.which) {
case 112: // 'F1'
alert("F1");
apex.submit('APPLY');
return false;
}
Further elaboration:
There are also AJAX Callbacks. These are processes on the serverside which can be invoked through a javascript call to the server. These processes are PLSQL-code, and can for example be used to return data to the calling javascript function, and avoid a full page refresh/submit.
It can be used to save data too of course. The data has to be passed to the server, and the process then works with that data. For example, when a field has been changed and you want to immediatly save this to the database but do not want a full page submit. The callback would be a plsql block which performs an update on a table.
Ajax callbacks are very interesting and useful, but i'd advise you to first get a good grip on the basics before tackling this!
Modified code: jsfiddle
<script language="javascript">
document.onkeydown = function (e) {
switch (e.keyCode) {
case 112: // 'F1'
e.preventDefault(); // prevent default behavior.
e.returnValue = false; // for IE to prevent default behavior.
alert("F1");
NewEntry();
return false;
}
}
</script>
What I want to do is to have a form field that allows a person to try to guess from a picture what type of bird it is, and if they get it right, it tells them they got it right and gives them the code to be able to get a discount.
Here is the code I'm using within the head tags:
formCheck()
{
var birdName = document.forms[0].birdName.value
if (birdName == "red bellied woodpecker")
alert("That's Correct! Please enjoy 10% off your next purchase by entering the code NAMETHATBIRD92 during checkout.")
else
alert("That's isn't the correct answer! Make sure your answer is very specific and keep trying, you can guess as many times as you want.")
}
Here is what I have within the body tag:
Can you name this bird?
It works here:
www.madhatwebsolutions.com/namethatbird.html
It does not work here, where I really need it to work:
http://www.wildbirdsmarketplace.com/pages/Name-That-Bird!.html
This shouldn't be JavaScript.
Any potential customer will be able to right click and view your JavaScript source and retrieve the code without bothering with the guesswork.
You'll need to query a server with the user input, and the server will need to return a response indicating whether this input is correct or not.
You might want to look at either a normal HTML form submission, or venture into AJAX
Workflow:
User enters guess into textfield
Launch a request to http://yourserver.com/check_bird.your_server_language?guess=theTextFieldValue
Server returns either a success or failure indication
Display response to client
Other things to consider: Are you going to allow your customers to guess multiple times, or restrict them? Are you going to be showing several different birds or not?
in http://www.wildbirdsmarketplace.com/pages/Name-That-Bird!.html
<script type="text/javascript" src="birdname.js"></script> refers to 404 - check the file path
don't use document.forms
var birdName = document.getElementById('birdName').value;