i can't return a response value on my cypress api call - cypress

I'm trying to make a cypress api call and get the value to be use on a next stage api call and when i make a return it just send me a big obj of commands
the call im making is
Cypress.Commands.add('getSession', () => {
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/New`,
headers: {
'Client-Type': 'backend'
}
})
.its('body')
.then(json => {
return {
id: json.value.props.id,
name: json.value.props.name
}
})
})
Cypress.Commands.add('createNew', (email = Cypress.env('userEmail'), password = Cypress.env('userPassword')) => {
const session = cy.getSession()
cy.log('api respond', session.id)
cy.createMember(email, password, session.id)
})
and the response im getting is
[$Chainer] with a big obj
I'm not sure if the return on .then put it on a container but i can't find the value any when if someone can suggest what i have made wrong on the request call, that will be helpful

From the cypress docs:
So the createNew command must be rewritten to respect the async nature of cy commands.
Using then
Cypress.Commands.add('createNew', (email = Cypress.env('userEmail'), password = Cypress.env('userPassword')) => {
cy.getSession().then( session => {
cy.log('api respond', session.id)
cy.createMember(email, password, session.id)
})
})
Using aliases
Cypress.Commands.add('createNew', (email = Cypress.env('userEmail'), password = Cypress.env('userPassword')) => {
cy.getSession().as("session")
cy.get("#session").then(session => {
cy.log('api respond', session.id)
})
cy.get("#session").then(session => {
cy.createMember(email, password, session.id)
})

Related

Cypress: How can we bypass cross origin error in Firefox? (cross origin issue, outside cy.origin)

Part 1 question: Cypress: How can we bypass cross origin error in Firefox? (iframes)
Hi, this is the part two for my question. I am also currently testing download functionality which needs to go to a different domain to check. I also list the format of the webpages. I altered my code a bit to not include sensitive information.
The process is:
From original application website, user will download the course (starting.originalWebsite.com)
Download link will be sent to the user's email, contains iframe (emailWebsite.com)
Mail contains username and password to access the document from the download link (download.originalWebsite.com)
User checks the contents of the downloaded document
The test stops after visiting the new link (original link: starting.originalWebsite.com, new link: emailWebsite.com) because it's already outside cy.origin() syntax. My problem with cy.origin() is that the email contains iframes and cy.origin() views the iframe as its native page. Cypress cannot see the original native page anymore and I cannot anymore interact with it. I also have the chromeWebSecurity set to false.
The code below works in Chrome but not in Firefox because we're getting the error below. What can I possibly do for this? So Firefox will allow my testing. Thank you!
And('user goes to mailtrap, logins and checks for the email link', () => {
const credentials = {
username: testdata.credentials.username,
password: testdata.credentials.password
}
cy.origin(Cypress.config().mailtrapUrl, { args: credentials }, ({ username, password }) => {
cy.visit(Cypress.config().mailtrapUrl)
})
mailtrapPO.getSignin().click()
cy.explicitWait()
mailtrapPO.getEmailField().scrollIntoView().click().type(testdata.credentials.username)
mailtrapPO.getNextButton().scrollIntoView().click()
cy.explicitWait()
mailtrapPO.getPasswordField().scrollIntoView().click().type(testdata.credentials.password)
mailtrapPO.getLoginButton().scrollIntoView().click()
cy.explicitWait()
mailtrapPO.getTransferStagingInbox().click()
cy.explicitWait()
mailtrapPO.getMessageList()
.find('span')
.contains('mail title')
.eq(0)
.scrollIntoView()
.click({ force: true })
mailtrapPO.getHTMLSourceTab().click({ force: true })
mailtrapPO.getCode().children().within((code) => {
var downloadUrl = Cypress.env('downloadCoursesUrl')
cy.get('span').contains('Password: ').scrollIntoView().invoke('text').then((documentDownloadPassword) => {
cy.wrap(documentDownloadPassword).as('passwordHint')
cy.log(documentDownloadPassword)
cy.get('#passwordHint').then((downloadPassword) => {
var delimeter = 'Password: ',
passwordIndex = delimeter.length
cy.wrap(downloadPassword.substring(passwordIndex)).as('documentPassword')
})
})
cy.get('span').contains(downloadUrl).scrollIntoView().invoke('text').then((documentDownloadLink) => {
cy.wrap(documentDownloadLink).as('downloadLink')
cy.log(documentDownloadLink)
cy.get('#downloadLink').then((link) => {
var cleanLink = link.replaceAll('"', '')
cy.log(cleanLink)
var delimeter = Cypress.env('downloadhmmm'),
linkFirstIndex = delimeter.length
cy.log(linkFirstIndex)
cy.wrap(cleanLink.substring(linkFirstIndex)).as('downloadhmmm')
})
})
})
cy.get('#downloadhmmm').then((finalLink) => {
cy.get('#documentPassword').then((password) => {
const linkBody = {
username: testdata.credentials.username,
password: password,
downloadlink: finalLink,
}
cy.origin(Cypress.env('transferUrl'), { args: linkBody }, ({ username, password, downloadlink }) => {
cy.visit(downloadlink, {
auth: {
username: username,
password: password
}
})
// to prevent Cypress from loading indefinitely when downloading, only works in Chrome
cy.window().document().then(function (doc) {
doc.addEventListener('click', () => {
setTimeout(function () { doc.location.reload() }, 5000)
})
cy.get('#downloadButton').click({ force: true })
cy.wait(4000)
})
})
})
})
cy.get('span').contains('courses').invoke('text').then((title) => {
cy.wrap(title).as('initialDocumentTitle')
cy.get('#initialDocumentTitle').then((initialTitle) => {
var convertedTitle = initialTitle.replaceAll(':', "_")
cy.wrap(convertedTitle).as('downloadedDocumentTitle')
cy.wait(10000)
})
})
cy.get('#courseNameArray').then((courseNamesArray) => {
cy.log(courseNamesArray)
cy.get('#downloadedDocumentTitle').then((documentTitle) => {
//start of reading files from Excel
var removeSpace = documentTitle.replace(/\s/g, '')
var excelFilePath = "cypress/downloads/" + removeSpace
cy.verifyDownload(removeSpace, { interval: 600 })
cy.wrap(excelFilePath).as('filePath')
cy.get('#filePath').then((filePath) => {
cy.task('checkExcelSheetContents', { filePath }).then((contents) => {
cy.log(contents)
expect(contents).to.deep.equal(courseNamesArray)
})
})
})
})

Set cookies and return user on Cypress request

Problem
I have a Cypress command where I can login with a random user. The API will return the following response:
{
user: { ... }
token: { ... }
}
What I would like to do is to:
Create user using cy.request
Set the cookie in the browser
Return the response out of the command so that I can work with it outside of the command
What I have tried
return cy.request({
method: 'POST',
url: getApiUrl('__cypress__/login'),
body: requestBody,
log: false,
})
.then(({ body }) => {
cy
.setCookie('_token', body.token.plainTextToken)
.then(() => {
Cypress.log({
name: 'login',
message: JSON.stringify(body),
consoleProps: () => ({ user: body }),
});
});
})
.its('body', { log: false }) 👈 times out here
What I'm looking for is to do something like:
cy.login().then(({ user }) => {
// use logged in user
})
Question
Cypress times out on .its(...) line. Is this possible to do it? Looking at the docs I couldn't find any example on what I'm trying to achieve
(from the comments)
It happens because previously chained subject, does not return anything. An explicit return for the body property will fix it.

How to implement a custom command In Cypress test

I wrote a custom command to get authentication token from the window like below
Cypress.Commands.add("getToken", AUTH => {
return cy.window().then(window => window.localStorage.getItem(AUTH));
});
const authToken = JSON.parse(window.localStorage.getItem("AUTH"));
authToken = returned the authtoken. I want to know how to make`enter code here` this as
function/custom command so that the other t`enter code here`est could use this.
I suggest something like this:
describe('', () => {
let tokens = {};
it('', () => {
cy
.getToken('AUTH', ({ token }) => {
Object.assign(tokens, { auth: token });
})
.request({
headers: { "Content-Type": "application/json", Authorization: `Bearer ${tokens.auth}`, }
})
});
});
Also you have to change little bit getToken command:
Cypress.Commands.add("getToken", (AUTH, cb) => {
return cy.window().then(window => cb(window.localStorage.getItem(AUTH)));
});

Cypress: Returning value in promise within custom command?

So I am trying to use a custom command to reduce the need to write the same thing in multiple files. Specifically this is for logging in and setting a token via JWT.
Here is the current working code (borrowed from JWT login example from cypress examples):
let user;
before(function() {
cy.request("POST", Cypress.env("auth_url"), {
username: Cypress.env("auth_username"),
password: Cypress.env("auth_password")
})
.its("body")
.then(res => {
user = res;
});
});
beforeEach(function() {
console.log(cy.get_auth_token)
cy.visit("/", {
onBeforeLoad(win) {
// set the user object in local storage
win.localStorage.setItem("token", user.token);
}
});
});
So i tried to do something similar via:
Cypress.Commands.add("get_auth_token", () => {
let user;
cy.request("POST", Cypress.env("auth_url"), {
username: Cypress.env("auth_username"),
password: Cypress.env("auth_password")
})
.its("body")
.then(res => {
user = res;
});
return user;
})
However when I try to call it within my beforeEach function as let user = cy.get_auth_token I get errors about user being undefined. Am I doing something wrong with returning the value? Im not an expert at promises...but this feels like it should be working?
Thanks!
Commands are not like functions, the return value is not assignable to a local variable. Instead they 'yield' it to the next command in the chain, which can be a then(). Also, the value is a 'subject' which is a jquery-wrapped version of the return value.
In short, this should be how you use your custom command:
beforeEach(function() {
cy.get_auth_token().then($user => {
console.log($user[0]);
cy.visit("/", {
onBeforeLoad(win) {
// set the user object in local storage
win.localStorage.setItem("token", $user[0].token);
}
});
});
});
Try to put your code inside a Promise and resolve 'user'. Using Cypress.Promise, it will wait until user is returned:
Cypress.Commands.add("get_auth_token", () => {
return new Cypress.Promise((resolve, reject) => {
cy.request("POST", Cypress.env("auth_url"), {
username: Cypress.env("auth_username"),
password: Cypress.env("auth_password")
})
.its("body")
.then(user => {
resolve(user);
});
})
})

Cannot connect Ember Simple Auth and DRF Token Auth

I have a trouble with Ember Simple Auth.
I'm trying to connect my server-side application, which working on Django 1.9 with DRF, and client-side which working on Ember 2.2.
On server side I'm obtaining token on 'http://localhost:8000/api-token-auth/'. Function requires two args from request: "username" and "password". But Ember Simple Auth send POST request with args: "username[identification]" and "password[password]", and server returns "400". I think that problem with arguments keys.
POST request
Responce
I tried to change .authenticate method in oauth2-password-grant.js(i can't write custom authenticator because i'm newbee in javascript), but nothing changed.
Manually POST request returns expected answer.
Please tell me the way to solve this problem.
And please forgive me for my english.
authenticate(identification, password, scope = []) {
return new RSVP.Promise((resolve, reject) => {
const data = { 'grant_type': 'password', username: identification, password };
const serverTokenEndpoint = this.get('serverTokenEndpoint');
const scopesString = Ember.makeArray(scope).join(' ');
if (!Ember.isEmpty(scopesString)) {
data.scope = scopesString;
}
this.makeRequest(serverTokenEndpoint, data).then((response) => {
run(() => {
const expiresAt = this._absolutizeExpirationTime(response['expires_in']);
this._scheduleAccessTokenRefresh(response['expires_in'], expiresAt, response['refresh_token']);
if (!isEmpty(expiresAt)) {
response = Ember.merge(response, { 'expires_at': expiresAt });
}
resolve(response);
});
}, (xhr) => {
run(null, reject, xhr.responseJSON || xhr.responseText);
});
});
},
My variant:
const data = { 'grant_type': 'password', 'username': identification, 'password': password };
authenticate: function () {
// var username = this.getProperties('username');
// var password = this.getProperties('password');
const {username, password} = this.getProperties('username', 'password');
this.get('session').authenticate('authenticator:oauth2', username, password).catch((reason) => {
this.set('errorMessage', reason.error || reason);
});
}
It was my mistake.

Resources