Reputation: 21
This is my first time using Cypress (and first SO post) and I keep running into an error. First, here is my code:
describe('Add new user to existing clinic team', () => {
const serverId = 'e6ar8r9c';
const testEmail = '[email protected]'
let confirmationLink
it('signs in as admin', () => {
cy.visit('******')
cy.get('#user_email').type('*******')
cy.get('#user_password').type('******')
cy.get('.button').click()
// show teams roster
cy.get('.hide-for-large > a > .fas').click()
cy.get('.vertical > :nth-child(1) > #programs-menu-btn > .fas').click()
// click into the clinic team
cy.get('table tbody > tr').contains('clinic team test apr 28#4').click()
// click into the user roster for the clinic team
cy.get('ul#program-team-tabs > li#team-icon-li').click()
// enter user email to be added
cy.get('#email').type(testEmail)
cy.get('button.non-button').click()
// get email
cy.mailosaurGetMessage(serverId, {
sentTo: testEmail
}).then(email => {
expect(email.subject).to.equal('Existing user invitation instructions');
cy.log(email.subject)
cy.log(email.html.links[0].href)
confirmationLink = email.html.links[0].href
})
// follow email link
cy.visit(confirmationLink)
})
})
When it logs the email link to the console, it logs the full URL of the link. However, it prints this error: "cy.visit() must be called with a url or an options object containing a url as its 1st argument" as if confirmationLink doesn't contain a URL, which, according to the console log, it does. Why is it not recognizing the URL?
Upvotes: 2
Views: 920
Reputation: 2509
Because of how the commands are queued in cypress, cy.visit(confirmationLink)
gets into the queue even before then
block of cy.mailosaurGetMessage
is executed and a value is assigned to confirmationLink
. So, confirmationLink
will be Undefined
when it is actually used by your cy.visit()
command.
This can be fixed by moving your cy.visit()
into the then
block. Your code will look as below.
describe('Add new user to existing clinic team', () => {
const serverId = 'e6ar8r9c';
const testEmail = '[email protected]';
it('signs in as admin', () => {
cy.visit('******');
cy.get('#user_email').type('*******');
cy.get('#user_password').type('******');
cy.get('.button').click();
// show teams roster
cy.get('.hide-for-large > a > .fas').click();
cy.get('.vertical > :nth-child(1) > #programs-menu-btn > .fas').click();
// click into the clinic team
cy.get('table tbody > tr').contains('clinic team test apr 28#4').click();
// click into the user roster for the clinic team
cy.get('ul#program-team-tabs > li#team-icon-li').click();
// enter user email to be added
cy.get('#email').type(testEmail);
cy.get('button.non-button').click();
// get email
cy.mailosaurGetMessage(serverId, {
sentTo: testEmail,
}).then((email) => {
expect(email.subject).to.equal('Existing user invitation instructions');
cy.visit(email.html.links[0].href);
});
});
});
Upvotes: 1
Reputation: 55
Cypress provides alias's to capture values from higher up the test.
For example,
cy.mailosaurGetMessage(serverId, {
sentTo: testEmail
})
.then(email => {
expect(email.subject).to.equal('Existing user invitation instructions');
cy.log(email.subject)
cy.log(email.html.links[0].href)
return email.html.links[0].href
})
.as('confirmationLink')
cy.get('@confirmationLink')
.then((confirmationLink ) => {
cy.visit(confirmationLink)
})
Upvotes: 1
Reputation: 32044
Short answer, wrap the visit in a .then()
:
// get email
cy.mailosaurGetMessage(serverId, {
sentTo: testEmail
}).then(email => {
expect(email.subject).to.equal('Existing user invitation instructions');
cy.log(email.subject)
cy.log(email.html.links[0].href)
confirmationLink = email.html.links[0].href
}).then(() => {
// follow email link
cy.visit(confirmationLink)
})
Reason is, Cypress scans the test for commands, adds them to the command queue then runs the queue.
So the value of confirmationLink
used when cy.vist(confirmationLink)
is added to the queue is the value at the beginning of the test.
Using a .then()
around any command defers adding to the queue until all preceding commands have run.
A better pattern is to pass the confirmationLink
down the chain
// get email
cy.mailosaurGetMessage(serverId, {
sentTo: testEmail
}).then(email => {
expect(email.subject).to.equal('Existing user invitation instructions');
cy.log(email.subject)
cy.log(email.html.links[0].href)
confirmationLink = email.html.links[0].href
return confirmationLink; // pass to next command
}).then((confirmationLink ) => {
// follow email link
cy.visit(confirmationLink)
})
Upvotes: 1