I am learning Cypress the hard way: on a legacy app with frames :(
I read that Cypress auto accepts alerts but here I have a Confirm pop-up that demands a user input. However, I am struggling to close this windows confirm pop ip asking to 'Cancel' or 'OK'.
The element which fires the pop-up is within a frame (not an iFrame) is as follows:
<a href="/tasksgui/manageScheduledJobs.do?userAction=runnow&userAction=select&selectedIndex=1&formContextKey=ListChunk[SchedulerJobsSearchResults]{1588676256461}1"
onclick="return(confirmRunNow())" ;>
RunJobs</a>
I know that the Cypress API exposes a way to handle these:
cy.on('window:confirm', (str) => {
//code here
}
But I'm unclear how to incorporate this into my test block"
it('gets the post', (done) => {
cy.visit('http://myapp.co.uk/mygui/index.jsp');
getLeftFrameBody().findByText('Manage Tasks').click();
cy.wait(2000)
getContentFrameBody().should('include.text', 'Scheduled Tasks')
getContentFrameBody().findByText('Task Name');
getContentFrameBody().find('input[name="jobName"]').type('Task one');
getContentFrameBody().findByText('Search').click();
cy.wait(2000)
cy.on('window:confirm', function(confirmText){
return true
});
getContentFrameBody().find('.resultrowone').find('a').eq(5).click();
})
By making the function async, you can await the window confirmation and then continue as seen in the example below.
it('gets the post', async (done) => {
cy.visit('http://companyapp.co.uk/mygui/index.jsp');
getLeftFrameBody().findByText('Manage Tasks').click();
cy.wait(2000)
getContentFrameBody().should('include.text', 'Scheduled Tasks')
getContentFrameBody().findByText('Job Name');
getContentFrameBody().find('input[name="jobName"]').type('runTasks');
getContentFrameBody().findByText('Search').click();
cy.wait(2000);
await new Promise(resolve => {
cy.on('window:confirm', (str) => {
resolve();
});
getContentFrameBody().find('.resultrowone').find('a').eq(5).click();
});
// Continue after window was confirmed
});
Related
I have a web page with some JavaScript code that copies stuff to the clipboard similar to what this demo does: https://davidwalsh.name/demo/javascript-copy-clipboard.php
My code is something like this:
// Within a listener that is triggered by a click on some button:
var copiedText = "...something";
navigator.clipboard.writeText(copiedText).then(
function() {
console.log("Succesfully copied");
},
function() {
console.log("FAILED to copy!!!!!!");
}
);
This works fine, but it always succeeds. I need to test that the behavior is correct when copying fails for whatever reason.
How can I cause the copy to fail on purpose so that I can test the behavior of my code in that situation?
I never get a prompt asking me permission to write to the clipboard.
In Chrome, I have tried going to the site settings for the site, and under "Clipboard" selecting "Block", but it does nothing (I guess that's only for reading from the clipboard).
Sure, just provide an invalid argument which will throw an exception during the stringification algorithm:
Note that this demo will work in your own page, but the success case won't work in the Stack Overflow code snippet iframe sandbox (where there is no clipboard permission).
function copyThenLog (input) {
navigator.clipboard.writeText(input).then(
() => console.log({success: true}),
(ex) => {
console.log({success: false});
console.error(ex);
},
);
}
document.querySelector('.success').addEventListener('click', () => {
const input = 'hello world';
copyThenLog(input);
});
document.querySelector('.fail').addEventListener('click', () => {
const input = {
toString () {
throw new Error('Oops');
}
};
copyThenLog(input);
});
<div class="success">Click me to succeed</div>
<div class="fail">Click me to fail</div>
First of all, I have to say this is my first question on stack ;)
I am trying to implement a reading via NFC on my test web, but i dunno why, the ndefReader doesn't works on startup, i have to press any field on the web to get it loaded (or asked for permission).
BUT, if i wrote some alerts to check why it doen't reach the function on startup, it works!!! (of course, it show alerts before). I don't know if when I accept the alert, I am interacting with the web and that's why it works, but anyways, I dunno why this happens (I need to click anywhere before starting).
function iniciar() {
document.getElementById("input1").focus();
//alert("test before"); <--- IF i remove this, it doesnt works
document.getElementById("input1").addEventListener("blur", async () => {
try{
const ndef = new NDEFReader();
alert("before wait");
await ndef.scan();
alert("after wait");
ndef.addEventListener("readingerror", () => {
alert("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
alert(`> Serial Number: ${serialNumber}`);
alert(`> Records: (${message.records.length})`);
});
} catch (error) {
alert("Argh! " + error);
}
},false);
To scan and write to NFC tags, you must first request the "nfc" permission while handling a user gesture (e.g a button click, or in your case the "alert" call). Once handled, the NDEFReader scan() and write() methods trigger a user prompt, if access was not previously granted.
Check out https://web.dev/nfc/#security-and-permissions to learn more.
Hopefully https://googlechrome.github.io/samples/web-nfc/ samples should help you as well.
scanButton.addEventListener("click", async () => {
console.log("User clicked scan button");
try {
const ndef = new NDEFReader();
await ndef.scan();
console.log("> Scan started");
ndef.addEventListener("readingerror", () => {
console.log("Argh! Cannot read data from the NFC tag. Try another one?");
});
ndef.addEventListener("reading", ({ message, serialNumber }) => {
console.log(`> Serial Number: ${serialNumber}`);
console.log(`> Records: (${message.records.length})`);
});
} catch (error) {
console.log("Argh! " + error);
}
});
Cypress overwrite: I would like to overwrite the existing visit command so that it still operates as is, but will attempt to dismiss a popup after the visit has successfully executed.
The popup is something we have very little control over and it appears after you login. Seeing as we're bypassing the login screen and logging in programmatically, we'll see the popup when we navigate to any page. The insufficient code I currently have:
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
originalFn(url, options);
cy.get("body").then($body => {
if ($body.find("[text='Got it']").length > 0) {
cy.contains("Got it", { matchCase: false }).click();
}
});
});
Thanks
You can do this by overwriting cy.visit() command. Try this:
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
originalFn(url, options);
// make sure to add a return here!
return cy.get('body').then($body => {
if ($body.find("[text='Got it']").length > 0) {
cy.contains('Got it', { matchCase: false }).click();
}
});
});
source: https://docs.cypress.io/api/cypress-api/custom-commands#Overwrite-visit-command
I'm working on a electron(-nuxt) based application. End to End test re-written with AVA + Spectron. The .click() function however doesnt seem to work.
I used this template:
https://github.com/michalzaq12/electron-nuxt
Everything seems to work except a simple button click.
<footer class="modal-card-foot">
<button id="loginButton" class="button " type="button" #click="login">
Login
</button>
</footer>
test('app should login', async t => {
let app = t.context.app
await app.client.click('#loginButton')
})
The message i got is:
1 test failed
app should login
Error: Test finished without running any assertions
That is truthy because there aren't any assertions.
BUT i can see that the Button is never clicked, because that would trigger a "Login failed" message from the app.
In your test case you should wait for element to be rendered on the page.
test('app should login', async t => {
const ELEMENT_SELECTOR = '#loginButton'
let app = t.context.app
try {
await app.client.nuxt.ready()
await app.client.nuxt.navigate('/') //optional
await app.client.waitForExist(ELEMENT_SELECTOR)
await app.client.click(ELEMENT_SELECTOR)
t.pass() //or other assertion
} catch (e) {
t.fail(e.message)
}
})
Checkout this repo that is an example of how to test an electron app:
https://github.com/StephenDavidson/electron-spectron-example
specifically this where they test the functionality of pressing a button.
Notice how they import in the page at the top.
Search.js
const SearchPage = require('./page-objects/search.page');
Then near the bottom they test the functionality of click
it('should search', async() => {
const input = 'this is a test';
await app.client.url(config.url)
.setValue(SearchPage.searchField, input)
.getValue(SearchPage.searchField)
.should.eventually.equal(input)
.click(SearchPage.searchButton)
.element(SearchPage.searchResult)
.should.eventually.exist;
});
See if this helps you get further along.
I am automating the UI test of my application. There are some cases when i want my test script to close the current browser and and run next test by opening new browser. The problem is that I am unable to figure out how to open new browser window in intern. remote.get(URL) doesn't do what i want to do here. Can someone please help.
I have updated my question to include code as well. My question is pretty much straight forward though. How to open new browser window using intern from inside test ?.
though if you want to see the code please comment, I will write it down .
Thanks.
// in tests/functional/index.js
define([
'intern!object',
'intern/chai!assert',
'Automation/ConfigFiles/dataurl',
'Automation/pages/login/loginpage',
'intern/dojo/node!fs',
'intern/dojo/node!leadfoot/helpers/pollUntil'
], function (registerSuite, assert, dataurl, LoginPage, fs, pollUntil) {
registerSuite(function () {
var loginPage;
var values;
return {
setup: function () {
var data = fs.readFileSync(loginpage, 'utf8');
json = JSON.parse(data);
values = json.values;
loginPage = new LoginPage(this.remote, json.locator);
return this.remote
.get(require.toUrl(json.locator.URL)).setFindTimeout(60000000000).sleep(5000)
},
beforeEach:function() {
// here i want to open new window
},
'valid loginname lands to password page':function () {
loginPage.submitLoginName(values.unamevalue);
loginPage.isPasswordPageDisplayed().then(function(isPasswordPageDisplayed) {
assert.true(isPasswordPageDisplayed, 'password page is not displayed, Invalid Login name');
})
},
'successful login': function () {
loginPage
.login(values.unamevalue, values.pwdvalue)
loginPage.isLoginSuccess().then(function (loginSuccess) {
assert.isTrue(loginSuccess, 'Login Failed');
});
},
afterEach: function () {
return this.remote.closeCurrentWindow()
}
};
});
});
You can open a new window with window.open. The trick is that you want to run that command in the remote browser. Intern (technically Leadfoot) gives you two methods for doing that on this.remote: execute and executeAsync. For example, to simply open a new window, you could do:
this.remote.execute(function () {
window.open();
})
Once you've opened a new window, you need to switch to it to interact with it. A script might look something like:
var windowHandles;
this.remote
.getAllWindowHandles()
.then(function (handles) {
windowHandles = handles;
})
.execute(function () { window.open() })
.sleep(500)
.getAllWindowHandles()
.then(function (handles) {
// compare the new handles to windowHandles to figure out which
// is the new window, then switch to it
return this.remote.switchToWindow(newWindowHandle);
})
.get('some_new_url')
// rest of test