Cypress stubbing XHR response based on request - url-routing

I am beginer in Cypress and looking for help with network stubbing.
My UI tiggers 3 API calls concurrently upon clicking on a button in the UI. All 3 API are of same endpoint, BUT each of them have different request and response.
I am able to stub the json response using cy.fixture, cy.server() and cy.route().
My need is to 'only stub the 3rd XHR call response', but, my test stubs all three because of the same endpoint.
Any suggessions on how could I test it using any condition ? example - Only stub the call if the parameters of 'request'XHR is 'XXX'?
I tried using before and after the .click() of submit button but that didn't work.
cy.fixture('myfixture').then(jsonresponse => {
function FixtureController(request, response) {
if (cy.url().request.body.contains("XXX")) {
cy.server()
cy.route('POST', 'URL', jsonresponse).as('myalias')
I appreciate any support.
Thanks!

You can use cy.intercept to match based on several things, including query parameters.
cy.intercept({
url: 'http://example.com/search*',
query: { q: 'expected terms' },
}, { fixture: 'myfixture' } )
If you need to match on the request body contents, you can use a route handler to specify.
cy.intercept('http://example.com/search*', (req) => {
if (req.body.contains('some string') {
req.reply({ statusCode: 200, fixture: 'myfixture' });
} else {
req.reply(); // not providing any input forwards the request as normal
}
});
Check out the cy.intercept documentation for more info.

Related

How to make assertions on graphql query variables when using Mock Service Worker?

When we are mocking out a graphql query with a mock service worker (MSW), we want to assert that the variables passed to the query have certain values. This goes beyond the type validation with the typescript typings. We are using jest with MSW. Do you spy on MSW to make those assertions? or is there another way to expect req.variables to have a certain value.
graphql.query<SaveContent, SaveContentVariables>('SaveContent', (req, res, ctx) => {
return res(
ctx.data({
saveContent: {
success: true,
id: req.variables.id,
errors: [],
},
})
);
})
Mock Service Worker recommends basing your request assertions on the UI (read more in the Request assertions recipe). In most cases, if your request/response data is correct, then your UI would be correct in the test. The same is true for the opposite scenario. Always assert the data-driven UI, when you can.
In your case, you wish to assert the query variables in a request. Consider returning data based on those variables that later result in a corresponding UI.
When you find it absolutely necessary to perform direct request/response assertions apart from the UI, use the Life-cycle events that allow executing arbitrary logic in response to various MSW events. For example, this is how you can assert request variables in your test:
const server = setupServer(...handlers)
it('saves the content', async () => {
expect.assertions(1)
server.on('request:match', (req) => {
expect(req.variables).toEqual({ id: 'abc-123' })
})
await performQuery(...)
})

How to extend the ion-loading till page renders in ionic-5

I've to make 3 back-end api-call before showing the UI screen. So, I used the ion-loading below snippet,
I'm presenting the loader in 1st backend call and it get closed in the first call itself. But I've to close the loader in third api call to show the screen.
How to extend the loader till the last api call,
this.presentLoading();
async presentLoading() {
this.loading = await this.loadingController.create({
spinner: null,
cssClass: 'custom-class custom-loading',
});
await this.loading.present();
}
One way to accomplish this would be to call .then() on loadingController.create() and then process all your api calls inside there. Here's how I would organize it so that your loading controller is dismissed properly either when the 3 api calls succeed or when one of them fails. This setup assumes your api call functions return promises.
this.loadingController.create({
message: 'Loading, please wait...'
}).then((loading) => {
loading.present();
Promise.all([apiCallOne(), apiCallTwo(), apiCallThree()])
.catch((err) => {
console.log(err);
loading.dismiss();
})
.then((results) => {
// do something with results ...
loading.dismiss();
});
});

How do I correctly call an HTTP API GET request to weatherstack?

I'm trying to do a GET request to api.weatherstack.com (see documentation).
Here's my react effect hook:
useEffect(() => {
if (country === undefined) return
console.log(country.name)
axios
.get('http://api.weatherstack.com/current', {
params: {
access_key: api_key,
query: country.name
}
})
.then(response => {
console.log(response.data)
setWeather(response.data)
})
}, [api_key, country])
However, every single time I run this, I get this error:
{ code: 105, type: "https_access_restricted", info: "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption." }
Doing the API call through my browser or through Postman works perfectly, so I'm thinking that there's probably an issue with how I'm using React or Axios.
Also, this API call works about 10% of the time, so I'm confused about why that might happen too.
I think it's because you are using the free plan
weatherstack.com https encryption
Try:
.get("http://api.weatherstack.com/current?access_key=YOUR_ACCESS_KEY&query=country.name)
on line 5.
Remove the params: {} on lines 6-9
Try: API Request
url: http://api.weatherstack.com/current?access_key=YOUR_ACCESS_KEYf&query=New%20York
From Documentation:
https://weatherstack.com/documentation

When attempting to stub a request in Cypress IO (JS) against a React app using fetch, the requests still call through to the server

I'm using Cypress to create some specs against my React app. My react app uses fetch to fetch data from an external api (isomorphic-fetch)
The fetch requests in my app are like so
import fetch from 'fetch'
...
fetch('http://www.external-server.com/ideas.json')
.then((response) => {
if (response.status >= 400) {
}
return response.json().then((result) => {
this._data = result
this._data((ele) => ele.key = ele.id)
});
})
In my Cypress specs, I want my regular specs to hit my lcoahost:3000 to get the initial page (which houses my React app). My react app in turn would normally make an external request (http://www.external-server.com/ideas.json) but in my specs I want to stub out that request and have that endpoint return fake data in my specs only.
The Cypress docs for cy.route() here, describe that I should be able to do something like
cy.server()
cy.route('http://www.external-server.com/ideas.json', [
{
id: 1,
name: 'john'
}
])
I attempted to put this into a beforeEach that runs in the context of my spec (thus running before every spec).
You will note that when I run the specs in the Cypress test running, it appears in the console output that the endpoint SHOULD be stubbed.
However, by examination, I can see that my app is in fact making the request to the real server, and calling the real endpoint (not stubbing it).
I tested several times and I am certain this is the behavior.
I found a solution online I will post below to answer my question
the solution is add to cypress/support/commands.js
this small hack will turn the window fetch into a no-op (disabling it) and will allow the native stubbing in Cypress to work without any alterations.
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
const opts = Object.assign({}, options = {}, {
onBeforeLoad: (window, ...args) => {
window.fetch = null;
if (options.onBeforeLoad) {
return options.onBeforeLoad(window, ...args);
}
},
});
return originalFn(url, opts);
});

How to call a function upon http get or post?

I'm sure this is a stupid question but I am very new to the backend so please forgive me.
I am building an angularjs app with express/node also and am trying to integrate PayPal (as a Node.js SDK), what I want is to call the pay method on the SDK from an angular controller and I am doing as follows:
On button click:
// controller
$scope.pay = function(amount) {
PaymentFactory.doPayment(amount);
}
Payment Factory:
// PaymentFactory
return {
doPayment: function(amount) {
$http.get("../../../server/payments/paypal.js")
.then(function(response) {
console.log( response );
})
}
}
Then the server-side file is as below:
require('paypal-adaptive');
var app = require('../../server.js');
var PayPal = require('paypal-adaptive');
var paypalSdk = new PayPal({
userId: 'userid',
password: 'password',
signature: 'signature',
sandbox: true //defaults to false
});
var payload = {
requestEnvelope: {
errorLanguage: 'en_US'
},
actionType: 'PAY_PRIMARY',
currencyCode: 'GBP',
feesPayer: 'EACHRECEIVER',
memo: 'Chained payment example',
cancelUrl: 'returnUrl,
returnUrl: 'cancelUrl',
receiverList: {
receiver: [
{
email: 'email1',
amount: '3.40',
primary:'true'
},
{
email: 'email2',
amount: '1.20',
primary:'false'
}
]
}
};
paypalSdk.pay(payload, function (err, response) {
if (err) {
console.log(err);
} else {
// Response will have the original Paypal API response
// But also a paymentApprovalUrl, so you can redirect the sender to checkout easily
console.log('Redirect to %s', response.paymentApprovalUrl);
return response;
}
});
Of course the get request just returns a string of the server-side file contents, I understand why the above doesn't work but not sure how one would make it work. My aim is to call the PayPal SDK from the angular factory and get back the response so that I can redirect a user to a URL. A direct solution would be helpful but even more so I need pointers to the principles that I am not understanding here as far as how one should call functions upon user actions to get this data from the server side. I have tried searching but I don't really the language to use in my search.
All you need to do is use curl (node-curl npm module). Using curl will help you post data to your paypal url and get back the response. Now you need to handle this response from paypal and accordingly generate your own response to be received by the angular http method.

Resources