-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve data in custom command #198
Comments
I'll look into this - there are a few known issues with custom commands. You can however write the following much easier without using a promise. By default all cypress commands are awaited so you can just do... Cypress.addParentCommand('signIn', function (email, password) {
return cy.request({
method: 'POST',
url: '/auth',
body: {email, password}
})
// this changes the subject to the body property from the cy.request object
.its("body")
}); |
Also sorry this took so long for a reply. |
Thank you Brian, I see how it should work now, however, I cannot find a way to get the result, this code always logs cy.signIn('my@email.com', 'password').then(function(res) {
console.log(res);
}); No error though, so the |
Ah okay the reason this is happening is due to the way Cypress chaining works - there are rules about parent > child commands which ultimately resets the subject between new 'chains'. It makes sense in the general API but when writing custom commands this is basically a hidden landmine. You need to do this... Cypress.addParentCommand('signIn', function (email, password) {
// chain onto the existing sets so that the subject
// is not reset when attempting to consume the subject
// from this custom command
return cy.chain()
.request({
method: 'POST',
url: '/auth',
body: {email, password}
})
// this changes the subject to the body property from the cy.request object
.its("body")
}); |
Hmm I have the same result with
This is on Cypress 0.16.5 by the way. I found a workaround, writing/reading in the localStorage, but that's not the cleanest solution 😄 |
This works for me when I added the Cypress.addParentCommand("signIn", function(email, password) {
return cy.chain().request({
method: "POST",
url: "http://md5.jsontest.com?text=foo"
}).its("body");
});
describe("custom command", function() {
it("resolves with the body", function() {
// the subject (body) is carried on and
// we can then add assertions about it
cy.signIn().should("deep.eq", {
md5: "acbd18db4cc2f85cedef654fccc4a4d8",
original: "foo"
});
});
}); |
Also I see what you're trying to do with However the good news is that in |
Ah, I found what was causing the error! You code works fine, but the following one does not: Cypress.addParentCommand("signIn", function(email, password) {
return cy.chain().request({
method: "POST",
url: "http://md5.jsontest.com?text=foo"
}).its("body");
});
describe("custom command", function() {
it("resolves with the body", function() {
// the subject (body) is carried on and
// we can then add assertions about it
cy.signIn().should("deep.eq", {
md5: "acbd18db4cc2f85cedef654fccc4a4d8",
original: "foo"
});
cy.visit('https://cypress.io');
});
}); The only difference is the |
We also had problems with returning values from custom commands. It took us a while to find this thread about |
@Hey @brian-mann, could you please explain in depth how the |
Yah these API's are expected to change as I've never been happy with the implementation. The way it currently works is that everytime you call off of the This is how you can start a new "series" of commands without being affected by the previous. The problem is that during a custom command you "may" want to For this you need to use Cypress.addParentCommand("login", function(){
cy
.chain() // reattaches itself to whatever was the previous cy call
.some()
.other()
.commands()
})
cy.login().then(function(subject){
// now we can access the subject from the custom command
}) |
Hi, @brian-mann, An example of how we're trying to use custom commands would be: Cypress.addParentCommand('createSystemObject', () => {
cy
.goToPage1()
.fillAndSubmitFormAtPage1()
.url()
.then((url) => {
const newObjId = extractIdFromUrl(url);
return newObjId;
});
});
Cypress.addChildCommand('useSystemObject', (objId) => {
console.log('objId', objId);
}); Then executing cy
.createSystemObject()
.useSystemObject(); prints We tried using Any help will be appreciated. |
Hey Brian, |
Okay we will look into this, but we'll need a bit of time. For the moment, just avoid using custom commands and switch to using regular javascript functions to compose your custom commands / page objects. With the new ES2015 support you can easily create util helpers and import them into your spec files. Also can you create a very small repo that exhibits this problem? It would help us look at the issue much faster if you can put together a small use case showing several custom commands in use together. Another solution is basically just avoid using the page object pattern altogether because there are generally other better approaches. For instance, there really shouldn't ever be this much duplication in your scripts to ever need to reuse them in different spec files. When I see commands like Using We are making progress on our If you can share your project (if its not private) or put together more use cases we can discuss this approach more in detail. |
@pehota and @ChristophP I cannot recreate your issue. Adding Cypress.addParentCommand("a", function(){
cy
.chain()
.wrap({foo: "bar"})
.its("foo")
})
Cypress.addChildCommand("b", function(subj){
cy
.chain()
.wrap(subj)
.should("eq", "bar")
})
it("can chain subjects", function(){
cy
.a()
.b()
.should("eq", "bar")
}) |
Hi @brian-mann, thanks for your reply. So the thing is I cannot reproduce the issue 100%. It started ocurring when I was in the middle of writing tests. And stuck around for a while and stopped when I refactored some things. My feeling is that the issue was caused by some other error in my code.
cy
.customCommand1() // <--- returns some data as subject
.customCommand2() // <--- should get the subject from previous command, but gets null
.customCommand3WithVisit() // <--- because this calls visit() internally and starts a new chain
let id;
beforeEach('does setup', () => {
cy
.window()
.then(win => {
win.client.createResource()
})
.then(result => {
id = res.id // save id to be able to call client.deleteResource(id) in the afterEach hook
someFunction(resourceId) //resouceId is not defined and should throw a Reference Error
})
.visitResource(id) // calls .visit(`/resource/${id}`);
}); Does this help you at all? Sorry I can't say more about reproducing the errors. Let me know if I can do something to help. |
We are planning to move the custom command interface to be on |
An interesting use case to throw into the mix: https://gitter.im/cypress-io/cypress?at=5953bf62bf7e6af22c81c5db Situation where user wants |
Fixed in |
Description
I cannot find a way to resolve data in a custom command, using a
Cypress.Promise
.Code
In
support/commands
In my test:
When I return the promise like above,
cy.signIn
times out. It does not fail when I do not return the promise, but I still can't access the request data.Am I doing anything wrong?
The text was updated successfully, but these errors were encountered: