Wait for specific response in XHR polling with Cypress - javascript

I have a cypress spec with which I want to test a function on my site which polls a third party API until it receives a correct answer and then shows more information for the user to continue with the function.
I start my spec with
cy.server();
cy.route('GET', '**/that-other-api/**').as('otherApi');
I know that this part works. The route is listed in the top of the Cypress test GUI, and my otherApi alias is attached to the XHR requests when they are listed in the command list when running.
When the user (or my test) clicks a button the site will start polling that endpoint. When I receive a status: success in the response, the user (or my test) is provided with a filled dropdown of options and can continue.
How can I get Cypress to wait until I get that specific response from the XHR request (or reaches a cypress timeout) and then continue onwards?
The Network request documentation doesn't explain if this is possible or not. I have tried
cy.wait('#billectaAccounts').should('have.property', 'response.body.status', 'success');
and just to see if stuff works
cy.wait('#billectaAccounts').should('have.property', 'status', 201);
which both throw an error:
InvalidStateError: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'json').
Logging the response with
cy.wait('#billectaAccounts').then(console.log);
logs the response and shows that my status variable is there, but is pending since it's only on the first request.
{
"xhr": {
"method": "GET",
"url": "https://myapi/longToken",
"id": "xhr193"
},
"id": "xhr193",
"url": "https://myapi/longToken",
"method": "GET",
"status": 200,
"statusMessage": "200 (OK)",
"request": {
"headers": {
"Accept": "application/json, text/plain, */*"
},
"body": null
},
"response": {
"headers": {
"cache-control": "max-age=0, private, must-revalidate",
"connection": "close",
"content-type": "application/json; charset=utf-8",
"date": "Tue, 24 Mar 2020 08:32:09 GMT",
"etag": "W/\"f0d6999f3be78c3dc8eab419745ec489\"",
"referrer-policy": "strict-origin-when-cross-origin",
"server": "Cowboy",
"vary": "Origin",
"via": "1.1 vegur",
"x-content-type-options": "nosniff",
"x-download-options": "noopen",
"x-frame-options": "SAMEORIGIN",
"x-permitted-cross-domain-policies": "none",
"x-request-id": "id",
"x-runtime": "0.006788",
"x-xss-protection": "1; mode=block"
},
"body": {
"id": 721,
"public_id": "longTokenId",
"bank": "bank-id",
"ssn": "ssn-number",
"status": "pending",
"created_at": "2020-03-24T09:32:05.362+01:00",
"updated_at": "2020-03-24T09:32:06.028+01:00",
"account_numbers": [],
"token": "pollingToken"
}
},
"duration": 230
}
I would prefer to not stub the response, It's nice to have the end to end test to that API.
Any help appreciated!

Related

Citi Bank Open API Authorization

I am trying to use the Citi Bank Open API in my React Native mobile app. I was able to call the API to let user sign in with their Citi Bank account and get the client authorization code. However, when I was trying to call another API for validating the code I got, it returned a weird error without any description.
I suspect problems may be caused by:
my app is still in development stage
I didn't do the calling on the redirect uri, but the domain is definitely the same
The API is supposed to return an access token for further interaction, but all I got is the error. I wanna know what might be the possible mistakes.
This is my first time trying to use an open API inside my app. Any suggestion will be much appreciated.
Official docs from Citi (may need to register an account):
https://sandbox.developerhub.citi.com/api/hong-kong/retail-bank/identity-security/authorize/documentation
Calling the API:
fetch(
"https://sandbox.apihub.citi.com/gcb/api/authCode/oauth2/token/hk/gcb",
{
method: "POST",
body: new URLSearchParams({
grant_type: "authorization_code",
code: auth_code,//got from the response of GET /authCode/oauth2/authorize
redirect_uri: "http://localhost:19000/redirect",
}),
headers: new Headers({
"Cross-Domain": true,
Accept: "application/json",
Authorization:
"Basic " + btoa(CITI_CLIENT_ID + ":" + CITI_CLIENT_SEC),
"Content-Type": "application/x-www-form-urlencoded",
}),
}
)
.then((data) => {
console.log(data);
data.json();
})
.then((result) => {
console.log(result);//undefined
});
Response:
Response {
"_bodyBlob": Blob {
"_data": Object {
"__collector": null,
"blobId": "f09ce99b-1a3b-4251-9a73-5a4a809a6296",
"offset": 0,
"size": 88,
},
},
"_bodyInit": Blob {
"_data": Object {
"__collector": null,
"blobId": "f09ce99b-1a3b-4251-9a73-5a4a809a6296",
"offset": 0,
"size": 88,
},
},
"bodyUsed": false,
"headers": Headers {
"map": Object {
"access-control-allow-credentials": "true",
"access-control-allow-headers": "",
"access-control-allow-methods": "",
"access-control-allow-origin": "",
"access-control-expose-headers": "",
"connection": "close",
"content-length": "88",
"content-type": "application/json",
"date": "Thu, 24 Mar 2022 06:37:39 GMT",
"set-cookie": "CITI_SITE=gtdc; expires=Thu, 24-Mar-2022 06:57:39 GMT; path=/; domain=sandbox.apihub.citi.com; secure; HttpOnly",
"x-akamai-citisite": "GTDC",
"x-backside-transport": "FAIL FAIL,FAIL FAIL",
"x-global-transaction-id": "6e68aa42623c11b387504e5d",
},
},
"ok": false,
"status": 400,
"statusText": "",
"type": "default",
"url": "https://sandbox.apihub.citi.com/gcb/api/authCode/oauth2/token/hk/gcb",
}

Get Data from an Object in the Browser

How can I get an object from my browser / get the data stored in the object from my browser?
The user presses submit button after filling out a form with a bad credit card number (a scenario I am testing), which triggers a jQuery function SubmitAPI() (code below).
Google Chrome console displays 400 Bad Request error (because the credit card number is bad) as well as an API Response holding the object with the declined credit card data (response below)
I specifically need to grab "response_type":"D","response_code":"U20","response_desc":"INVALID CREDIT CARD NUMBER" because I want to display this error message to the user. How can I do this in jQuery?
I have tried for hours to figure this out. I use response.response.response_type to get the Response Type when the transaction is successful (approved credit card). However with a bad credit card number, this same attempt results in "undefined". So, instead, I just want to grab the data from my Google Chrome browser that managed to get the Response Code response.
PART 1: jQuery Code (Directly from the API's documentation - except I changed the credit card to be a bad number)
function SubmitAPI() {
var settings = {
"url":
"https://sandbox.forte.net/api/v3/organizations/org_ID/locations/loc_ID/transactions",
"method": "POST",
"headers": {
"X-Forte-Auth-Organization-Id": "org_ID",
"Authorization": "ID",
"Content-Type": "application/json"
},
"data": JSON.stringify({ "action": "sale", "authorization_amount": 102.45, "subtotal_amount": 99.95, "billing_address": { "first_name": "Jennifer", "last_name": "McFly" }, "card": { "card_type": "visa", "name_on_card": "Jennifer McFly", "account_number": "41111sdf11111111", "expire_month": "12", "expire_year": "2017", "card_verification_value": "123" } }),
};
$.ajax(settings).always(function (response) {
console.log(response);
});
}
PART 2: Console Response:
400 (Bad Request)
PART 3: Response Object in Browser:
{"location_id":"loc_241789","action":"sale","authorization_amount":102.45,"entered_by":"59ae172b3bd78bed493ecd5892975764","billing_address":{"first_name":"Jennifer","last_name":"McFly"},"card":{"name_on_card":"Jennifer McFly","last_4_account_number":"1111","masked_account_number":"****1111","expire_month":12,"expire_year":2017,"card_type":"visa"},"response":{"environment":"sandbox","response_type":"D","response_code":"U20","response_desc":"INVALID CREDIT CARD NUMBER"}}
Using error handler for the Ajax call and was able to get the error message with no issues.
var settings = {
"url": "https://sandbox.forte.net/api/v3/organizations/org_381529/locations/loc_241789/transactions",
"method": "POST",
"headers": {
"X-Forte-Auth-Organization-Id": "org_381529",
"Authorization": "Basic NTlhZTE3MmIzYmQ3OGJlZDQ5M2VjZDU4OTI5NzU3NjQ6ZWUwZTZiZDA4ZThlMWNhNWQ3MzUyNGU0ZWU5ZDFjNTg=",
"Content-Type": "application/json"
},
"data": JSON.stringify({
"action": "sale",
"authorization_amount": 102.45,
"subtotal_amount": 99.95,
"billing_address": {
"first_name": "Jennifer",
"last_name": "McFly"
},
"card": {
"card_type": "visa",
"name_on_card": "Jennifer McFly",
"account_number": "41111sdf11111111",
"expire_month": "12",
"expire_year": "2017",
"card_verification_value": "123"
}
}),
};
$.ajax(settings).error(function(xhr) {
console.log("Error", xhr.responseJSON.response.response_desc);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

how do I grab data from an API that returns CSV file

I am working with Pluralsight API and their API responds CSV files as results, which I would like to grab this data from response and print out.
this is the URL of the Pluralsight API:
https://app.pluralsight.com/plans/api/reports/docs
and this is the code I am trying to do:
request
.get('https://api.pluralsight.com/api-v0.9/users?planId=x&token=y')
.on('response', function (response) {
res.json(response);
})
The response does not show any data except for the data as below:
{
"statusCode": 200,
"headers": {
"cache-control": "private",
"content-disposition": "attachment; filename=Users.csv",
"content-type": "text/csv",
"date": "Fri, 27 May 2016 03:42:06 GMT",
"ps-build": "2016.5.1849.0",
"ps-node": "0Q5JR",
"ps-responsetime": "00:00:00.1406230",
"content-length": "11391",
"connection": "Close"
},
"request": {
"uri": {
"protocol": "https:",
"slashes": true,
"auth": null,
"host": "api.pluralsight.com",
"port": 443,
"hostname": "api.pluralsight.com",
"hash": null,
"search": "?planId=x&token=y",
"query": "planId=x&token=y",
"pathname": "/api-v0.9/users",
"path": "/api-v0.9/users?planId=x&token=y",
"href": "https://api.pluralsight.com/api-v0.9/users?planId=x&token=y",
},
"method": "GET",
"headers": {}
}
}
Is there anyway that I get get the file from attachment and extract it?
Thanks
Request body is accessible through data and end events.
var body = [];
request
.get('https://api.pluralsight.com/api-v0.9/users?planId=x&token=y')
.on('data', function (chunk) {
body.push(chunk);
})
.on('end', function () {
body = body.join('');
// body now contains csv contents as a string
});

Problems using api auth with Google Calendar JS API

I'm working on a small website that can do stuff with the Google Calendar API. I've posted it over here: http://evansiroky.com/temp-gcal-question/tests/ Whenever I try to authorize, it doesn't seem to matter what clientId I use, it always says it is authorized. Also, it doesn't seem to matter if immediate is set to true or false. Here is the authorization code:
gapi.auth.authorize({
client_id: clientId,
scope: ['https://www.googleapis.com/auth/calendar'],
immediate: immediate
}, function(authResult) {
if(authResult && !authResult.error) {
isAuthorized = true;
} else {
isAuthorized = false;
}
if(callback) {
var out = isAuthorized ? null : authResult;
callback(out);
}
});
However, once I try to list events of a calendar, I get a dailyLimitExceededUnreg error. Here is the code for listing events:
gapi.client.load('calendar', 'v3', function() {
var request = gapi.client.calendar.events.list(_.extend({
calendarId: 'primary',
orderBy: 'starttime',
singleEvents: true,
showDeleted: true,
}, options.data));
request.then(function(resp) {
options.success(resp);
}, function(reason) {
options.failure(reason);
});
});
And here is the error that is returned:
{
"result": {
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
},
"body": "{\n \"error\": {\n \"errors\": [\n {\n \"domain\": \"usageLimits\",\n \"reason\": \"dailyLimitExceededUnreg\",\n \"message\": \"Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.\",\n \"extendedHelp\": \"https://code.google.com/apis/console\"\n }\n ],\n \"code\": 403,\n \"message\": \"Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.\"\n }\n}\n",
"headers": {
"date": "Fri, 02 Oct 2015 19:08:41 GMT",
"content-encoding": "gzip",
"server": "GSE",
"vary": "Origin, X-Origin",
"content-type": "application/json; charset=UTF-8",
"cache-control": "private, max-age=0",
"content-length": "215",
"expires": "Fri, 02 Oct 2015 19:08:41 GMT"
},
"status": 403,
"statusText": "OK"
}
What am I doing wrong?

JSONP Object Error

I am trying to make a cross domain request to send/recieve some data. I can't get past the object error. Before I was getting the No Transport Error but adding Query.support.cors = true; solved this issue.
var url = "http://CROSSDOMAINSERVER:PORT/Service1.svc/GetDataUsingDataContract";
$.ajax({
type: 'GET',
url: url,
data: 'tool=1&product=Some%20Product&details=9&bogus=should%20not%20pass%20validation',
datatype: "jsonp",
contentType: "application/json",
success: function (response) {
alert(response.data);
},
error: function (error) {
alert(error.statusText);
}
});
If I type the url out in a browser:
http://CROSSDOMAINSERVER:PORT/Service1.svc/GetDataUsingDataContract?&tool=1&product=Some%20Product&details=9&bogus=should%20not%20pass%20validation
I get the correct response.
{"d":{"__type":"ClientSideData:#ProdResourceToolService","details":"9","product":"Some Product","result":"1","site":"Somewhere, SD","systime":"2\/6\/2013 2:50:20 PM","team":"0000000000","tool":"1","user":"username"}}
When I use ajax it does not submit it to the database or return data, just object error. Does anyone have any suggestions on how to get around this?
I should also specify if I remove http://CROSSDOMAINSERVER:PORT/ from var url when debugging locally I get the correct json response. Why does cross domain not work?
This is your current response:
{
"d": {
"__type": "ClientSideData:#ProdResourceToolService",
"details": "9",
"product": "Some Product",
"result": "1",
"site": "Somewhere, SD",
"systime": "2/6/2013 2:50:20 PM",
"team": "0000000000",
"tool": "1",
"user": "username"
}
}
This is a valid JSON string. However, its not valid JSONP. If possible, make your service wrap the json in a function:
responseFunc({
"d": {
"__type": "ClientSideData:#ProdResourceToolService",
"details": "9",
"product": "Some Product",
"result": "1",
"site": "Somewhere, SD",
"systime": "2/6/2013 2:50:20 PM",
"team": "0000000000",
"tool": "1",
"user": "username"
}
});
And in your $.ajax() call, add a property: jsonpCallback: 'responseFunc'.
Also, I would suggest passing the data as an object:
data: { tool: 1, product: 'Some Product' } //etc...
If you can access the service from the serverside without any issues you could create a httphandler (.ashx for example) and let it generate the JSON for you. Then you wouldn't have to deal with the cross domain issues on the client side.

Categories

Resources