Way to log API response time in Cypress - api

I was trying to log the API response time in Cypress, but could not find any solution. What to use, cy.intercept() or cy.request()?
I was trying to use the advice like this:
cy.intercept('POST', '**/create-insurance-view-model', (req) => {
const start = Date.now()
req.continue(res => {
res.responseTime = Date.now() - start;
})
}).as('apiViewModel')
cy.wait('#apiViewModel').then(intercept => {
cy.log(`Time to get the license plate data was: ${intercept.response.responseTime} seconds`)
})
And I am getting undefined in the log.

There's two scenarios
there's a web page that calls an API and you want to test the response time. This scenario uses cy.intercept()
you have an API that you want to test directly (not called from a web page). This scenario uses cy.request() to start each API call.
Examples:
it('tests API response via web page', () => {
cy.intercept('api/resource/3', (req) => {
const start = Date.now()
req.continue(res => {
res.headers.responseTime = Date.now() - start;
})
}).as('apiCall')
cy.visit('/')
cy.wait('#apiCall').then(intercept => {
cy.log(intercept.response.headers.responseTime)
})
it('tests API response by direct call', () => {
const start = Date.now()
cy.request('api/resource/3')
.then(response) => {
const responseTime = Date.now() - start;
cy.log(responseTime)
})

Ok, so I solved it like this, thanks to the help from Paolo. Addes custom commands.
let responseTime
Cypress.Commands.add('inteceptasd', (method, request, apiVariable) => {
cy.intercept(method, request, (req) => {
const start = Date.now()
req.reply(() => {
responseTime = (Date.now() - start) / 1000
})
}).as(apiVariable)
})
Cypress.Commands.add('waitasd', (apiVariable, timeVariable, describe) => {
cy.wait(apiVariable).then(() => {
timeVariable = responseTime
cy.log(timeVariable)
cy.on('test:after:run', (test) => addContext({ test }, `Time to get the endpoint data ${apiVariable} was: ${timeVariable}s - ${describe}`))
})
})
Then I used it in test like this
cy.interceptForResponseTime('GET', '**/get-vehicle-identification*', 'apiVehicleByVin')
cy.get('cebia-price-loader > div > .btn').contains(domData.btnLoadPrice).should('exist').click()
cy.waitWithResponseTime('#apiVehicleByVin', 'timeVehicleByVin', 'description for this api time check')

Related

React-native-iap getAvailablePurchases() return empty array ios

I use auto renewal subscription with react-native-iap in my app
I need to check user has subscription on phone or not, for do this I use getAvailablePurchases()
like this
import * as RNIap from 'react-native-iap';
const init = await RNIap.initConnection();
if (init) {
await RNIap.getAvailablePurchases()
.then((resp) => {
const sortedAvailablePurchases = resp.sort(
(a, b) => b.transactionDate - a.transactionDate,
);
const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;
RNIap.endConnection();
return API({
method: 'POST',
url: '/subscription/check-receipt',
data: {
latestAvailableReceipt,
},
});
})
.catch((err) => {
RNIap.endConnection();
});
}
When I try to do this on my test device with sandbox, it works, but if I try to do this in the store build, I get the response - empty array
P.S I draw up subscription and then start testing

PWA fetch request in service worker sends "the site can't be reached" error on login with google the 2nd time

This error is really driving me crazy for the last 2 days. Please help.
So when I try to login with google the 1st time on my website, it doesn't cause any problem but when I try to do it the second time, with any account, it shows this error in the console:
The FetchEvent for "http://localhost:3000/auth/google/callback?code=4%2F0AX4somethingsomethingsomethingsomething&scope=profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile" resulted in a network error response: an object that was not a Response was passed to respondWith().
and the webpage shows this error:
This site can’t be reached The web page at http://localhost:3000/auth/google/callback?code=4%2F0AX4somethingsomethingsomethingsomething&scope=profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile might be temporarily down or it may have moved permanently to a new web address.
I am quite new to pwa and don't understand some of the code in the service worker file (I have copy pasted the 'fetch' part of the code from this webiste: blog.bitsrc.io) so that might be the reason I am not able to identify the error in the code. But you might identify it, this is my service worker code:
const staticCacheName = "site-static-v2";
const dynamicCacheName = "site-dynamic-v2";
const assets = ["/", "/stories", "/groups", "offline.html"];
// cache size limit function
const limitCacheSize = (name, size) => {
caches.open(name).then((cache) => {
cache.keys().then((keys) => {
if (keys.length > size) {
cache.delete(keys[0]).then(limitCacheSize(name, size));
}
});
});
};
// install event
self.addEventListener("install", (evt) => {
//console.log('service worker installed');
evt.waitUntil(
caches.open(staticCacheName).then((cache) => {
console.log("caching shell assets");
cache.addAll(assets);
})
);
});
// activate event
self.addEventListener("activate", (evt) => {
//console.log('service worker activated');
evt.waitUntil(
caches.keys().then((keys) => {
//console.log(keys);
return Promise.all(
keys
.filter((key) => key !== staticCacheName && key !== dynamicCacheName)
.map((key) => caches.delete(key))
);
})
);
});
// fetch events
self.addEventListener("fetch", function (event) {
event.respondWith(
fetch(event.request)
.catch(function () {
return caches.match(event.request);
})
.catch("offline.html")
);
});
This is my script in main.hbs (just like index.html).
if('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/serviceworker.js', { scope: '/' })
.then((reg) => console.log('Success: ', reg.scope))
.catch((err) => console.log('Failure: ', err));
})
}
I am making my website using express by the way.
I have tried pretty much every solution on stackoverflow but none seem to work.
Just for Information, I have also tried this for the 'fetch' part:
self.addEventListener('fetch', evt => {
evt.respondWith(
caches.match(evt.request).then(cacheRes => {
return cacheRes || fetch(evt.request).then(fetchRes => {
return caches.open(dynamicCacheName).then(cache => {
cache.put(evt.request.url, fetchRes.clone());
// check cached items size
limitCacheSize(dynamicCacheName, 15);
return fetchRes;
})
});
}).catch(() => {
return caches.match('offline.html');
})
);
}
);
(The above code also lets me login only once but doesn't let me logout unlike the previous code)
I have copy pasted almost every 'fetch' code on the internet but all of them have a problem with google auth (I am using passport for google auth).
This is my auth.js code:
const express = require("express");
const router = express.Router();
const passport = require("passport");
//Authenticate with google
//GET /auth/google
router.get("/google", passport.authenticate("google", { scope: ["profile"] }));
//Google auth callback
//GET /auth/google/callback
router.get(
"/google/callback",
passport.authenticate("google", { failureRedirect: "/" }),
function (req, res) {
// Successful authentication, redirect home.
res.redirect("/stories");
}
);
router.get("/logout", (req, res) => {
req.logout();
res.redirect("/");
});
module.exports = router;
You can also suggest a workaround with workbox

How to get total member count of any Discord server?

I'm trying to build a scraping script to get a bunch of Discord server's total members. I actually did that with Puppeteer like below but I think my IP address has been banned because I'm getting "Invite Invalid" error from Discord even though invite links are working.
My question is that does Discord have APIs to get any server's total member count? Or is there any 3rd party library for that purpose? Or any other method?
const puppeteer = require('puppeteer')
const discordMembers = async ({ server, browser }) => {
if (!server) return
let totalMembers
const page = await browser.newPage()
try {
await page.goto(`https://discord.com/invite/${server}`, {
timeout: 3000
})
const selector = '.pill-qMtBTq'
await page.waitForSelector(selector, {
timeout: 3000
})
const totalMembersContent = await page.evaluate(selector => {
return document.querySelectorAll(selector)[1].textContent
}, selector)
if (totalMembersContent) {
totalMembers = totalMembersContent
.replace(/ Members/, '')
.replace(/,/g, '')
totalMembers = parseInt(totalMembers)
}
} catch (err) {
console.log(err.message)
}
await page.close()
if (totalMembers) return totalMembers
}
const asyncForEach = async (array, callback) => {
for (let i = 0; i < array.length; i++) {
await callback(array[i], i, array)
}
}
const run = async () => {
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox']
})
const servers = ['tQp4pSE', '3P5K3dzgdB']
await asyncForEach(servers, async server => {
const members = await discordMembers({ server, browser })
console.log({ server, members })
// result
// { server: 'tQp4pSE', members: 57600 }
// { server: '3P5K3dzgdB', members: 159106 }
})
await browser.close()
}
run()
Update: Mar 22, 2022
Thanks for #Vaviloff's answer we can actually access Discord's private APIs but the problem is it's only accessible over browser. I'm getting Request failed with status code 400 issue from Axios. Is it a CORS issue? How do we get the results in a Node.js app?
const axios = require('axios')
const discordMembers = async ({ server }) => {
try {
const apiResult = await axios({
data: {},
method: 'get',
url: `https://discord.com/api/v9/invites/${server}?with_counts=true&with_expiration=true`
})
console.log(apiResult)
} catch (err) {
console.log(err)
}
}
discordMembers({ server: 'tQp4pSE' })
A lot of modern web applications have their own internal APIs. Oftentimes you can spot frontend making requests to it, by using Networking tab in Devtools (filter by Fetch/XHR type):
Such API endpoints can change any time of course, but usually the last for a long time and is a rather convenient way of scraping
Currently Discord uses this URL for basic instance description:
https://discord.com/api/v9/invites/tQp4pSE?with_counts=true&with_expiration=true
By accessing it you get the desired data:
Update
To make your code work don't send any data in the request:
const apiResult = await axios({
method: 'get',
url: `https://discord.com/api/v9/invites/${server}?with_counts=true&with_expiration=true`
})

How to fetch data from an API using express.js

API
(https://api.mosmarts.com/truck/v0/api.php)
The API is scripted in PHP and accepts GET & POST commands and in return it responds back with a JSON response data.
To retrieve data the API requires “functionality” and “action” among other params as show below.
Command for retrieving all truck
Command for retrieving all truck
Payloads
{
"functionality" : "get",
"action" : "get_all_truck"
}
Command to retrieving truck inspection details by id
Payloads
{
"functionality" : "get",
"action" : "get_inspection_history",
"truckId" : "1"
}
NB: you will get truckId from command "get_all_truck" above
What’s expected from you
As the software developer you are tasked to design and develop a web-based backend solution that will have:
Dashboard: -
• Retrieve and indicate total number of trucks
• Retrieve and indicate number of inspection repairs requested 2. List all Trucks: -
• Implement search option
Inspection List: -
• Implement filter by truck
i have some code using express.js bt i get is a 404 error, no data retrieved.
app.js
const apiCallFromRequest = require('./Request')
const apiCallFromNode = require('./NodeJsCall')
const http = require('http')
http.createServer((req, res) => {
if(req.url === "/request"){
apiCallFromRequest.callApi(function(response){
//console.log(JSON.stringify(response));
res.write(JSON.stringify(response));
res.end();
});
}
else if(req.url === "/node"){
apiCallFromNode.callApi(function(response){
res.write(response);
res.end();
});
}
// res.end();
}).listen(3000);
console.log("service running on 3000 port....");
NodeJsCall.js
const https = require('https');
_EXTERNAL_URL = 'https://api.mosmarts.com/truck/v0/api.php';
const callExternalApiUsingHttp = (callback) => {
https.get(_EXTERNAL_URL, (resp) => {
let data = '';
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
return callback(data);
// console.log(JSON.stringify(data));
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
}
module.exports.callApi = callExternalApiUsingHttp;
Request.js
const request = require('request');
_EXTERNAL_URL = 'https://api.mosmarts.com/truck/v0/api.php';
const callExternalApiUsingRequest = (callback) => {
request(_EXTERNAL_URL, { json: true }, (err, res, body) => {
if (err) {
return callback(err);
}
return callback(body);
});
}
module.exports.callApi = callExternalApiUsingRequest;
Hey Gerald you can find a simple response for this kind of question on google.
if you are a real beginner I would propose you the Axios npm.
here is an example of a really simple GET request with axios.
axios.get('https://api.github.com/users/mapbox')
.then(response => {
console.log(response.data.created_at);
});

Logging with express-winston: wrong order of logs

I'm using code like this:
const app = require('express')();
const winston = require('winston');
const expressWinston = require('express-winston');
app.use(expressWinston.logger({
transports: [
new winston.transports.Console(),
],
format: winston.format.combine(
winston.format.printf(info => `Date from winston: ${Date.now()} ${info.message}`),
),
expressFormat: true,
}));
app.get('/check', (req, res) => {
console.log(`Date from route: ${Date.now()}`);
res.end('OK');
});
app.listen(3000, () => console.log('Listening...'));
and when I try to call /check route, I get this in the console:
Date from route: 1588531901238
Date from winston: 1588531901247 GET /check 200 2ms
As you can see, time from middleware is later than time from route handler.
Why? How can I fix it? I need to get right order of passing middlewares.
Update
This feature doesn't exist in express-winston yet according to this issue.
A workaround could be that you add a middleware to express before your routes to intercept all request and then log the information you need through your custom logger or you create a custom transport in winston for that. A simple example is just
function logRequest(req, res, next) {
console.log('Request', req.path, Date.now());
next();
}
app.use(logRequest);
// routes...
Previous answer
Question 1:
As you can see, time from middleware is later than time from route
handler. Why?
Answer:
This because the console transport new winston.transports.Console() logs your HTTP reqest to the console and not your console.log(<some-text>). This is from the documentation of express-winston
Use expressWinston.logger(options) to create a middleware to log your
HTTP requests
To demonstrate this, lets take your code and see the result:
// Your above code here...
app.get('/check', (req, res) => {
console.log(`Date from route: ${Date.now()}`);
let i = 1;
const handle = setInterval(() => {
console.log('i:', i);
i++;
}, 1000);
setTimeout(() => {
console.log('i before response:', i);
clearInterval(handle);
res.end('OK');
}, 3000);
});
app.listen(3000, () => console.log('Listening...'));
Result
Listening...
Date from route: 1588616514869
i: 1
i: 2
i before response: 3
Date from winston: 1588616517889 GET /check 200 3005ms
From the result we see that you only get the custom message Date from winston: 1588616065807 from winston after you we call res.end('OK') instead of when we call console.log('Date from route: ${Date.now()}');.
Question 2:
How can I fix it?
Answer:
Rather than using the default console.log you create your own logger where you format the message and then stdout. Something like this:
const app = require('express')();
const winston = require('winston');
const { combine, timestamp, printf } = winston.format;
const myFormat = printf(({ message, timestamp }) => {
const customMessage = `Date from winston: ${timestamp}`;
return `${customMessage}\n${message}`;
});
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
],
format: combine(timestamp(), myFormat)
});
app.get('/check', (req, res) => {
logger.info(`Date from route: ${Date.now()}`);
let i = 1;
const handle = setInterval(() => {
console.log('i:', i);
i++;
}, 1000);
setTimeout(() => {
console.log('i before response:', i);
clearInterval(handle);
res.end('OK');
}, 3000);
});
app.listen(3000, () => console.log('Listening...'));
Result
Listening...
Date from winston: 2020-05-04T18:26:26.508Z
Date from route: 1588616786506
i: 1
i: 2
i before response: 3
In this case you see the formatted message displays when you call logger.info rather than when you call res.end('OK').
In summary use your custom logger to get the logs look the way you want.