Testing javascript alerts with Jasmine - javascript

I'm writing some Jasmine tests for some legacy javascript that produces an alert or a confirm at some points in the code.
At the moment where the alert pops up it pauses execution in the browser requiring me to press ok before going on.
I'm sure I'm missing something but is there a way of faking an alert?
Even better is it possible to find out what the message was for the alert?
Thanks for your help.

spyOn(window, 'alert');
. . .
expect(window.alert).toHaveBeenCalledWith('a message');

var oldalert = alert;
alert = jasmine.createSpy();
// do something
expect(alert).toHaveBeenCalledWith('message')
alert = oldalert

Another way is to do this in spec helper.
window.alert = function(){return;};
Or if you need the message.
var actualMessage = '';
window.alert = function(message){actualMessage = message; return;}

You simply create a spy, surprisingly with createSpy(), to mock the function that contains the alert. So you can do something like this:
beforeEach(function() {
functionWithAlert = jasmine.createSpy("functionWithAlert");
functionWithAlert("called as usual");
});
You can also do this to return something
oldFunctionWithAlert = jasmine.createSpy("oldFunctionWithAlert() spy").andCallFake(function() {
console.log("Doing some testing");
return "Test";
});
On a side note, I would suggest you replace the alert if possible with less disruptive alternatives. There are a ton of options out there like JQuery UI dialog.

Related

textarea javascript debug result to innerHTML paragraph "undefined"

I am doing a code editor, almost everything is working, I type the text in the texarea and press a button to load a function, and the result of the code appears on the web browser console, I am trying to do like "document.getElementById('output').innerhtml = window.eval(txtarea.value);"
But it does not seem to work.
function DebugInp(){
var txtarea = document.getElementById('input');
document.getElementById('output').innerHTML = window.eval(txtarea.value);//output = paragraph in html.
};
/**
*My problem is that the innerHTML is showing undefined, but when I'm getting to console,
*it appears the result.
*I'm thinking of maybe getting all of the outputs of the console, but IDK how to do it
*Kind of like: document.getElementById('output').innerHTML = console.logs?
*I am still searching but any help would be nice.
*/
thanks in advance!
PS: I am better at frontend dev, trying to understand more of backend so don't hate 🙂 please.
What you're doing is very unsafe and there are many better ways to go about it. But nevertheless, you need to constrain the context of your input code. Simply evaluating the whole code won't give you the console logs. You need to expose an API for the code to send output to.
Minimal example:
var txtarea = document.getElementById('input');
document.getElementById('output').innerHTML = window.eval(`
const console = {
log(...args) {
document.getElementById('output').innerText += '\n' + args.join(' ');
}
};
${txtarea.value}
`);
OH!!! i did it guys!
Just create a new standard function for console.log so it stores every logs i found the answer right here:
https://stackoverflow.com/a/19846113/16260964
console.stdlog = console.log.bind(console);
console.logs = [];
console.log = function(){
console.logs.push(Array.from(arguments));
console.stdlog.apply(console, arguments);
}
var txtarea = document.getElementById('input');
window.eval(txtarea.value);
document.getElementById('output').innerHTML = console.logs;
GG! Have an great day everyone!🎊🎉🥳

How can we test the alert and the text it is displaying using Cypress.io Js automation framework?

How can we test the alert and text inside is displaying using Cypress.io Js automation framework? I am unable to figure out the relevant example in Cypress documentation, please advise.
describe('Test an alert and the text displaying', function() {
it('Verify alert and its text content', function(){
cy.visit('http://www.seleniumeasy.com/test/javascript-alert-box-demo.html')
cy.get('button').contains('Click me!').click()
cy.on ('window:alert', 'I am an alert box!')
})
})
Figured out the answer using cy.stub() method as advised by Richard Matsen:
describe('Test an alert and the text displaying', function() {
it('Verify alert and its text content', function(){
cy.visit('http://www.seleniumeasy.com/test/javascript-alert-box-demo.html')
const stub = cy.stub()
cy.on ('window:alert', stub)
cy
.get('button').contains('Click me!').click()
.then(() => {
expect(stub.getCall(0)).to.be.calledWith('I am an alert box!')
})
})
})
This is a much simpler and more intuitive way:
cy.on('window:alert', (str) => {
expect(str).to.equal(`This is an alert box!`)
})
I've found the stub() method of doing this to be way too messy, unintuitive and error-prone.
I couldn't get the accepted answer using .stub() to work, despite it being official Cypress solution for alert. Apparently I'm not alone here so I thought I'd share my workaround in case it helps someone in the same boat.
Expanding on #codemon's answer, this workaround will fail the test if no alert was fired:
var alerted = false;
cy.on('window:alert', msg => alerted = msg);
cy.get('button').contains('Click me!').click() //or whatever code that triggers alert
.then( () => expect(alerted).to.match(/clicked!/); //or whatever regex is appropriate
Cypress docs now advise to set an alias to the stub. This works fine:
// Give an alias to the stub, so we can use "get" on it.
const alertShown = cy.stub().as("alertShown")
cy.on ('window:alert', alertShown)
cy.contains("button", "Click Me").click()
// By using get, we ensure this will be retried if the checkbox has
// not been called yet.
cy.get("#alertShown").should("have.been.calledOnceWith", "I am an alert box!")
If you happen to be using this: alert.js, then maybe I can save you some headache. Try something like this to find the element that is NOT registered with the DOM:
// for example, a button in the modal that needs clicking
// the event that fires the alert
cy.get('<some element>').click()
cy.window().then(win => {
const el = win.Alert.$(`<whatever element you're looking for>`)
cy.wrap(el)
.find('button')
.contains('Confirm')
.click()
})
From the Catalog of events available to cypress:
window:alert
Yields: the alert text (String)
Fires when your app calls the global window.alert() method. Cypress will auto accept alerts. You cannot change this behavior.
window:confirm
Yields: the confirmation text (String)
Fires when your app calls the global window.confirm() method. Cypress will auto accept confirmations. Return false from this event and the confirmation will be canceled.
//to validate the alert box string
cy.on('window:alert', (str) => {
expect(str).to.equal('Please fill out Username and Password.')
})
cy.log('The alert is having the expected text')
//to click the 'ok' button in the alert box
cy.on('window:confirm', () => true);
cy.log('The alert is having the "ok" button')

Show an alert or popup if a Javascript error occurs

Is it possible to get visuel notifyed if I get a Javascript error?
In developing I have Firebug or something else open so I spot it.
But in the case where I do a light demostration for someone else I can not have it open.
I still prefer to know about the error instead of it failing silently and I dont know about trailings errors where I can't distinct wish between real and trailing errors.
You can surround your code in a try-catch and call alert with the error message. For example, if your code is as follows:
var x = document.getElementById("wrong_id"); //returns null
x.innerHTML = "Hello world!"; //null exception
you can surround it with the try-catch as follows:
try {
var x = document.getElementById("wrong_id"); //returns null
x.innerHTML = "Hello world!"; //null exception
}
catch(err) {
alert(err.message);
}
err.message basically contains the error message, similar to the one you see in Firebug.
Edit: You may also define window.onerror. See this answer
I believe you can use try catch functionality to show the error.
Something like this:
try {var a = 20 / f;}
catch (err) {alert(err);}
http://jsfiddle.net/magwalls/h7kqr/
Hope this helps!

Is there any way to get the origin of an alert box?

I work with some very large and confusing JavaScript files that I did not write. Sometimes an alert will come up but I don't know where it's coming from.
You could search all files for the text contained in the alert but if that text is dynamic it won't work.
Is there a way to set a breakpoint in order to intercept an alert?
At the very top of your HTML:
window.alert = function() {
debugger;
}
debugger is a statement that invokes any debugging functionality available. With developer tools open, you'll automatically hit a breakpoint whenever alert is called. You can then inspect the call stack to see exactly what called the custom alert function.
It may or may not be helpful to you, but you can overwrite the alert function to do whatever you want with it. For example, instead of alert boxes, you could have it log the message to the console.
window.alert = function(msg) {
console.log(msg);
}
alert('test');
I agree with Brian Glaz, but in order to get more details (line number) you might try to throw an error when alerting something and outputting the error on the console. this way, the console will point you to the right line number where the alert function was called.
Put this snippet at the top of your document and give it a try :
var originalAlert = window.alert;
window.alert = function(){
try{
throw new Error('alert was called');
} catch(e){
console.warn(e);
}
return originalAlert.apply(window, arguments);
}
Open Chrome push F12 key and go to Sources.
Then choose a script file Ctrl+F and search for alert.
You can put breakpoint on any line you wish

why is javascript-function just executed if an alert() is put at the beginning?

var callback = function(result){
//alert(result);
var json = eval('('+result+')');
if(json.criticalerror==true) dialogCriticalError(json.errormessage);
else{
if(json.error==true) dialogError(json.errormessage);
else{
// Do something else
}
}
};
When this callback-function is executed the "Do something else" part is called without problems. But in the case the json.error is true the dialogError-function is not executed. I've checked the transmitted JSON in Firebug. Everything is ok. The result is a JSON string as it should be.
The interesting thing is, that it actually is executed if i call the JSON-response with an alert() function at the beginning of the callback function. I'm new to JavaScript and probably missing something obvious but i just can't figure it out. Where's the bug?
EDIT:
It seems the problem is the time. If i put a 100ms delay between the JSON-result and the actual callback, everything works perfectly. But this can't be right... I'm kind of clueless.
(Oh and by the way: the communication is done by JBoss Seam Remoting)
The whole function looks like that:
function nextNode() {
var callback = function(result){
var json = JSON.parse(result);
if (json.criticalerror==true) {
dialogCriticalError(json.errormessage);
}else if (json.error==true) {
dialogError(json.errormessage);
}else {
document.getElementById('currentTree').innerHTML = json.state;
document.getElementById('countTrees').innerHTML = json.amountSteps;
document.getElementById('iframe').contentWindow.importGraph(json.tree);
document.getElementById('relevantnode').innerHTML = json.node;
createNodeBar(json);
}
};
manager.nextNode(callback);
}
The manager object is provided by the Seam Framework through the following function:
var manager = Seam.Component.getInstance("solverTreeStructure");
LAST EDIT:
Okay now i got the definite source of the problem. Its not not the Seam Remoting but the dialogError() function and the library it uses to display the dialog.
The dialogError() function looks like that:
function dialogError(error){
TINY.box.show({html:error,width:250,height:100,close:true,mask:true,opacity:20,topsplit:3})
}
It uses a small dialog library called TINYBOX. Now this library offers a variety of parameters to configure the dialog boxes. The 'mask' parameter caused all the trouble. It is resposible for darkening the background of the dialog box. If its turned on, TINYBOX needs a start-delay in order to work with the callback function. (i have NO idea why)
But for those who like riddles:
Thats the library. Its very small and clear. Unfortunately my JavaScript skills are not yet sophisticated enough to understand it.
http://www.scriptiny.com/2011/03/javascript-modal-windows/
Thats the answer. Have a nice day folks! ;)
Just a general advice: do not mix blocks with and without {}. The following form is much more readable and you can pinpoint your problem quicker.
console.log(json);
if (json.criticalerror == true) {
console.log("criticalerror");
dialogCriticalError(json.errormessage);
} else if (json.error == true) {
console.log("error");
dialogError(json.errormessage);
} else {
console.log("something else");
// Do something else
}
It seems the problem is the time. If i
put a 100ms delay between the
JSON-result and the actual callback,
everything works perfectly. But this
can't be right... I'm kind of
clueless.
Sounds like your doing asynchronous (ajax) communication. WHere is the rest of your code that asks the server for some data. Your handling the result before the server gives it to you. This explains the delay.

Categories

Resources