Cypress waiting until graphql query finishes - graphql

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');
});
});

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)

Do a HTTP Post in Cypress without using a test

I have a Cypress test:
describe('Create a session ', () => {
it('creates a session', () => {
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/user/login/`,
form: true,
body: {
email: Cypress.env('email'),
password: Cypress.env('password'),
},
}).then((response) => {
expect(response.status).to.eq(200);
cy.task('setKey', response.body.data.key);
});
});
});
This POST returns some session data needed to create a dummy account:
describe('Create a company ', () => {
it('creates a company', () => {
cy.task('getKey')
.then((data: Key) => {
key = data;
})
.then(() => {
createNonce();
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/cli/`,
headers: {
'X-Auth-Timestamp': epochTime(),
'X-Auth-Key': key.key,
'X-Auth-Nonce': nonce,
'X-Auth-Signature': createSignature(),
},
body: {
args: ['seeder', 'create', 'abc1'],
},
}).then((response) => {
expect(response.status).to.eq(200);
// TODO: we need some REST endpoints to return a JSON object instead of a string
data = JSON.parse(response.body.substring(response.body.indexOf('{')));
cy.task('setCompany', data);
});
});
});
});
I'm not sure I need these functions to be tests since they don't test anything, but just do a POST request. Is it possible to maybe move the functionality into a cypress task?
You can add the post request in your commands file:
function postRequest() {
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/cli/`,
headers: {
'X-Auth-Timestamp': epochTime(),
'X-Auth-Key': key.key,
'X-Auth-Nonce': nonce,
'X-Auth-Signature': createSignature(),
},
body: {
args: ['seeder', 'create', 'abc1'],
},
})
}
Cypress.Commands.add('postRequest', postRequest)
An assuming all the rest of your code is fine, and you want only to abstract the logic; then in your test you can invoke that command:
describe('Create a company ', () => {
it('creates a company', () => {
cy.task('getKey')
.then((data: Key) => {
key = data;
})
.then(() => {
createNonce();
cy.postRequest().then((response) => {
expect(response.status).to.eq(200);
data = JSON.parse(response.body.substring(response.body.indexOf('{')));
cy.task('setCompany', data);
});
});
});
});
You can move these into before() or beforeEach() so they will be separate from your tests.
describe('Create a company ', () => {
before(() => {
cy.task('getKey')
.then((data: Key) => {
key = data;
})
.then(() => {
createNonce();
cy.request({
method: 'POST',
url: `${Cypress.env('apiURL')}/api/v1/cli/`,
headers: {
'X-Auth-Timestamp': epochTime(),
'X-Auth-Key': key.key,
'X-Auth-Nonce': nonce,
'X-Auth-Signature': createSignature(),
},
body: {
args: ['seeder', 'create', 'abc1'],
},
}).then((response) => {
expect(response.status).to.eq(200);
// TODO: we need some REST endpoints to return a JSON object instead of a string
data = JSON.parse(response.body.substring(response.body.indexOf('{')));
cy.task('setCompany', data);
});
});
})
it('creates a company', () => {
//test code
});
});

Invoke Chainer object in Cypress

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)
})
})

Not able to use alias across tests in Cypress

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))
})
})
})

Apollo Client delays request

I have a very weird issue with Apollo Client.
We are using apollo-client#1.9.3 with react (react-apollo#1.4.16).
In our project, we notice that apollo always wait for 1 to 2 seconds before sending the request.
Below is a screenshot of the situation:
This is how our client config looks like:
const customNetworkInterface = {
query: request =>
fetch('/graphql', {
method: 'POST',
credentials: 'include',
mode: 'cors',
cache: 'default',
headers: {
Accept: '*/*',
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify({
...request,
query: print(request.query),
}),
})
.then(resp => resp.json())
.then(({ data, errors }) => {
if (errors) {
const userErrors = errors
.filter(({ code }) => +code >= 400 && +code <= 401)
.map(({ message }) => message)
.join('\n');
const serverErrors = errors
.filter(
({ code }) => !code || (+code < 400 && +code > 401)
)
.map(({ message }) => message)
.join('\n');
if (serverErrors.length > 0) {
error(serverErrors);
if (isProduction) {
window.triggerAlert(
'danger',
'The server encountered an error. Our technical team has been notified.'
);
} else {
window.triggerAlert('danger', serverErrors);
}
} else if (userErrors.length > 0) {
window.triggerAlert('danger', userErrors);
}
}
return { data, errors };
}),
};
const networkInterface = createNetworkInterface({
uri: '/graphql',
opts: {
credentials: 'same-origin',
},
});
networkInterface.useAfter([
{
applyAfterware({ response }, next) {
response
.clone()
.json()
.then(responseJson => {
if (responseJson.errors) {
error(
responseJson.errors
.map(({ message }) => message)
.join('\n')
);
}
next();
});
},
},
]);
export const client = new ApolloClient({
networkInterface: customNetworkInterface,
queryDeduplication: true,
addTypename: true,
});
Then the query code is with react-apollo:
graphql(RaceResultsQuery, {
props: ({ ownProps, data }) => ({
race_results: _.get(data, 'me.my_race_results', []),
}),
}),
This would need a complete, minimal example to provide an answer for sure (delete as much of your code as possible with the issue still happening).
My guess would be that you have a parent component with a very expensive query and it only renders the component with the delayed query after the expensive query returned.

Resources