Trying to set a cookie established on a web session as a header back to API - testing

I am trying to login via the webfront end and trying to intercept a cookie and then using that in the subsequent API request. I am having trouble getting the cookie back into the GET request. Code posted below.
import https from 'https';
import { bitbucketUser } from "../userRole.js"
import { ClientFunction } from 'testcafe';
fixture `Request/Response API`
// .page `https://myurl.company.com/login`
.beforeEach(async t => {
await t.useRole(bitbucketUser)
});
test('test', async t => {
const getCookie = ClientFunction(() => {
return document.cookie;
});
var mycookie = await getCookie()
const setCookie = ClientFunction(mycookie => {
document.cookie = mycookie;
});
var validatecookie = await getCookie()
console.log(validatecookie)
const executeRequest = () => {
return new Promise(resolve => {
const options = {
hostname: 'myurl.company.com',
path: '/v1/api/policy',
method: 'GET',
headers: {
'accept': 'application/json;charset=UTF-8',
'content-type': 'application/json'
}
};
const req = https.request(options, res => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
let body = "";
res.on("data", data => {
body += data;
});
res.on("end", () => {
body = JSON.parse(body);
console.log(body);
});
resolve();
});
req.on('error', e => {
console.error(e);
});
req.end();
});
};
await setCookie(mycookie)
await executeRequest();
});
I have tried several examples but am quite not able to figure what is it that I am missing.

When you call the setCookie method, you modify cookies in your browser using the ClientFunction.
However, when you call your executeRequest method, you run it on the server side using the nodejs library. When you set cookies on the client, this will not affect your request sent from the server side. You need to add cookie information directly to your options object as described in the following thread: How do I create a HTTP Client Request with a cookie?.

In TestCafe v1.20.0 and later, you can send HTTP requests in your tests using the t.request method. You can also use the withCredentials option to attach all cookies to a request.
Please also note that TestCafe also offers a cookie management API to set/get/delete cookies including HTTPOnly.

Related

refetch or poll an external api with fetch in svelte

New to Svelte and am running into some issues.
Currently doing the following in +page.server.js
I would like to poll this API every couple hundred milliseconds, I am unsure how to do that. I have tried using set Interval here to no avail.
export async function load({params}) {
const response = await fetch(
`http://localhost:9595/api/v1/chrysalis/example?uid=${params.uid}`
)
const site = await response.json()
const siteData = site[0]
console.log(siteData)
return {
uid: params.uid,
partitions: siteData.partitions,
zones: siteData.zones,
zTypes: siteData.zTypes,
zStates: siteData.zStates,
zNames: siteData.zNames
}
}
For example, I've built this in next.Js using SWR with refreshInterval: 1.
const {data, error, isLoading} = useSWR(
'http://localhost:9595/api/v1/chrysalis/example',
(url) => {
const searchParams = new URLSearchParams();
searchParams.append("uid", body.uid)
const newUrl = `${url}?${searchParams.toString()}`
const options = {
method: 'GET',
headers: {'Content-Type': 'application/json'},
}
return fetch(newUrl, options).then(res => res.json())
},
{
refreshInterval: 1
}
);
I have also tried to do the following onMount of the +page.svelte but when trying to hit the API from the client I get CORS error.( ran into this before if +page.js was not +page.server.js
let x;
onMount(async () => {
setInterval(async () => {
const response = await fetch(
`http://localhost:9595/api/v1/chrysalis/example?uid=${data.uid}`
)
const site = await response.json()
x = site[0]
console.log(x)
}, 3000)
})
The CORS error results because +page.svelte/+page.js are run in the browser. So you need to proxy the call through a service that allows being called from the browser. (Or relax the CORS restrictions on http://localhost:9595)
You can use SvelteKit itself to proxy the call by creating an internal endpoint. So:
The internal endpoint simply fetches http://localhost:9595/... and returns the results. (You can just forward the response object from fetch())
+page.svelte calls that internal endpoint from setInterval().

Why Axios is not providing response header when app is opening second time?

Here is my API request
const getData= async () => {
const cookie='workid_token=eyJra4rgrtF7SnlSETjIGrFYQy-P2SFmlE6A.Tw_rx0Ut_Kj9zLWRQ9X23w';
const qs = require('qs')
let body = qs.stringify({
gid: '1196'
})
await axios.post(
'https://www.google.com', body,
{
headers: {
'Cookie': cookie,
'Content-Type': 'application/x-www-form-urlencoded',
},
},
).then(response => {
console.log('data', response);
if (response.data.status === '1') {
const PHPSESSID = response.headers['set-cookie'];
var separatedvalue = PHPSESSID[0];
var sessid = separatedvalue.split('; path=/')[0];
}
}).catch(error => {
console.log(error);
});
};
I am implementing Axios API post request in my React Native application. When I run the application first time I am getting set-cookie value in response headers. If I kill the application and I open it second time I am not getting value in set-cookie. Also not receiving response from the API.
Note: I want to receive value from set-cookie all the times.

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 test `verify` of an express middleware in Jest

I have a function which returns a middleware as such:
const jsonParser = () => {
return express.json({
limit: '5mb',
verify: (req, res, buf) => {
// If the incoming request is a stripe event,
if (req.headers['some-header']) {
httpContext.set('raw-body', buf.toString());
}
},
});
};
I would like to test that the httpContext.setis indeed called when the some-header header is present.
My test:
describe('jsonParser middleware', () => {
it('sets the http context', async () => {
const req = {
headers: {
'some-header': 'some-sig',
'content-type': 'application/json',
},
body: JSON.stringify({
some: 'thing',
}),
};
const res = {};
const middleware = jsonParser();
middleware(req, res, () => {});
expect(httpContext.set).toHaveBeenCalled();
});
});
I have no idea how to make the test run the function passed to verify. Express docs state that the content type should be json, but nothing more. Anyone that can point me in the right direction is highly appreciated.
Thank you.
as mentioned in the comments i want to give you an example of an integration test which tests the header and jsonwebtoken. i am also using the express framework but i wrote my code in JS.
this is a test for creating a forumpost in a forum i built. a middleware is checking for the token of the user so this case could be similiar to yours.
const request = require('supertest');
test('create authorized 201', async () => {
const forumCountBefore = await ForumPost.countDocuments();
const response = await request(app)
.post('/api/forumPosts')
.set({
Authorization: `Bearer ${forumUserOne.tokens[0].token}`,
userData: {
userId: forumUserOneId,
email: 'forum#controller.com',
username: 'forum',
},
})
.send(forumPost)
.expect(201);
expect(response.body.message).toBe('created forumPost');
const forumCountAfter = await ForumPost.countDocuments();
expect(forumCountBefore + 1).toBe(forumCountAfter);
});
i am using mongoDB thats why i use ForumPost.countDocuments to count the amount of entries in the DB.
as you can see in the test i use supertest (imported as request) to send an http call. in the set block i set the authorization token. this causes the middleware to be executed in the integration test.
the test can only pass when the code of the middleware gets executed correctly so it should cover the code of your middleware.

How do you make a post request via Fetch in Nativescript?

I have a server.js file. With a post request (/login). It looks like this:
require('dotenv').config();
const express = require('express');
const mysql = require('mysql')
const app = express();
const PORT = process.env.PORT || 3000
app.listen(PORT, console.log(`Server started on port ${PORT}`))
app.post('/login', (req, res) => {
console.log("login")
console.log(req);
})
I also have a function in NativeScript that is supposed to make a post request (where the fetch is) when a button is pressed. It looks like this:
export function onLoginButtonTap() {
console.log("login button tapped")
const frame = Frame.getFrameById("mainFrame");
// TODO: user authentication
var userEmail = `${bindingContext.get('email')}`;
var userPassword = `${bindingContext.get('password')}`;
// make sure fields are filled out
if (userPassword === "" || userEmail === "") {
alert({
title: "Login Error",
message: "One or more fields is empty. Please fill in every field.",
okButtonText: "OK",
})
} else {
// TODO: post request (send user input to backend for verification)
console.log("here1")
const data = {userEmail, userPassword};
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
}
fetch("http://localhost:3000/login", options);
// if user is in database change page to home
frame.navigate("pages/home/home-page");
}
// navigates to home page without requiring login info (for testing)
frame.navigate("pages/home/home-page");
}
The post request doesn't work. I would like the console.logs in the server file to print the request. I think the problem is how I wrote the post request? Currently nothing happens.
Fetch return a promise, you need to resolve it to actually make the POST request. Try the following block of code.
fetch('http://localhost:3000/login', options)
.then((response) => response.json())
.then((result) => {
console.log('Success:', result);
})
.catch((error) => {
console.error('Error:', error);
});