How do I check network response in playwright? - testing

I want to test the network https status response with playwright.
test.only('Rights.2: Users without the required author role do not have access.', async ({page}) => {
await login(page, 'xxx', "password.xxx");
const search = await searchForProcess(page, `${process.process1.title}`);
await login(page, 'PortalUser');
const open = await openProcess(page, `${process.process1.title}`);
});
So I tried with this
expect(response.status()).toEqual(403);
But it won't work, because response is not defined. Thats curious, because Playwright does document the "response.status()" as a function.
Can somebody help?

You could try page.waitForResponse(). Official docs:
https://playwright.dev/docs/api/class-page#page-wait-for-response
Here is an example where we click a button and we want to monitor that certain API calls actually happen and that they have certain response statuses:
// Start waiting for all required API calls as we select company.
// We can accept only 200 but we could accept 403 like with /api/Environment/
await Promise.all([
page.waitForResponse(resp => resp.url().includes('/api/Environment/') && (resp.status() === 200 || resp.status() === 403)),
page.waitForResponse(resp => resp.url().includes('/api/Security/') && (resp.status() === 200)),
// We already started waiting before we perform the click that triggers the API calls. So now we just perform the click
page.locator('div[role="gridcell"]:has-text("text")').click()
]);
If you wish to validate other reponse data, see: https://playwright.dev/docs/api/class-response
If you want to monitor all network traffic, this official docs would be more suitable: https://playwright.dev/docs/network#network-events

Related

Axios onUploadProgress jumps at 100% even before the request is done

I have a controller that calls multiple external api from Gmail API concurrently, and then saves the retrieved data into the database, all of this in ONE post request.
To start, I pooled the external api requests, map the results and save it to db.
In my Controller:
$resp = Http::pool(fn (Pool $pool) [
$pool->as('pool-1')->withToken($user->token)->get('https://....call-1');
$pool->as('pool-2')->withToken($user->token)->get('https://....call-2');
$pool->as('pool-3')->withToken($user->token)->get('https://....call-3');
]);
collect($resp)->map(function ($req) {
Email::firstOrCreate(...);
})
In my vue component:
const config = {
onUploadProgress: progressEvent => {
console.log(`sent: ${Math.floor((progressEvent.loaded * 100) / progressEvent.total)}`)
}
}
axios.post(url, param, config).then(response => {}).catch(err => {})
Now, when I check in console.
It should be logging:
sent:0
sent:1
sent:2
...
sent:100
But instead, it automatically logs sent:100 even though the post request is still pending.
Is this a bug in chrome? or axios?, or perhaps it has something to do with external api calls?
Or if it isn't, can someone point out where I went wrong?

Using node-spotify-web-api to grant user access and fetch data

So I'm new to using OAuth and I honestly got quite lost trying to make this work. I looked up the documentation for Spotify's Authorization code and also found a wrapper for node which I used.
I want to be able to log in a user through spotify and from there do API calls to the Spotify API.
Looking through an example, I ended up with this code for the /callback route which is hit after the user is granted access and Spotify Accounts services redirects you there:
app.get('/callback', (req, res) => {
const { code, state } = req.query;
const storedState = req.cookies ? req.cookies[STATE_KEY] : null;
if (state === null || state !== storedState) {
res.redirect('/#/error/state mismatch');
} else {
res.clearCookie(STATE_KEY);
spotifyApi.authorizationCodeGrant(code).then(data => {
const { expires_in, access_token, refresh_token } = data.body;
// Set the access token on the API object to use it in later calls
spotifyApi.setAccessToken(access_token);
spotifyApi.setRefreshToken(refresh_token);
// use the access token to access the Spotify Web API
spotifyApi.getMe().then(({ body }) => {
console.log(body);
});
res.redirect(`/#/user/${access_token}/${refresh_token}`);
}).catch(err => {
res.redirect('/#/error/invalid token');
});
}
});
So above, at the end of the request the token is passed to the browser to make requests from there: res.redirect('/#/user/${access_token}/${refresh_token}');
What if insted of redirecting there, I want to redirect a user to a form where he can search for artists. Do I need so somehow pass the token around the params at all time? How would I redirect a user there? I tried simply rendering a new page and passing params there but it didn't work.
you could store the tokens in a variety of places, including the query parameters or cookies - but I'd recommend using localstorage. When your frontend loads the /#/user/${access_token}/${refresh_token} route, you could grab the values and store them in localstorage (e.g. localstorage.set('accessToken', accessToken)) and retrieve them later when you need to make calls to the API.

getaddrinfo ENOTFOUND API Google Cloud

I'm trying to execute API.AI tutorial for building a weather bot for Google Assistant (the one here: https://dialogflow.com/docs/getting-started/basic-fulfillment-conversation)
I made everything successfully, created the bot within API, created the Fulfillments, installed NodeJS on my pc, connected Google Cloud Platform, etc.
Then I created the index.js file by copying it exactly how it's stated on API.ai tutorial with my API key from World Weather Organisation (see below).
But when I use the bot, it doesn't work. On the Google Cloud Platform the error is always the same:
Error: getaddrinfo ENOTFOUND api.worldweatheronline.com
api.worldweatheronline.com:80
at errnoException (dns.js:28)
at GetAddrInfoReqWrap.onlookup (dns.js:76)
No matter how often I do it I get the same error. So I don't actually reach the API. I tried to see if anything changed from WWO side (URL, etc.) but apparently no. I updated NodeJS and still same issue. I refreshed the Google Cloud platform completely and didn't help.
That one I really can't debug. Could anyone help?
Here's the code from API.ai:
'use strict';
const http = require('http');
const host = 'api.worldweatheronline.com';
const wwoApiKey = '[YOUR_API_KEY]';
exports.weatherWebhook = (req, res) => {
// Get the city and date from the request
let city = req.body.result.parameters['geo-city']; // city is a required param
// Get the date for the weather forecast (if present)
let date = '';
if (req.body.result.parameters['date']) {
date = req.body.result.parameters['date'];
console.log('Date: ' + date);
}
// Call the weather API
callWeatherApi(city, date).then((output) => {
// Return the results of the weather API to Dialogflow
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ 'speech': output, 'displayText': output }));
}).catch((error) => {
// If there is an error let the user know
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ 'speech': error, 'displayText': error }));
});
};
function callWeatherApi (city, date) {
return new Promise((resolve, reject) => {
// Create the path for the HTTP request to get the weather
let path = '/premium/v1/weather.ashx?format=json&num_of_days=1' +
'&q=' + encodeURIComponent(city) + '&key=' + wwoApiKey + '&date=' + date;
console.log('API Request: ' + host + path);
// Make the HTTP request to get the weather
http.get({host: host, path: path}, (res) => {
let body = ''; // var to store the response chunks
res.on('data', (d) => { body += d; }); // store each response chunk
res.on('end', () => {
// After all the data has been received parse the JSON for desired data
let response = JSON.parse(body);
let forecast = response['data']['weather'][0];
let location = response['data']['request'][0];
let conditions = response['data']['current_condition'][0];
let currentConditions = conditions['weatherDesc'][0]['value'];
// Create response
let output = `Current conditions in the ${location['type']}
${location['query']} are ${currentConditions} with a projected high of
${forecast['maxtempC']}°C or ${forecast['maxtempF']}°F and a low of
${forecast['mintempC']}°C or ${forecast['mintempF']}°F on
${forecast['date']}.`;
// Resolve the promise with the output text
console.log(output);
resolve(output);
});
res.on('error', (error) => {
reject(error);
});
});
});
}
Oh boy, in fact the reason was most stupid ever. I didn't enable "billing" on Google Cloud Platform and that's why it blocked everything (even though I'm using a free test of the API). They just wanted my credit card number. It works now
I had the same issue trying to hit my db. Billing wasn't the fix as I had billing enabled already.
For me it was knexfile.js setup for MySql - specifically the connection object. In that object, you should replace the host key with socketPath; and prepend /cloudsql/ to the value. Here's an example:
connection: {
// host: process.env.APP_DB_HOST, // The problem
socketPath: `/cloudsql/${process.env.APP_DB_HOST}`, // The fix
database: process.env.APP_DB_NAME,
user: process.env.APP_DB_USR,
password: process.env.APP_DB_PWD
}
Where process.env.APP_DB_HOST is your Instance connection name.
PS: I imagine that even if you're not using Knex, the host or server parameter of a typical DB connectionstring will have to be called socketPath when connecting to Google Cloud SQL.

Where do you place NPM's request code?

I want to use the request module in my express app, but I am not sure where the actual requests code goes.
Usage:
When a user loads a page, make a GET request and populate the page with data.
When a users clicks on a item from a table, make a GET request.
When a user fills out a form, POST.
I tried searching for answers but it seems to be implied that the developer knows where to place the code.
Example of a code snippet using request that I am unsure where to place in the express app:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Show the HTML for the Google homepage.
}
})
I am guessing that I should not place the code in the server.js file especially if I am going to be making many different calls, but that's what it looks like others are doing on StackOverflow.
Does the request belong in a model?
If you are doing this in response to a user interaction, like clicking on something you can just do it from the route handler. Below, I just return the results to the client, or I pass an error to the next handler in the chain.
var request = require('request');
var express = require('express');
var app = express();
app.get('/click', function(req, res, next){
request('http://www.google.com', function (error, response, body) {
if (error || response.statusCode != 200)
return next(err);
response.send(body) // return the html to the client
})
});
app.listen(3000);
In bigger apps you might move routes into separate modules.

Using Node JS to proxy http and modify response

I'm trying to write a front end to an API service with Node JS.
I'd like to be able to have a user point their browser at my node server and make a request. The node script would modify the input to the request, call the api service, then modify the output and pass back to the user.
I like the solution here (with Express JS and node-http-proxy) as it passes the cookies and headers directly from the user through my site to the api server.
proxy request in node.js / express
I see how to modify the input to the request, but i can't figure out how to modify the response. Any suggestions?
transformer-proxy could be useful here. I'm the author of this plugin and I'm answering here because I found this page when looking for the same question and wasn't satisfied with harmon as I don't want to manipulate HTML.
Maybe someone else is looking for this and finds it useful.
Harmon is designed to plug into node-http-proxy https://github.com/No9/harmon
It uses trumpet and so is stream based to work around any buffering problems.
It uses an element and attribute selector to enable manipulation of a response.
This can be used to modify output response.
See here: https://github.com/nodejitsu/node-http-proxy/issues/382#issuecomment-14895039
http-proxy-interceptor is a middleware I wrote for this very purpose. It allows you to modify the http response using one or more transform streams. There are tons of stream-based packages available (like trumpet, which harmon uses), and by using streams you can avoid buffering the entire response.
var httpProxy = require('http-proxy');
var modifyResponse = require('http-proxy-response-rewrite');
var proxy = httpProxy.createServer({
target:'target server IP here',
});
proxy.listen(8001);
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
proxy.on('proxyRes', function (proxyRes, req, res) {
modifyResponse(res, proxyRes.headers['content-encoding'], function (body) {
if (body && (body.indexOf("<process-order-response>")!= -1)) {
var beforeTag = "</receipt-text>"; //tag after which u can add data to
// response
var beforeTagBody = body.substring(0,(body.indexOf(beforeTag) + beforeTag.length));
var requiredXml = " <ga-loyalty-rewards>\n"+
"<previousBalance>0</previousBalance>\n"+
"<availableBalance>0</availableBalance>\n"+
"<accuruedAmount>0</accuruedAmount>\n"+
"<redeemedAmount>0</redeemedAmount>\n"+
"</ga-loyalty-rewards>";
var afterTagBody = body.substring(body.indexOf(beforeTag)+ beforeTag.length)+
var res = [];
res.push(beforeTagBody, requiredXml, afterTagBody);
console.log(res.join(""));
return res.join("");
}
return body;
});
});