When using Selenium IDE to record actions on a web page the application is stopping the JavaScript and displays the error message "too much recursion."
I'm using Selenium IDE 2.9.1.1 on FireFox 54.0.1
I wrote a simple javascript alert for testing, but it is also being stopped by Selenium.
<html>
<head>
<script>
function hello(){
alert("Hello\nHow are you?");
}
</script>
</head>
<body>
<input type="button" onclick="hello();" value="Say Hi" />
</body>
</html>
enter image description here
selenium-ide/content/recorder.js
Recorder.prototype.reattachWindowMethods = function() {
var window = this.getWrappedWindow();
//this.log.debug("reattach");
if (!this.windowMethods) {
this.originalOpen = window.open;
}
this.windowMethods = {};
['alert', 'confirm', 'prompt', 'open'].forEach(function(method) {
this.windowMethods[method] = window[method];
}, this);
var self = this;
window.alert = function(alert) {
self.windowMethods['alert'].call(self.window, alert);
self.record('assertAlert', alert);
}
}
This is because the function calls are actually being overridden at runtime by Selenium’s own JavaScript.
Add below Javascript code to selenium core user extension, after restart can fix this problem.
//http://docs.seleniumhq.org/docs/08_user_extensions.jsp
Selenium.prototype.doExecute = function(script) {
this.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getExecute = function(script) {
return this.browserbot.getCurrentWindow().eval(script);
};
Selenium.prototype.getJqMethod = function(selector, method) {
return this.getExecute('$("' + selector + '").' + method + '();');
};
Selenium.prototype.getJqText = function(selector) {
return this.getJqMethod(selector, "text");
};
Selenium.prototype.getJqHtml = function(selector) {
return this.getJqMethod(selector, "html");
};
Selenium.prototype.getJqVal = function(selector) {
return this.getJqMethod(selector, "val");
};
PageBot.prototype.locateElementByJq = function(selector, inDocument) {
// FF/Chrome/IE9+: defaultView, OldIE: parentWindow
return (inDocument.defaultView || inDocument.parentWindow)
.eval("jQuery('" + selector.replace(/'/g, "\\'") + "')[0];");
};
Related
I want to implement the BarcodeDetector in an Angular app. I tested out the API with the following code:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<script src="./script.js"></script>
</head>
<body>
<button onclick="scan()">Click me</button>
<img src="./barcode.gif">
<pre></pre>
</body>
</html>
JavaScript:
function scan() {
const images = document.querySelectorAll('img');
const pres = document.querySelectorAll('pre');
try {
pres[0].textContent += 'started\n';
let barcodeDetector = new BarcodeDetector();
pres[0].textContent += 'created and detecting\n';
barcodeDetector.detect(images[0]).then(detectedCodes => {
for (const barcode of detectedCodes) {
pres[0].textContent += barcode.rawValue + '\n';
}}).catch((e) => {
pres[0].textContent += e + '\n';
});
} catch (e) {
pres[0].textContent += e + '\n';
}
}
and it works perfectly. On the PC I got a NotSupported error and the decoded barcode when I opened the page on my phone.
Since TypeScript is a superset of JavaScript I tought that it should be quite simple to port the code but, apparently it isn't. The HTML in the angular app pretty much the same. The component code is the following:
var BarcodeDetector: any;
#Component({
templateUrl: './index.component.html'
})
export class IndexComponent {
#ViewChild('imgRef')
image: ElementRef;
hasBarcodeDetector = '';
errors = '';
scanData = '';
constructor() {
try {
this.hasBarcodeDetector = 'BarcodeDetector' in window ? 'true' : 'false';
const barcodeDetector = new BarcodeDetector();
barcodeDetector.detect(this.image.nativeElement).then(detectedCodes => {
for (const barcode of detectedCodes) {
this.scanData += barcode.rawValue + '\n';
}
});
} catch (e) {
this.errors = e;
}
}
}
The check whether the detector exists works, because I get true, but both on PC and mobile I get the following error:
TypeError: (void 0) is not a constructor
I'm guessing it has something to do with the declaration of the decoder, but I really have no idea on what to do.
I think with your variable you're accidentally overwriting the window.BarcodeDetector. Also note that you're not making use of the result of the feature detection. Feature detection, by the way, should happen differently now, as outlined in the recently updated article:
await BarcodeDetector.getSupportedFormats();
/* On a macOS computer logs
[
"aztec",
"code_128",
"code_39",
"code_93",
"data_matrix",
"ean_13",
"ean_8",
"itf",
"pdf417",
"qr_code",
"upc_e"
]
*/
This allows you to detect the specific feature you need, for example, QR code scanning:
if (('BarcodeDetector' in window) &&
((await BarcodeDetector.getSupportedFormats()).includes('qr_code'))) {
console.log('QR code scanning is supported.');
}
I have a PHP script hosted in the root of a working LAMP server which provides me with the output of a MySQL query. The typical output of values.php:
2017-01-12 22:02:17/12/2017-01-12 22:03:18/12/2017-01-12
22:04:18/12/2017-01-12 22:05:18/12/2017-01-12 22:06:18/12/2017-01-12
22:07:19/12/2017-01-12 22:08:19/12/2017-01-12 22:09:19/12/2017-01-12
22:10:20/12/2017-01-12 22:11:20/12/2017-01-12 22:12:20/12/2017-01-12
22:13:21/12/2017-01-12 22:14:21/12/2017-01-12 22:15:21/12/2017-01-12
22:16:21/12/2017-01-12 22:17:22/12/2017-01-12 22:18:22/11/2017-01-12
22:19:22/11/2017-01-12 22:20:23/12/2017-01-12 22:21:23/11/2017-01-12
22:22:23/11/2017-01-12 22:23:24/11/2017-01-12 22:24:24/11/2017-01-12
22:25:24/11/2017-01-12 22:26:25/11/2017-01-12 22:27:25/11/2017-01-12
22:28:25/11
I am trying to use $.get to break it up and list it on a page. My code is as follows but it won't work:
<!DOCTYPE html>
<html>
<body>
<script>
function() {
var switch1 = true;
$.get('values.php', function(data) {
data = data.split('/');
for (var i in data)
{
if (switch1 == true)
{
document.write(data[i] + " Temp: ");
switch1 = false;
}
else
{
document.writeln(data[i]);
switch1 = true;
}
}
});
};
</script>
</body>
</html>
Any ideas where I am going wrong?
I should have added the code <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script> in the html. Final code is as follows and works fine:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<script>
var switch1 = true;
$.get('values.php', function(data) {
data = data.split('/');
for (var i in data)
{
if (switch1 == true)
{
document.write(data[i] + " Temp: ");
switch1 = false;
}
else
{
document.write(data[i] + "<br>");
switch1 = true;
}
}
});
</script>
</body>
</html>
Thanks to all.
I don't know what your PHP script actually returns but if I store manually to data it seems to work the way you expected. Can you explain what exactly does not work?
I would shorten code bit though:
var switch1 = true;
var data = "2017-01-12 22:02:17/12/2017-01-12 22:03:18/12/2017-01-12 22:04:18/12/2017-01-12 22:05:18/12/2017-01-12 22:06:18/12/2017-01-12 22:07:19/12/2017-01-12 22:08:19/12/2017-01-12 22:09:19/12/2017-01-12 22:10:20/12/2017-01-12 22:11:20/12/2017-01-12 22:12:20/12/2017-01-12 22:13:21/12/2017-01-12 22:14:21/12/2017-01-12 22:15:21/12/2017-01-12 22:16:21/12/2017-01-12 22:17:22/12/2017-01-12 22:18:22/11/2017-01-12 22:19:22/11/2017-01-12 22:20:23/12/2017-01-12 22:21:23/11/2017-01-12 22:22:23/11/2017-01-12 22:23:24/11/2017-01-12 22:24:24/11/2017-01-12 22:25:24/11/2017-01-12 22:26:25/11/2017-01-12 22:27:25/11/2017-01-12 22:28:25/11"
data = data.split('/').map(function(i){
document.write(i + (switch1 ? " Temp: " : ""));
switch1 = !switch1;
});
Give this a try, should do what you are looking for...
var content = "2017-01-12 22:02:17/12/2017-01-12 22:03:18/12/2017-01-12 22:04:18/12/2017-01-12 22:05:18/12/2017-01-12 22:06:18/12/2017-01-12 22:07:19/12/2017-01-12 22:08:19/12/2017-01-12 22:09:19/12/2017-01-12 22:10:20/12/2017-01-12 22:11:20/12/2017-01-12 22:12:20/12/2017-01-12 22:13:21/12/2017-01-12 22:14:21/12/2017-01-12 22:15:21/12/2017-01-12 22:16:21/12/2017-01-12 22:17:22/12/2017-01-12 22:18:22/11/2017-01-12 22:19:22/11/2017-01-12 22:20:23/12/2017-01-12 22:21:23/11/2017-01-12 22:22:23/11/2017-01-12 22:23:24/11/2017-01-12 22:24:24/11/2017-01-12 22:25:24/11/2017-01-12 22:26:25/11/2017-01-12 22:27:25/11/2017-01-12 22:28:25/11";
var regexp = /(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\/(\d{2})/g;
var matches;
while ( matches = regexp.exec( content ) ) {
document.write( matches[1] + " Temp: " + matches[2] + "<br/>");
}
Hope this helps!
I am new to web development.
Today I learn about classes(function) in javascript. I got an error how to call dynamically added method.
My Code :
<head runat="server">
<title></title>
<script type="text/javascript" language="javascript">
function MyMethod(name, fn) {
var str = "MyFunction1.prototype." + name + "= fn;";
eval(str);
}
function MyFunction1() {
MyMethod("start", function () { return "hi"; });
var abc = this.start(); //gives error
}
</script>
</head>
<body>
<form id="form1" runat="server" >
<div>
<input type="button" value="Click" onclick="MyFunction1()"/>
</div>
</form>
Here when I click the input button then not able to call the dynamically added function
How can i call the start() function that i added here.
Please Help me.
Thanks in Advance.
this in MyFunction1 referes to the global object in that case(for browsers it is window) , because you call MyFunction1 as function and you don't create an object by using new MyFunction1().
Another thing to be noted. You should not use eval when it is possible to do it without eval.
You can do the same thing using:
function MyMethod(name, fn) {
MyFunction1.prototype[name] = fn;
}
Using eval prevents you from using optimization tools or tools to validate your code. At least most of these tools don't take eval into account or even give a warning about that you are using it.
Try adding "new" before your onclick call to MyFunction1, creating an instance of it.
It reseolved I did
Hi , It resolved .Thanks for the gret help i did :
function fnOnload() {
MyMethod("start", function () { return "hi"; });
}
function MyMethod(name, fn) {
var str = "MyFunction1.prototype." + name + "= fn;";
eval(str);
}
function MyFunction1() {
}
function MyFunction2()
{
var aa = new MyFunction1();
var answee = aa.start();
}
and in click of button i callled function MyFunction2()
without changing your code you can do as follow , but I say it would be helpful if you read about invocations types and about this variable.
function MyMethod(name, fn) {
MyFunction1.prototype[name]= fn;
return MyFunction1.prototype;
}
function MyFunction1() {
var myPrototype= MyMethod("start", function () { return "hi"; });
var returnValue = myPrototype.start();
console.log(returnValue);
}
I come from the world of Java. In Java there are packages, for example, "com.mycompany.billing" and classes that are inside the package, for example, "BillProcessor". The company in which I work is starting a new project and I need to decide on a good namespace schema. I'm thinking of projecting how it's done in Java to JavaScript, for example, having a namespace "com.mycompany.billing" and a class that's in a file like "BillProcessor.js". In addition, unit testing is vital so I need such a structure that is easy to unit test.
Can somebody suggest a good approach?
I think that I came up with a good solution, please advise. As an example I'll make a billing page. There are 4 files:
${root}/billing.html - contains an input box for the name on credit card
${root}/js/com/mycompany/common/common.js - initializes logging and error handling
${root}/js/com/mycompany/common/Url.js - class that is used to perform an AJAX call
${root}/js/com/mycompany/aproject/billing.js - initializes things on the billing page
So for example, common.js contains:
var com_mycompany_common_common = function() {
function log(message) {
console.log((new Date()) + ': ' + message);
}
function init() {
window.onerror = function(message) {
log('Unhandled error: ' + message);
}
}
return {
log: log,
init: init
}
} ();
$(document).ready(function() {
try {
com_mycompany_common_common.init();
} catch (e) {
console.log('Error during initialization: ' + e);
}
});
Url.js:
function com_mycompany_common_Url(url) {
this.url = url;
}
com_mycompany_common_Url.prototype.addParameter(name, value) {
this.url += '?' + name + '=' + value;
}
com_mycompany_common_Url.prototype.ajax() {
com_mycompany_common_common.log('Send ajax to: ' + this.url);
}
billing.js
var com_mycompany_aproject_billing = function() {
function init() {
$('#submitButton').click(function() {
Url url = new com_mycompany_common_Url('http://bla.com/process/billing');
var creditCardName = $('#ccName').val();
url.addParameter('name', creditCardName);
url.ajax();
}
}
return {init: init};
} ();
$(document).ready(function() {
try {
com_mycompany_aproject_billing.init();
} catch (e) {
console.log('Error during initialization: ' + e);
}
});
billing.html
<!DOCTYPE html>
<html>
<head>
<title>Billing</title>
</head>
<body>
Enter name on credit card: <input type="text" id="ccName" /><br><br>
<button id="submitButton">Submit Payment</button>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript" src="js/com/mycompany/common/common.js"></script>
<script type="text/javascript" src="js/com/mycompany/common/Url.js"></script>
<script type="text/javascript" src="js/com/mycompany/aproject/billing.js"></script>
</body>
</html>
Most of the time people use the Object Literal pattern to achieve name spacing in JavaScript.
More info: http://msdn.microsoft.com/en-us/scriptjunkie/gg578608
You can "nest" namespaces like so:
var MyCompany = MyCompany || {};
MyCompany.Billing = MyCompany.Billing || {};
// etc...
Another ScriptJunkie article that covers some namespacing stuff: http://msdn.microsoft.com/en-us/scriptjunkie/hh377172.aspx
I'M POSTING THIS QUESTION ON https://codereview.stackexchange.com/questions/8393/approach-to-organizing-javascript-for-an-html-page MAYBE I'LL GET ANSWERS THERE.
A sample bit of code:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<div id="myinfo">info</div>
<input id="clickme" type="button" value="click here to display info"/>
<script type="text/javascript">
function Fighter() {
this.name = "Kenny"; // fighters name
this.hp = 10; // fighters hp
this.getHP = function() {
return this.hp;
}
this.getName = function() {
return this.name;
}
this.initUpdateButton = function(button_id) {
$(button_id).click(function() {
$("#myinfo").html("Name: "+this.getName()+"<br/>HP:"+this.getHP());
// this.getName is undefined
});
}
};
var me = new Fighter();
alert("Name: "+me.getName()+"<br/>HP:"+me.getHP()); // works properly
me.initUpdateButton("#clickme"); // bind it to some ID
</script>
Simply put, given a JavaScript class with JQuery mixed in, I understand that on the callback for JQuery functions (i.e. $.click()), that this is referring to the object that was clicked and Not the Class or root function(). so this.getName() and this.getHP() don't work.
But what is the best way to get around this problem?
I saw some similar posts but they weren't of use to me so sorry if this is a repost and thanks in advance.
this.initUpdateButton = function(button_id) {
var self = this;
$(button_id).click(function() {
$("#myinfo").html("Name: "+self.getName()+"<br/>HP:"+self.getHP());
});
}