The web app I am testing gives an alert. I wanted to use cypress to test if the alert is being shown and click cancel on the alert but cypress is automatically confirming the alert.
Here is the code:
cy.get('a').contains('Concepts').click();
cy.on('window:alert', (t) => {
//assertions
expect(t).to.contains('You have unsaved changes, are you sure you want to leave?');
return false;
})
I have returned false but still, on running the test, it says confirm without the assertion being handled and it goes to the new URL (which it should not). (see image below)
What am I doing wrong?
Look like you are using window:confirm not alert.
Change it to confirm instead
cy.on('window:confirm', (t) => {
//assertions
expect(t).to.contains('You have unsaved changes, are you sure you want to leave?');
return false;
})
Related
I have a page on my site to enter some values. These can be saved and modified later. I want a prompt to appear when the user attempts to leave the page, but only when there is unsaved data. I have the code to determine if a value is saved or not working fine. In the function I assign to window.onBeforeUnload, it should either return a string if there is an unsaved value, or nothing if nothing was entered/everything is saved. However in Firefox and Internet Explore, the prompt warning about unsaved changed appears even the function returns nothing (which will be undefined). Chrome works fine.
I have tried to instead attach the event to the window via addEventListener and the same result occured. I have also removed the evt.preventDefault() and evt.stopPropagation() and it still appears. I have tried setting the evt.returnValue to null and delete evt['returnValue'] and it still appears.
The code is like this:
componentDidMount() {
window.onbeforeunload = this.warnUnsaved;
}
warnUnsavedRecords = (evt) => {
if (evt) {
evt.preventDefault();
evt.stopPropagation();
}
if (this._unsaved) {
return "There are unsaved records.";
}
return;
}
Even adding console.log proves it is reaching the return and yet it still occurs.
Normally, removing the evt.preventDefault(); part should be sufficient. This works for me in FF at least.
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')
jQuery Error
I've done some extensive searching, and have found samples of code to handle an alert box when you expect it; but I haven't been able to find anything on handling a random alert box that might, or might not appear.
The website I'm dealing with is very stubborn to begin with. Several elements without any kind of ID's, timeouts, network failures, etc.
98% of the time when I run the tests, they run without getting the alert box error and everything is good. When the alert box does popup the other 2% of the time which says "Error:jQuery not found," all my other tests fail with unexpected alert errors.
My first question is, could it be something in my code that's causing the error to happen? (see code below) My gut tells me it's probably the website. So if that's the case, could someone please show me an example that would handle a "possible" alert box and accept it, without failing my test? The swithTab() test is running first, and then the setDates() test is running next. The alert box error pops up after the switch tab, as the page is loading. I've tried using a deferred promise to handle the alert, and catch the error, but it fails before it can even catch the error. It fails as soon as it hits browser.switchTo().alert() because the alert usually doesn't exist. I really appreciate any help I could get.
this.switchTab = function(){
browser.getAllWindowHandles().then(function(handles){
browser.switchTo().window(handles[1]);
browser.sleep(2000);
var lockBoxTitle = element(by.css('td.title'));
browser.driver.wait(EC.visibilityOf(lockBoxTitle),5000);
});
}
this.setDates = function(yesterdayDate){
browser.sleep(3000);
//handleAlert();
startDateTextBox.clear();
startDateTextBox.sendKeys(yesterdayDate);
endDateTextBox.clear();
endDateTextBox.sendKeys(yesterdayDate);
retrieveBtn.click();
browser.sleep(5000);
expect(validateStart.getText()).toEqual(yesterdayDate);
expect(validateEnd.getText()).toEqual(yesterdayDate);
}
You can check if popup is displayed and if is displayed click the button for closing it:
var popUpElm = element(by.model(""));
var closeBtn= element(by.model(""));
popUpElm.isDisplayed().then(function(isDisplayed) {
if (isDisplayed) {
closeBtn.click();
console.log("Popup is closed");
} else {
console.log("Popup is not displayed");
}
});
I am just detecting the printed status in web browser.
As you can see , browser support the status as cancel or print button.
For seeing if user clicked cancel, print button, I am just using javascript.
but I had not got good result for that.
Are there good way to detect the status ?
window.print() doesn't return any value.
I don't think there's a way to know if the user clicked Save or Cancel. It's more of your operating system's job to watch what's going on in there. There're, however, two event handlers
window.onbeforeprint and
window.onafterprint.
Code Snippet
window.onbeforeprint = function() {
console.log('This will be called before the user prints.');
};
window.onafterprint = function() {
console.log('This will be called after the user prints');
};
Take a look here
I want to insert my debugger function inside another JS function and halt the execution.
I know return false/true does the job, but I want my debugger function to do that automatically.
Example:
<script type="javascript">
function validateFirstName () {
//validating first name field
var fn = $('#firstname').val();
if(fn == "") {
$("#errorMsg").html("Please insert first name");
$("#firstname").focus();
return false;
}
debugger(); //I want to stop everything here
// if validation passes, redirect browser:
window.location = 'nextpage.html';
}
function debugger () {
console.log("Some custom message here");
return false;
}
</script>
You'll notice I put my debugger function inside the validateFirstName() function.
I assumed that return false in my debugger() function will stop the validateFirstName() from executing. But it doesn't.
Without adding return false inside the validateFirstName() function, how can I use my debugger() function to stop all execution?
replace
debugger(); //I want to stop everything here
with
return debugger(); //I want to stop everything here
the above example will always stop on true or false.
This will continue to the window.location if it's true and stop if it's false.
if(!debugger())
return;
in your case it seems to be a function inside of a function so you might as well use
if(!debugger())
return false;
Seems what you really want to do is set a breakpoint on the executing code.
In Chrome Browser press Ctrl+Shift+I
Then Go to Sources Tab
Click the Arrow pointing right (looks like a play button) on top of the counting line numbers to see list of websites
Find your website click on the folder
Find whatever script that you want
Now click anywhere in the code to close the side bar
Now finally click on any number on the side thats counting down the lines
That will set a breakpoint which means it will stop on that code if you make the code go there by doing something on your website, or forcing the code to run using the
Console tab or simply in your address bar typing javascript: function_to_call();
You could throw from debugger () like this.
function debugger () {
console.log('Some custom message here');
throw 'Debugging Code';
}
Although this will do what you want it to, I don't recommend it. Basically what's happening is you are throwing an error which isn't being caught in your code (the browser will catch it, but that is probably not as clean).
You could throw an error:
function validateFirstName () {
//validating first name field
var fn = $('#firstname').val();
if(fn==""){
$("#errorMsg").html("Please insert first name");
$("#firstname").focus();
return false;
}
debugger(); //I want to stop everything here
// if validation passes, redirect browser:
window.location='nextpage.html';
}
function debugger () {
throw new Error("Some custom message here");
}
try{
validateFirstName();
}catch(e){
console.log(e);
}
If you are using a modern browser like Chrome, why not just use debugger instead?
that will trigger the debugger in your developer tools.
like this:
debugger; //I want to stop everything here
notice the missing ()