how to mock fetch api call using angular jasmine - unit-testing

I have service where javascript fetch is used to call an endpoints
How to mock fetch API calls in angular using jasmine
fetch('https://' + this.sericeOption.url + '/rest/ms/2/user',
{
method: 'PUT', headers: headers,
body: JSON.stringify(updatedUser)
}
).then((res) =>
{
return res.status != 200
? res.json()
.then((error) => Promise.reject
(
{ code: error.code, message: error.message })
)
: res.json();
});

Related

AWS Lambda Rerouting after Twitter Authorizing

I implemented a twitter login authorizer and I put an API route as the callback.
The Lambda function evoked on that route is the following:
const loginTwitterCallback = async (e, context) => {
const fetch = (...args) =>
import("node-fetch").then(({ default: fetch }) => fetch(...args));
const state = e.queryStringParameters.state;
const code = e.queryStringParameters.code;
try {
await fetch(
"https://api.twitter.com/2/oauth2/token?code=" +
code +
"&grant_type=authorization_code&client_id=" +
process.env.TWITTER_CLIENT_ID +
"&code_verifier=jwqoijoiw&redirect_uri=" + MY REDIRECT URI,
{
method: "POST",
headers: {
"Content-type": "application/x-www-form-urlencoded",
},
}
)
.then((res) => {
return res.json();
})
.then(async (data) => {
const accessToken = data.access_token;
return {
headers: {
Location:
"http://127.0.0.1:3000/auth/social?type=twitter&access_token=" +
encodeURIComponent(accessToken),
},
body: null,
statusCode: 302,
};
});
} catch (err) {
console.log(err);
}
};
Basically the user should be re-routed to the front-end where another POST request will be made to the API which will make a request to the Twitter API with the Bearer token and update the database.
The point is, I'm not being redirected to the front-end in the first place and I don't understand how to fix it.
Thanks a lot in advance.

React Native - Sending token to Django server

So I have this react native code that sends a token in string format, yes I've checked that var token = getAccessToken() is a string and I've console.log it to ensure it is a JWT token as well. But on the Django side when I check request.headers.get('Authorization', None) it outputs: 'Bearer [object Object]' what's going on?
React Native Code
import {Auth} from 'aws-amplify';
export async function getAccessToken() {
try {
const currentUser = await Auth.currentAuthenticatedUser();
console.log(currentUser);
Auth
.currentSession()
.then(res => {
let accessToken = res.getAccessToken();
// let jwt = accessToken.getJwtToken();
// You can print them to see the full objects
// console.log(`myAccessToken: ${JSON.stringify(accessToken)}`);
// console.log(`myJwt: ${JSON.stringify(jwt)}`);
console.log(accessToken.jwtToken)
return accessToken.jwtToken
});
} catch (error) {
console.log('error signing up:', error);
}
}
const getPosts = () => {
var token = getAccessToken();
const config = {
headers: { Authorization: `Bearer ` + token }
};
axios
.get(`${url}/posts`, config)
.then(response => {
console.log(response)
setData(response.data);
})
.catch(error => {
console.log(JSON.stringify(error));
});
}
I also tried
const config = {
headers: { Authorization: `Bearer ${token}` }
};
I also tried
function getPosts() {
var token = getAccessToken().then(token => {
const config = {
headers: {
Authorization: `Bearer ${token}`
}
};
console.log(token)
axios
.get(`${url}/posts`, config)
.then(response => {
console.log(response)
setData(response.data);
})
.catch(error => {
console.log(JSON.stringify(error));
});
}).catch(error => {
console.log(JSON.stringify(error));
});;
};
and console.log(token) is outputting "undefined"
Update getAccessToken to return result of
Auth .currentSession()
And
Make getPosts function async and await getAccessToken().
OR
Use the then block to result of promise
getAccessToken().then(token=>{ // Call the api },err=>{ // Handle the error }
Otherwise what you are getting is a promise that's not resolved yet.

What does JWT being stateless really means?

Hi and thanks in advance,
I've successfully setup JWT authentication using django-rest-framework-simplejwt and React but I'm still very confused about the advantages and specifically database hits.
I'm using simplejwt with ROTATE_REFRESH_TOKENS': True 'BLACKLIST_AFTER_ROTATION': True, when my access_token expire I ask for a new one through /api/token/refresh and it blacklist old tokens, I'm using axios interceptors to perform that automatically.
But in my understanding the benefits of JWt is that they are stateless, meaning I don't have to hit the user database table everytime I want to make an a request that needs authentication permission.
The problem is even with a simple view like this :
class IsConnecteddAPI(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request, *args, **kwargs):
data = "You seem to be connected"
return Response(data, status=status.HTTP_200_OK)
using django-silk I see that it still performs 1 query to my user table when I call it with a valid access token, is that normal ? If so why do we say that JWT are stateless ? I'm really confused.
That's my axios code if needed :
import axios from "axios";
const baseURL = "http://localhost:5000";
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
Authorization: localStorage.getItem("accesstoken")
? "JWT " + localStorage.getItem("accesstoken")
: null,
"Content-Type": "application/json",
accept: "application/json",
},
});
const axioAnonymousInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
"Content-Type": "application/json",
accept: "application/json",
},
});
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
async function (error) {
const originalRequest = error.config;
if (typeof error.response === "undefined") {
alert(
"A server/network error occurred. " +
"Looks like CORS might be the problem. " +
"Sorry about this - we will get it fixed shortly."
);
return Promise.reject(error);
}
if (
error.response.status === 401 &&
originalRequest.url === baseURL + "token/refresh/"
) {
window.location.href = "/login/";
return Promise.reject(error);
}
if (
error.response.data.code === "token_not_valid" &&
error.response.status === 401 &&
error.response.statusText === "Unauthorized"
) {
const refreshToken = localStorage.getItem("refreshtoken");
if (refreshToken) {
const tokenParts = JSON.parse(atob(refreshToken.split(".")[1]));
// exp date in token is expressed in seconds, while now() returns milliseconds:
const now = Math.ceil(Date.now() / 1000);
console.log(tokenParts.exp);
if (tokenParts.exp > now) {
return axioAnonymousInstance
.post("/api/token/refresh/", { refresh: refreshToken })
.then((response) => {
localStorage.setItem("accesstoken", response.data.access);
localStorage.setItem("refreshtoken", response.data.refresh);
axiosInstance.defaults.headers["Authorization"] =
"JWT " + response.data.access;
originalRequest.headers["Authorization"] =
"JWT " + response.data.access;
return axiosInstance(originalRequest);
})
.catch((err) => {
// redirect ro /login here if wanted
console.log("axios Safe Instance error");
console.log(err);
// window.location.href = "/login/";
});
} else {
console.log("Refresh token is expired", tokenParts.exp, now);
window.location.href = "/login/";
}
} else {
console.log("Refresh token not available.");
window.location.href = "/login/";
}
}
// specific error handling done elsewhere
return Promise.reject(error);
}
);
export { axiosInstance, axioAnonymousInstance };
( I know I shouldn't use localStorage but whatever )
and I would typically just call this function to make the simple request to the view written above :
const IsConnected = () => {
axiosInstance
.get("/api/is_connected/")
.then((response) => {
if (response.status === 200) {
console.log(response.data);
console.log("Is connected : CONNECTED ");
} else {
console.log("IS connected : not connected");
}
})
.catch((error) => {
console.log("Is connected : NOT CONNECTED");
console.log(error);
});
};
Without the specifics of the exact query hit your db, it's hard to tell what is happening (the db query must have originated from a middleware because there's nothing in your code that does it, and I suspect it's django's CsrfViewMiddleware). However, as for your question of JWT being stateless, I suggest you to take a look at the official introduction.
Basically, what happens with a JWT is that your server performs a signature verification on the token using your server's secret key (please beware of some problems). If the verification passes, then the data stored inside the JWT is trusted and read as is, which is why no database query is necessary. Of course, this does mean that your user will know exactly what is stored inside their token because the data is a simple base64 encoded JSON object.

How to fix "Unable to verify the first certificate" when testing axios-based API with JEST and axios-mock-adapter?

I'm using Jest and axios-mock-adapter to write tests for my API services. The problem is that when I run the test I get an error stating:
Error: unable to verify the first certificate.
app.service.js is the following
import ApiService from '#/services/api.service'
export default {
async loadDashboard (psRef) {
let result = await ApiService.get('user/' + psRef + '/dashboard')
.catch(error => {
console.error(error)
})
return result.data
}
}
api.service.js is where I create my axios instance like so
import Axios from 'axios'
const baseDomain = process.env.VUE_APP_BACKEND
const baseURL = `${baseDomain}${process.env.VUE_APP_API}`
export default Axios.create({
baseURL: baseURL,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
The test is the following:
const baseDomain = process.env.VUE_APP_BACKEND
const baseURL = `${baseDomain}${process.env.VUE_APP_API}`
test('loadDashboard should return the dashboard data for the user', async () => {
mock.onGet(`${baseURL}user/85/dashboard`).reply(200, { dashBoardData })
let response = await AppService.loadDashboard(85)
expect(response).toEqual(dashBoardData)
// AppService.loadDashboard(85).then(response => {
// expect(response.data).toEqual(dashBoardData)
// })
})
Does anybody know how to fix this error?

Angular 6 - Jasmine - mock httpClient get map and error flows

I'm new to Angular testing and am trying to figure out how to write a test that mocks an error response of HttpClient.get() function. Basically my service has both map() and catchError() inside of its pipe() and I would like to excercise both flows. Here's what I have so far:
my.service.ts:
getItems(): Observable<ItemViewModels[]> {
return
this.httpClient.get<any>(this.getItemsUrl)
.pipe(
map(json => {
return json.map(itemJson => this.getVmFromItemJson(itemJson));
}),
catchError(() => {
// Log stuff here...
return of(null);
})
);
}
my.service.spec.ts:
it('should catch error and return null if API returns error', () => {
spyOn(service.httpClient, 'get').and.returnValue(new Observable()); // Mock error here
service.getItems().subscribe($items => expect($items).toBe(null));
});
it('should return valid view model array if API returns a valid json', () => {
const mockResponse = [
new SideNavItemViewModel(1),
new SideNavItemViewModel(2),
new SideNavItemViewModel(3)
];
spyOn(service.httpClient, 'get').and.returnValue(of(JSON.stringify(mockResponse)));
service.getSidenavViewModel().subscribe(x => expect(x).toBe(mockResponse));
});
So the actual issue is that the observables that I mock for the httpClient to return on get in the unit tests don't seem to get into the .pipe() function, which means that my tests aren't working :(
Any ideas?
Thanks!
Have you tried injecting your service into the test? I also try test the function that subscribes to the api call instead of creating another subscribe:
for errors:
it('should display error when server error occurs',
inject([HttpTestingController, AService],
(httpMock: HttpTestingController, svc: MyService) => {
svc.getItems(); // has the subscribe in it
const callingURL = svc['API']; // your api call eg. data/items
httpMock.expectOne((req: HttpRequest < any > ) => req.url.indexOf(callingURL) !== -1)
.error(new ErrorEvent('Customer Error', {
error: 500
}), {
status: 500,
statusText: 'Internal Server Error'
});
httpMock.verify();
expect(component.svc.Jobs).toBeUndefined();
fixture.detectChanges();
// UI check here
}));
data test
it('should display the correct amount of data elements',
inject([HttpTestingController, AService],
(httpMock: HttpTestingController, svc: MyService) => {
svc.getItems(); // has the subscribe in it
const callingURL = svc['API']; // your api call eg. data/items
const mockReq = httpMock.expectOne((req: HttpRequest < any > ) => req.url.indexOf(callingURL) !== -1);
mockReq.flush(mockData);
httpMock.verify();
expect(component.svc.data.length).toBe(mockData.length);
fixture.detectChanges();
// UI check here
}));
So basically these functions:
call your get and subscribe
checks that your api url is contained in the http call
mocks the response - you pass in the data - 'mockData'
mockReq.flush(mockData); will trigger the call
httpMock.verify(); will check the url and other things
now the service data can be tested - if you subscribe sets anything in there
fixture.detectChanges(); - then this will allow to test ui components
I prefer this way because you can keep your logic and tests separate.