Cypress, loop till response of api call has expected value - cypress

Im making an api call with cypress. This apis returns status of operation happening server side. Sample response {'status':'13'}. This means job completed 13%. I have to wait till I get status as 100 before performing other operations.
...
cy.request(getStatusUrl)
.then(response => {
console.log(response.body.status);
});
...
I have keep polling getStatusUrl till status comes as "100".
How do I get the value of response.body.status out of then{...} to use in a loop?

function pollProgress(url, done) {
cy.request(url)
.then(response => {
const progress = response.body.status;
// Poll every 500ms until progress reaches 100%
setTimeout(() => {
if (progress < 100) {
pollProgress(url, done);
} else {
done({ status: 'OK' });
}
}, 500);
})
.catch(() => {
done({ status: 'ERROR' })
})
}
...
new Promise((resolve, reject) => {
pollProgress(getStatusUrl, ({ status }) => {
if (status == 'OK') ? resolve() : reject();
});
})
.then(() => {
// it's 100% here if there's no error
})

Related

Cypress: Availability check before Test Case run

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)

Cypress waiting until graphql query finishes

I'm trying to wait for a specific graphql request to finish before I check for an element on the page but it doesn't seem to wait the way I have it set up
describe('CopyrightModule', () => {
it('edit, cancel, edit, save', () => {
cy.intercept(
{
method: 'POST',
url: '/graphql',
},
req => {
console.log(req.body.id);
console.log(req);
if (req.body.id === 'TakedownUserRendererQuery') {
req.alias = 'TakedownUserRendererQuery';
}
},
);
cy.visit('/');
cy.get(selectors.DMCA_LINK).click({ force: true });
cy.contains('My Requests').click();
cy.get(selectors.REQUEST_ROW)
.first()
.click();
cy.wait('#TakedownUserRendererQuery');
cy.get(selectors.COPYRIGHT_EDIT).click();
cy.contains('Cancel').click();
cy.get(selectors.COPYRIGHT_EDIT).click();
cy.contains('div', 'Owner Website URLs')
.find('input')
.first()
.type('8000-1612023');
});
});

socket.io client events are not firing

I am trying to run my client without my server connected (on purpose) and catch ERR_CONNECTION_REFUSED error and display it to the user. I read here that this can be achieved using socket events, specifically connect_error
Below in my code, I can never get the events to fire and display the console logs inside. logging this.io.socket prints stuff but none of the events do.. why is that?
$.ajax(args)
.done((msg) => {
this.io.socket.on('connect', msg => {
console.log('connect socket io', msg)
})
resolve(msg);
})
.fail((jqXHR, msg) => {
return new Promise((resolve, reject) => {
console.log('inside promise of fail() - this.io.socket', this.io.socket) // this will log data to console
this.io.socket.on('connect_error', msg => {
console.log('connect_error socket io', msg)
})
this.io.socket.on('connect_failed', (msg) => {
console.log('connect_failed', msg);
});
// return some error here for user
})
});
From what I see, you are attempting to wire up the event handlers only if you get a bad response from your first ajax call. This will not result in any of the socket.io event handlers being initiated.
Move the event handler into the code where you initialize the socket instance.
See below for a full example where all the manager and socket events will be logged to console.
$.ajax(args)
.done((msg) => {
// connect to your server
const socket = io('http://localhost:3000', {
transports: ['websocket']
});
// manager events
//_________________________________________________________________________________________________
socket.io.on('connect_error', (err) => {
console.error(`manager:connect_error ${err}`);
});
socket.io.on('connect_timeout', () => {
console.error(`manager:connect_timeout`);
});
socket.io.on('reconnect_attempt', (attempt) => {
console.error(`manager:reconnect_attempt ${attempt}`);
});
socket.io.on('reconnecting', (attempt) => {
console.error(`manager:reconnecting ${attempt}`);
});
socket.io.on('reconnect_error', (err) => {
console.error(`manager:reconnect_error ${err}`);
});
socket.io.on('reconnect_failed', () => {
console.error(`manager:reconnect_failed`);
});
//_________________________________________________________________________________________________
// socket events
//_________________________________________________________________________________________________
socket.on('connect', () => {
console.log(`socket:connect ${socket.connected}`);
});
socket.on('connect_error', (err) => {
console.error(`socket:connect_error ${err}`);
});
socket.on('connect_timeout', (timeout) => {
console.error(`socket:connect_timeout ${timeout}`);
});
socket.on('error', (err) => {
console.error(`socket:error ${err}`);
});
socket.on('disconnect', (reason) => {
console.info(`socket:disconnect ${reason}`);
if (reason === 'io server disconnect') {
// the disconnection was initiated by the server, you need to reconnect manually
socket.connect();
}
// else the socket will automatically try to reconnect
});
socket.on('reconnect', (attempt) => {
console.error(`socket:reconnect ${attempt}`);
});
socket.on('reconnect_attempt', (attempt) => {
console.error(`socket:reconnect_attempt ${attempt}`);
});
socket.on('reconnecting', (attempt) => {
console.error(`socket:reconnecting ${attempt}`);
});
socket.on('reconnect_error', (err) => {
console.error(`socket:reconnect_error ${err}`);
});
socket.on('reconnect_failed', () => {
console.error(`socket:reconnect_failed`);
});
//_________________________________________________________________________________________________
// custom events
//_________________________________________________________________________________________________
socket.on('hello', (message) => {
console.info(message);
socket.emit('hello', {foo: 'baz'});
});
//_________________________________________________________________________________________________
resolve(msg);
})
.fail((jqXHR, msg) => {
console.error(msg);
});

I can't get the js response in variable that say is null

When I connect axion in get method I get a response from my api and I want to print info on the website.
I tried to change this line:
.then(response => (this.username= response.data.username)) or this
.then(response => (this.username= response.data[0].username)) or this
.then(response => (this.username= response.data.username[0]))
Script
<script>
import axios from 'axios';
export default {
name: "acount",
el: '#app',
data() {
return {
username: null,
pseudo: null,
email: null,
date: null,
};
},
mounted () {
axios
.get('http://127.0.0.1:8080/api/user/65', {
headers: {
token: ''
}
})
.then(response => (this.username= response.data[0].username[0]))
.then(response => (this.pseudo = response.data.pseudo))
.then(response => (this.email = response.data.email))
.then(response => (this.date = response.data.create_at))
}
}
</script>
To chain promises, each function within then() needs to return a value. other than that we could only help, if we would know how the actual response looks like.
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)
alert(result); // 1
return result * 2;
}).then(function(result) { // (***)
alert(result); // 2
return result * 2;
}).then(function(result) {
alert(result); // 4
return result * 2;
});
This arrow function uses implicitly returned value:
.then(response => (this.username= response.data[0].username[0]))
This results in having response parameter in next then equal to this.username. To avoid such mistakes, ESLint no-return-assign rule can be used.
Instead, it should be:
.then(response => {
this.username= response.data[0].username[0];
return response;
})
Multiple then are unnecessary because there are no multiple promises to chain. They could be rewritten to single then:
axios.get(...)
.then(response => {
this.username= response.data[0].username[0]);
...
});

Cypress not waiting for Before block to complete

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();

Resources