How can I execute javascript commands within a test?
I have a scenario when I need to run an app-level javascript command in order to proceed to the next step.
Thank you
You have native access to every host object in your application.
cy.window().then((win) => {
// call whatever you want on your app's window
// so your app methods must be exposed somehow
})
Alright, so I do have a custom JavaScript method in my project that I cannot access it simply by doing
cy.window().then(win => myCustomMethod())
Would exposing it as window.myCustomMethod be the last resort?
Cypress can only access it the same way you could access it from your Dev Tools Console.
For instance - visit your app (outside of Cypress) and pop open the dev tools. That's the same boat as Cypress.
You have to expose the internals globally somewhere else its impossible to be accessed. So yes, setting on window is the only way.
I would recommend setting your App instance (or whatever everything is attached to) on window so you have access to all of them.
This is use case specific so without knowing more thats all I can say.
Nice one. One observation though is that given
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
function myCustomMethod() {
console.log('being hit')
}
</script>
</head>
<body>
foo bar
</body>
</html>
and
// cypress/integration/test.js
describe(`testing custom method run`, () => {
it(`should run custom method`, () => {
cy.visit('http://127.0.0.1:8080/')
cy.window().then(win => win.myCustomMethod()) // this works
cy.window().then(win => myCustomMethod()) // this fails
})
})
you can't access the method globally, just as you'd do in Dev Tools Console. It happens to be inside window object, which does the trick.
Right, I guess I meant that. The test specs are isolated from your application. They have to be because they exist before you visit anything! They have their own global context aka window
.
When you do cy.window()
you're then able to access the remote application's window as a local variable, which at that point, you use that context which is the same thing as the default context in Dev Tools.
Thanks @brian-mann
function someFunc() {
console.log('oh, hey.');
}
cy.window().then( win => {
win.someFunc();
})
But I'm getting the error:
TypeError: win.someFunc is not a function
How do I call an async function?
I just found the answer - you return a promise-like thing
@JimTheMan because you've created someFunc
which is local to your specs, which has nothing to do with what's attached to the remote window. You'd just call someFunc()
in your tests to invoke that function.
@dylanb you just return the invocation of an async function and if it returns a Promise in a cy.then
or cy.invoke
it will be awaited...
cy.window().invoke('someAsyncFunction', arg1, arg2, arg3) // will be awaited if returning promise
cy.window().then((win) => {
return win.someAsyncFunction(arg1, arg2, arg3) // will also be awaited if returning promise
})
cy.window().then((win) => {
return new Cypress.Promise((resolve, reject) => {
win.someAsyncFunction(arg1, (err, val) {
if (err) {
return reject(err)
}
return resolve(val)
})
})
})
All the normal ways you interop with async. With bluebird there are even extra little helpers to make it easier to promisify node function signatures, etc.
@brian-mann The issue that @JimTheMan is facing is the same that I'm facing.
And the solution that you've suggested to him I didn't completely understand.
Can you please elaborate?
@nitingupta220 Calling win.someFunc();
in his example would be attempting to invoke someFunc()
from your application code, but someFunc
was defined within the test files - not your app. Instead of win.someFunc();
, you should just be able to call someFunc()
inside your tests.
Suggestion for Docs: Add info about using Cypress to test JS that has no UI.
I am looking at using Cypress to test modules / functions that have no UI. Much of the code is legacy. eg the following silly simple example:
// app.js in http://127.0.0.1:8500/Sites/CypressTestApp/index.html
var myFunc = {
lastMsg : '',
say: function(msg){
console.log('Last msg: '+this.lastMsg)
console.log('You said: '+msg)
this.lastMsg = msg;
},
getLastMsg : function(){
return this.lastMsg
}
}
It took me a while to find this issue post that answered the question: How do I test the function directly without reference to the DOM? Answer below.
describe('The Home Page', function () {
it('successfully loads', function () {
cy.visit('http://127.0.0.1:8500/Sites/CypressTestApp')
cy.window().should('have.property', 'myFunc')
})
it('Should set name to Jane',function(){
cy.window().then(function(win){
win.myFunc.say('Fred')
win.myFunc.say('Jane')
var lm = win.myFunc.getLastMsg()
expect(lm).to.equal("Jane")
})
})
})
Loving Cypress. This will save me months of work! Thanks.
Hey @flowt-au, If you want to open an issue on our docs, you can open it here.
Done: 1109
Thanks.
Hi,
is it somehow possible to put the return value into a variable?
As an example:
On the console with the command gives:
require('settings!io.ox/mail').get('layout')
this back:
"list"
I want to put the whole thing in var viewmode
to make a if query in the code later on
even more so:
var viewmode = cy.window().then(win => win.require('settings!io.ox/mail').get('layout')))
if (viewmode = xy) ...
@danielpondruff I think you should find our Variables and Aliases doc helpful.
Most helpful comment
You have native access to every host object in your application.