Flutter Unit test http mock returns 400 when it should return 200 - flutter

Not really sure what's going on, and every tutorial I find seems to set things up the same way.
Essentially I've mocked out an http.client using Mockito and I'm trying to stub an http get request like so:
test("Return 'has_on_boarded' when firebaseUid is valid", () async {
final client = MockClient();
const uid = "123";
when(client.get(Uri.parse("${dotenv.env['BASE_API_URL']}/users/$uid")))
.thenAnswer((_) async =>
http.Response('{"user":{"has_onboarded":true}}', 200));
expect(await UserRepository().initialize(client, uid), "has_on_boarded");
});
For some reason, I only get 400s and not the 200 or body I'm telling it to return with.
Update:
Here is the Flutter tutorial I'm using.
I did discover that using testwidgetsflutterbinding makes all http requests return 400, though since it is being mocked that seems weird.
I've removed that part, however, while it's no longer erroring http.Response('{"user":{"has_onboarded":true}} still resulting in {"user":{"has_onboarded":true}} being returned...

Related

Flutter async rest api call in synchronised way

I have an API to fetch results based on some user typed text. I want api calls to run in syncronized way so last API call result should be in last.
Use case
User type #cbc
API is calling 4 time
#, #c, #cb and #cbc
Issue is API result is giving result randomly not in syncronized way.
Future<void> getHashtags(String tagName) async {
var params = jsonEncode(
{"tag_name": tagName, "latest_hashtag_community": true});
var response = await _postRepository.getHashTags(params,
pageNo: pageNumberHashtags);
}

Workbox - NetworkOnly executes even if I return false

Using Workbox, I am trying to deal with graphql.
Anyone know why I am getting this error message from NetworkOnly? I am returning false in the route matcher, so I don't know why new NetworkOnly() is even executing. This only happens in offline mode (no network available).
The strategy could not generate a response for ... The underlying error is TypeError: Failed to fetch.
at NetworkOnly._handle (webpack://service-workers/./node_modules/workbox-strategies/NetworkOnly.js?:101:19)
at async NetworkOnly._getResponse (webpack://service-workers/./node_modules/workbox-strategies/Strategy.js?:155:24)
const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
maxRetentionTime: 24 * 60
});
const isGraphqlSubmitForm = async(event) => {
const clonedRequest = event.request.clone();
const body = await clonedRequest.json();
if (body?.operationName === 'submitForm') {
return true;
}
return false; // I MADE SURE THIS IS BEING RETURNED
};
registerRoute(
isGraphqlSubmitForm,
new NetworkOnly({
plugins: [bgSyncPlugin]
}),
'POST'
);
Sorry about that—you're seeing that behavior because the truthiness of the return value from this function is used to determine whether a route matches, and an async function always returns a Promise, which is a "truthy" value.
There's a log message that warns about this if you're in Workbox's development mode.
If it's possible for you to add in a header on the requests you want to match, that would probably be the easiest way to synchronously trigger your route, since any attempt to access a request body needs to be async. Failing that, the cleanest approach would be to just match all of your GraphQL requests with a given route, and then inside of that route's handler, use whatever async logic you need to trigger different strategies for different types of traffic.

How to pass json data to aws lambda through API Gateway?

I am trying to send the JSON to AWS lambda to trigger lambda handler. I am using Flutter web for this project and my API end point is as below. Below is my code to hit AWS lambda endpoint.
Future<String> getResponse(jsonData) async {
var response =
await http.post(Uri.parse("https://7jua06h1r4.execute-api.ap-south-1.amazonaws.com/stage1/calc"), headers: header, body: jsonData);
if (response.statusCode == 200) {
print("Success");
} else {
print("Error");
}
}
When I try to hit and get response using postman, everything works fine and i get 200 status with response as well. But when i test it using my browser, it display the body is empty. Can you help me out please? How can i pass JSON data through API Gateway to lambda?
{"statusCode": 200, "body": {}}
When i try using Postman, it works as expected. you can see in the image below:
[1]: https://i.stack.imgur.com/Tczfw.png
My Lambda function:
import json
import boto3
def lambda_handler(event, context):
print(event['body'])
# TODO implement
return {
'statusCode': 200,
'body': event['body']
}
Here, i am not able to get the body i.e. JSON Data from my app.
I think that in your code need to replace it:
print(event['body'])
by
print(event.body.body)
Event is not the call body, body is inside of that object and you have an attribute called body.
When you tested it using your browser, did you pass body to the url? Assuming that you just typed your url
https://7jua06h1r4.execute-api.ap-south-1.amazonaws.com/stage1/calc
into the browser, you would have gotten an empty body in response, which is the correct behaviour.

flutter http request/response details including headers?

while http request details can easily be inspected in browser dev tools(for web app), I tried to explore, where I can find the same for requests sent in flutter App, but couldn't locate it.
like for example - I can see the actual response from api by print(response), but I am talking about complete request response including headers.
I am using VScode IDE for Flutter.
update:
I want to view the headers sent like response.header. reason for the same is like I am using flutter cahe manager and the issue I am facing is like I have set the -cache control max-age=1.
so the flutter should try to fetch the same every time I access the page, which it is doing, but it is serving the page from the cache and then fetching the request. so if there is any change is on server side, it doesn't reflect when first open the page, but shows the change on every second visit.
so what I want is like if the flutter gets 304 response from server, it will serve from the cache else it should serve from the fetched data. but it is not happening.
also the response.header is not showing response code like it is 200 or 304, so that flutter can fetch or serve from cache.
Actual code being used is like this:
Future<MyUserProfile> fetchMyUserProfile() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
final userid = prefs.getString('user_id');
var userProfile = await DefaultCacheManager().getSingleFile("url");
final response = await userProfile.readAsString();
if (response != '') {
print(userProfile);
// If the server did return a 200 OK response,
// then parse the JSON.
return MyUserProfile.fromJson(json.decode(response));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load Profile');
}
}
Don't wanna be rude, but the information you are looking for is quite easy to find... That is if you look in the right place, like official documentation.
https://api.flutter.dev/flutter/dart-io/HttpResponse-class.html
HttpResponse class ... headers → HttpHeaders Returns the response
headers. [...] read-only
http.Response response = await http.get(url...
print(response.headers);
EDIT: Answering the sub-question that was added to the original question.
To check what the status code is you simply access it via response.statusCode
Example:
http.Response response = await http.get(url...
if (response.statusCode == 200) {
// do something
} else if (response.statusCode == 304) {
// do something else
} else {
// handle this
}

How do I use Futures in Futures in Flutter?

Soo, the title might be a bit confusing but let me clear that up right now.
I have a class called UserController which has a method called updateUserData. It gets a Map<String, dynamic> and updates the given attributes of a user with whatever is given in the value of the map.
What I wanted to do is: Send a patch request to the server, wait for the server to return a changed user object, write that to some local variable and return either the value or the error to whoever called that method (which in my case is a GUI class).
The current method as it is:
Future<User> updateUserData(Map<String, dynamic> changes) async {
return await http.patch(
"url",
headers: {HttpHeaders.authorizationHeader: "token"},
body: changesMap
).then((newUserObject) => {
currentUser = newUserObject;
//return new user object for display
}); //error from server gets forwarded to GUI.
}
Sadly this doesn't work at all. Seems like Flutter/dart doesn't know what to return there (it gives me a return_of_invalid_type_from_closure error).
I hope it's clear what my goal was. I want to use a "then" clause in this method but then still return a future which either contains the user I get from the server or the error I get.
How do I do that? I looked up so many Future tutorials so far and none used something similar.
You never need to use async/await with then. In your case, the simplest thing to do is await the response of your request, and then, put it to your local variable.
Then you just need to return the value.
Future<User> updateUserData(Map<String, dynamic> changes) async {
final response = await http.patch(
"url",
headers: {HttpHeaders.authorizationHeader: "token"},
body: changesMap,
);
// You need to parse the response to get your User object.
final responseJson = json.decode(response.body);
newUserObject = User.fromJson(responseJson);
currentUser = newUserObject;
return newUserObject;
}
If you need to decode your Map to a Class, you can see the answer given here