I'm trying to test behaviour following a redirect request performed with fetch API.
I've been using sinon to mock window.fetch and have it return the desired response. Here's what I do, simplified:
windowFetch = sinon.stub(window, 'fetch');
windowFetch.withArgs('http://example.com/resource')
.returns(Promise.resolve(new Response(body, {
status: 200,
headers: new Headers(headers)
})));
This works fine for standard responses. To handle redirects I want to access the Response#url property but I haven't found a way to have it set in unit tests.
It's not possible to set it using the new Response() constructor and it's read only so I also can't do that.
Finally, I tried calling Response.redirect(toAddr) but it creates the redirect response and the one that follows. The one the browser transparently returns.
Related
In my sveltekit app I make AJAX calls to my api endpoints. For example:
+page.svelte
<script>
async function get_card() {
const url = '/api/card/?category=' + $page.params.slug;
const response = await fetch(url, {
method: 'GET',
})
const card = await response.json();
return card;
}
</script>
In the browser javascript console I get this warning:
Loading /api/card/?category=Neurology using `window.fetch`.
For best results, use the `fetch` that is passed to your `load`
function: https://kit.svelte.dev/docs/load#making-fetch-requests
But as far as I can tell, that fetch function is only accessible to me on the server, and I do not see a way to use it in a script that may run on the client (such as +page.svelte). I tried passing the function as part of the data object from load:
+layout.server.js
export const load = async ({ fetch, locals }) => {
return {
email: locals.user.email,
group: locals.user.group,
fetch: fetch
}
}
But, not surprisingly, that does not work since the function is not serializable.
Am I Doing It Wrong™, or should I just ignore the warning?
fetch is originally a browser API and SvelteKit defines it on the server as well, if it does not exist. The warning is there to tell you that you are creating another round trip to the server (one for the page and one for the data) when you possibly could have loaded the data on the server so it could be transmitted as part of the page (during server-side rendering).
If the code of your function is not executed right away, then this is a false positive (recent issue on this). I.e. if the data should be requested at a significantly later point, there is no way to bundle the request with the page.
(You are definitely not meant to pass on the fetch of load, you are supposed to use it to get the data.)
I am trying to get the axios to wait until one extra call in the interceptor finishes. So I am using NuxtJS as a frontend SPA and API in Laravel 8.
I've tried a lot of different things over the course of last ~ 4 days but nothing seems to be working.
THE GOAL
I need my axios REQUEST interceptor to check for existence of the cookie. If cookie is not present I need to make an API call first to grab the cookie and then we can continue with any other request.
WHAT I AM DOING?
So basically I have Axios interceptor for the requests that will call cookie endpoint if the cookie doesn't exist.
I am also saving cookie request promise to be reused in case there are multiple calls and the cookie still is not there.
PROBLEM
While it was supposed to just call cookie API first and everything else after I am mostly getting two results in different variations of the attached code.
A) I am making an extra cookie call but it is not in the required order so I still end up hitting laravel endpoint multiple times without cookies which causes extra sessions to spawn.
B) It is not making any calls at all (attached example).
Does anyone know what in the world I am confusing here?
export default function ({$axios, redirect, $cookiz, store}) {
$axios.onRequest(async request => {
// make sure that XSRF cookie exists before we make aby calls to prevent backend from
// creating multiple session when page on load calls more than one endpoint, if we don't have
// that cookie we will first have to get it and then call the rest of the endpoints
const xsrfCookie = $cookiz.get('XSRF-TOKEN')
if (xsrfCookie === undefined || xsrfCookie === null || xsrfCookie === '') {
await store.dispatch('login/getXsrfCookie')
$axios.request(request)
}
$axios.request(request)
})
}
getXsrfCookie(context) {
if (context.state.xsrfCookiePromise instanceof Promise) {
return context.state.xsrfCookiePromise
}
const xsrfCookiePromise = this.$axios.get('/csrf-cookie').then(response => {
context.commit('setXsrfCookiePromise', null)
console.log('This is the cookie response', response)
})
context.commit('setXsrfCookiePromise', xsrfCookiePromise)
return context.state.xsrfCookiePromise
}
I don't know anything about nuxt, and have only a vague idea about axios interceptors, but just looking at the code...
I think you want to persist a cookie, not the promise for a cookie.
I don't think you need to involve the store.
I think you can do that with your cookie plugin. If I'm right about that, using the set method is what you need. (you might need an options param, described here)
async getXsrfCookie() {
if (!$cookiz.get('XSRF-TOKEN')) {
// the op should double check which part of the response to persist, whether to stringify it, etc.
const response = await this.$axios.get('/csrf-cookie');
$cookiz.set('XSRF-TOKEN', response.data);
}
}
export default function ({$axios, redirect, $cookiz, store}) {
$axios.onRequest(async request => {
await getXsrfCookie();
return $axios.request(request)
})
}
I'm trying to figure out how to use 'googleapis' library with a lot of requests.
Initialize oauth2Client using 'googleapis' library
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
YOUR_CLIENT_ID,
YOUR_CLIENT_SECRET,
YOUR_REDIRECT_URL
);
Everything goes fine, then I take the refresh_token and save it somewhere in the database. Now with each user request, I need to somehow get the oauth2Client instance or create a new one via new(like from above) and pass the saved refresh_token via setCredentials
oauth2Client.setCredentials({
refresh_token: savedToken
});
in this case, a new access_token will be generated on every request, anyway now I can use library API to create requests by passing oauth2Client
const oauth2 = google.oauth2({
version: 'v2',
auth: oauth2Client
})
Well, first of all, is it normal to do this?
When using an already created (one instance), I'm afraid something may not work correctly and the request will be made with a different token.
and also with each request, since I pass the refresh_token, a new access_token will be created, which I also wanted to avoid.
It is desirable that I can use this library, and that the token is not refreshed with each request.
or maybe it's better to create a class in which I make requests myself, something like,
but in this case i need to control and refresh token manualy
class DocsGoogle {
...
getAll () {
// make HTTP request with tokens what needs and return
}
...
}
How is best to do this?
I'm wondering if there's any way to listen for console messages and act on console messages when they're received. Mainly, is there any way to do this without an external module, and using the http module?
The goal is to trigger a NodeJS function or code snippet on an event like click in the HTML. If there's also a way to do this, then that's great. But once again, I'd like to do this without an external module, and just use those that are built-in to NodeJS.
Use onclick() function in JavaScript to trigger a function call when clicking on a element. Then use fetch to make a api call to the nodejs server.
I know #Haris Wilson already got the answer, but I'd just like to provide a code example.
Instead of trying to catch a console message and then execute a function if we find it, we can use fetch() to make a request to whatever URL we need, and this can allow us to make other requests.
In this case, we can use the url module and the http module to parse the url and serve the API and website, respectively.
const url = require('url')
const http = require('http')
const requestListener = async function (req, res) {
// Basic server setup
res.writeHead(200, {
'Content-Type': 'text/html'
});
res.end(/** Content here */)
// API
if (url.parse(req.url, true).pathname === '/APIcall') {
let arguments = url.parse(req.url, true).query
// Preform necassary actions here
}
}
We can now use onClick to call a function inside our webpage JavaScript, and use fetch([API URL]) to give our NodeJS data to preform an action. We can use URL params to do this, such as https://localhost:8080/APIcall?data=someData&moreParam=more-data, where ?data=someData&moreParam=more-data are the URL params.
I'm trying to test my live web server data responses (e.g. no stubbing/mocking). I tried using cy.server() with cy.route(), but since the content type of the response is application/json apparently cy.server() does not cover this and the cypress error message tells me to use cy.request().
However, I can not use cy.wait() with cy.request() . I have to resort to nesting the second cy.request() in the callback of the first. Is there a way to not nest the second cy.request inside the callback of the first cy.request?
So in this contrived example, I need to grab the user data first before making the call to get book data. I could only get this to work by nesting the book request within the callback of the user request. I would prefer to use something akin to the cy.wait() API instead of nesting.
it(`should get book based on user`, () => {
cy.request({
url: `/user`,
}).as('user');
cy.get('#user').then((userResp) => {
const user = userResp.body;
cy.request({
url: `/user/${user.id}/book`,
}).as('userBook');
cy.get('#userBook').then((userBookResp) => {
cy.log(userBookResp);
});
});
});