Is that possible in Cypress to invoke the Chainer to obtain the results of a get request?
let chainer = cy.request(
{
url: "http://localhost:8080/v1/submit",
method: "GET",
timeout: timeouts.request,
failOnStatusCode: failOnStatusCode
})
let response = chainer.invoke() /// <---- THIS DOESN"T EXISTS
console.log(response) // I would like to use response here
You can't do it (not in the same code block).
You are thinking of the async/await pattern, but Cypress does not support it.
You can use a beforeEach() block to set a closure variable or an alias.
describe('request a variable', () => {
let response;
before(() => {
cy.request(...).then(res => response = res)
})
it('uses response', () => {
console.log(response)
})
})
or use an alias to put the response on this
describe('request a variable', () => {
before(function() {
cy.request(...).as('response')
})
it('uses response', function() {
console.log(this.response)
})
})
Related
i would like to check (in before) if the homepage is online. If it is online, the Test steps (it()) have to be run.
If the homepage is offline, the test case have to terminate, before the it() run.
describe('check Homepage', () => {
before(() => {
cy.visit('/')
cy.get('.welcomeText').then((text) => {
if(text.text() !== 'Welcome to x'){
//terminate Test Case
}
})
})
it('check a', () => {
})
it('check b', () => {
})
it('check c', () => {
})
})
Thank you!
Well, you can just let it fail :)
But the check you want can be done with cy.request()
// NOTE must be function
function checkHomepage() {
const homepageUrl = Cypress.config('baseUrl')
cy.request({
url: homepageUrl,
failOnStatusCode: false
})
.then(response => {
if (response.statusCode !== 200) { // homepage is offline
this.skip() // skip the test
}
})
}
beforeEach(checkHomepage)
You could also take a proactive approach and retry until the homepage is accessable
function checkHomepage() {
const homepageUrl = Cypress.config('baseUrl')
cy.request({
url: homepageUrl,
retryOnStatusCodeFailure: true,
retryOnNetworkFailure: true
})
}
beforeEach(checkHomepage)
export function createDashboardGroup(dashboardGroupName: string): string {
let preferredOrgId = '';
var ID = '' // it will be string;
cy.request({
method: 'GET',
url: getRequestUrl('/v2/user/_/preferences'),
})
.then((res) => {
preferredOrgId = res.body.sf_preferredOrg;
cy.request({
method: 'POST',
url: getRequestUrl(`/v2/dashboardgroup?organizationId=${preferredOrgId}`),
body: {
name: dashboardGroupName,
},
})
.then((dashboardRes) => {
ID = dashboardRes.body.id;
})
});
return ID;
}
Once I try to get the value of ID it returns an empty value. I was searching around, and could not find a solution. How I can get the value of the response and assign it to the global ID var and return it?
Please set it in an alias
.then((dashboardRes) => {
cy.wrap(dashboardRes.body.id).as('id')
})
Access it later via
cy.get('#id').then(id => {
})
Read this page to get background Variables and Aliases
You could store the variable as a global Cypress variable. In your last .then() block...
.then((dashboardRes) => {
Cypress.env('dashboardRes', dashboardRes)
})
.then(() => {
// test what you need with `Cypress.env('dashboardRes')`;
});
You could then reference it in your test by calling Cypress.env('dashboardRes');
What I did was not necessarily a global variable, but going off of this https://glebbahmutov.com/blog/cypress-tips-and-tricks/#wait-for-data
I created an object, then on the response, set a variable to the object. Then in the test, wrap the object, do .then() and then you have access to it.
Not saying this is the best way at all but it worked for my use case and may be helpful to someone
// commands.js
let data = {}
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
cy.intercept(/endpoint', (req) => {
req.continue((res) => {
data.info = res.body.info
})
})
})
export { data }
/// ----- in test file ------ ////
import { data } from '../support/commands'
it('test', () => {
cy.wrap(data).then((data) => {
console.log(data.info) // here you have access to it
})
})
I am trying to create a framework for API tests using cypress and I am facing an issue accessing the data between tests using an alias. Is there something that I am missing?
custom.js
Cypress.Commands.add('getResource', function (uri) {
cy.request({
url: uri,
method: 'GET'
}).then(function (response) {
return cy.wrap(response);
});
});
test.js
exports.__esModule = true;
context('requests', function () {
it('validate get call response', function () {
let re = cy.getResource('https://reqres.in/api/users?page=2','resp')
re.then(function (response) {
cy.wrap(response.body).as('respbody');
cy.wrap(response.status).as('respstatus');
//cy.log(JSON.stringify(response.body));
});
});
it('Tests test', function () {
cy.wait('#respbody').then((body) => {
console.log(JSON.stringify(body));
});
});
});
cypress version - 8.2.0
By design cypress cleans up aliases after each test. So you can do something like this cypress recipe
Your getResource custom command is taking just one parameter, hence we are passing just one papameter.
exports.__esModule = true;
let responseBody;
let responseStatus;
context('requests', () => {
before(() => {
cy.getResource('https://reqres.in/api/users?page=2')
.then(function(response) {
responseBody = response.body
responseStatus = response.status
})
})
beforeEach(() => {
cy.wrap(responseBody).as('responseBody')
cy.wrap(responseStatus).as('responseStatus')
})
it('Get Response status', function() {
cy.wait('#responseStatus').then((responseStatus) => {
console.log(responseStatus)
})
})
it('Get Response Body', function() {
cy.wait('#responseBody').then((responseBody) => {
console.log(JSON.stringify(responseBody))
})
})
})
Most of my api calls are a function that get called from an action like this
Action:
export const fetchSomethingAction = () => {
return (dispatch) => {
dispatch({ type: types.FETCH_SOMETHING_REQUEST })
return api.fetchSomething()
.then((response) => {
dispatch({ type: types.FETCH_SOMETHING_SUCCESS, data: response.data })
})
.catch(error => {
dispatch({ type: types.FETCH_SOMETHING_FAILURE, error })
})
}
}
And the axios request goes something like this:
export const fetchSomething = () => {
return axios({
method: 'GET',
url: `${api}/endpoint`
});
}
Now I need to make two chained requests, and have the action dispatch an error if any of the two requests fails
So how do I chain the request to achieve this?
I was doing for example
export const fetchSomething = () => {
axios({
method: 'GET',
url: `${api}/endpoint1`
})
.then(res => {
return fetchSomething2(res.param)
})
.catch(err => return err)
}
const fetchSomething2 = (param) => {
return axios({
method: 'GET',
url: `${api}/endpoint1?param=${param}`
});
}
But I get Cannot read property 'then' of undefined in the action.
Do I need two actions, one for each function? Is that the proper way to do it?
Thank you
Your fetchSomething function has an arrow function that is defined with braces, but does not have a return statement, and thus implicitly returns undefined. Change it to either not use braces, or have a return statement.
Without braces:
export const fetchSomething = () =>
axios({
method: 'GET',
url: `${api}/endpoint1`
})
.then(res => {
return fetchSomething2(res.param)
})
.catch(err => return err)
With a return:
export const fetchSomething = () => {
return axios({
method: 'GET',
url: `${api}/endpoint1`
})
.then(res => {
return fetchSomething2(res.param)
})
.catch(err => return err)
}
Here's a smaller example you can use to understand the difference:
> a = () => 1; a()
1
> a = () => { 1 }; a()
undefined
> a = () => { return 1 }; a()
1
I am trying to achieve the following functionality
Before Block : Call the Cy.visit("/login") and call a Function which will trigger a REST API and process the REST API response and set the local storage.
Only after the local storage is set click on "My Account" Link
Here is the source Code I am trying.
import * as subscriberHelpers from '../../../helpers/subscriberHelpers';
import * as localStorage from '../../../helpers/localStorage';
describe('testCode', () => {
before((done) => {
cy.visit('/login', {
timeout: 10000,
onLoad: () => {
localStorage.write("CD-Environment", Cypress.env('defaultEnvironment'));
localStorage.write("CD-Language", "en-US");
localStorage.write("CD-SystemId", "85788485-e411-48a9-b478-610c1285dc1a");
}
})
subscriberHelpers.createSubscriber().then(()=>{
done();
})
})
it('sClick on my account link', () => {
cy.get('.c-header-listItem > .c-link').contains("My Account").click();
})
})
Here is the code to createSubscriber function
export function createSubscriber() {
let URL = `SOME URL`;
let body = {
Some Body
}
return new Promise((resolve, reject) => {
request.subscriberServiceRequest(URL, body).then((response) => {
if (response.status === 200 && ("SessionId" in response.body)) {
localStorage.write("CD-SessionId", response.body.SessionId);
localStorage.write("CD-SubscriberId", response.body.Subscriber.Id);
resolve();
}
else if (response.status === 200 && ("Fault" in response.body)) {
reject(response.body.Fault.Message);
}
})
})
}
Here is the code to subscriber Service request function
export function subscriberServiceRequest(url, body, headers = null) {
let defaultHeaders = { "CD-SystemId": "85788485-e411-48a9-b478-610c1285dc1a" }
if (headers != null) {
defaultHeaders = addHeaders(defaultHeaders, headers);
}
return new Cypress.Promise((resolve, reject) => {
cy.request({
url: url,
method: 'POST',
body: body,
headers: defaultHeaders
}).then((response) => {
resolve(response);
});
})
}
When I try Executing the code I am getting following error in cypress
But the element existing in the UI
Questions:
Why I am getting the error
How to call more than one async functions
in before block
How to tell cypress to wait till the functions on
before block get processed meaning not only wait till receiving the
response but wait till the response got processed in the THEN block
To answer your first question:
Why I am getting the error
.contains() specifically searches for elements within but not including the tag it is called on. In other words, someElement.contains("My Account") will not match someElement.
What you should have instead is this:
cy.get('.c-header-listItem').contains("My Account").click();
Or simply:
cy.contains("My Account").click();