How to check response's status code in zapier's test cases - zapier

I am writing some code to test action in Zapier's CLI. I want to add one more condition here something like response.status == 200 or 201; to check API response code is 200 or 201.
How can I do it? when I log response it gives me whole JSON object that
API is returning.
describe("contact create", () => {
it("should create a contact", done => {
const bundle = {
inputData: {
firstName: "Test",
lastName: "Contact",
email: "Contact#test.com",
mobileNumber: "+12125551234",
type: "contact"
}
};
appTester(App.creates.contact.operation.perform, bundle)
.then(response => {
// Need one more condition whether response status is 200 or 201.
response.should.not.be.an.Array();
response.should.have.property('id');
done();
})
.catch(done);
});
});

appTester returns the result of the perform method, which isn't an API response. It's the data that's passed back into Zapier.
The best thing to do is to add a line like this to your perform:
// after your `z.request`
if (!(response.status === 200 || response.status === 201)) {
throw new Error('need a 200/201 response')
}
That will ensure you're getting exactly the response you want. But, more likely, you can add a response.throwForStatus() to make sure it's not an error code and not worry if it's exactly 200/201.

Related

Cypress: Is it possible to complete a test after failure

Overview
I want to automatically test all 200 pages of our website every week after the update to see if the update broke any of them
The test case
Login and go to the sitemap
Get the URLs and check each for their HTTP status
The code
it('check HTTP status', () => {
cy.visit(Cypress.config('siteMapUrl'))
cy.get('.portlet-separator').should('contain', 'Available Links')
cy.get('.inputwrapper>a')
.each(($el, index, $list) => {
if($list){
cy.get($el)
.invoke('attr', 'href')
.then(href => {
cy.request(Cypress.config('url')+href)
.should('have.property', 'status', 200)
})
}
})
What happens:
Once an URL returns anything else than status 200 the test fails.
What I would like:
I would like Cypress to iterate through the complete list of URLs before returning the URLs that failed.
Why?
If more than one URL in the list is broken, I will not find the 2nd broken URL with this test until our devs have fixed the first one. Yet I need to produce a list with all broken URLs at the beginning of the week
I have already seen this answer but I would like to know if there is a different solution before I try to implement this
You should not use .should() after each URL - that will fail immediately, even if setting failOnStatus: false.
Instead save the results and check at the end.
const failed = []
cy.get(".inputwrapper>a").each(($el, index, $list) => {
cy.get($el)
.invoke("attr", "href")
.then((href) => {
cy.request({
url: Cypress.config("url") + href,
failOnStatusCode: false,
})
.its('status')
.then(status => {
if (status !== 200) {
failed.push(href)
}
})
})
}
})
.then(() => {
// check inside then to ensure loop has finished
cy.log(`Failed links: `${failed.join(', ')`)
expect(failed.length).to.eq(0)
})

Problem when displaying errors in friendly way in Zapier

I'm trying to display errors in a friendly way, but I'm always getting the errors stack trace with console logs that I want to get rid of.
The idea is to create a Lead in our platform using any source, for example, Google Sheets.
When an invalid email is provided in the lead and posted to our API, I'm getting the expected message I want to display followed by the stack trace.
My custom error message is
INVALID FORMAT for email. Object didn't pass validation for format email: as1#mail.
But this is what I'm getting:
INVALID FORMAT for email. Object didn't pass validation for format email: as1#mail. What happened: Starting POST request to https://cosmo-charon-production.herokuapp.com/v1/lead/vehicle Received 500 code from https://cosmo-charon-production.herokuapp.com/v1/lead/vehicle?api-key=gIBp04HVdTgsHShJj6bXKwjbcxXTogsh after 62ms Received content "{"code":"SCHEMA_VALIDATION_FAILED","message":"Request validation failed: Parameter (lead) failed sch" INVALID FORMAT for email. Object didn't pass validation for format email: as1#mail. Console logs:
Image showing error displayed in Zapier
I've added a middleware for ErrorHandling into afterResponse, just as one of the examples provided in Zapier docs.
The function analyzeAndParse() receives an error object from the API and returns a string with the error message translated in a friendly way
const checkForErrors = (response, z) => {
// If we get a bad status code, throw an error, using the ErrorTranslator
if (response.status >= 300) {
throw new Error(analyzeAndParse(response.json))
}
// If no errors just return original response
return response
}
This is the code that creates a Lead in our platform, making a request to our API.
function createLead (z, bundle) {
const industry = bundle.inputData.industry
// add product to request based on the inputFields
leadType[industry].addProductFields(bundle.inputData)
const requestOptions = {
url: `${baseUrl}lead/${_.kebabCase(industry)}`,
method: 'POST',
body: JSON.stringify(checkSourceForCreate(bundle.inputData)),
headers: {
'content-type': 'application/json'
}
}
return z.request(requestOptions).then((response) => {
if (response.status >= 300) {
throw new Error(analyzeAndParse(response.content))
}
const content = JSON.parse(response.content)
if (content && content.leads) {
// get only the last lead from the list of leads
content.lead = content.leads[0]
delete content.leads
}
return content
})
}
Any ideas?
Thanks!

workbox offline response from IDB instead of cache

I am building an vueJs application with a service worker. I decided to use Workbox with an InjestManifest method to had my own routes.
on fetch when online :
1- answer with the network
2- wrtting body to IDB (through localforage)
3- send back the response
here everything is working perfectly, the sw intercepts the fetch and come back with an appropirate response, IDB contains rigth details.
response sent back to fecth when online:
Response {type: "cors", url: "http://localhost:3005/api/events", redirected: false, status: 200, ok: true, …}
the issue is when I go offline.
my intention id to connect to Locaforage and retrieve the content and build a response.
The issue is that this response is not considered as appropriate by Fetch who then reject it. Console.log confirms that the .catch in sw is working but it looks like the response it sends is rejected.
here is the console.log of the response I am sending back to fetch when offline;
Response {type: "default", url: "", redirected: false, status: 200, ok: true, …}
I do not know if fetch is not happy becasue the url of the repsonse is not the same as on the request but workbox is supposed to allow responding with other resposnes than the ones coming from cache or fetch.
here is the code
importScripts('localforage.min.js')
localforage.config({
name: 'Asso-corse'
})
workbox.skipWaiting()
workbox.clientsClaim()
workbox.routing.registerRoute(
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
workbox.strategies.cacheFirst({
cacheName: 'googleapis',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 30
})
]
})
)
workbox.routing.registerRoute( new RegExp('http://localhost:3005/api/'), function (event) {
fetch(event.url)
.then((response) => {
var cloneRes = response.clone()
console.log(cloneRes)
cloneRes.json()
.then((body) => {
localforage.setItem(event.url.pathname, body)
})
return response
})
.catch(function (error) {
console.warn(`Constructing a fallback response, due to an error while fetching the real response:, ${error}`)
localforage.getItem(event.url.pathname)
.then((res) => {
let payload = new Response(JSON.stringify(res), { "status" : 200 ,
"statusText" : "MyCustomResponse!" })
console.log(payload)
return payload
})
})
})
workbox.precaching.precacheAndRoute(self.__precacheManifest || [])
I am really stuck there as all documentation on workbox relates to leveraging cache. I am leveraging localforage as it supports promises which is what is required to make offline capability working.
Thanks
Your catch() handler needs to return either a Response object, or a promise for a Response object.
Adjusting the formatting of your sample code a bit, you're currently doing:
.catch(function (error) {
console.warn(`Constructing a fallback response, due to an error while fetching the real response:, ${error}`)
localforage.getItem(event.url.pathname).then((res) => {
let payload = new Response(JSON.stringify(res), { "status" : 200 , "statusText" : "MyCustomResponse!" })
console.log(payload)
return payload
})
})
Based on that formatting, I think it's clearer that you're not returning either a Response or a promise for a Response from within your catch() handler—you're not returning anything at all.
Adding in a return before your localforage.getItem(...) statement should take care of that:
.catch(function (error) {
console.warn(`Constructing a fallback response, due to an error while fetching the real response:, ${error}`)
return localforage.getItem(event.url.pathname).then((res) => {
let payload = new Response(JSON.stringify(res), { "status" : 200 , "statusText" : "MyCustomResponse!" })
console.log(payload)
return payload
})
})
But, as mentioned in the comments to your original question, I don't think that using IndexedDB to store this type of URL-addressable data is necessary. You can just rely on the Cache Storage API, which Workbox will happily use by default, when storing and retrieving JSON data obtained from an HTTP API.

Zapier JS Action to Fetch Klout Scores

I'm trying to create a Java Script Code Action on Zapier to fetch Klout Scores for any given Twitter user name...
I've realized that this needs to be done in 2 stages:
1) First get the Klout ID for any Twitter screen_name:
http://api.klout.com/v2/identity.json/twitter?screenName="+screen_name+"&key="+klout_apikey"
Klout replies back to that with JSon:
{"id":"85568398087870011","network":"ks"}
2) second get the Klout score for that Klout id:
http://api.klout.com/v2/user.json/"+klout.id+"/score?key="+klout_apikey"
Klout replies back to this with JSon:
{"score":65.68382904221806,"scoreDelta":{"dayChange":-0.03663891859041257,"weekChange":-0.5495711661078815,"monthChange":-1.4045672671990417},"bucket":"60-69"}
Of course, what I need is the "score":65.68382904221806 object of the JSon reply array.
I use these following JS functions proposed by #KayCee:
var klout_apikey = '<my klout api key>';
fetch("http://api.klout.com/v2/identity.json/twitter?screenName="+screen_name+"&key="+klout_apikey")
.then(function(res) {
return res.json();
})
.then(function(klout) {
console.log(klout);
if(klout.id) {
return fetch("http://api.klout.com/v2/user.json/"+klout.id+"/score?key="+klout_apikey")
}
}).then(function(res) {
return res.json();
}).then(function(body) {
// console.log(body.score);
//Here is where you are telling Zapier what you want to output.
callback(null, body.score)
}).catch(callback); //Required by Zapier for all asynchronous functions.
In the "input data" section of the Zapier code action i pass the screen_name as a variable:
screen_name: [the twitter handle]
What I get back is the following error message:
SyntaxError: Invalid or unexpected token
What is the error that you see? You could do this by simply using the fetch client. You might want to remove the variable declarations before adding this to the code step.
var inputData = {'screen_name': 'jtimberlake'}
//Remove the line above before pasting in the Code step. You will need to configure it in the Zap.
var klout_apikey = '2gm5rt3hsdsdrzgvnskmgm'; //Not a real key
fetch("http://api.klout.com/v2/identity.json/twitter?screenName="+inputData.screen_name+"&key="+klout_apikey)
.then(function(res) {
return res.json();
})
.then(function(body) {
console.log(body);
if(body.id) {
return fetch("http://api.klout.com/v2/user.json/"+body.id+"/score?key="+klout_apikey)
}
}).then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
//Here is where you are telling Zapier what you want to output.
callback(null, body)
}).catch(callback); //Required by Zapier for all asynchronous functions.
Refer to their documentation here - https://zapier.com/help/code/#introductory-http-example
Also refer to their Store client which allows you to store values (for cache) - https://zapier.com/help/code/#storeclient-javascript

Backbone.js: POST request with empty value

I am trying to make a POST request.
Here my code:
var myModel = new MydModel({
content: "ciao"
});
console.log(myModel.get("content")); // "ciao"
myModel.save();
If I look to the network activity it looks like this:
The response part {id:0, content:"", ……}
In the header part: Request Payload {"content":"ciao"}
Here my model:
define([], function () {
var MyModel = Backbone.Model.extend({
url: function url ()
{
return "http://localhost/users";
}
});
return MyModel;
});
Is it my problem or is it in the server part?
send/receive vs request/response
a server receives requests and sends responses
a client sends requests and receives responses
in short
if {id:0, content:"", ……} (the response) is wrong, it's your server
if {"content":"asdasdsa"} (the request) is wrong, it's your client
There is little problem with receiving JSON-payload that "Backbone-client" sends to your Apache-server.
All you need to do is to manually parse JSON-payload from input on the server side ("php://input", for PHP), like this:
if($_SERVER['REQUEST_METHOD'] == 'PUT' || $_SERVER['REQUEST_METHOD'] == 'POST') {
$postStr = file_get_contents("php://input");
//json_decode throws error or returns null if input is invalid json
try {
$json = json_decode($postStr, true);
if(empty($json)) {
throw new Exception("Not valid json");
}
//must not be json, try query str instead
} catch(Errfor $e) {
$postVars = parse_str($postStr);
foreach($postVars as $key=>$data) {
$_POST[$key] = $data;
}
}
}
Full explanation you can find here:
http://colinbookman.com/2014/04/08/php-puts-posts-and-backbone-js/

Resources