Testcafe multiple requests to endpoint synchronously not working - testing

Currently I am setting up testcafe and have hit a hurdle when making a request to the same endpoint.
This is an authentication request. The steps are currently:
Initial request is sent to server which responds with a body. This is awaited
Once step is retrieved from step 1 this is mutated and sent back to the server.
We then the same endpoint and pass in the body generated in step 2
But I am having issues in the testcafe tests as it always using the first request and returns that twice.
I have referred to this issue on testcafe https://github.com/DevExpress/testcafe/issues/2477 however this did not work.
const mock = (mockResponse, status) => {
return RequestMock()
.onRequestTo(/\/apitest\/authenticate\)
.respond(mockResponse, status, {
"Access-Control-Allow-Origin": "http://localhost:3000",
"Access-Control-Allow-Credentials": "true"
});
};
const mock1 = mock(RESPONSE1, 200);
const mock2 = mock(RESPONSE2, 200);
test.requestHooks(mock1)(
"Should redirect to error if user has been suspended after submitting",
async t => {
const usernameInput = Selector("#username");
const mobileDigitOne = Selector("#mobile-digit-0");
const mobileDigitTwo = Selector("#mobile-digit-1");
const mobileDigitThree = Selector("#mobile-digit-2");
const submitButton = Selector("#submit-button");
await t
.typeText(usernameInput, "username123456")
.click(digits)
.typeText(digits, "123456")
.click(submitButton);
await t.removeRequestHooks(mock1);
await t.addRequestHooks(mock2);
Any ideas on how to request same endpoint multiple times?

You can distinguish different requests to the same endpoint using the request body. You can pass different kinds of filter to the mock's onRequestTo method, including a predicate function. Refer to the Filter with a Predicate article for more details.
Thus, you can use a single mock for both requests, like this:
function isTheSecondRequest(requestBody) {
// This should return `true` for the mutated request body
// and `false` for the original one.
//
// For example:
return requestBody.indexOf('{ foo: bar }') !== -1;
}
const mock = RequstMock()
.onRequestTo(request => {
request.url === '/apitest/authenticate' &&
!isTheSecondRequest(request.body)
})
.respond(RESPONSE1, 200, HEADERS)
.onRequestTo(request => {
request.url === '/apitest/authenticate' &&
isTheSecondRequest(request.body)
})
.respond(RESPONSE2, 200, HEADERS);

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().

Post request with useAxios

I am trying to use the composition api on my Vue app, and I need to do a post request to my backend api. I am trying to make use of the "useAxios" utility from vueuse, but I can't figure out how to pass data into a post request. It isn't shown properly in the docs...
I want to convert the following axios request into one that uses "useAxios".
await axios.put(`/blog/posts/${route.params.postID}/`, post.value)
.then(() => notification = "Post Created!")
.catch(() => {
error = "Failed to create post"
});
I tried setting the value of the data field, but that didn't work...
const {data, execute, isFinished} = useAxios(axios)
data.value = post
await execute(`/admin/blog/posts/${route.params.postID}/`, {method: "PUT"})
I also tried passing the post object into the execute method as a parameter, but my ide complained.
Thanks in advance!
Set up your pending request ahead of time:
const { data, execute, isFinished } =
useAxios(`/admin/blog/posts/${route.params.postID}/`,
{ method: "PUT" },
{ immediate:false });
Then in the future you can call it by passing the data as follows:
const requestBody = { /* your data */ };
await execute({ data: requestBody });

Managing Gcal Response + express and header issue

I'm new to node and banging my head against a wall on what should be a simple node+express+googlecal+pug issue
node/express route accepts requests and calls controller
controller ensures validation of auth and then...
executes a successful gcal function...console.log has the data i need
trying to directly (in controller function) returns "Cannot set headers after they are sent to the client"....why is a call to Gcal API forcing a response back to client?
Trying to make it more micro via individual calls to each function results in same result
What am I missing here?
getcalendars: async function(oAuth2Client, res) {
const calendar = google.calendar({ version: "v3", auth: oAuth2Client });
cal = await calendar.calendarList.list(
{},
(err, result) => {
//console.log("HEADERS SENT1?: "+res.headersSent);
if (err) {
console.log('The API returned an error: ' + err);
return;
}
console.log(JSON.stringify(result));
message2 = JSON.stringify(result)
res.render('schedules', {message2: message2})
return
});
},
EDIT: Calling function
router.route('/dashboard/schedules')
.get(async function(req, res) {
if (req.session.loggedin) {
//x = gcalController.getcalendars(req, res);
token = await gcalController.gettoken(req, res);
isAuth = await gcalController.calauth(token);
listcalendars = await gcalController.getcalendars(isAuth,res);
} else {
res.redirect("/?error=failedAuthentication")
//res.send('Please login to view this page!');
}
});
Can't set headers already sent happens when you're sending a response more than once. Usually you can terminate the function by returning your res.send() call.
It looks like the express middleware that created the res object is sending a response by the time your res.render() gets pulled out of the microtask queue.
Can you show the full code? It seems that this is probably originating in the scope where getcalendars is called.

Angular 10 get webservice status with Await?

Just before login in the user, I need to test if the WebServce respond then if the system is in maintenance. On the WebService part (core3 .net) I got 2 functions:
HeartBeat that return: return Ok("OK");
MaintenanceInfo that return Return OK("No");
I display in real time the result of the 2 tests and if no problems, I display the login panel.
I need to do these tests in sequence, I was thinking doing it with await operator.
I got a TestHelperServie class with 2 functions that return bool. But I can't find how to pass from a HTTP subscribe function to a bool result. With true if I got the OK response and false if I got a timeout or another fail HTTP.
For now I do this:
async TestHeartBeat()
{
let Response:Boolean = false;
const headers = new HttpHeaders()
.set('Content-Type','application/json');
const options = {
headers: headers,
observe: "response" as const,
responseType: "json" as const
};
await this.http.get(`${environment.apiUrl}/TestController/HeartBeat`, options)
.subscribe(res=>{
Response = true;
},
error=>{
Response = false;
})
return Respone;
}
But the function does not wait for the http response.
How can I fix this?
Sorry for my newbies question, but I came from the c# world and we use await/async a lot. I don't think I can do that the same way in angular 10.
You can not await on Observables, you have to convert it to promise using toPromise()
return await this.http.get(....).toPromise().then(res=> Response = true).catch(err => Response = false);
Use rxjs pipe, map and catchError.
async TestHeartBeat()
{
const headers = new HttpHeaders()
.set('Content-Type','application/json');
const options = {
headers: headers,
observe: "response" as const,
responseType: "json" as const
};
return await this.http.get(`${environment.apiUrl}/TestController/HeartBeat`, options)
.pipe(
map(res => true),
catchError(error => false)
).toPromise();
}
Now you can call it like the following:
if (await TestHeartBeat()) {
// Display your panel
} else {
// Service is in maintenance
}

Disable concurrent or simultaneous HTTP requests AXIOS

We are having a trouble with our refresh authentication token flow, where if multiple requests are made with the same expired access token at the same time, all of them would make backend to refresh the token and would have different refreshed tokens in their responses. Now when the next request is made, the refresh token of the last response would be used which may or may not be latest.
One solution to this problem is to have UI (which is using axios in vue) send only one request at a time. So if a token is refreshed, the following request would have the latest token.
Hence I am wondering if axios has a default option to disable simultaneous requests as I couldn't find anything online about it. Another solution would be to maintain a queue of requests, where each request is only sent when a response (either success or fail) is received for the previous request(manual option). I understand that this might decrease the performance as it may seem in the UI, but it would also take the load off backend.
One possible solution I found here is to use interceptor:
let isRefreshing = false;
let refreshSubscribers = [];
const instance = axios.create({
baseURL: Config.API_URL,
});
instance.interceptors.response.use(response => {
return response;
}, error => {
const { config, response: { status } } = error;
const originalRequest = config;
if (status === 498) { //or 401
if (!isRefreshing) {
isRefreshing = true;
refreshAccessToken()
.then(newToken => {
isRefreshing = false;
onRrefreshed(newToken);
});
}
const retryOrigReq = new Promise((resolve, reject) => {
subscribeTokenRefresh(token => {
// replace the expired token and retry
originalRequest.headers['Authorization'] = 'Bearer ' + token;
resolve(axios(originalRequest));
});
});
return retryOrigReq;
} else {
return Promise.reject(error);
}
});
subscribeTokenRefresh(cb) {
refreshSubscribers.push(cb);
}
onRrefreshed(token) {
refreshSubscribers.map(cb => cb(token));
}